mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-27 00:07:58 +01:00
Selection
This commit is contained in:
@@ -38,6 +38,11 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
SpecialMask = 0xfff00000,
|
||||
|
||||
/// <summary>
|
||||
/// The key code for the user pressing Control-spacebar
|
||||
/// </summary>
|
||||
ControlSpace = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The key code for the user pressing Control-A
|
||||
/// </summary>
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
//
|
||||
// TODO:
|
||||
// Attributed text on spans
|
||||
// Render selection
|
||||
// Mark/Delete/Cut commands
|
||||
// Replace insertion with Insert method
|
||||
// String accumulation (Control-k, control-k is not preserving the last new line, see StringToRunes
|
||||
//
|
||||
@@ -63,7 +61,7 @@ namespace Terminal.Gui {
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (i - start > 0)
|
||||
if (i - start >= 0)
|
||||
lines.Add (ToRunes (content [start, null]));
|
||||
return lines;
|
||||
}
|
||||
@@ -138,8 +136,11 @@ namespace Terminal.Gui {
|
||||
int leftColumn;
|
||||
int currentRow;
|
||||
int currentColumn;
|
||||
bool used;
|
||||
int selectionStartColumn, selectionStartRow;
|
||||
bool selecting;
|
||||
//bool used;
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Changed event, raised when the text has clicked.
|
||||
/// </summary>
|
||||
@@ -148,7 +149,7 @@ namespace Terminal.Gui {
|
||||
/// raised when the text in the entry changes.
|
||||
/// </remarks>
|
||||
public event EventHandler Changed;
|
||||
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Public constructor.
|
||||
/// </summary>
|
||||
@@ -197,6 +198,12 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
public override void PositionCursor ()
|
||||
{
|
||||
if (selecting) {
|
||||
var minRow = Math.Min (Math.Max (Math.Min (selectionStartRow, currentRow)-topRow, 0), Frame.Height);
|
||||
var maxRow = Math.Min (Math.Max (Math.Max (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
|
||||
|
||||
SetNeedsDisplay (new Rect (0, minRow, Frame.Width, maxRow));
|
||||
}
|
||||
Move (CurrentColumn - leftColumn, CurrentRow - topRow);
|
||||
}
|
||||
|
||||
@@ -209,20 +216,117 @@ namespace Terminal.Gui {
|
||||
}
|
||||
}
|
||||
|
||||
void ColorNormal ()
|
||||
{
|
||||
Driver.SetAttribute (ColorScheme.Normal);
|
||||
}
|
||||
|
||||
void ColorSelection ()
|
||||
{
|
||||
if (HasFocus)
|
||||
Driver.SetAttribute (ColorScheme.Focus);
|
||||
else
|
||||
Driver.SetAttribute (ColorScheme.Normal);
|
||||
}
|
||||
|
||||
// Returns an encoded region start..end (top 32 bits are the row, low32 the column)
|
||||
void GetEncodedRegionBounds (out long start, out long end)
|
||||
{
|
||||
long selection = ((long)(uint)selectionStartRow << 32) | (uint)selectionStartColumn;
|
||||
long point = ((long)(uint)currentRow << 32) | (uint)currentColumn;
|
||||
if (selection > point) {
|
||||
start = point;
|
||||
end = selection;
|
||||
} else {
|
||||
start = selection;
|
||||
end = point;
|
||||
}
|
||||
}
|
||||
|
||||
bool PointInSelection (int col, int row)
|
||||
{
|
||||
long start, end;
|
||||
GetEncodedRegionBounds (out start, out end);
|
||||
var q = ((long)(uint)row << 32) | (uint)col;
|
||||
return q >= start && q <= end;
|
||||
}
|
||||
|
||||
//
|
||||
// Returns a ustring with the text in the selected
|
||||
// region.
|
||||
//
|
||||
public ustring GetRegion ()
|
||||
{
|
||||
long start, end;
|
||||
GetEncodedRegionBounds (out start, out end);
|
||||
int startRow = (int)(start >> 32);
|
||||
var maxrow = ((int)(end >> 32));
|
||||
int startCol = (int)(start & 0xffffffff);
|
||||
var endCol = (int)(end & 0xffffffff);
|
||||
var line = model.GetLine (startRow);
|
||||
|
||||
if (startRow == maxrow)
|
||||
return StringFromRunes (line.GetRange (startCol, endCol));
|
||||
|
||||
ustring res = StringFromRunes (line.GetRange (startCol, line.Count - startCol));
|
||||
|
||||
for (int row = startRow+1; row < maxrow; row++) {
|
||||
res = res + ustring.Make (10) + StringFromRunes (model.GetLine (row));
|
||||
}
|
||||
line = model.GetLine (maxrow);
|
||||
res = res + ustring.Make (10) + StringFromRunes (line.GetRange (0, endCol));
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// Clears the contents of the selected region
|
||||
//
|
||||
public void ClearRegion ()
|
||||
{
|
||||
long start, end;
|
||||
long currentEncoded = ((long)(uint)currentRow << 32) | (uint)currentColumn;
|
||||
GetEncodedRegionBounds (out start, out end);
|
||||
int startRow = (int)(start >> 32);
|
||||
var maxrow = ((int)(end >> 32));
|
||||
int startCol = (int)(start & 0xffffffff);
|
||||
var endCol = (int)(end & 0xffffffff);
|
||||
var line = model.GetLine (startRow);
|
||||
|
||||
if (startRow == maxrow) {
|
||||
line.RemoveRange (startCol, endCol - startCol);
|
||||
currentColumn = startCol;
|
||||
SetNeedsDisplay (new Rect (0, startRow - topRow, Frame.Width, startRow - topRow + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
line.RemoveRange (startCol, line.Count - startCol);
|
||||
var line2 = model.GetLine (maxrow);
|
||||
line.AddRange (line2.Skip (endCol));
|
||||
for (int row = startRow + 1; row <= maxrow; row++) {
|
||||
model.RemoveLine (startRow+1);
|
||||
}
|
||||
if (currentEncoded == end) {
|
||||
currentRow -= maxrow - (startRow);
|
||||
}
|
||||
currentColumn = startCol;
|
||||
|
||||
SetNeedsDisplay ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Redraw the text editor region
|
||||
/// </summary>
|
||||
/// <param name="region">The region to redraw.</param>
|
||||
public override void Redraw (Rect region)
|
||||
{
|
||||
Driver.SetAttribute (ColorScheme.Focus);
|
||||
Move (0, 0);
|
||||
ColorNormal ();
|
||||
|
||||
int bottom = region.Bottom;
|
||||
int right = region.Right;
|
||||
for (int row = region.Top; row < bottom; row++) {
|
||||
int textLine = topRow + row;
|
||||
if (textLine >= model.Count) {
|
||||
ColorNormal ();
|
||||
ClearRegion (region.Left, row, region.Right, row + 1);
|
||||
continue;
|
||||
}
|
||||
@@ -237,6 +341,11 @@ namespace Terminal.Gui {
|
||||
for (int col = region.Left; col < right; col++) {
|
||||
var lineCol = leftColumn + col;
|
||||
var rune = lineCol >= lineRuneCount ? ' ' : line [lineCol];
|
||||
if (selecting && PointInSelection (col, row))
|
||||
ColorSelection ();
|
||||
else
|
||||
ColorNormal ();
|
||||
|
||||
AddRune (col, row, rune);
|
||||
}
|
||||
}
|
||||
@@ -366,6 +475,8 @@ namespace Terminal.Gui {
|
||||
int restCount;
|
||||
List<Rune> rest;
|
||||
|
||||
// Handle some state here - whether the last command was a kill
|
||||
// operation and the column tracking (up/down)
|
||||
switch (kb.Key) {
|
||||
case Key.ControlN:
|
||||
case Key.CursorDown:
|
||||
@@ -381,6 +492,7 @@ namespace Terminal.Gui {
|
||||
break;
|
||||
}
|
||||
|
||||
// Dispatch the command.
|
||||
switch (kb.Key) {
|
||||
case Key.ControlN:
|
||||
case Key.CursorDown:
|
||||
@@ -560,6 +672,24 @@ namespace Terminal.Gui {
|
||||
|
||||
case Key.ControlY: // Control-y, yank
|
||||
InsertText (Clipboard.Contents);
|
||||
selecting = false;
|
||||
break;
|
||||
|
||||
case Key.ControlSpace:
|
||||
selecting = true;
|
||||
selectionStartColumn = currentColumn;
|
||||
selectionStartRow = currentRow;
|
||||
break;
|
||||
|
||||
case (Key)((int)'w' + Key.AltMask):
|
||||
SetClipboard (GetRegion ());
|
||||
selecting = false;
|
||||
break;
|
||||
|
||||
case Key.ControlW:
|
||||
SetClipboard (GetRegion ());
|
||||
ClearRegion ();
|
||||
selecting = false;
|
||||
break;
|
||||
|
||||
case (Key)((int)'b' + Key.AltMask):
|
||||
@@ -690,7 +820,7 @@ namespace Terminal.Gui {
|
||||
SetNeedsDisplay ();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user