Mouse text selection with cut, copy and paste on text fields

This commit is contained in:
BDisp
2019-11-17 01:10:00 +00:00
parent c072e29a68
commit 85015ee2f4
9 changed files with 1105 additions and 572 deletions

View File

@@ -3,7 +3,10 @@ using System;
using Mono.Terminal;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using NStack;
static class Demo {
class Box10x : View {
@@ -42,6 +45,9 @@ static class Demo {
Rune r;
switch (x % 3) {
case 0:
Driver.AddRune (y.ToString ().ToCharArray (0, 1) [0]);
if (y > 9)
Driver.AddRune (y.ToString ().ToCharArray (1, 1) [0]);
r = '.';
break;
case 1:
@@ -60,11 +66,15 @@ static class Demo {
static void ShowTextAlignments (View container)
{
int i = 0;
string txt = "Hello world, how are you doing today";
container.Add (
new Label (new Rect (0, 0, 40, 3), "1-Hello world, how are you doing today") { TextAlignment = TextAlignment.Left },
new Label (new Rect (0, 4, 40, 3), "2-Hello world, how are you doing today") { TextAlignment = TextAlignment.Right },
new Label (new Rect (0, 8, 40, 3), "3-Hello world, how are you doing today") { TextAlignment = TextAlignment.Centered },
new Label (new Rect (0, 12, 40, 3), "4-Hello world, how are you doing today") { TextAlignment = TextAlignment.Justified });
new FrameView (new Rect (75, 1, txt.Length + 6, 20), "Text Alignments") {
new Label(new Rect(0, 1, 40, 3), $"{i+1}-{txt}") { TextAlignment = TextAlignment.Left },
new Label(new Rect(0, 5, 40, 3), $"{i+2}-{txt}") { TextAlignment = TextAlignment.Right },
new Label(new Rect(0, 9, 40, 3), $"{i+3}-{txt}") { TextAlignment = TextAlignment.Centered },
new Label(new Rect(0, 13, 40, 3), $"{i+4}-{txt}") { TextAlignment = TextAlignment.Justified }
});
}
static void ShowEntries (View container)
@@ -75,9 +85,11 @@ static class Demo {
ShowVerticalScrollIndicator = true,
ShowHorizontalScrollIndicator = true
};
#if false
scrollView.Add (new Box10x (0, 0));
//scrollView.Add (new Filler (new Rect (0, 0, 40, 40)));
#else
scrollView.Add (new Filler (new Rect (0, 0, 40, 40)));
#endif
// This is just to debug the visuals of the scrollview when small
var scrollView2 = new ScrollView (new Rect (72, 10, 3, 3)) {
@@ -143,7 +155,9 @@ static class Demo {
new TimeField (3, 20, DateTime.Now),
new TimeField (23, 20, DateTime.Now, true),
progress,
new Label (3, 22, "Press F9 (on Unix, ESC+9 is an alias) to activate the menubar")
new Label (3, 24, "Press F9 (on Unix, ESC+9 is an alias) to activate the menubar"),
menuKeysStyle,
menuAutoMouseNav
);
@@ -164,10 +178,11 @@ static class Demo {
//
// Creates a nested editor
static void Editor(Toplevel top) {
static void Editor (Toplevel top)
{
var tframe = top.Frame;
var ntop = new Toplevel(tframe);
var menu = new MenuBar(new MenuBarItem[] {
var ntop = new Toplevel (tframe);
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Close", "", () => {Application.RequestStop ();}),
}),
@@ -177,25 +192,25 @@ static class Demo {
new MenuItem ("_Paste", "", null)
}),
});
ntop.Add(menu);
ntop.Add (menu);
string fname = null;
foreach (var s in new[] { "/etc/passwd", "c:\\windows\\win.ini" })
if (System.IO.File.Exists(s)) {
foreach (var s in new [] { "/etc/passwd", "c:\\windows\\win.ini" })
if (System.IO.File.Exists (s)) {
fname = s;
break;
}
var win = new Window(fname ?? "Untitled") {
var win = new Window (fname ?? "Untitled") {
X = 0,
Y = 1,
Width = Dim.Fill(),
Height = Dim.Fill()
Width = Dim.Fill (),
Height = Dim.Fill ()
};
ntop.Add(win);
ntop.Add (win);
var text = new TextView (new Rect (0, 0, tframe.Width - 2, tframe.Height - 3));
var text = new TextView(new Rect(0, 0, tframe.Width - 2, tframe.Height - 3));
if (fname != null)
text.Text = System.IO.File.ReadAllText (fname);
win.Add (text);
@@ -211,7 +226,7 @@ static class Demo {
static void Close ()
{
MessageBox.ErrorQuery (50, 5, "Error", "There is nothing to close", "Ok");
MessageBox.ErrorQuery (50, 7, "Error", "There is nothing to close", "Ok");
}
// Watch what happens when I try to introduce a newline after the first open brace
@@ -223,7 +238,7 @@ static class Demo {
var d = new OpenDialog ("Open", "Open a file");
Application.Run (d);
MessageBox.Query (50, 7, "Selected File", string.Join (", ", d.FilePaths), "ok");
MessageBox.Query (50, 7, "Selected File", string.Join (", ", d.FilePaths), "Ok");
}
public static void ShowHex (Toplevel top)
@@ -254,9 +269,103 @@ static class Demo {
};
win.Add (hex);
Application.Run (ntop);
}
public class MenuItemDetails : MenuItem {
ustring title;
string help;
Action action;
public MenuItemDetails (ustring title, string help, Action action) : base (title, help, action)
{
this.title = title;
this.help = help;
this.action = action;
}
public static MenuItemDetails Instance (MenuItem mi)
{
return (MenuItemDetails)mi.GetMenuItem ();
}
}
public delegate MenuItem MenuItemDelegate (MenuItemDetails menuItem);
public static void ShowMenuItem (MenuItem mi)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
MethodInfo minfo = typeof (MenuItemDetails).GetMethod ("Instance", flags);
MenuItemDelegate mid = (MenuItemDelegate)Delegate.CreateDelegate (typeof (MenuItemDelegate), minfo);
MessageBox.Query (70, 7, mi.Title.ToString (),
$"{mi.Title.ToString ()} selected. Is from submenu: {mi.GetMenuBarItem ()}", "Ok");
}
private static void MenuKeysStyle_Toggled (object sender, EventArgs e)
{
menu.UseKeysUpDownAsKeysLeftRight = menuKeysStyle.Checked;
}
private static void MenuAutoMouseNav_Toggled (object sender, EventArgs e)
{
menu.WantMousePositionReports = menuAutoMouseNav.Checked;
}
//private static TextField GetTextFieldSelText (View vt)
//{
// TextField textField;
// foreach (View v in vt.Subviews) {
// if (v is TextField && ((TextField)v).SelText != "")
// return v as TextField;
// else
// textField = GetTextFieldSelText (v);
// if (textField != null)
// return textField;
// }
// return null;
//}
private static void Copy ()
{
TextField textField = menu.LastFocused as TextField;
if (textField != null && textField.SelLength > 0) {
Clipboard.Contents = textField.SelText;
textField.SelLength = 0;
textField.SetNeedsDisplay ();
}
}
private static void Cut ()
{
TextField textField = menu.LastFocused as TextField;
if (textField != null && textField.SelLength > 0) {
Clipboard.Contents = textField.SelText;
string actualText = textField.Text.ToString ();
string newText = actualText.Substring (0, textField.SelStart) +
actualText.Substring (textField.SelStart + textField.SelLength, actualText.Length - textField.SelStart - textField.SelLength);
textField.Text = newText;
textField.SelLength = 0;
textField.CursorPosition = textField.SelStart == -1 ? textField.CursorPosition : textField.SelStart;
textField.SetNeedsDisplay ();
}
}
private static void Paste ()
{
TextField textField = menu.LastFocused as TextField;
if (textField != null) {
string actualText = textField.Text.ToString ();
int start = textField.SelStart == -1 ? textField.CursorPosition : textField.SelStart;
string newText = actualText.Substring (0, start) +
Clipboard.Contents?.ToString() +
actualText.Substring (start + textField.SelLength, actualText.Length - start - textField.SelLength);
textField.Text = newText;
textField.SelLength = 0;
textField.SetNeedsDisplay ();
}
}
#region Selection Demo
static void ListSelectionDemo ()
@@ -295,14 +404,19 @@ static class Demo {
public static Label ml;
public static MenuBar menu;
public static CheckBox menuKeysStyle;
public static CheckBox menuAutoMouseNav;
static void Main ()
{
if (Debugger.IsAttached)
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.GetCultureInfo ("en-US");
//Application.UseSystemConsole = true;
Application.Init ();
var top = Application.Top;
var tframe = top.Frame;
//Open ();
#if true
var win = new Window ("Hello") {
@@ -312,27 +426,63 @@ static class Demo {
Height = Dim.Fill ()
};
#else
var tframe = top.Frame;
var win = new Window (new Rect (0, 1, tframe.Width, tframe.Height - 1), "Hello");
#endif
var menu = new MenuBar (new MenuBarItem [] {
MenuItemDetails [] menuItems = {
new MenuItemDetails ("F_ind", "", null),
new MenuItemDetails ("_Replace", "", null),
new MenuItemDetails ("_Item1", "", null),
new MenuItemDetails ("_Not From Sub Menu", "", null)
};
menuItems [0].Action = () => ShowMenuItem (menuItems [0]);
menuItems [1].Action = () => ShowMenuItem (menuItems [1]);
menuItems [2].Action = () => ShowMenuItem (menuItems [2]);
menuItems [3].Action = () => ShowMenuItem (menuItems [3]);
menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("Text Editor Demo", "", () => { Editor (top); }),
new MenuItem ("_New", "Creates new file", NewFile),
new MenuItem ("_Open", "", Open),
new MenuItem ("_Hex", "", () => ShowHex (top)),
new MenuItem ("_Close", "", () => Close ()),
null,
new MenuItem ("_Quit", "", () => { if (Quit ()) top.Running = false; })
}),
new MenuBarItem ("_Edit", new MenuItem [] {
new MenuItem ("_Copy", "", null),
new MenuItem ("C_ut", "", null),
new MenuItem ("_Paste", "", null)
new MenuItem ("_Copy", "", Copy),
new MenuItem ("C_ut", "", Cut),
new MenuItem ("_Paste", "", Paste),
new MenuItem ("_Find and Replace",
new MenuBarItem (new MenuItem[] {menuItems [0], menuItems [1] })),
menuItems[3]
}),
new MenuBarItem ("_List Demos", new MenuItem [] {
new MenuBarItem ("_List Demos", new MenuItem [] {
new MenuItem ("Select Items", "", ListSelectionDemo),
}),
new MenuBarItem ("Test Menu and SubMenus", new MenuItem [] {
new MenuItem ("SubMenu1Item1",
new MenuBarItem (new MenuItem[] {
new MenuItem ("SubMenu2Item1",
new MenuBarItem (new MenuItem [] {
new MenuItem ("SubMenu3Item1",
new MenuBarItem (new MenuItem [] { menuItems [2] })
)
})
)
})
)
}),
});
menuKeysStyle = new CheckBox (3, 25, "UseKeysUpDownAsKeysLeftRight", true);
menuKeysStyle.Toggled += MenuKeysStyle_Toggled;
menuAutoMouseNav = new CheckBox (40, 25, "UseMenuAutoNavigation", true);
menuAutoMouseNav.Toggled += MenuAutoMouseNav_Toggled;
ShowEntries (win);
int count = 0;
@@ -341,14 +491,14 @@ static class Demo {
ml.Text = $"Mouse: ({me.X},{me.Y}) - {me.Flags} {count++}";
};
var test = new Label (3, 18, "Se iniciará el análisis");
win.Add (test);
win.Add (ml);
// ShowTextAlignments (win);
ShowTextAlignments (win);
top.Add (win);
top.Add (menu);
Application.Run ();
}
}
}

View File

@@ -228,6 +228,8 @@ namespace Terminal.Gui {
View container = null;
View focused = null;
Direction focusDirection;
public event EventHandler OnEnter;
public event EventHandler OnLeave;
internal Direction FocusDirection {
get => SuperView?.FocusDirection ?? focusDirection;
@@ -430,7 +432,7 @@ namespace Terminal.Gui {
SetNeedsDisplay (Bounds);
}
bool layoutNeeded = true;
internal bool layoutNeeded = true;
internal void SetNeedsLayout ()
{
@@ -826,11 +828,16 @@ namespace Terminal.Gui {
}
internal set {
if (base.HasFocus != value)
if (value == true)
OnEnter?.Invoke (this, new EventArgs ());
else
OnLeave?.Invoke (this, new EventArgs ());
SetNeedsDisplay ();
base.HasFocus = value;
// Remove focus down the chain of subviews if focus is removed
if (value == false && focused != null) {
OnLeave?.Invoke (focused, new EventArgs ());
focused.HasFocus = false;
focused = null;
}
@@ -1283,6 +1290,19 @@ namespace Terminal.Gui {
/// toplevel and then invoke <see cref="M:Terminal.Gui.Application.Run"/> with the
/// new toplevel.
/// </para>
/// <para>
/// TopLevels can also opt-in to more sophisticated initialization
/// by implementing <see cref="ISupportInitialize"/>. When they do
/// so, the <see cref="ISupportInitialize.BeginInit"/> and
/// <see cref="ISupportInitialize.EndInit"/> methods will be called
/// before running the view.
/// If first-run-only initialization is preferred, the <see cref="ISupportInitializeNotification"/>
/// can be implemented too, in which case the <see cref="ISupportInitialize"/>
/// methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
/// is <see langword="false"/>. This allows proper View inheritance hierarchies
/// to override base class layout code optimally by doing so only on first run,
/// instead of on every run.
/// </para>
/// </remarks>
public class Toplevel : View {
/// <summary>
@@ -1799,25 +1819,25 @@ namespace Terminal.Gui {
{
var chain = toplevels.ToList();
foreach (var topLevel in chain) {
if (topLevel.Modal)
break;
if (topLevel.ProcessHotKey (ke))
return;
if (topLevel.Modal)
break;
}
foreach (var topLevel in chain) {
if (topLevel.Modal)
break;
if (topLevel.ProcessKey (ke))
return;
if (topLevel.Modal)
break;
}
foreach (var topLevel in chain) {
if (topLevel.Modal)
break;
// Process the key normally
if (topLevel.ProcessColdKey (ke))
return;
if (topLevel.Modal)
break;
}
}
@@ -2041,11 +2061,28 @@ namespace Terminal.Gui {
DrawBounds (state.Toplevel);
state.Toplevel.PositionCursor ();
Driver.Refresh ();
} else if (CheckLayoutNeeded (state.Toplevel)) {
TerminalResized ();
layoutNeeded = false;
} else
Driver.UpdateCursor ();
}
}
static bool layoutNeeded;
static bool CheckLayoutNeeded (View view)
{
if (view.layoutNeeded)
return layoutNeeded = view.layoutNeeded;
for (int i = 0; view.Subviews.Count > i; i++) {
CheckLayoutNeeded (view.Subviews [i]);
if (layoutNeeded)
return layoutNeeded;
}
return layoutNeeded;
}
internal static bool DebugDrawBounds;
// Need to look into why this does not work properly.

View File

@@ -142,6 +142,10 @@ namespace Terminal.Gui {
/// </summary>
public Attribute Normal;
/// <summary>
/// The default color for text, when the view is disabled.
/// </summary>
public Attribute Disabled;
/// <summary>
/// The color for text when the view has the focus.
/// </summary>
public Attribute Focus;

View File

@@ -264,6 +264,7 @@ namespace Terminal.Gui {
Colors.Menu.Focus = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_BLACK);
Colors.Menu.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN);
Colors.Menu.Normal = Curses.A_BOLD | MakeColor (Curses.COLOR_WHITE, Curses.COLOR_CYAN);
Colors.Menu.Disabled = MakeColor(Curses.COLOR_WHITE, Curses.COLOR_CYAN);
Colors.Dialog.Normal = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_WHITE);
Colors.Dialog.Focus = MakeColor (Curses.COLOR_BLACK, Curses.COLOR_CYAN);

View File

@@ -144,6 +144,7 @@ namespace Terminal.Gui {
Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan);
Colors.Menu.Disabled = MakeColor(ConsoleColor.DarkGray, ConsoleColor.Cyan);
Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);

View File

@@ -553,7 +553,7 @@ namespace Terminal.Gui {
case WindowsConsole.EventType.WindowBufferSize:
cols = inputEvent.WindowBufferSizeEvent.size.X;
rows = inputEvent.WindowBufferSizeEvent.size.Y - 1;
rows = inputEvent.WindowBufferSizeEvent.size.Y;
ResizeScreen ();
UpdateOffScreen ();
TerminalResized?.Invoke();
@@ -566,7 +566,9 @@ namespace Terminal.Gui {
private MouseEvent ToDriverMouse (WindowsConsole.MouseEventRecord mouseEvent)
{
MouseFlags mouseFlag = MouseFlags.AllEvents;
MouseFlags mouseFlag = 0;
// The ButtonState member of the MouseEvent structure has bit corresponding to each mouse button.
// This will tell when a mouse button is pressed. When the button is released this event will
@@ -577,7 +579,8 @@ namespace Terminal.Gui {
LastMouseButtonPressed = null;
}
if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null) {
if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null ||
mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved && mouseEvent.ButtonState != 0) {
switch (mouseEvent.ButtonState) {
case WindowsConsole.ButtonState.Button1Pressed:
mouseFlag = MouseFlags.Button1Pressed;
@@ -587,8 +590,8 @@ namespace Terminal.Gui {
mouseFlag = MouseFlags.Button2Pressed;
break;
case WindowsConsole.ButtonState.Button3Pressed:
mouseFlag = MouseFlags.Button3Pressed;
case WindowsConsole.ButtonState.RightmostButtonPressed:
mouseFlag = MouseFlags.Button4Pressed;
break;
}
LastMouseButtonPressed = mouseEvent.ButtonState;
@@ -602,11 +605,14 @@ namespace Terminal.Gui {
mouseFlag = MouseFlags.Button2Clicked;
break;
case WindowsConsole.ButtonState.Button3Pressed:
mouseFlag = MouseFlags.Button3Clicked;
case WindowsConsole.ButtonState.RightmostButtonPressed:
mouseFlag = MouseFlags.Button4Clicked;
break;
}
LastMouseButtonPressed = null;
} else if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseWheeled) {
mouseFlag = MouseFlags.ButtonWheeled;
LastMouseButtonPressed = null;
} else if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) {
mouseFlag = MouseFlags.ReportMousePosition;
}
@@ -759,6 +765,7 @@ namespace Terminal.Gui {
Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan);
Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan);
Colors.Menu.Disabled = MakeColor(ConsoleColor.DarkGray, ConsoleColor.Cyan);
Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan);

View File

@@ -400,11 +400,11 @@ namespace Terminal.Gui {
/// </summary>
Button4TripleClicked = unchecked((int)0x400000),
/// <summary>
/// The fourth button was pressed.
/// Flag: the shift key was pressed when the mouse button took place.
/// </summary>
ButtonShift = unchecked((int)0x2000000),
/// <summary>
/// Flag: the shift key was pressed when the mouse button took place.
/// Flag: the ctrl key was pressed when the mouse button took place.
/// </summary>
ButtonCtrl = unchecked((int)0x1000000),
/// <summary>
@@ -416,6 +416,10 @@ namespace Terminal.Gui {
/// </summary>
ReportMousePosition = unchecked((int)0x8000000),
/// <summary>
/// Vertical button wheeled.
/// </summary>
ButtonWheeled = unchecked((int)0x4040),
/// <summary>
/// Mask that captures all the events.
/// </summary>
AllEvents = unchecked((int)0x7ffffff),

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ namespace Terminal.Gui {
/// Client code can hook up to this event, it is
/// raised when the text in the entry changes.
/// </remarks>
public event EventHandler Changed;
public event EventHandler<ustring> Changed;
/// <summary>
/// Public constructor that creates a text field, with layout controlled with X, Y, Width and Height.
@@ -58,6 +58,7 @@ namespace Terminal.Gui {
this.text = TextModel.ToRunes (text);
point = text.Length;
CanFocus = true;
WantMousePositionReports = true;
}
/// <summary>
@@ -98,7 +99,10 @@ namespace Terminal.Gui {
}
set {
ustring oldText = ustring.Make (text);
text = TextModel.ToRunes (value);
Changed?.Invoke (this, oldText);
if (point > text.Count)
point = Math.Max (text.Count-1, 0);
@@ -145,6 +149,9 @@ namespace Terminal.Gui {
public override void Redraw (Rect region)
{
ColorScheme color = Colors.Menu;
SetSelStartSelLength ();
Driver.SetAttribute (ColorScheme.Focus);
Move (0, 0);
@@ -157,11 +164,14 @@ namespace Terminal.Gui {
if (idx < first)
continue;
var cols = Rune.ColumnWidth (rune);
System.Diagnostics.Debug.WriteLine ($"SelStart: {SelStart}, SelLength: {SelLength} SelText: {SelText}");
Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : ColorScheme.Focus);
if (col + cols < width)
Driver.AddRune ((Rune)(Secret ? '*' : rune));
col += cols;
}
Driver.SetAttribute (ColorScheme.Focus);
for (int i = col; i < Frame.Width; i++)
Driver.AddRune (' ');
@@ -193,8 +203,6 @@ namespace Terminal.Gui {
void SetText (List<Rune> newText)
{
text = newText;
if (Changed != null)
Changed (this, EventArgs.Empty);
}
void SetText (IEnumerable<Rune> newText)
@@ -215,6 +223,9 @@ namespace Terminal.Gui {
public override bool ProcessKey (KeyEvent kb)
{
if (selResetNeeded || SelStart > -1)
ClearAllSelection ();
// remember current cursor position
// because the new calculated cursor position is needed to be set BEFORE the change event is triggert
// Needed for the Elmish Wrapper issue https://github.com/DieselMeister/Terminal.Gui.Elmish/issues/2
@@ -222,6 +233,7 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.DeleteChar:
// TODO: If text length greater than 0 delete all selected text and reposition the cursor
case Key.ControlD:
if (text.Count == 0 || text.Count== point)
return true;
@@ -232,6 +244,7 @@ namespace Terminal.Gui {
case Key.Delete:
case Key.Backspace:
// TODO: If text length greater than 0 delete all selected text and reposition the cursor
if (point == 0)
return true;
@@ -401,9 +414,18 @@ namespace Terminal.Gui {
return -1;
}
public override bool MouseEvent (MouseEvent ev)
public int SelStart { get; set; } = -1;
public int SelLength { get; set; } = 0;
public ustring SelText { get; set; }
bool selResetNeeded;
int start, length;
public override bool MouseEvent (MouseEvent ev)
{
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked))
if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked) && !ev.Flags.HasFlag (MouseFlags.Button1Pressed))
return false;
if (!HasFocus)
@@ -416,10 +438,41 @@ namespace Terminal.Gui {
if (point < first)
point = 0;
// FIXME: If mouse exits out of view with left button pressed I can't change selResetNeeded to true
if (ev.Flags.HasFlag (MouseFlags.Button1Clicked) && SelStart > -1)
selResetNeeded = true;
else if (ev.Flags.HasFlag (MouseFlags.Button1Pressed)) {
if (selResetNeeded)
ClearAllSelection ();
selResetNeeded = false;
SelStart = SelStart == -1 && text.Count > 0 && ev.X >= 0 && ev.X <= text.Count ? ev.X : SelStart;
if (SelStart > -1) {
SelLength = SelStart > -1 && ev.X <= text.Count ? ev.X - SelStart : text.Count - SelStart;
SetSelStartSelLength ();
SelText = length > 0 ? ustring.Make (text).ToString ().Substring (start, length) : "";
}
}
SetNeedsDisplay ();
return true;
}
void ClearAllSelection ()
{
SelStart = -1;
SelLength = 0;
SelText = "";
}
void SetSelStartSelLength ()
{
if (SelLength < 0) {
start = SelLength + SelStart;
length = Math.Abs (SelLength);
} else {
start = SelStart;
length = SelLength;
}
}
}
}