KMNBotaSearchTopView.swift 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. //
  2. // KMNBotaSearchTopVIew.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by User-Tangchao on 2024/12/1.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. enum KMNBotaSearchTopItemKey: Int {
  10. case search = 1
  11. case replace = 2
  12. case `switch` = 3
  13. case previous = 4
  14. case next = 5
  15. case replaceText
  16. case replaceAllText
  17. }
  18. class KMNBotaSearchTopView: NSView, NibLoadable {
  19. @IBOutlet weak var topBox: NSBox!
  20. @IBOutlet weak var centerBox: NSBox!
  21. @IBOutlet weak var bottomBox: NSBox!
  22. @IBOutlet weak var centerHeightConst: NSLayoutConstraint!
  23. var itemClick: KMCommonClickBlock?
  24. var valueDidChange: KMValueDidChangeBlock?
  25. var replaceValueDidChange: KMValueDidChangeBlock?
  26. private var topHeight_: CGFloat = 40
  27. private var centerHeight_ : CGFloat = 72
  28. private var bottomHeight_: CGFloat = 32
  29. private var vSpace_: CGFloat = 8
  30. private lazy var searchButton_: ComponentButton = {
  31. let view = ComponentButton()
  32. view.properties = ComponentButtonProperty(type: .text_gray, size: .xxxs, state: .normal, onlyIcon: true, icon: NSImage(named: "KMImageNameBotaSearch"))
  33. view.setTarget(self, action: #selector(searchAction))
  34. return view
  35. }()
  36. private lazy var searchInput_: NSTextField = {
  37. let view = NSTextField()
  38. view.placeholderString = KMLocalizedString("Search (⌥⌘F)")
  39. view.isBordered = false
  40. view.drawsBackground = false
  41. view.delegate = self
  42. return view
  43. }()
  44. private lazy var replaceButton_: ComponentButton = {
  45. let view = ComponentButton()
  46. view.properties = ComponentButtonProperty(type: .text_gray_low, size: .xxs, state: .normal, onlyIcon: true, icon: NSImage(named: "KMImageNameBotaSearchReplace"), keepPressState: false)
  47. view.setTarget(self, action: #selector(replaceAction))
  48. return view
  49. }()
  50. private lazy var switchButton_: ComponentButton = {
  51. let view = ComponentButton()
  52. view.properties = ComponentButtonProperty(type: .text_gray_low, size: .xxs, state: .normal, onlyIcon: true, icon: NSImage(named: "KMImageNameBotaSearchSwitch"), keepPressState: false)
  53. view.setTarget(self, action: #selector(switchAction))
  54. return view
  55. }()
  56. private lazy var centerView_: KMNSearchReplaceItemView = {
  57. let view = KMNSearchReplaceItemView()
  58. return view
  59. }()
  60. private lazy var resultLabel_: NSTextField = {
  61. let view = NSTextField(labelWithString: "")
  62. view.font = ComponentLibrary.shared.getFontFromKey("mac/body-xs-medium")
  63. return view
  64. }()
  65. private lazy var previousButton_: ComponentButton = {
  66. let view = ComponentButton()
  67. view.properties = ComponentButtonProperty(type: .text_gray_low, size: .xxxs, state: .normal, onlyIcon: true, icon: NSImage(named: "KMImageNameBotaSearchPreviousDisable"), keepPressState: false)
  68. view.setTarget(self, action: #selector(previousAction))
  69. return view
  70. }()
  71. private lazy var nextButton_: ComponentButton = {
  72. let view = ComponentButton()
  73. view.properties = ComponentButtonProperty(type: .text_gray_low, size: .xxxs, state: .normal, onlyIcon: true, icon: NSImage(named: "KMImageNameBotaSearchNext"), keepPressState: false)
  74. view.setTarget(self, action: #selector(nextActon))
  75. return view
  76. }()
  77. private lazy var bottomLine_: NSView = {
  78. let view = NSView()
  79. view.wantsLayer = true
  80. return view
  81. }()
  82. var searchInput: NSTextField {
  83. get {
  84. return searchInput_
  85. }
  86. }
  87. var replaceInput: ComponentInput {
  88. get {
  89. return centerView_.input
  90. }
  91. }
  92. var replaceButton: ComponentButton {
  93. get {
  94. return centerView_.replaceButton
  95. }
  96. }
  97. var replaceAllButton: ComponentButton {
  98. get {
  99. return centerView_.replaceAllButton
  100. }
  101. }
  102. var previousButton: ComponentButton {
  103. get {
  104. return previousButton_
  105. }
  106. }
  107. var nextButton: ComponentButton {
  108. get {
  109. return nextButton_
  110. }
  111. }
  112. var resultLabel: NSTextField {
  113. get {
  114. return resultLabel_
  115. }
  116. }
  117. var bottomLine: NSView {
  118. get {
  119. return bottomLine_
  120. }
  121. }
  122. var inputValue: String? {
  123. get {
  124. return searchInput_.stringValue
  125. }
  126. set {
  127. searchInput_.stringValue = newValue ?? ""
  128. }
  129. }
  130. var replaceText: String? {
  131. get {
  132. return centerView_.inputValue
  133. }
  134. set {
  135. centerView_.inputValue = newValue ?? ""
  136. }
  137. }
  138. override func draw(_ dirtyRect: NSRect) {
  139. super.draw(dirtyRect)
  140. // Drawing code here.
  141. }
  142. override func awakeFromNib() {
  143. super.awakeFromNib()
  144. initSubviews()
  145. }
  146. func initSubviews() {
  147. topBox.borderWidth = 0
  148. topBox.contentView?.addSubview(searchButton_)
  149. searchButton_.km_add_leading_constraint(constant: 12)
  150. searchButton_.km_add_size_constraint(size: NSSize(width: 16, height: 16))
  151. searchButton_.km_add_centerY_constraint()
  152. topBox.contentView?.addSubview(searchInput_)
  153. searchInput_.km_add_leading_constraint(equalTo: searchButton_, attribute: .trailing, constant: 8)
  154. searchInput_.km_add_centerY_constraint()
  155. searchInput_.km_add_height_constraint(constant: 20)
  156. searchInput_.km_add_trailing_constraint(constant: -76)
  157. topBox.contentView?.addSubview(switchButton_)
  158. switchButton_.km_add_trailing_constraint(constant: -12)
  159. switchButton_.km_add_centerY_constraint()
  160. switchButton_.km_add_size_constraint(size: NSSize(width: 24, height: 24))
  161. topBox.contentView?.addSubview(replaceButton_)
  162. replaceButton_.km_add_trailing_constraint(equalTo: switchButton_, attribute: .leading, constant: -8)
  163. replaceButton_.km_add_centerY_constraint()
  164. replaceButton_.km_add_size_constraint(size: NSSize(width: 24, height: 24))
  165. topBox.contentView?.addSubview(bottomLine_)
  166. bottomLine.km_add_leading_constraint()
  167. bottomLine.km_add_trailing_constraint()
  168. bottomLine.km_add_height_constraint(constant: 2)
  169. bottomLine.km_add_bottom_constraint()
  170. centerBox.isHidden = true
  171. centerBox.borderWidth = 0
  172. centerBox.contentView = centerView_
  173. centerView_.itemClick = { [unowned self] idx, _ in
  174. if idx == 1 {
  175. replaceAllButton.properties.state = .normal
  176. replaceAllButton.reloadData()
  177. itemClick?(KMNBotaSearchTopItemKey.replaceAllText.rawValue)
  178. } else if idx == 2 {
  179. replaceButton.properties.state = .normal
  180. replaceButton.reloadData()
  181. itemClick?(KMNBotaSearchTopItemKey.replaceText.rawValue)
  182. }
  183. }
  184. centerView_.valueDidChange = { [unowned self] value, _ in
  185. if let data = value as? String {
  186. replaceValueDidChange?(replaceInput, [.newKey : replaceInput.properties.text])
  187. }
  188. }
  189. bottomBox.isHidden = true
  190. bottomBox.borderWidth = 0
  191. bottomBox.contentView?.addSubview(resultLabel_)
  192. resultLabel_.km_add_top_constraint(constant: 16)
  193. resultLabel_.km_add_leading_constraint(constant: 16)
  194. bottomBox.contentView?.addSubview(nextButton_)
  195. nextButton_.km_add_trailing_constraint(constant: -16)
  196. nextButton_.km_add_top_constraint(constant: 16)
  197. nextButton_.km_add_size_constraint(size: .init(width: 16, height: 16))
  198. bottomBox.contentView?.addSubview(previousButton_)
  199. previousButton_.km_add_trailing_constraint(equalTo: nextButton_, attribute: .leading, constant: -8)
  200. previousButton_.km_add_top_constraint(constant: 16)
  201. previousButton_.km_add_size_constraint(size: .init(width: 16, height: 16))
  202. }
  203. func showSearch() {
  204. centerBox.isHidden = true
  205. centerHeightConst.constant = 0
  206. }
  207. func showReplace() {
  208. centerBox.isHidden = false
  209. centerHeightConst.constant = centerHeight_
  210. }
  211. func showResult(type: KMNBotaSearchType) {
  212. bottomBox.isHidden = false
  213. }
  214. func hideResult(type: KMNBotaSearchType) {
  215. bottomBox.isHidden = true
  216. }
  217. func fetchContentHeight(type: KMNBotaSearchType, hasResult: Bool) -> CGFloat {
  218. var height: CGFloat = topHeight_
  219. if type == .search {
  220. } else if type == .replace {
  221. height += centerHeight_
  222. }
  223. height += (hasResult ? bottomHeight_+vSpace_ : 0)
  224. return height
  225. }
  226. // MARK: - Actions
  227. @objc func searchAction() {
  228. itemClick?(KMNBotaSearchTopItemKey.search.rawValue, searchButton_)
  229. }
  230. @objc func replaceAction() {
  231. itemClick?(KMNBotaSearchTopItemKey.replace.rawValue)
  232. }
  233. @objc func switchAction() {
  234. itemClick?(KMNBotaSearchTopItemKey.switch.rawValue)
  235. }
  236. @objc func previousAction() {
  237. itemClick?(KMNBotaSearchTopItemKey.previous.rawValue)
  238. }
  239. @objc func nextActon() {
  240. itemClick?(KMNBotaSearchTopItemKey.next.rawValue)
  241. }
  242. }
  243. extension KMNBotaSearchTopView: NSTextFieldDelegate {
  244. func controlTextDidChange(_ obj: Notification) {
  245. if searchInput_.isEqual(to: obj.object) {
  246. valueDidChange?(searchInput_, [.newKey : searchInput_.stringValue])
  247. }
  248. }
  249. }