KMHomeQuickToolsCollectionView.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. //
  2. // KMHomeQuickToolsCollectionView.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lizhe on 2023/10/31.
  6. //
  7. import Cocoa
  8. typealias KMHomeQuickToolsCollectionViewDataDidChange = (_ view: KMHomeQuickToolsCollectionView, _ showData: [NSNumber]) ->Void
  9. class KMHomeQuickToolsCollectionView: BaseXibView {
  10. @IBOutlet weak var showBox: NSBox!
  11. @IBOutlet weak var showLabel: NSTextField!
  12. @IBOutlet weak var removeBox: NSBox!
  13. @IBOutlet weak var removeButton: NSButton!
  14. @IBOutlet weak var removeButtonLayoutConstraint: NSLayoutConstraint!
  15. @IBOutlet weak var showCollectionView: NSCollectionView!
  16. @IBOutlet weak var showScrollView: NSScrollView!
  17. @IBOutlet weak var hideBox: NSBox!
  18. @IBOutlet weak var hideLabel: NSTextField!
  19. @IBOutlet weak var addBox: NSBox!
  20. @IBOutlet weak var addButton: NSButton!
  21. @IBOutlet weak var addButtonLayoutConstraint: NSLayoutConstraint!
  22. @IBOutlet weak var hideCollectionView: NSCollectionView!
  23. @IBOutlet weak var hideScrollView: NSScrollView!
  24. @IBOutlet weak var promptLabel: NSTextField!
  25. @IBOutlet weak var showCollectionBox: NSBox!
  26. @IBOutlet weak var hideCollectionBox: NSBox!
  27. var dataChange: KMHomeQuickToolsCollectionViewDataDidChange?
  28. var indexPathsOfItemsBeingShowItemDragged: Set<IndexPath> = []
  29. var indexPathsOfItemsBeingHideItemDragged: Set<IndexPath> = []
  30. var showArray: [NSNumber] = []
  31. var hideArray: [NSNumber] = []
  32. var selectShowItemMutableArray: [IndexPath] = []
  33. var selectHideItemMutableArray: [IndexPath] = []
  34. var collectionItemWidth: CGFloat = 0
  35. let collectionItemHeight: CGFloat = 32
  36. func setup() {
  37. showLabel.stringValue = NSLocalizedString("Show", comment: "")
  38. hideLabel.stringValue = NSLocalizedString("Hide", comment: "")
  39. removeButton.title = NSLocalizedString("Remove", comment: "")
  40. addButton.title = NSLocalizedString("Add", comment: "")
  41. promptLabel.stringValue = NSLocalizedString("Drag and drop to add, remove and reorder the tools.", comment: "")
  42. promptLabel.textColor = KMAppearance.Layout.h1Color()
  43. showScrollView.drawsBackground = false
  44. hideScrollView.drawsBackground = false
  45. removeBox.borderColor = NSColor.gridColor
  46. addBox.borderColor = NSColor.gridColor
  47. removeBox.fillColor = NSColor.gridColor
  48. addBox.fillColor = NSColor.gridColor
  49. removeButton.isEnabled = false
  50. addButton.isEnabled = false
  51. let removeButtonConstant = labelReturnedValue(withString: NSLocalizedString("Remove", comment: ""), height: 20, fontSize: 11.0)
  52. let addButtonConstant = labelReturnedValue(withString:NSLocalizedString("Add", comment: ""), height: 20.0, fontSize: 11.0)
  53. var constant: CGFloat = 0
  54. if removeButtonConstant > addButtonConstant {
  55. constant = removeButtonConstant + 30
  56. } else {
  57. constant = addButtonConstant + 30
  58. }
  59. removeButtonLayoutConstraint.constant = constant
  60. addButtonLayoutConstraint.constant = constant
  61. showCollectionView.enclosingScrollView?.scrollerStyle = .legacy
  62. hideCollectionView.enclosingScrollView?.scrollerStyle = .legacy
  63. let shadow = NSShadow()
  64. shadow.shadowColor = KMAppearance.Status.hovColor()
  65. shadow.shadowOffset = NSMakeSize(0, 1)
  66. showCollectionBox.wantsLayer = true
  67. showCollectionBox.shadow = shadow
  68. hideCollectionBox.wantsLayer = true
  69. hideCollectionBox.shadow = shadow
  70. showCollectionView.register(KMHomeQuickToolsWindowCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("KMHomeQuickToolsWindowCollectionViewItem"))
  71. hideCollectionView.register(KMHomeQuickToolsWindowCollectionViewItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("KMHomeQuickToolsWindowCollectionViewItem"))
  72. showCollectionView.delegate = self
  73. showCollectionView.dataSource = self
  74. hideCollectionView.delegate = self
  75. hideCollectionView.dataSource = self
  76. showCollectionView.layer?.cornerRadius = 3.0
  77. hideCollectionView.layer?.cornerRadius = 3.0
  78. registerForCollectionViewDragAndDrop()
  79. // self.showCollectionView.reloadData()
  80. // self.hideCollectionView.reloadData()
  81. }
  82. func showData(showArr: [NSNumber], hideArr: [NSNumber]) {
  83. collectionItemWidth = self.itemReturnedWidthValue(withShowArray: showArr, hideArray: hideArr, fontSize: 12, height: collectionItemHeight) + 40
  84. showArray = showArr
  85. hideArray = hideArr
  86. }
  87. func registerForCollectionViewDragAndDrop() {
  88. showCollectionView.registerForDraggedTypes([NSPasteboard.PasteboardType.string])
  89. showCollectionView.setDraggingSourceOperationMask(.every, forLocal: false)
  90. showCollectionView.setDraggingSourceOperationMask(.every, forLocal: true)
  91. hideCollectionView.registerForDraggedTypes([NSPasteboard.PasteboardType.string])
  92. hideCollectionView.setDraggingSourceOperationMask(.every, forLocal: false)
  93. hideCollectionView.setDraggingSourceOperationMask(.every, forLocal: true)
  94. }
  95. func moveCell(fromIndex: Int, toIndex: Int, collectionView: NSCollectionView) {
  96. if collectionView == showCollectionView {
  97. let fromNumber = showArray[fromIndex]
  98. var currentIndex = fromIndex
  99. if fromIndex <= toIndex {
  100. for _ in fromIndex..<toIndex {
  101. currentIndex = showArray.firstIndex(of: fromNumber) ?? fromIndex
  102. if currentIndex < toIndex {
  103. showArray.swapAt(currentIndex, currentIndex + 1)
  104. currentIndex += 1
  105. }
  106. }
  107. } else {
  108. for _ in toIndex..<fromIndex {
  109. currentIndex = showArray.firstIndex(of: fromNumber) ?? fromIndex
  110. if currentIndex > toIndex {
  111. showArray.swapAt(currentIndex, currentIndex - 1)
  112. currentIndex -= 1
  113. }
  114. }
  115. }
  116. } else if collectionView == hideCollectionView {
  117. let fromNumber = hideArray[fromIndex]
  118. var currentIndex = fromIndex
  119. if fromIndex <= toIndex {
  120. for _ in fromIndex..<toIndex {
  121. currentIndex = hideArray.firstIndex(of: fromNumber) ?? fromIndex
  122. if currentIndex < toIndex {
  123. hideArray.swapAt(currentIndex, currentIndex + 1)
  124. currentIndex += 1
  125. }
  126. }
  127. } else {
  128. for _ in toIndex..<fromIndex {
  129. currentIndex = hideArray.firstIndex(of: fromNumber) ?? fromIndex
  130. if currentIndex > toIndex {
  131. hideArray.swapAt(currentIndex, currentIndex - 1)
  132. currentIndex -= 1
  133. }
  134. }
  135. }
  136. }
  137. }
  138. func labelReturnedValue(withString value: String, height: CGFloat, fontSize: CGFloat) -> CGFloat {
  139. if let value = value as NSString? {
  140. let rect = value.boundingRect(with: CGSize(width: .greatestFiniteMagnitude, height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: fontSize)], context: nil)
  141. return rect.size.width
  142. }
  143. return 0
  144. }
  145. }
  146. extension KMHomeQuickToolsCollectionView {
  147. @IBAction func removeButtonAction(_ sender: Any) {
  148. for indexPath in selectShowItemMutableArray {
  149. let itemCount = indexPath.item
  150. hideArray.append(showArray[itemCount])
  151. showArray.remove(at: itemCount)
  152. }
  153. removeBox.borderColor = NSColor.gridColor
  154. removeButton.isEnabled = false
  155. addBox.borderColor = NSColor.gridColor
  156. addButton.isEnabled = false
  157. hideCollectionView.reloadData()
  158. showCollectionView.reloadData()
  159. guard let callBack = dataChange else { return }
  160. callBack(self, showArray)
  161. }
  162. @IBAction func addButtonAction(_ sender: Any) {
  163. for indexPath in selectHideItemMutableArray {
  164. let itemCount = indexPath.item
  165. showArray.append(hideArray[itemCount])
  166. hideArray.remove(at: itemCount)
  167. }
  168. removeBox.borderColor = NSColor.gridColor
  169. addButton.isEnabled = false
  170. addBox.borderColor = NSColor.gridColor
  171. removeButton.isEnabled = false
  172. showCollectionView.reloadData()
  173. hideCollectionView.reloadData()
  174. guard let callBack = dataChange else { return }
  175. callBack(self, showArray)
  176. }
  177. }
  178. extension KMHomeQuickToolsCollectionView: NSCollectionViewDelegate, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout {
  179. func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
  180. let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "KMHomeQuickToolsWindowCollectionViewItem"), for: indexPath) as! KMHomeQuickToolsWindowCollectionViewItem
  181. if collectionView.isEqual(showCollectionView) {
  182. item.model = KMQucikToolsModel(type: DataNavigationViewButtonActionType(rawValue: Int(truncating: showArray[indexPath.item])))
  183. } else if collectionView.isEqual(hideCollectionView) {
  184. item.model = KMQucikToolsModel(type: DataNavigationViewButtonActionType(rawValue: Int(truncating: hideArray[indexPath.item])))
  185. }
  186. return item
  187. }
  188. func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
  189. if collectionView.isEqual(showCollectionView) {
  190. return showArray.count
  191. } else if collectionView.isEqual(hideCollectionView) {
  192. return hideArray.count
  193. }
  194. return 0
  195. }
  196. func collectionView(_ collectionView: NSCollectionView, didSelectItemsAt indexPaths: Set<IndexPath>) {
  197. let indexPathArr = Array(indexPaths)
  198. if collectionView.isEqual(showCollectionView) {
  199. self.selectShowItemMutableArray.removeAll()
  200. if self.showArray.count > 6 {
  201. removeBox.borderColor = KMAppearance.Layout.h2Color()
  202. removeButton.isEnabled = true
  203. }
  204. for indexPath in indexPathArr {
  205. self.selectShowItemMutableArray.append(indexPath)
  206. }
  207. } else if collectionView.isEqual(hideCollectionView) {
  208. self.selectHideItemMutableArray.removeAll()
  209. addBox.borderColor = KMAppearance.Layout.h2Color()
  210. addButton.isEnabled = true
  211. for indexPath in indexPathArr {
  212. self.selectHideItemMutableArray.append(indexPath)
  213. }
  214. }
  215. }
  216. func collectionView(_ collectionView: NSCollectionView, layout collectionViewLayout: NSCollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> NSSize {
  217. return NSSize(width: collectionItemWidth, height: collectionItemHeight)
  218. }
  219. // NSCollectionViewDelegate Drag-and-Drop Methods
  220. func collectionView(_ collectionView: NSCollectionView, canDragItemsAt indexPaths: Set<IndexPath>, with event: NSEvent) -> Bool {
  221. return true
  222. }
  223. func collectionView(_ collectionView: NSCollectionView, pasteboardWriterForItemAt indexPath: IndexPath) -> NSPasteboardWriting? {
  224. return String(indexPath.item) as NSPasteboardWriting
  225. }
  226. func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItemsAt indexPaths: Set<IndexPath>) {
  227. if collectionView.isEqual(showCollectionView) {
  228. indexPathsOfItemsBeingShowItemDragged = indexPaths
  229. } else if collectionView.isEqual(hideCollectionView) {
  230. indexPathsOfItemsBeingHideItemDragged = indexPaths
  231. }
  232. }
  233. func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
  234. if collectionView.isEqual(showCollectionView) {
  235. // if self.showArray.count <= 6 {
  236. // return NSDragOperation(rawValue: 0)
  237. // }
  238. if indexPathsOfItemsBeingShowItemDragged.count != 0 {
  239. return .move
  240. } else {
  241. return .copy
  242. }
  243. } else if collectionView.isEqual(hideCollectionView) {
  244. if indexPathsOfItemsBeingHideItemDragged.count != 0 {
  245. return .move
  246. } else {
  247. if self.showArray.count <= 6 {
  248. return NSDragOperation(rawValue: 0)
  249. }
  250. return .copy
  251. }
  252. }
  253. return []
  254. }
  255. func collectionView(_ collectionView: NSCollectionView, acceptDrop draggingInfo: NSDraggingInfo, indexPath: IndexPath, dropOperation: NSCollectionView.DropOperation) -> Bool {
  256. var result = false
  257. if collectionView.isEqual(showCollectionView) {
  258. if indexPathsOfItemsBeingShowItemDragged.count != 0 {
  259. var toItemIndex = indexPath.item
  260. for fromIndexPath in indexPathsOfItemsBeingShowItemDragged {
  261. let fromItemIndex = fromIndexPath.item
  262. if fromItemIndex > toItemIndex {
  263. moveCell(fromIndex: fromItemIndex, toIndex: toItemIndex, collectionView: collectionView)
  264. collectionView.animator().moveItem(at: fromIndexPath, to: IndexPath(item: toItemIndex, section: indexPath.section))
  265. toItemIndex += 1
  266. }
  267. }
  268. var adjustedToItemIndex = indexPath.item
  269. for fromIndexPath in indexPathsOfItemsBeingShowItemDragged.reversed() {
  270. let fromItemIndex = fromIndexPath.item
  271. if fromItemIndex < adjustedToItemIndex {
  272. if adjustedToItemIndex >= showArray.count {
  273. adjustedToItemIndex = showArray.count - 1
  274. }
  275. moveCell(fromIndex: fromItemIndex, toIndex: adjustedToItemIndex, collectionView: collectionView)
  276. let adjustedToIndexPath = IndexPath(item: adjustedToItemIndex, section: indexPath.section)
  277. collectionView.animator().moveItem(at: fromIndexPath, to: adjustedToIndexPath)
  278. adjustedToItemIndex -= 1
  279. }
  280. }
  281. result = true
  282. } else if indexPathsOfItemsBeingHideItemDragged.count != 0 {
  283. let toItemIndex = indexPathsOfItemsBeingHideItemDragged.first!.item
  284. showArray.insert((hideArray[toItemIndex] as! Int) as NSNumber, at: indexPath.item)
  285. hideArray.remove(at: toItemIndex)
  286. result = true
  287. self.dataChange?(self, showArray)
  288. }
  289. } else if collectionView.isEqual(hideCollectionView) {
  290. if indexPathsOfItemsBeingHideItemDragged.count != 0 {
  291. var toItemIndex = indexPath.item
  292. for fromIndexPath in indexPathsOfItemsBeingHideItemDragged {
  293. let fromItemIndex = fromIndexPath.item
  294. if fromItemIndex > toItemIndex {
  295. moveCell(fromIndex: fromItemIndex, toIndex: toItemIndex, collectionView: collectionView)
  296. collectionView.animator().moveItem(at: fromIndexPath, to: IndexPath(item: toItemIndex, section: indexPath.section))
  297. toItemIndex += 1
  298. }
  299. }
  300. var adjustedToItemIndex = indexPath.item - 1
  301. for fromIndexPath in indexPathsOfItemsBeingHideItemDragged.reversed() {
  302. let fromItemIndex = fromIndexPath.item
  303. if fromItemIndex < adjustedToItemIndex {
  304. if adjustedToItemIndex >= showArray.count {
  305. adjustedToItemIndex = showArray.count - 1
  306. }
  307. moveCell(fromIndex: fromItemIndex, toIndex: adjustedToItemIndex, collectionView: collectionView)
  308. let adjustedToIndexPath = IndexPath(item: adjustedToItemIndex, section: indexPath.section)
  309. collectionView.animator().moveItem(at: fromIndexPath, to: adjustedToIndexPath)
  310. adjustedToItemIndex -= 1
  311. }
  312. }
  313. result = true
  314. } else if indexPathsOfItemsBeingShowItemDragged.count != 0 {
  315. if self.showArray.count <= 6 {
  316. return false
  317. }
  318. let toItemIndex = indexPathsOfItemsBeingShowItemDragged.first!.item
  319. hideArray.insert((showArray[toItemIndex] as! Int) as NSNumber, at: indexPath.item)
  320. showArray.remove(at: toItemIndex)
  321. result = true
  322. self.dataChange?(self, showArray)
  323. }
  324. }
  325. return result
  326. }
  327. func collectionView(_ collectionView: NSCollectionView, draggingSession session: NSDraggingSession, endedAt screenPoint: NSPoint, dragOperation operation: NSDragOperation) {
  328. if collectionView.isEqual(showCollectionView) {
  329. indexPathsOfItemsBeingShowItemDragged.removeAll()
  330. removeBox.borderColor = KMAppearance.Layout.h2Color()
  331. removeButton.isEnabled = false
  332. } else if collectionView.isEqual(hideCollectionView) {
  333. indexPathsOfItemsBeingHideItemDragged.removeAll()
  334. addBox.borderColor = KMAppearance.Layout.h2Color()
  335. addButton.isEnabled = false
  336. }
  337. showCollectionView.reloadSections(IndexSet(integer: 0))
  338. hideCollectionView.reloadSections(IndexSet(integer: 0))
  339. }
  340. }
  341. extension KMHomeQuickToolsCollectionView {
  342. func itemReturnedWidthValue(withShowArray showArr: [Any], hideArray hideArr: [Any], fontSize: CGFloat, height: CGFloat) -> CGFloat {
  343. var itemWidth: CGFloat = 0.0
  344. if showArr.count != 0 {
  345. for number in showArr {
  346. let value = KMQucikToolsModel(type: DataNavigationViewButtonActionType(rawValue: Int(truncating: number as! NSNumber))).titleString()
  347. let rect = value.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: fontSize)], context: nil)
  348. if itemWidth < rect.size.width {
  349. itemWidth = rect.size.width
  350. }
  351. }
  352. }
  353. if hideArr.count != 0 {
  354. for number in hideArr {
  355. let value = KMQucikToolsModel(type: DataNavigationViewButtonActionType(rawValue: Int(truncating: number as! NSNumber))).titleString()
  356. let rect = value.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: NSFont.systemFont(ofSize: fontSize)], context: nil)
  357. if itemWidth < rect.size.width {
  358. itemWidth = rect.size.width
  359. }
  360. }
  361. }
  362. return itemWidth
  363. }
  364. }