Merge pull request #5390 from jlewin/main

Add initial support for terminal text selection
This commit is contained in:
Lars Brubaker 2022-10-18 22:41:46 -07:00 committed by GitHub
commit c4b5333628
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 7 deletions

View file

@ -106,13 +106,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "geometry3Sharp", "Submodule
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestInvoker", "Submodules\agg-sharp\Tests\TestInvoker\TestInvoker.csproj", "{A1F2F1DA-2B86-461E-9602-EAB2BD899A8F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarkdigAgg", "Submodules\agg-sharp\MarkdigAgg\MarkdigAgg.csproj", "{C0E747D6-53CA-4747-B581-D175DCDD085F}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Submodules\agg-sharp\Typography\Typography.OpenFont\Typography.OpenFont.projitems*{235a071b-8d06-40ae-a5c5-b1ce59715ee9}*SharedItemsImports = 13
Submodules\agg-sharp\Typography\Typography.GlyphLayout\Typography.GlyphLayout.projitems*{b112455b-e42e-4718-821f-862884b9c07c}*SharedItemsImports = 5
Submodules\agg-sharp\Typography\Typography.OpenFont\Typography.OpenFont.projitems*{b112455b-e42e-4718-821f-862884b9c07c}*SharedItemsImports = 5
Submodules\agg-sharp\Typography\Typography.GlyphLayout\Typography.GlyphLayout.projitems*{d8861cf8-c506-472b-8a57-632bd6ca6496}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
@ -286,6 +282,10 @@ Global
{A1F2F1DA-2B86-461E-9602-EAB2BD899A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1F2F1DA-2B86-461E-9602-EAB2BD899A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1F2F1DA-2B86-461E-9602-EAB2BD899A8F}.Release|Any CPU.Build.0 = Release|Any CPU
{C0E747D6-53CA-4747-B581-D175DCDD085F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C0E747D6-53CA-4747-B581-D175DCDD085F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C0E747D6-53CA-4747-B581-D175DCDD085F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C0E747D6-53CA-4747-B581-D175DCDD085F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -334,10 +334,17 @@ Global
{34383A75-1831-4816-A38A-AB06B969D7C7} = {FED00F38-E911-45E1-A788-26980E84C3D6}
{3A25C796-F676-4422-8F30-01D4FDB240F1} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB}
{A1F2F1DA-2B86-461E-9602-EAB2BD899A8F} = {FBE6DF29-85A9-4A8B-B739-35BE4CA0A9B7}
{C0E747D6-53CA-4747-B581-D175DCDD085F} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {42D74E06-00EA-43D2-A05B-9BEAD4A2C8A0}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Submodules\agg-sharp\Typography\Typography.OpenFont\Typography.OpenFont.projitems*{235a071b-8d06-40ae-a5c5-b1ce59715ee9}*SharedItemsImports = 13
Submodules\agg-sharp\Typography\Typography.GlyphLayout\Typography.GlyphLayout.projitems*{b112455b-e42e-4718-821f-862884b9c07c}*SharedItemsImports = 5
Submodules\agg-sharp\Typography\Typography.OpenFont\Typography.OpenFont.projitems*{b112455b-e42e-4718-821f-862884b9c07c}*SharedItemsImports = 5
Submodules\agg-sharp\Typography\Typography.GlyphLayout\Typography.GlyphLayout.projitems*{d8861cf8-c506-472b-8a57-632bd6ca6496}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = MatterControl.csproj
EndGlobalSection

View file

@ -52,6 +52,12 @@ namespace MatterHackers.MatterControl
/// </summary>
private int forceStartLine = -1;
// Text selection
private bool dragActive = false;
private int selectionStartLine;
private int selectionEndLine = -1;
private double selectionMouseDown;
private Func<TerminalLine, string> _lineFilterFunction;
public TextScrollWidget(PrinterConfig printer, TerminalLog terminalLog)
@ -67,6 +73,8 @@ namespace MatterHackers.MatterControl
printer.Connection.TerminalLog.LogCleared += this.TerminalLog_LogCleared;
}
private double documentHeight => visibleLines.Count * typeFacePrinter.TypeFaceStyle.EmSizeInPixels;
public double Position0To1
{
get
@ -89,6 +97,7 @@ namespace MatterHackers.MatterControl
// If the start would be less than one screen worth of content, allow
// the whole screen to have content and scroll with new material.
// Note: alternatively, if scrolled and sticking to bottom
if (forceStartLine > visibleLines.Count - NumVisibleLines)
{
forceStartLine = -1;
@ -173,6 +182,9 @@ namespace MatterHackers.MatterControl
int numLinesToDraw = NumVisibleLines;
int selectionStart = Math.Min(selectionStartLine, selectionEndLine);
int selectionEnd = Math.Max(selectionStartLine, selectionEndLine);
double y = LocalBounds.Bottom + typeFacePrinter.TypeFaceStyle.EmSizeInPixels * numLinesToDraw;
lock (locker)
{
@ -201,7 +213,13 @@ namespace MatterHackers.MatterControl
{
typeFacePrinter.Text = visibleLines[lineIndex];
typeFacePrinter.Origin = new Vector2(bounds.Left + 2, y);
typeFacePrinter.Render(graphics2D, TextColor);
// Account for text selection
var textSelected = selectionEndLine != -1
&& lineIndex >= selectionStart
&& lineIndex <= selectionEnd;
typeFacePrinter.Render(graphics2D, textSelected ? AppContext.Theme.PrimaryAccentColor : TextColor);
}
}
@ -216,6 +234,57 @@ namespace MatterHackers.MatterControl
base.OnDraw(graphics2D);
}
private int GetLineIndexFromMouse(Vector2 mousePosition)
{
var yPosFromTop = LocalBounds.Height - mousePosition.Y;
var lineIndex = (int)Math.Ceiling(yPosFromTop / typeFacePrinter.TypeFaceStyle.EmSizeInPixels);
// After the view fills up and/or when not pinned bottom, scroll offset is simply forceStartLine
// Otherwise it's the offset from the bottom
int scrollOffset = forceStartLine >= 0 ? forceStartLine : visibleLines.Count - NumVisibleLines;
// Account for scroll
return lineIndex + scrollOffset;
}
public override void OnMouseDown(MouseEventArgs mouseEvent)
{
dragActive = mouseEvent.Button == MouseButtons.Left;
selectionMouseDown = mouseEvent.Y;
if (dragActive)
{
// Account for scroll
selectionStartLine = GetLineIndexFromMouse(mouseEvent.Position);
// Reset end index on start drag
selectionEndLine = -1;
this.Invalidate();
}
base.OnMouseDown(mouseEvent);
}
public override void OnMouseUp(MouseEventArgs mouseEvent)
{
dragActive = false;
base.OnMouseUp(mouseEvent);
}
public override void OnMouseMove(MouseEventArgs mouseEvent)
{
if (dragActive)
{
// Recompute line index from mouse position into doc, rather than the more
// typical start/current delta, to ensure range stay in sync with scrolling text
selectionEndLine = GetLineIndexFromMouse(mouseEvent.Position);
this.Invalidate();
}
base.OnMouseMove(mouseEvent);
}
public override void OnMouseWheel(MouseEventArgs mouseEvent)
{
base.OnMouseWheel(mouseEvent);
@ -294,5 +363,30 @@ namespace MatterHackers.MatterControl
}
}
}
public override void OnKeyUp(KeyEventArgs keyEvent)
{
if (keyEvent.KeyCode == Keys.C
&& keyEvent.Control
&& Math.Abs(selectionStartLine - selectionEndLine) > 0)
{
int selectionStart = Math.Min(selectionStartLine, selectionEndLine);
int selectionEnd = Math.Max(selectionStartLine, selectionEndLine);
// Filter visiblelines to selection range
var filteredLines = visibleLines.Where((l, i) => i >= selectionStart && i <= selectionEnd);
if (UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowInputOutputMarks, true))
{
// Drop leading communication/direction indicators
filteredLines = filteredLines.Select(l => l.Substring(l.IndexOf(' ') + 1));
}
// Push selected text to clipboard
Clipboard.Instance.SetText(string.Join("\r\n", filteredLines));
}
base.OnKeyUp(keyEvent);
}
}
}