Skip to content

Commit df7e9ab

Browse files
committed
Some selection work, some mouse support work
1 parent 183a66d commit df7e9ab

File tree

2 files changed

+157
-38
lines changed

2 files changed

+157
-38
lines changed

SwiftTerm/Sources/SwiftTerm/MacTerminalView.swift

+154-38
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,6 @@ public protocol TerminalViewDelegate {
4646
* wiring this up to a pseudo-terminal.
4747
*/
4848
public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserInterfaceValidations {
49-
public func selectionChanged(source: Terminal) {
50-
abort()
51-
}
52-
5349
public func setTerminalIconTitle(source: Terminal, title: String) {
5450
//
5551
}
@@ -137,6 +133,8 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
137133
print ("Scroller .decrementLine clicked")
138134
case .incrementLine:
139135
print ("Scroller .incrementLine clicked")
136+
default:
137+
print ("Scroller: New value introduced")
140138
}
141139
}
142140

@@ -940,6 +938,7 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
940938
}
941939

942940
public func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {
941+
//print ("Validating selector: \(item.action)")
943942
switch item.action {
944943
case #selector(performTextFinderAction(_:)):
945944
if let fa = NSTextFinder.Action (rawValue: item.tag) {
@@ -955,28 +954,95 @@ public class TerminalView: NSView, TerminalDelegate, NSTextInputClient, NSUserIn
955954
}
956955
}
957956
return false
958-
//case #selector(paste:):
959-
// return true
957+
case #selector(paste(_:)):
958+
return true
960959
case #selector(selectAll(_:)):
961960
return true
962-
//case #selector(copy:):
963-
// return true
961+
case #selector(copy(_:)):
962+
return selection.active
964963
default:
965964
print ("Validating User Interface Item: \(item)")
966965
return false
967966
}
968967
}
969968

969+
public func selectionChanged(source: Terminal) {
970+
selectionView.update()
971+
}
972+
970973
func cut (sender: Any?) {}
971-
func copy (sender: Any?) {}
972-
func paste (sender: Any?) {}
973-
public override func selectAll(_ sender: Any?) { }
974-
func undo (sender: Any) {}
975-
func redo (sender: Any) {}
974+
975+
@objc
976+
public func paste(_ sender: Any)
977+
{
978+
let clipboard = NSPasteboard.general
979+
let text = clipboard.string(forType: .string)
980+
insertText(text ?? "", replacementRange: NSRange(location: 0, length: 0))
981+
}
982+
983+
@objc
984+
public func copy(_ sender: Any)
985+
{
986+
// find the selected range of text in the buffer and put in the clipboard
987+
let str = selection.getSelectedText()
988+
989+
let clipboard = NSPasteboard.general
990+
clipboard.clearContents()
991+
clipboard.setString(str, forType: .string)
992+
}
993+
994+
public override func selectAll(_ sender: Any?)
995+
{
996+
selection.selectAll()
997+
}
998+
999+
//func undo (sender: Any) {}
1000+
//func redo (sender: Any) {}
9761001
func zoomIn (sender: Any) {}
9771002
func zoomOut (sender: Any) {}
9781003
func zoomReset (sender: Any) {}
1004+
1005+
// Returns the vt100 mouseflags
1006+
func encodeMouseEvent (with event: NSEvent, down: Bool) -> Int
1007+
{
1008+
let flags = event.modifierFlags
1009+
1010+
return terminal.encodeButton(button: event.buttonNumber, release: false, shift: flags.contains(.shift), meta: flags.contains(.option), control: flags.contains(.control))
1011+
}
1012+
1013+
func calculateMouseHit (with event: NSEvent, down: Bool) -> (col: Int, row: Int)
1014+
{
1015+
let point = convert(event.locationInWindow, from: nil)
1016+
let col = Int (point.x / cellWidth)
1017+
let row = Int ((frame.height-point.y) / cellHeight)
1018+
return (col, row)
1019+
}
1020+
1021+
func sharedMouseEvent (with event: NSEvent, down: Bool)
1022+
{
1023+
let (col, row) = calculateMouseHit(with: event, down: down)
1024+
let buttonFlags = encodeMouseEvent(with: event, down: down)
1025+
terminal.sendEvent(buttonFlags: buttonFlags, x: col, y: row)
1026+
}
9791027

1028+
public override func mouseDown(with event: NSEvent) {
1029+
if terminal.mouseEvents {
1030+
sharedMouseEvent (with: event, down: true)
1031+
return
1032+
}
1033+
// TODO: autoscrolltimer setup
1034+
}
1035+
1036+
public override func mouseUp(with event: NSEvent) {
1037+
// todo disable autoscrolltimer
1038+
if terminal.mouseEvents {
1039+
if terminal.mouseSendsRelease {
1040+
sharedMouseEvent (with: event, down: false)
1041+
}
1042+
return
1043+
}
1044+
1045+
}
9801046
}
9811047

9821048

@@ -1031,7 +1097,7 @@ class SelectionView: NSView {
10311097
rowHeight = terminalView.cellHeight
10321098
colWidth = terminalView.cellWidth
10331099
rowDelta = terminalView.cellDelta
1034-
selectionColor = NSColor.red
1100+
selectionColor = NSColor (calibratedRed: 0.4, green: 0.2, blue: 0.9, alpha: 0.8)
10351101

10361102
super.init (frame: frame)
10371103
wantsLayer = true
@@ -1051,7 +1117,74 @@ class SelectionView: NSView {
10511117

10521118
func notifyScrolled ()
10531119
{
1120+
update ()
1121+
}
1122+
1123+
func update ()
1124+
{
1125+
updateMask ()
1126+
}
1127+
1128+
func updateMask ()
1129+
{
1130+
// remove the prior mask
1131+
maskLayer.path = nil
1132+
1133+
maskLayer.frame = bounds
1134+
let path = CGMutablePath()
1135+
let terminal = terminalView.terminal!
1136+
let screenRowStart = selection.start.row - terminal.buffer.yDisp;
1137+
let screenRowEnd = selection.end.row - terminal.buffer.yDisp;
1138+
1139+
// mask the row that contains the start position
1140+
// snap to either the first or last column depending on
1141+
// where the end position is in relation to the start
1142+
var col = selection.end.col
1143+
if screenRowEnd > screenRowStart {
1144+
col = terminal.cols
1145+
}
1146+
if screenRowEnd < screenRowStart {
1147+
col = 0
1148+
}
1149+
1150+
maskPartialRow (path: path, row: screenRowStart, colStart: selection.start.col, colEnd: col)
1151+
1152+
if screenRowStart == screenRowEnd {
1153+
// we're done, only one row to mask
1154+
maskLayer.path = path
1155+
return
1156+
}
1157+
1158+
// now mask the row with the end position
1159+
col = selection.start.col
1160+
if screenRowEnd > screenRowStart {
1161+
col = 0
1162+
if (screenRowEnd < screenRowStart) {
1163+
col = terminal.cols
1164+
}
1165+
}
1166+
maskPartialRow (path: path, row: screenRowEnd, colStart: col, colEnd: selection.end.col)
1167+
1168+
// now mask any full rows in between
1169+
let fullRowCount = screenRowEnd - screenRowStart
1170+
if fullRowCount > 1 {
1171+
// Mask full rows up to the last row
1172+
maskFullRows (path: path, rowStart: screenRowStart + 1, rowCount: fullRowCount-1)
1173+
} else if fullRowCount < -1 {
1174+
// Mask full rows up to the last row
1175+
maskFullRows (path: path, rowStart: screenRowStart - 0, rowCount: fullRowCount+1)
1176+
}
10541177

1178+
maskLayer.path = path
1179+
}
1180+
1181+
func maskFullRows (path: CGMutablePath, rowStart: Int, rowCount: Int)
1182+
{
1183+
let cursorYOffset: CGFloat = 2
1184+
let startY = frame.height - (CGFloat (rowStart + rowCount) * rowHeight - rowDelta - cursorYOffset)
1185+
let pathRect = CGRect (x: 0, y: startY, width: frame.width, height: rowHeight * CGFloat (rowCount))
1186+
1187+
path.addRect (pathRect)
10551188
}
10561189

10571190
func maskPartialRow (path: CGMutablePath, row: Int, colStart: Int, colEnd: Int)
@@ -1067,32 +1200,15 @@ class SelectionView: NSView {
10671200
if colStart == colEnd {
10681201
// basically the same as the cursor
10691202
pathRect = CGRect (x: startX - cursorXPadding, y: startY, width: colWidth + (2 * cursorXPadding), height: rowHeight)
1070-
path.addRect(pathRect)
1071-
return
1072-
}
1073-
1074-
if (colStart < colEnd) {
1203+
} else if (colStart < colEnd) {
10751204
// start before the beginning of the start column and end just before the start of the next column
1076-
pathRect = CGRect (
1077-
x: startX - cursorXPadding,
1078-
y: startY,
1079-
width: (CGFloat (colEnd - colStart) * colWidth) + (2 * cursorXPadding),
1080-
height: rowHeight);
1081-
1082-
path.addRect (pathRect)
1083-
return;
1205+
pathRect = CGRect (x: startX - cursorXPadding, y: startY, width: (CGFloat (colEnd - colStart) * colWidth) + (2 * cursorXPadding), height: rowHeight);
1206+
} else {
1207+
// start before the beginning of the _end_ column and end just before the start of the _start_ column
1208+
// note this creates a rect with negative width
1209+
pathRect = CGRect (x: startX + cursorXPadding, y: startY, width: (CGFloat(colEnd - colStart) * colWidth) - (2 * cursorXPadding), height: rowHeight)
10841210
}
1085-
1086-
// start before the beginning of the _end_ column and end just before the start of the _start_ column
1087-
// note this creates a rect with negative width
1088-
pathRect = CGRect (
1089-
x: startX + cursorXPadding,
1090-
y: startY,
1091-
width: (CGFloat(colEnd - colStart) * colWidth) - (2 * cursorXPadding),
1092-
height: rowHeight)
1093-
1094-
path.addRect (pathRect)
1211+
path.addRect(pathRect)
10951212
}
1096-
10971213
}
10981214
#endif

TODO.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
autoScrollTimer.Elapsed += AutoScrollTimer_Elapsed;
3+

0 commit comments

Comments
 (0)