ComponentInputNumber.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. //
  2. // ComponentInputNumber.swift
  3. // KMComponentLibrary
  4. //
  5. // Created by Niehaoyu on 2024/8/27.
  6. //
  7. import Cocoa
  8. import AppKit
  9. @objc public protocol ComponentInputNumberDelegate: AnyObject {
  10. @objc optional func componentInputNumberDidValueChanged(inputNumber: ComponentInputNumber?)
  11. }
  12. public class ComponentInputNumber: ComponentBaseXibView {
  13. @IBOutlet var contendBox: NSBox!
  14. @IBOutlet var lefticonImage: NSImageView!
  15. @IBOutlet var righticonImage: NSImageView!
  16. @IBOutlet var inputField: ComponentTextField!
  17. @IBOutlet var stepperView: ComponentStepper!
  18. @IBOutlet var errorTipLabel: NSTextField!
  19. @IBOutlet var contendBoxBottomConst: NSLayoutConstraint!
  20. @IBOutlet var stepperHeightConst: NSLayoutConstraint!
  21. @IBOutlet var inputFieldLeftConst: NSLayoutConstraint!
  22. @IBOutlet var inputFieldRightConst: NSLayoutConstraint!
  23. // MARK: Private Property
  24. private var _properties : ComponentInputNumberProperty = ComponentInputNumberProperty()
  25. private let formatter = ComponentNumberFormatter()
  26. weak open var delegate: ComponentInputNumberDelegate?
  27. // MARK: 初始化
  28. deinit {
  29. NotificationCenter.default.removeObserver(self)
  30. }
  31. public required init?(coder decoder: NSCoder) {
  32. super.init(coder: decoder)
  33. }
  34. override init(frame frameRect: NSRect) {
  35. super.init(frame: frameRect)
  36. }
  37. public override func awakeFromNib() {
  38. super.awakeFromNib()
  39. // formatter.regexString = "^[0123456789]*$"
  40. // formatter.controlSize = true
  41. //
  42. // self.inputField.formatter = formatter
  43. self.inputField.componentDelegate = self
  44. self.inputField.focusRingType = .none
  45. self.stepperView.componentDelegate = self
  46. NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidBeginEditingNotification(_:)), name: NSControl.textDidBeginEditingNotification, object: inputField)
  47. NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChangeNotification(_:)), name: NSControl.textDidChangeNotification, object: inputField)
  48. NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidEndEditingNotification(_:)), name: NSControl.textDidEndEditingNotification, object: inputField)
  49. }
  50. // MARK: - Set & Get
  51. public var properties : ComponentInputNumberProperty {
  52. get {
  53. return _properties
  54. }
  55. set {
  56. _properties = newValue
  57. ComponentLibrary.shared.configInputNumberComponent(properties: _properties)
  58. self.reloadData()
  59. }
  60. }
  61. public func reloadData() {
  62. self.setupUI()
  63. self.refreshUI()
  64. }
  65. func setupUI() {
  66. if self.properties.size == .m {
  67. self.stepperHeightConst.constant = 28
  68. } else if self.properties.size == .s {
  69. self.stepperHeightConst.constant = 24
  70. }
  71. self.inputField.alignment = properties.alignment
  72. if self.properties.showPrefix == true {
  73. self.lefticonImage.isHidden = false
  74. self.inputFieldLeftConst.constant = 32
  75. } else {
  76. self.lefticonImage.isHidden = true
  77. self.inputFieldLeftConst.constant = 8
  78. }
  79. if self.properties.showSuffix == true {
  80. self.righticonImage.isHidden = false
  81. self.inputFieldRightConst.constant = 56
  82. } else {
  83. self.righticonImage.isHidden = true
  84. self.inputFieldRightConst.constant = 32
  85. }
  86. self.reloadStepperViewEnable()
  87. self.inputField.stringValue = properties.text ?? ""
  88. self.inputField.placeholderString = String(format: "%d~%d", self.properties.minSize, self.properties.maxSize)
  89. formatter.minSize = properties.minSize
  90. formatter.maxSize = properties.maxSize
  91. }
  92. func refreshUI() {
  93. if self.properties.isError == true && properties.showErrorInfo {
  94. self.errorTipLabel.isHidden = false
  95. self.contendBoxBottomConst.constant = 18
  96. } else {
  97. self.errorTipLabel.isHidden = true
  98. self.contendBoxBottomConst.constant = 0
  99. }
  100. self.contendBox.cornerRadius = self.properties.propertyInfo.cornerRadius
  101. self.contendBox.borderWidth = self.properties.propertyInfo.borderWidth
  102. var fillColor = NSColor.clear
  103. var borderColor = NSColor.clear
  104. if self.properties.state == .normal {
  105. fillColor = (self.properties.propertyInfo.color_nor)
  106. borderColor = (self.properties.propertyInfo.borderColor_nor)
  107. } else if self.properties.state == .hover {
  108. fillColor = (self.properties.propertyInfo.color_hov)
  109. if self.properties.isError == true {
  110. fillColor = (self.properties.propertyInfo.color_error_hov)
  111. }
  112. borderColor = (self.properties.propertyInfo.borderColor_hov)
  113. } else if self.properties.state == .pressed {
  114. fillColor = (self.properties.propertyInfo.color_active)
  115. borderColor = (self.properties.propertyInfo.borderColor_active)
  116. }
  117. if self.properties.isDisabled == true {
  118. fillColor = (self.properties.propertyInfo.color_dis)
  119. borderColor = (self.properties.propertyInfo.borderColor_dis)
  120. }
  121. if self.properties.isError == true {
  122. borderColor = (self.properties.propertyInfo.borderColor_error)
  123. }
  124. self.contendBox.fillColor = fillColor
  125. self.contendBox.borderColor = borderColor
  126. if self.properties.isDisabled == false {
  127. self.inputField.isEditable = true
  128. } else {
  129. self.inputField.isEditable = false
  130. }
  131. self.inputField.font = self.properties.propertyInfo.textFont
  132. self.errorTipLabel.textColor = self.properties.propertyInfo.errorTipTextColor
  133. self.errorTipLabel.font = self.properties.propertyInfo.errorTipTextFont
  134. }
  135. func reloadStepperViewEnable() {
  136. if self.properties.isDisabled == true {
  137. self.stepperView.upEnable = false
  138. self.stepperView.downEnable = false
  139. } else {
  140. self.stepperView.upEnable = true
  141. self.stepperView.downEnable = true
  142. let curValue = self.inputField.intValue
  143. if curValue >= self.properties.maxSize {
  144. self.stepperView.upEnable = false
  145. self.stepperView.downEnable = true
  146. }
  147. if curValue <= self.properties.minSize {
  148. self.stepperView.upEnable = true
  149. self.stepperView.downEnable = false
  150. }
  151. }
  152. self.stepperView.reloadData()
  153. }
  154. func inputFieldStringDidChanged() {
  155. if self.inputField.stringValue.isEmpty {
  156. self.properties.isError = false
  157. } else {
  158. if properties.valueType == .intType {
  159. let curValue = self.inputField.intValue
  160. if curValue > self.properties.maxSize ||
  161. curValue < self.properties.minSize {
  162. self.properties.isError = true
  163. } else {
  164. self.properties.isError = false
  165. }
  166. }
  167. }
  168. self.reloadStepperViewEnable()
  169. if inputField.stringValue.isEmpty == false {
  170. if properties.valueType == .intType {
  171. let curValue: Int = Int(inputField.stringValue) ?? 0
  172. if curValue > properties.maxSize {
  173. inputField.stringValue = properties.text ?? ""
  174. } else if curValue < properties.minSize {
  175. inputField.stringValue = properties.text ?? ""
  176. }
  177. }
  178. properties.text = inputField.stringValue
  179. } else {
  180. inputField.stringValue = properties.text ?? ""
  181. }
  182. self.delegate?.componentInputNumberDidValueChanged?(inputNumber: self)
  183. }
  184. //MARK: - TextNotification
  185. @objc func textFieldDidBeginEditingNotification(_ notification: Notification) {
  186. }
  187. @objc func textFieldDidChangeNotification(_ notification: Notification) {
  188. self.inputFieldStringDidChanged()
  189. self.refreshUI()
  190. }
  191. @objc func textFieldDidEndEditingNotification(_ notification: Notification) {
  192. self.inputField.isResponder = false
  193. if self.properties.isDisabled == false {
  194. self.properties.state = .normal
  195. }
  196. self.refreshUI()
  197. self.inputFieldStringDidChanged()
  198. }
  199. //MARK: - MouseEvent
  200. public override func mouseEntered(with event: NSEvent) {
  201. super.mouseEntered(with: event)
  202. if self.properties.isDisabled == false &&
  203. self.inputField.isResponder == false {
  204. self.properties.state = .hover
  205. }
  206. self.refreshUI()
  207. }
  208. public override func mouseMoved(with event: NSEvent) {
  209. super.mouseMoved(with: event)
  210. }
  211. public override func mouseExited(with event: NSEvent) {
  212. super.mouseExited(with: event)
  213. if self.properties.isDisabled == false &&
  214. self.inputField.isResponder == false{
  215. self.properties.state = .normal
  216. }
  217. self.refreshUI()
  218. }
  219. public override func mouseDown(with event: NSEvent) {
  220. super.mouseDown(with: event)
  221. }
  222. public override func mouseUp(with event: NSEvent) {
  223. super.mouseUp(with: event)
  224. if self.properties.isDisabled == false &&
  225. self.inputField.isResponder == false {
  226. self.properties.state = .normal
  227. }
  228. self.refreshUI()
  229. }
  230. }
  231. extension ComponentInputNumber: ComponentTextFieldDelegate {
  232. func componentTextFieldDidResponderChanged(textField: NSTextField) {
  233. if self.properties.isDisabled == false {
  234. if self.inputField.isResponder {
  235. self.properties.state = .pressed
  236. } else {
  237. self.properties.state = .normal
  238. }
  239. }
  240. self.refreshUI()
  241. }
  242. }
  243. extension ComponentInputNumber: ComponentStepperDelegate {
  244. func componentStepperDidIncrease(stepper: ComponentStepper) {
  245. if properties.valueType == .intType {
  246. let curValue = self.inputField.intValue + 1
  247. self.inputField.stringValue = String(curValue)
  248. } else if properties.valueType == .floatType {
  249. let curValue = self.inputField.floatValue + 0.1
  250. self.inputField.stringValue = String(format: "%.1f", curValue)
  251. }
  252. self.inputFieldStringDidChanged()
  253. self.reloadStepperViewEnable()
  254. }
  255. func componentStepperDidDecrease(stepper: ComponentStepper) {
  256. if properties.valueType == .intType {
  257. let curValue = self.inputField.intValue
  258. self.inputField.stringValue = String(curValue-1)
  259. } else if properties.valueType == .floatType {
  260. let curValue = self.inputField.floatValue - 0.1
  261. self.inputField.stringValue = String(format: "%.1f", curValue)
  262. }
  263. self.inputFieldStringDidChanged()
  264. self.reloadStepperViewEnable()
  265. }
  266. }