]> git.r.bdr.sh - rbdr/captura/commitdiff
Add resize, keyboard shortcuts, menu items
authorRuben Beltran del Rio <redacted>
Tue, 25 Jul 2023 21:19:13 +0000 (23:19 +0200)
committerRuben Beltran del Rio <redacted>
Tue, 25 Jul 2023 21:19:13 +0000 (23:19 +0200)
Captura.xcodeproj/project.pbxproj
Captura/CapturaApp.swift
Captura/RecordingWindow.swift

index 95ecff08ce16dc5e93b5980c6a66974efc49d70f..a796c6af5993ac25927b6eed0b2a1775c1cf6362 100644 (file)
                                ENABLE_HARDENED_RUNTIME = YES;
                                ENABLE_PREVIEWS = YES;
                                GENERATE_INFOPLIST_FILE = YES;
+                               INFOPLIST_KEY_LSUIElement = YES;
                                INFOPLIST_KEY_NSHumanReadableCopyright = "";
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
                                ENABLE_HARDENED_RUNTIME = YES;
                                ENABLE_PREVIEWS = YES;
                                GENERATE_INFOPLIST_FILE = YES;
+                               INFOPLIST_KEY_LSUIElement = YES;
                                INFOPLIST_KEY_NSHumanReadableCopyright = "";
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
index 4dc65a478d25a7c8bea47f22a12ed51dbe09fca2..933e00bb4d601d84682d2f4ea01cac989f5dad9e 100644 (file)
@@ -45,10 +45,17 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate {
       statusItem.isVisible = true
       statusItem.menu = NSMenu()
       
-      let recordItem = NSMenuItem(title: "record", action: #selector(CapturaAppDelegate.onClickStartRecording), keyEquivalent: "6")
+      let recordItem = NSMenuItem(title: "Record", action: #selector(CapturaAppDelegate.onClickStartRecording), keyEquivalent: "6")
       recordItem.keyEquivalentModifierMask = [.command, .shift]
       
       statusItem.menu?.addItem(recordItem)
+      statusItem.menu?.addItem(NSMenuItem.separator())
+      
+      let preferencesItem = NSMenuItem(title: "Preferences", action: #selector(CapturaAppDelegate.onOpenPreferences), keyEquivalent: "")
+      statusItem.menu?.addItem(preferencesItem)
+      
+      let quitItem = NSMenuItem(title: "Quit", action: #selector(CapturaAppDelegate.onQuit), keyEquivalent: "")
+      statusItem.menu?.addItem(quitItem)
     }
   
     private func closeWindow() {
@@ -63,6 +70,14 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate {
       NotificationCenter.default.post(name: .startAreaSelection, object: nil, userInfo: nil)
     }
   
+    @objc private func onOpenPreferences() {
+      print("Preferences pressed")
+    }
+  
+    @objc private func onQuit() {
+      NSApplication.shared.terminate(self)
+    }
+  
   
     // MARK: - App State Event Listeners
   
@@ -93,7 +108,6 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate {
       if captureState != .selectingArea {
         captureState = .selectingArea
         recordingWindow = RecordingWindow()
-        print("Recording")
       }
     }
   
@@ -111,5 +125,7 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate {
   
     func reset() {
       captureState = .idle
+      recordingWindow?.close()
+      self.recordingWindow = nil
     }
 }
index cf572e18d61f77f093bc2451559835194f72e0cf..d737dec3461a11f8f713b751dbd6f34fc9e7716a 100644 (file)
@@ -16,6 +16,7 @@ class RecordingWindow: NSWindow {
       backing: .buffered,
       defer: false)
 
+    self.isReleasedWhenClosed = false
     self.center()
     self.isMovableByWindowBackground = false
     self.isMovable = false
@@ -44,13 +45,25 @@ class RecordingWindow: NSWindow {
   override var canBecomeMain: Bool {
     return true
   }
+  
+  override func resignMain() {
+    super.resignMain()
+    self.ignoresMouseEvents = false
+  }
+  
+  override func becomeMain() {
+    super.becomeMain()
+    (self.contentView as? RecordingContentView)?.state = .idle
+  }
+}
+
+enum RecordingWindowState {
+  case passthrough, idle, drawing, moving, resizing;
 }
 
 class RecordingContentView: NSView {
   
-  var isDrawing = false
-  var isMoving = false
-  var isResizing = false
+  var state: RecordingWindowState = .idle
   var box: NSRect? = nil
   var mouseLocation: NSPoint = NSPoint()
   var origin: NSPoint = NSPoint()
@@ -99,7 +112,7 @@ class RecordingContentView: NSView {
   
   override func mouseDragged(with event: NSEvent) {
     self.mouseLocation = self.convert(event.locationInWindow, from: nil)
-    if isDrawing {
+    if state == .drawing {
       box = NSRect(
         x: round(min(origin.x, mouseLocation.x)),
         y: round(min(origin.y, mouseLocation.y)),
@@ -108,11 +121,22 @@ class RecordingContentView: NSView {
       )
     }
     
-    if isMoving && box != nil {
-      NSCursor.closedHand.set()
-      box!.origin = NSPoint(
-        x: self.boxOrigin.x - self.origin.x + self.mouseLocation.x,
-        y: self.boxOrigin.y - self.origin.y + self.mouseLocation.y)
+    if box != nil {
+      if state == .moving {
+        NSCursor.closedHand.set()
+        box!.origin = NSPoint(
+          x: self.boxOrigin.x - self.origin.x + self.mouseLocation.x,
+          y: self.boxOrigin.y - self.origin.y + self.mouseLocation.y)
+      }
+      
+      if state == .resizing {
+        box = NSRect(
+          x: round(min(origin.x, mouseLocation.x)),
+          y: round(min(origin.y, mouseLocation.y)),
+          width: round(abs(mouseLocation.x - origin.x)),
+          height: round(abs(mouseLocation.y - origin.y))
+        )
+      }
     }
     self.setNeedsDisplay(self.bounds)
   }
@@ -122,7 +146,7 @@ class RecordingContentView: NSView {
   }
 
   override func hitTest(_ point: NSPoint) -> NSView? {
-    return self
+    return state == .passthrough ? nil : self
   }
       
   override var acceptsFirstResponder: Bool {
@@ -132,29 +156,57 @@ class RecordingContentView: NSView {
   override func mouseDown(with event: NSEvent) {
     self.origin = self.convert(event.locationInWindow, from: nil)
     if let box {
+      if resizeBox!.contains(origin) {
+        self.origin = NSPoint(x: box.minX, y: box.maxY)
+        state = .resizing
+        return
+      }
       if box.contains(origin) {
-        isMoving = true
+        state = .moving
         self.boxOrigin = NSPoint(x: box.origin.x, y: box.origin.y)
         return
       }
     }
     
-    isDrawing = true
+    state = .drawing
   }
 
   override func mouseUp(with event: NSEvent) {
-    isDrawing = false
-    isMoving = false
+    state = .idle
+  }
+  
+  override func keyDown(with event: NSEvent) {
+    print("key down")
+    switch event.keyCode {
+      case 53:  // Escape key
+        NotificationCenter.default.post(name: .reset, object: nil, userInfo: nil)
+      default:
+        super.keyDown(with: event)
+    }
+  }
+  
+  override func flagsChanged(with event: NSEvent) {
+      if event.modifierFlags.contains(.shift) {
+        state = .passthrough
+        window?.ignoresMouseEvents = true
+      } else {
+        state = .idle
+        window?.ignoresMouseEvents = false
+      }
   }
   
   override func draw(_ dirtyRect: NSRect) {
-    NSColor(white: 1.0, alpha: 0.001).setFill()
+    if state == .passthrough {
+      NSColor.clear.setFill()
+    } else {
+      NSColor(white: 1.0, alpha: 0.001).setFill()
+    }
     dirtyRect.fill()
     
     let dashLength: CGFloat = 5.0
     let lineWidth = 0.5
 
-    if !isDrawing && box == nil {
+    if state == .idle && box == nil {
       let blackLine = NSBezierPath()
       blackLine.lineWidth = lineWidth
       blackLine.setLineDash([dashLength, dashLength], count: 2, phase: 0)
@@ -220,29 +272,50 @@ class RecordingContentView: NSView {
         clearBox.fill()
       }
       
-      if box.contains(mouseLocation) && !isResizing {
+      if state == .moving {
+        let string = "\(Int(box.minX)), \(Int(box.maxY))" as NSString
+        drawText(string, NSPoint(
+          x: box.minX,
+          y: box.maxY
+        ), true)
+      }
+      
+      if state == .resizing {
+        let string = "\(Int(mouseLocation.x)), \(Int(mouseLocation.y))" as NSString
+        drawText(string, mouseLocation)
+      }
+      
+      if box.contains(mouseLocation) && state != .resizing {
         return;
       }
     }
     
     // Draw text
-    
-    let offset = NSPoint(x: 10, y: 10)
-    let padding = NSPoint(x: 5, y: 2)
+
+    let string = "\(Int(mouseLocation.x)), \(Int(mouseLocation.y))" as NSString
+    drawText(string, mouseLocation)
+  }
+  
+  private func drawText(_ text: NSString, _ location: NSPoint, _ isBottomRight: Bool = false) {
     
     let textAttributes = [
       NSAttributedString.Key.font: NSFont(name: "Hiragino Mincho ProN", size: 12) ?? NSFont.systemFont(ofSize: 12),
       NSAttributedString.Key.foregroundColor: NSColor.white,
     ]
-
-    let string = "\(Int(mouseLocation.x)), \(Int(mouseLocation.y))" as NSString
-    let size = string.size(withAttributes: textAttributes)
-    let rect = NSRect(x: mouseLocation.x + offset.x, y: mouseLocation.y + offset.y, width: size.width + 2 * padding.x, height: size.height + 2 * padding.y)
-    let textRect = NSRect(x: mouseLocation.x + offset.x + padding.x, y: mouseLocation.y + offset.y + padding.y, width: size.width, height: size.height)
+    let offset = NSPoint(x: 10, y: 10)
+    let padding = NSPoint(x: 5, y: 2)
+    let size = text.size(withAttributes: textAttributes)
+    var rect = NSRect(x: location.x + offset.x, y: location.y + offset.y, width: size.width + 2 * padding.x, height: size.height + 2 * padding.y)
+    var textRect = NSRect(x: location.x + offset.x + padding.x, y: location.y + offset.y + padding.y, width: size.width, height: size.height)
+    
+    if (isBottomRight) {
+      rect = rect.offsetBy(dx: -size.width - 2 * offset.x, dy: 0)
+      textRect = textRect.offsetBy(dx: -size.width - 2 * offset.x, dy: 0)
+    }
 
     NSColor.black.set()
     rect.fill()
 
-    string.draw(in: textRect, withAttributes: textAttributes)
+    text.draw(in: textRect, withAttributes: textAttributes)
   }
 }