reorganize
This commit is contained in:
658
Source/Game/Console/ConsoleContentTextBox.cs
Normal file
658
Source/Game/Console/ConsoleContentTextBox.cs
Normal file
@@ -0,0 +1,658 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FlaxEditor;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace Cabrito
|
||||
{
|
||||
public class ConsoleContentTextBox : Control
|
||||
{
|
||||
struct LineInfo
|
||||
{
|
||||
public int lineIndex;
|
||||
public int lineOffset;
|
||||
public int lineLength;
|
||||
}
|
||||
|
||||
[HideInEditor] public ConsoleInputTextBox inputBox;
|
||||
|
||||
protected TextLayoutOptions _layout;
|
||||
|
||||
private FontReference Font;
|
||||
|
||||
public int FontHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return Font.GetFont().Height;
|
||||
}
|
||||
}
|
||||
|
||||
public float LineSpacing = 1.0f;
|
||||
|
||||
public TextWrapping Wrapping;
|
||||
|
||||
public Color SelectionColor = new Color(0x00, 0x7A, 0xCC, 0xFF);
|
||||
public Color BackgroundSelectedColor = Color.Transparent;
|
||||
public float BackgroundSelectedFlashSpeed = 0;
|
||||
public Color BorderSelectedColor = Color.Transparent;
|
||||
public float CaretFlashSpeed = 0;
|
||||
public Color BorderColor;
|
||||
public Color TextColor = Color.White;
|
||||
|
||||
public int DefaultMargin = 1;
|
||||
public int ScrollOffset = 0;
|
||||
public int ScrollMouseLines = 3;
|
||||
|
||||
private float heightMultiplier = 1.0f;
|
||||
|
||||
public float HeightMultiplier
|
||||
{
|
||||
get => heightMultiplier;
|
||||
set
|
||||
{
|
||||
heightMultiplier = value;
|
||||
UpdateHeight();
|
||||
}
|
||||
}
|
||||
|
||||
private int selectionStartLine = 0;
|
||||
private int selectionStartChar = 0;
|
||||
private int selectionEndLine = 0;
|
||||
private int selectionEndChar = 0;
|
||||
|
||||
|
||||
private bool selectionActive;
|
||||
public bool HasSelection => !(selectionStartLine == selectionEndLine && selectionStartChar == selectionEndChar);
|
||||
|
||||
public ConsoleContentTextBox() : base()
|
||||
{
|
||||
}
|
||||
|
||||
public ConsoleContentTextBox(FontReference font, ConsoleInputTextBox inputBox, float x, float y, float width, float height) : base(
|
||||
x, y, width, height)
|
||||
{
|
||||
this.inputBox = inputBox;
|
||||
Height = height;
|
||||
|
||||
Font = font;
|
||||
|
||||
_layout = TextLayoutOptions.Default;
|
||||
_layout.VerticalAlignment = TextAlignment.Near;
|
||||
_layout.TextWrapping = TextWrapping.WrapChars;
|
||||
_layout.Bounds = new Rectangle(DefaultMargin, 1, Width - 2 * DefaultMargin, Height - 2);
|
||||
|
||||
|
||||
//IsMultiline = true;
|
||||
//IsReadOnly = true;
|
||||
//CaretColor = new Color(0f, 0f, 0f, 0f);
|
||||
AutoFocus = false;
|
||||
}
|
||||
|
||||
private int GetFontCharacterWidth()
|
||||
{
|
||||
var font = Font.GetFont();
|
||||
if (!font)
|
||||
return 0;
|
||||
return (int) font.MeasureText("a").X; // hacky, but works for fixed-size fonts...
|
||||
}
|
||||
|
||||
public int GetFontHeight()
|
||||
{
|
||||
var font = Font.GetFont();
|
||||
if (font == null)
|
||||
return (int) Height;
|
||||
|
||||
return (int) Mathf.Round(LineSpacing * (font.Height / Platform.DpiScale) * Scale.Y);
|
||||
}
|
||||
|
||||
private int GetHeightInLines()
|
||||
{
|
||||
var font = Font.GetFont();
|
||||
if (!font)
|
||||
return 0;
|
||||
return (int) (Height / (font.Height / Platform.DpiScale)); // number of fully visible lines
|
||||
}
|
||||
|
||||
protected override void OnParentChangedInternal()
|
||||
{
|
||||
base.OnParentChangedInternal();
|
||||
|
||||
if (Parent != null)
|
||||
OnParentResized();
|
||||
}
|
||||
|
||||
public override void OnParentResized()
|
||||
{
|
||||
UpdateHeight();
|
||||
base.OnParentResized();
|
||||
}
|
||||
|
||||
private void UpdateHeight()
|
||||
{
|
||||
if (Parent != null && Parent.Parent != null)
|
||||
Height = (Parent.Parent.Size.Y * HeightMultiplier) - GetFontHeight();
|
||||
}
|
||||
|
||||
|
||||
private void CalculateVisibleLines(IReadOnlyCollection<ConsoleLine> lines, out int firstVisibleLine,
|
||||
out int lastVisibleLine, out LineInfo[] wrappedLines)
|
||||
{
|
||||
wrappedLines = null;
|
||||
firstVisibleLine = 0;
|
||||
lastVisibleLine = 0;
|
||||
|
||||
var font = Font.GetFont();
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
float fontWidth = GetFontCharacterWidth();
|
||||
int lineMaxChars = (int) (Width / fontWidth);
|
||||
int lineMaxLines = GetHeightInLines();
|
||||
int numLines = 0;
|
||||
int lineIndex = lines.Count;
|
||||
List<LineInfo> lineInfos = new List<LineInfo>(lineMaxLines + 1);
|
||||
int linesSkipped = 0;
|
||||
foreach (string line in lines.Reverse())
|
||||
{
|
||||
lineIndex--;
|
||||
if (linesSkipped < ScrollOffset)
|
||||
{
|
||||
linesSkipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int numChars = 0;
|
||||
int startIndex = lineInfos.Count;
|
||||
while (numChars < line.Length)
|
||||
{
|
||||
LineInfo li = new LineInfo();
|
||||
li.lineIndex = lineIndex;
|
||||
li.lineOffset = numChars;
|
||||
li.lineLength = Math.Min(line.Length - numChars, lineMaxChars);
|
||||
lineInfos.Add(li);
|
||||
|
||||
numChars += lineMaxChars;
|
||||
}
|
||||
|
||||
if (lineInfos.Count - startIndex > 1)
|
||||
lineInfos.Reverse(startIndex, lineInfos.Count - startIndex);
|
||||
numLines++;
|
||||
|
||||
if (lineInfos.Count > lineMaxLines)
|
||||
break;
|
||||
}
|
||||
|
||||
lineInfos.Reverse();
|
||||
wrappedLines = lineInfos.ToArray();
|
||||
|
||||
//return lines[lines.Count - numLines .. lines.Count]; // C# 8.0...
|
||||
lastVisibleLine = lineIndex;
|
||||
firstVisibleLine = lastVisibleLine - numLines;
|
||||
}
|
||||
|
||||
public static double accumDrawTime = 0.0;
|
||||
public static long accumDrawTimes = 0;
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
// Cache data
|
||||
var rect = new Rectangle(Vector2.Zero, Size);
|
||||
var font = Font.GetFont();
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
// Background
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_Background");
|
||||
Color backColor = BackgroundColor;
|
||||
if (IsMouseOver)
|
||||
backColor = BackgroundSelectedColor;
|
||||
if (backColor.A > 0.0f)
|
||||
Render2D.FillRectangle(rect, backColor);
|
||||
|
||||
Color borderColor = IsFocused ? BorderSelectedColor : BorderColor;
|
||||
if (borderColor.A > 0.0f)
|
||||
Render2D.DrawRectangle(rect, borderColor);
|
||||
Profiler.EndEvent();
|
||||
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_FetchLines");
|
||||
var lines = Console.Lines;
|
||||
Profiler.EndEvent();
|
||||
if (lines.Count > 0)
|
||||
{
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_Lines");
|
||||
|
||||
// Apply view offset and clip mask
|
||||
var textClipRectangle = new Rectangle(1, 1, Width - 2, Height - 2);
|
||||
Render2D.PushClip(textClipRectangle);
|
||||
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_CalcVisLines");
|
||||
// Make sure lengthy lines are split
|
||||
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
|
||||
Profiler.EndEvent();
|
||||
|
||||
float lineHeight = font.Height / Platform.DpiScale;
|
||||
float accumHeight = wrappedLines.Length * lineHeight;
|
||||
|
||||
// selection in line-space, wrapping ignored
|
||||
int selectionLeftLine = selectionStartLine;
|
||||
int selectionLeftChar = selectionStartChar;
|
||||
int selectionRightLine = selectionEndLine;
|
||||
int selectionRightChar = selectionEndChar;
|
||||
|
||||
if (selectionLeftLine > selectionRightLine ||
|
||||
(selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar))
|
||||
{
|
||||
selectionLeftLine = selectionEndLine;
|
||||
selectionLeftChar = selectionEndChar;
|
||||
selectionRightLine = selectionStartLine;
|
||||
selectionRightChar = selectionStartChar;
|
||||
}
|
||||
|
||||
// render selection
|
||||
if (selectionActive)
|
||||
{
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_Selection");
|
||||
//float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f);
|
||||
//alpha = alpha * alpha;
|
||||
Color selectionColor = SelectionColor; // * alpha;
|
||||
|
||||
TextLayoutOptions layout = _layout;
|
||||
layout.Bounds = rect;
|
||||
layout.Bounds.Y -= accumHeight - Height;
|
||||
//for (int i = startLine; i < lastLine; i++)
|
||||
foreach (LineInfo li in wrappedLines)
|
||||
{
|
||||
var lineIndex = li.lineIndex;
|
||||
string fullLine = lines.ElementAt(lineIndex);
|
||||
string line = fullLine.Substring(li.lineOffset, li.lineLength);
|
||||
|
||||
int leftChar = selectionLeftChar;
|
||||
int rightChar = selectionRightChar;
|
||||
|
||||
Rectangle selectionRect = new Rectangle(layout.Bounds.X, layout.Bounds.Y, 0f, 0f);
|
||||
|
||||
// apply selection
|
||||
if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine)
|
||||
{
|
||||
if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine)
|
||||
{
|
||||
// whole line is selected
|
||||
Vector2 lineSize = font.MeasureText(line);
|
||||
selectionRect.Width = lineSize.X;
|
||||
selectionRect.Height = lineSize.Y;
|
||||
}
|
||||
else if (lineIndex == selectionLeftLine)
|
||||
{
|
||||
if (lineIndex < selectionRightLine)
|
||||
{
|
||||
// right side of the line is selected
|
||||
Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar));
|
||||
Vector2 rightSize = font.MeasureText(fullLine.Substring(leftChar));
|
||||
selectionRect.X += leftSize.X;
|
||||
selectionRect.Width = rightSize.X;
|
||||
selectionRect.Height = rightSize.Y;
|
||||
|
||||
//int diff = line.Length - selectionLeftChar;
|
||||
//line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : "");
|
||||
}
|
||||
else if (lineIndex == selectionRightLine && leftChar != rightChar)
|
||||
{
|
||||
// selecting middle of the one line
|
||||
Vector2 lineSize = font.MeasureText(fullLine);
|
||||
Vector2 leftSize = font.MeasureText(fullLine.Substring(0, leftChar));
|
||||
Vector2 midSize =
|
||||
font.MeasureText(fullLine.Substring(leftChar, rightChar - leftChar));
|
||||
|
||||
selectionRect.X += leftSize.X;
|
||||
selectionRect.Width = midSize.X;
|
||||
selectionRect.Height = lineSize.Y;
|
||||
|
||||
//int diff = selectionRightChar - selectionLeftChar;
|
||||
//line = line.Substring(0, selectionLeftChar) + (diff > 0 ? new string('X', diff) : "") + line.Substring(selectionRightChar);
|
||||
}
|
||||
}
|
||||
else if (lineIndex == selectionRightLine)
|
||||
{
|
||||
// left side of the line is selected
|
||||
Vector2 leftSize = font.MeasureText(fullLine.Substring(0, rightChar));
|
||||
selectionRect.Width = leftSize.X;
|
||||
selectionRect.Height = leftSize.Y;
|
||||
|
||||
//line = (selectionRightChar > 0 ? new string('X', selectionRightChar) : "") + line.Substring(selectionRightChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Render2D.FillRectangle(selectionRect, selectionColor);
|
||||
|
||||
layout.Bounds.Y += lineHeight;
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
// render lines
|
||||
{
|
||||
Profiler.BeginEvent("ConsoleContentTextBoxDraw_Lines_Render");
|
||||
TextLayoutOptions layout = _layout;
|
||||
layout.Bounds = rect;
|
||||
layout.Bounds.Y -= accumHeight - Height;
|
||||
foreach (LineInfo li in wrappedLines)
|
||||
{
|
||||
var lineIndex = li.lineIndex;
|
||||
string line = lines.ElementAt(lineIndex).content.Substring(li.lineOffset, li.lineLength);
|
||||
Render2D.DrawText(font, line, TextColor, ref layout);
|
||||
layout.Bounds.Y += lineHeight;
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
/*if (CaretPosition > -1)
|
||||
{
|
||||
var prefixSize = TextPrefix != "" ? font.MeasureText(TextPrefix) : new Vector2();
|
||||
var caretBounds = CaretBounds;
|
||||
caretBounds.X += prefixSize.X;
|
||||
|
||||
float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f);
|
||||
alpha = alpha * alpha * alpha * alpha * alpha * alpha;
|
||||
Render2D.FillRectangle(caretBounds, CaretColor * alpha);
|
||||
}*/
|
||||
|
||||
Render2D.PopClip();
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
accumDrawTime += sw.Elapsed.TotalSeconds;
|
||||
accumDrawTimes++;
|
||||
}
|
||||
|
||||
|
||||
private void OnSelectingBegin()
|
||||
{
|
||||
if (selectionActive)
|
||||
return;
|
||||
|
||||
selectionActive = true;
|
||||
StartMouseCapture();
|
||||
}
|
||||
|
||||
private void OnSelectingEnd()
|
||||
{
|
||||
if (!selectionActive)
|
||||
return;
|
||||
|
||||
selectionActive = false;
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
public bool HitTestText(Vector2 location, out int hitLine, out int hitChar)
|
||||
{
|
||||
hitLine = 0;
|
||||
hitChar = 0;
|
||||
var font = Font.GetFont();
|
||||
if (font == null)
|
||||
return false;
|
||||
|
||||
var lines = Console.Lines;
|
||||
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
|
||||
|
||||
TextLayoutOptions layout = _layout;
|
||||
layout.Bounds = new Rectangle(0, 0, Size);
|
||||
float lineHeightNormalized = font.Height;
|
||||
float lineHeight = lineHeightNormalized / Platform.DpiScale;
|
||||
float visibleHeight = wrappedLines.Length * lineHeight;
|
||||
float top = (layout.Bounds.Bottom - visibleHeight) /
|
||||
Platform.DpiScale; // UI coordinate space remains normalized
|
||||
int lineMaxLines = (int) (Height / lineHeight);
|
||||
|
||||
int hiddenLines = 0;
|
||||
if (wrappedLines.Length > lineMaxLines)
|
||||
hiddenLines = wrappedLines.Length - lineMaxLines;
|
||||
//if (top < layout.Bounds.Top)
|
||||
// hiddenLines = (int)Math.Ceiling((layout.Bounds.Top - top) / (float)lineHeight);
|
||||
|
||||
int hitWrappedLine = (int) ((location.Y - top) / lineHeight); //+ hiddenLines;
|
||||
if (hitWrappedLine < 0 || hitWrappedLine >= wrappedLines.Length)
|
||||
return false;
|
||||
|
||||
hitLine = wrappedLines[hitWrappedLine].lineIndex;
|
||||
string line = lines.ElementAt(hitLine).content.Substring(wrappedLines[hitWrappedLine].lineOffset,
|
||||
wrappedLines[hitWrappedLine].lineLength);
|
||||
|
||||
layout.Bounds.Y = top + ((hitWrappedLine) * lineHeight);
|
||||
layout.Bounds.Height = top + 9999; //(visibleHeight / Platform.DpiScale);
|
||||
/*if (layout.Bounds.Y < 0)
|
||||
{
|
||||
layout.Bounds.Y = 1;
|
||||
}*/
|
||||
|
||||
hitChar = font.HitTestText(line, location, ref layout);
|
||||
hitChar += wrappedLines[hitWrappedLine].lineOffset;
|
||||
|
||||
//FlaxEngine.Debug.Log(string.Format("hit line {0}/{1}, char {2}", hitWrappedLine, wrappedLines.Length, hitChar));
|
||||
return true;
|
||||
}
|
||||
|
||||
/*public int CharIndexAtPoint(ref Vector2 location)
|
||||
{
|
||||
return HitTestText(location + _viewOffset);
|
||||
}*/
|
||||
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||
bool ctrlDown = Root.GetKey(KeyboardKeys.Control);
|
||||
|
||||
if ((shiftDown && key == KeyboardKeys.Delete) || (ctrlDown && key == KeyboardKeys.Insert) ||
|
||||
(ctrlDown && key == KeyboardKeys.C) || (ctrlDown && key == KeyboardKeys.X))
|
||||
{
|
||||
Copy();
|
||||
return true;
|
||||
}
|
||||
else if (key == KeyboardKeys.PageUp)
|
||||
{
|
||||
ScrollOffset += GetHeightInLines() / 2;
|
||||
// should count the wrapped line count here over Console.Lines.Count
|
||||
//var maxOffset = Console.Lines.Count - GetHeightInLines();
|
||||
var maxOffset = Console.Lines.Count - 1;
|
||||
if (ScrollOffset > maxOffset)
|
||||
ScrollOffset = maxOffset;
|
||||
}
|
||||
else if (key == KeyboardKeys.PageDown)
|
||||
{
|
||||
ScrollOffset -= GetHeightInLines() / 2;
|
||||
if (ScrollOffset < 0)
|
||||
ScrollOffset = 0;
|
||||
}
|
||||
|
||||
//else if (ctrlDown && key == KeyboardKeys.A)
|
||||
// SelectAll();
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
public override bool OnMouseWheel(Vector2 location, float delta)
|
||||
{
|
||||
if (delta < 0)
|
||||
{
|
||||
ScrollOffset -= ScrollMouseLines;
|
||||
if (ScrollOffset < 0)
|
||||
ScrollOffset = 0;
|
||||
}
|
||||
else if (delta > 0)
|
||||
{
|
||||
ScrollOffset += ScrollMouseLines;
|
||||
var maxOffset = Console.Lines.Count - GetHeightInLines();
|
||||
if (ScrollOffset > maxOffset)
|
||||
ScrollOffset = maxOffset;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
bool ret = false;
|
||||
if (button == MouseButton.Left && !IsFocused)
|
||||
{
|
||||
Focus();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (button == MouseButton.Left && Console.Lines.Count > 0)
|
||||
{
|
||||
bool selectionStarted = !selectionActive;
|
||||
Focus();
|
||||
OnSelectingBegin();
|
||||
|
||||
//FlaxEngine.Debug.Log("mousedown, started: " + selectionStarted.ToString());
|
||||
|
||||
if (HitTestText(location, out int hitLine, out int hitChar))
|
||||
{
|
||||
selectionStartLine = hitLine;
|
||||
selectionStartChar = hitChar;
|
||||
selectionEndLine = hitLine;
|
||||
selectionEndChar = hitChar;
|
||||
//FlaxEngine.Debug.Log(string.Format("start line {0} char {1}", hitLine, hitChar));
|
||||
}
|
||||
|
||||
|
||||
// Select range with shift
|
||||
/*if (_selectionStart != -1 && RootWindow.GetKey(KeyboardKeys.Shift) && SelectionLength == 0)
|
||||
{
|
||||
if (hitPos < _selectionStart)
|
||||
SetSelection(hitPos, _selectionStart);
|
||||
else
|
||||
SetSelection(_selectionStart, hitPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSelection(hitPos);
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void OnMouseMove(Vector2 location)
|
||||
{
|
||||
if (selectionActive)
|
||||
{
|
||||
if (HitTestText(location, out int hitLine, out int hitChar))
|
||||
{
|
||||
selectionEndLine = hitLine;
|
||||
selectionEndChar = hitChar;
|
||||
//FlaxEngine.Debug.Log(string.Format("end line {0} char {1}", hitLine, hitChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
OnSelectingEnd();
|
||||
Focus(inputBox);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
base.OnMouseLeave();
|
||||
|
||||
if (selectionActive)
|
||||
{
|
||||
OnSelectingEnd();
|
||||
Focus(inputBox);
|
||||
}
|
||||
}
|
||||
|
||||
protected void Copy()
|
||||
{
|
||||
if (!selectionActive)
|
||||
return;
|
||||
|
||||
// selection in line-space, wrapping ignored
|
||||
int selectionLeftLine = selectionStartLine;
|
||||
int selectionLeftChar = selectionStartChar;
|
||||
int selectionRightLine = selectionEndLine;
|
||||
int selectionRightChar = selectionEndChar;
|
||||
|
||||
if (selectionLeftLine > selectionRightLine ||
|
||||
(selectionLeftLine == selectionRightLine && selectionLeftChar > selectionRightChar))
|
||||
{
|
||||
selectionLeftLine = selectionEndLine;
|
||||
selectionLeftChar = selectionEndChar;
|
||||
selectionRightLine = selectionStartLine;
|
||||
selectionRightChar = selectionStartChar;
|
||||
}
|
||||
|
||||
var lines = Console.Lines;
|
||||
CalculateVisibleLines(lines, out int startLine, out int lastLine, out LineInfo[] wrappedLines);
|
||||
|
||||
StringBuilder selectedText = new StringBuilder();
|
||||
int lastLineIndex = -1;
|
||||
|
||||
foreach (LineInfo li in wrappedLines)
|
||||
{
|
||||
var lineIndex = li.lineIndex;
|
||||
if (lineIndex < selectionLeftLine || lineIndex > selectionRightLine)
|
||||
continue;
|
||||
|
||||
if (lastLineIndex != lineIndex && lastLineIndex != -1)
|
||||
selectedText.AppendLine();
|
||||
lastLineIndex = lineIndex;
|
||||
|
||||
string fullLine = lines.ElementAt(lineIndex);
|
||||
string line = fullLine.Substring(li.lineOffset, li.lineLength);
|
||||
|
||||
int leftChar = selectionLeftChar;
|
||||
int rightChar = selectionRightChar;
|
||||
|
||||
if (lineIndex >= selectionLeftLine && lineIndex <= selectionRightLine)
|
||||
{
|
||||
if (lineIndex > selectionLeftLine && lineIndex < selectionRightLine)
|
||||
{
|
||||
// whole line is selected
|
||||
selectedText.Append(line);
|
||||
}
|
||||
else if (lineIndex == selectionLeftLine)
|
||||
{
|
||||
if (lineIndex < selectionRightLine)
|
||||
{
|
||||
// right side of the line is selected
|
||||
selectedText.Append(fullLine.Substring(leftChar));
|
||||
}
|
||||
else if (lineIndex == selectionRightLine && leftChar != rightChar)
|
||||
{
|
||||
// selecting middle of the one line
|
||||
selectedText.Append(fullLine.Substring(leftChar, rightChar - leftChar));
|
||||
}
|
||||
}
|
||||
else if (lineIndex == selectionRightLine)
|
||||
{
|
||||
// left side of the line is selected
|
||||
selectedText.Append(fullLine.Substring(0, rightChar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedText.Length > 0)
|
||||
Clipboard.Text = selectedText.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user