DoubleClickHandler.swift 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. //
  2. // Copyright © 2022 osy. All rights reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. import SwiftUI
  17. // from https://gist.github.com/joelekstrom/91dad79ebdba409556dce663d28e8297
  18. extension View {
  19. /// Adds a double click handler this view (macOS only)
  20. ///
  21. /// Example
  22. /// ```
  23. /// Text("Hello")
  24. /// .onDoubleClick { print("Double click detected") }
  25. /// ```
  26. /// - Parameters:
  27. /// - handler: Block invoked when a double click is detected
  28. func onDoubleClick(handler: @escaping () -> Void) -> some View {
  29. modifier(DoubleClickHandler(handler: handler))
  30. }
  31. }
  32. struct DoubleClickHandler: ViewModifier {
  33. let handler: () -> Void
  34. func body(content: Content) -> some View {
  35. content.overlay(DoubleClickListeningViewRepresentable(handler: handler))
  36. }
  37. }
  38. struct DoubleClickListeningViewRepresentable: NSViewRepresentable {
  39. let handler: () -> Void
  40. func makeNSView(context: Context) -> DoubleClickListeningView {
  41. DoubleClickListeningView(handler: handler)
  42. }
  43. func updateNSView(_ nsView: DoubleClickListeningView, context: Context) {}
  44. }
  45. class DoubleClickListeningView: NSView {
  46. let handler: () -> Void
  47. init(handler: @escaping () -> Void) {
  48. self.handler = handler
  49. super.init(frame: .zero)
  50. }
  51. required init?(coder: NSCoder) {
  52. fatalError("init(coder:) has not been implemented")
  53. }
  54. override func mouseDown(with event: NSEvent) {
  55. if event.modifierFlags.contains(.control) {
  56. let rightEvent = NSEvent.mouseEvent(with: .rightMouseDown,
  57. location: event.locationInWindow,
  58. modifierFlags: event.modifierFlags.subtracting(.control),
  59. timestamp: event.timestamp,
  60. windowNumber: event.windowNumber,
  61. context: nil,
  62. eventNumber: event.eventNumber,
  63. clickCount: event.clickCount,
  64. pressure: event.pressure)!
  65. super.rightMouseDown(with: rightEvent)
  66. } else {
  67. super.mouseDown(with: event)
  68. }
  69. if event.clickCount == 2 {
  70. handler()
  71. }
  72. }
  73. override func hitTest(_ point: NSPoint) -> NSView? {
  74. if point.x > bounds.width - 40 {
  75. return nil
  76. } else {
  77. return self
  78. }
  79. }
  80. }