Selection

This commit is contained in:
Miguel de Icaza
2018-03-22 02:13:57 -04:00
parent c0761d84bd
commit daf24b1672
2 changed files with 143 additions and 8 deletions

View File

@@ -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>

View File

@@ -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
}
}