瀏覽代碼

Some selection work, some mouse support work

Miguel de Icaza 5 年之前
父節點
當前提交
df7e9ab134
共有 2 個文件被更改,包括 157 次插入38 次删除
  1. 154 38
      SwiftTerm/Sources/SwiftTerm/MacTerminalView.swift
  2. 3 0
      TODO.md

+ 154 - 38
SwiftTerm/Sources/SwiftTerm/MacTerminalView.swift

@@ -46,10 +46,6 @@ public protocol TerminalViewDelegate {
  * wiring this up to a pseudo-terminal.
  */
 public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserInterfaceValidations {
-    public func selectionChanged(source: Terminal) {
-        abort()
-    }
-    
     public func setTerminalIconTitle(source: Terminal, title: String) {
         //
     }
@@ -137,6 +133,8 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
             print ("Scroller .decrementLine clicked")
         case .incrementLine:
             print ("Scroller .incrementLine clicked")
+        default:
+            print ("Scroller: New value introduced")
         }
     }
     
@@ -940,6 +938,7 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
     }
     
     public func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
+        //print ("Validating selector: \(item.action)")
         switch item.action {
         case #selector(performTextFinderAction(_:)):
             if let fa = NSTextFinder.Action (rawValue: item.tag) {
@@ -955,28 +954,95 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
                 }
             }
             return false
-        //case #selector(paste:):
-        //    return true
+        case #selector(paste(_:)):
+            return true
         case #selector(selectAll(_:)):
             return true
-        //case #selector(copy:):
-        //    return true
+        case #selector(copy(_:)):
+            return selection.active
         default:
             print ("Validating User Interface Item: \(item)")
             return false
         }
     }
     
+    public func selectionChanged(source: Terminal) {
+        selectionView.update()
+    }
+
     func cut (sender: Any?) {}
-    func copy (sender: Any?) {}
-    func paste (sender: Any?) {}
-    public override func selectAll(_ sender: Any?) {    }
-    func undo (sender: Any) {}
-    func redo (sender: Any) {}
+        
+    @objc
+    public func paste(_ sender: Any)
+    {
+        let clipboard = NSPasteboard.general
+        let text = clipboard.string(forType: .string)
+        insertText(text ?? "", replacementRange: NSRange(location: 0, length: 0))
+    }
+
+    @objc
+    public func copy(_ sender: Any)
+    {
+        // find the selected range of text in the buffer and put in the clipboard
+        let str = selection.getSelectedText()
+        
+        let clipboard = NSPasteboard.general
+        clipboard.clearContents()
+        clipboard.setString(str, forType: .string)
+    }
+
+    public override func selectAll(_ sender: Any?)
+    {
+        selection.selectAll()
+    }
+    
+    //func undo (sender: Any) {}
+    //func redo (sender: Any) {}
     func zoomIn (sender: Any) {}
     func zoomOut (sender: Any) {}
     func zoomReset (sender: Any) {}
+ 
+    // Returns the vt100 mouseflags
+    func encodeMouseEvent (with event: NSEvent, down: Bool) -> Int
+    {
+        let flags = event.modifierFlags
+        
+        return terminal.encodeButton(button: event.buttonNumber, release: false, shift: flags.contains(.shift), meta: flags.contains(.option), control: flags.contains(.control))
+    }
+    
+    func calculateMouseHit (with event: NSEvent, down: Bool) -> (col: Int, row: Int)
+    {
+        let point = convert(event.locationInWindow, from: nil)
+        let col = Int (point.x / cellWidth)
+        let row = Int ((frame.height-point.y) / cellHeight)
+        return (col, row)
+    }
+    
+    func sharedMouseEvent (with event: NSEvent, down: Bool)
+    {
+        let (col, row) = calculateMouseHit(with: event, down: down)
+        let buttonFlags = encodeMouseEvent(with: event, down: down)
+        terminal.sendEvent(buttonFlags: buttonFlags, x: col, y: row)
+    }
     
+    public override func mouseDown(with event: NSEvent) {
+        if terminal.mouseEvents {
+            sharedMouseEvent (with: event, down: true)
+            return
+        }
+        // TODO: autoscrolltimer setup
+    }
+    
+    public override func mouseUp(with event: NSEvent) {
+        // todo disable autoscrolltimer
+        if terminal.mouseEvents {
+            if terminal.mouseSendsRelease {
+                sharedMouseEvent (with: event, down: false)
+            }
+            return
+        }
+        
+    }
 }
 
 
@@ -1031,7 +1097,7 @@ class SelectionView: NSView {
         rowHeight = terminalView.cellHeight
         colWidth = terminalView.cellWidth
         rowDelta = terminalView.cellDelta
-        selectionColor = NSColor.red
+        selectionColor = NSColor (calibratedRed: 0.4, green: 0.2, blue: 0.9, alpha: 0.8)
         
         super.init (frame: frame)
         wantsLayer = true
@@ -1051,7 +1117,74 @@ class SelectionView: NSView {
 
     func notifyScrolled ()
     {
+        update ()
+    }
+    
+    func update ()
+    {
+        updateMask ()
+    }
+    
+    func updateMask ()
+    {
+        // remove the prior mask
+        maskLayer.path = nil
+        
+        maskLayer.frame = bounds
+        let path = CGMutablePath()
+        let terminal = terminalView.terminal!
+        let screenRowStart = selection.start.row - terminal.buffer.yDisp;
+        let screenRowEnd = selection.end.row - terminal.buffer.yDisp;
+        
+        // mask the row that contains the start position
+        // snap to either the first or last column depending on
+        // where the end position is in relation to the start
+        var col = selection.end.col
+        if screenRowEnd > screenRowStart {
+            col = terminal.cols
+        }
+        if screenRowEnd < screenRowStart {
+            col = 0
+        }
+        
+        maskPartialRow (path: path, row: screenRowStart, colStart: selection.start.col,  colEnd: col)
+        
+        if screenRowStart == screenRowEnd {
+            // we're done, only one row to mask
+            maskLayer.path = path
+            return
+        }
+        
+        // now mask the row with the end position
+        col = selection.start.col
+        if screenRowEnd > screenRowStart {
+            col = 0
+            if (screenRowEnd < screenRowStart) {
+                col = terminal.cols
+            }
+        }
+        maskPartialRow (path: path, row: screenRowEnd, colStart: col, colEnd: selection.end.col)
+        
+        // now mask any full rows in between
+        let fullRowCount = screenRowEnd - screenRowStart
+        if fullRowCount > 1 {
+            // Mask full rows up to the last row
+            maskFullRows (path: path, rowStart: screenRowStart + 1, rowCount: fullRowCount-1)
+        } else if fullRowCount < -1 {
+            // Mask full rows up to the last row
+            maskFullRows (path: path, rowStart: screenRowStart - 0, rowCount: fullRowCount+1)
+        }
         
+        maskLayer.path = path
+    }
+    
+    func maskFullRows (path: CGMutablePath, rowStart: Int, rowCount: Int)
+    {
+        let cursorYOffset: CGFloat = 2
+        let startY = frame.height  - (CGFloat (rowStart + rowCount) * rowHeight - rowDelta - cursorYOffset)
+        let pathRect = CGRect (x: 0, y: startY, width: frame.width, height: rowHeight * CGFloat (rowCount))
+
+        path.addRect (pathRect)
     }
     
     func maskPartialRow (path: CGMutablePath, row: Int, colStart: Int, colEnd: Int)
@@ -1067,32 +1200,15 @@ class SelectionView: NSView {
         if colStart == colEnd {
             // basically the same as the cursor
             pathRect = CGRect (x: startX - cursorXPadding, y: startY, width: colWidth + (2 * cursorXPadding), height: rowHeight)
-            path.addRect(pathRect)
-            return
-        }
-        
-        if (colStart < colEnd) {
+        } else if (colStart < colEnd) {
             // start before the beginning of the start column and end just before the start of the next column
-            pathRect =  CGRect (
-                x: startX - cursorXPadding,
-                y: startY,
-                width: (CGFloat (colEnd - colStart) * colWidth) + (2 * cursorXPadding),
-                height: rowHeight);
-            
-            path.addRect (pathRect)
-            return;
+            pathRect =  CGRect (x: startX - cursorXPadding, y: startY, width: (CGFloat (colEnd - colStart) * colWidth) + (2 * cursorXPadding), height: rowHeight);
+        } else {
+            // start before the beginning of the _end_ column and end just before the start of the _start_ column
+            // note this creates a rect with negative width
+            pathRect = CGRect (x: startX + cursorXPadding, y: startY, width: (CGFloat(colEnd - colStart) * colWidth) - (2 * cursorXPadding), height: rowHeight)
         }
-        
-        // start before the beginning of the _end_ column and end just before the start of the _start_ column
-        // note this creates a rect with negative width
-        pathRect = CGRect (
-            x: startX + cursorXPadding,
-            y: startY,
-            width: (CGFloat(colEnd - colStart) * colWidth) - (2 * cursorXPadding),
-            height: rowHeight)
-        
-        path.addRect (pathRect)
+        path.addRect(pathRect)
     }
-
 }
 #endif

+ 3 - 0
TODO.md

@@ -0,0 +1,3 @@
+
+                        autoScrollTimer.Elapsed += AutoScrollTimer_Elapsed;
+