From 6dfdf13603f24aa65800e9f68fc5c8e17b419810 Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 11 Mar 2020 02:46:22 +0000 Subject: [PATCH] Fixed some bugs with the mouse event and text selection, copy, cut and paste. There is still a random failure in the mouse events that lock on button released and only trigger button clicked after moving the mouse. --- Example/demo.cs | 28 ++++----- Terminal.Gui/Core.cs | 82 +++++++++++++-------------- Terminal.Gui/Dialogs/FileDialog.cs | 1 + Terminal.Gui/Drivers/ConsoleDriver.cs | 27 ++++++--- Terminal.Gui/Drivers/CursesDriver.cs | 4 +- Terminal.Gui/Drivers/NetDriver.cs | 4 +- Terminal.Gui/Drivers/WindowsDriver.cs | 46 +++++++++++---- Terminal.Gui/Views/TextField.cs | 27 ++++++--- 8 files changed, 134 insertions(+), 85 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index f4f87c069..e94a9e36a 100644 --- a/Example/demo.cs +++ b/Example/demo.cs @@ -87,7 +87,7 @@ static class Demo { }; #if false scrollView.Add (new Box10x (0, 0)); -#else +#else scrollView.Add (new Filler (new Rect (0, 0, 40, 40))); #endif @@ -176,7 +176,7 @@ static class Demo { Application.Run (d); } - // + // // Creates a nested editor static void Editor (Toplevel top) { @@ -235,10 +235,11 @@ static class Demo { public static void Open () { - var d = new OpenDialog ("Open", "Open a file"); + var d = new OpenDialog ("Open", "Open a file") { AllowsMultipleSelection = true }; Application.Run (d); - MessageBox.Query (50, 7, "Selected File", string.Join (", ", d.FilePaths), "Ok"); + if (!d.Canceled) + MessageBox.Query (50, 7, "Selected File", string.Join (", ", d.FilePaths), "Ok"); } public static void ShowHex (Toplevel top) @@ -328,24 +329,24 @@ static class Demo { private static void Copy () { TextField textField = menu.LastFocused as TextField; - if (textField != null && textField.SelLength > 0) { + 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) { + 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); + int selStart = textField.SelLength < 0 ? textField.SelLength + textField.SelStart : textField.SelStart; + int selLength = Math.Abs (textField.SelLength); + string newText = actualText.Substring (0, selStart) + + actualText.Substring (selStart + selLength, actualText.Length - selStart - selLength); textField.Text = newText; - textField.SelLength = 0; - textField.CursorPosition = textField.SelStart == -1 ? textField.CursorPosition : textField.SelStart; + textField.ClearAllSelection (); + textField.CursorPosition = selStart >= textField.Text.Length ? textField.Text.Length : textField.CursorPosition; textField.SetNeedsDisplay (); } } @@ -356,7 +357,7 @@ static class Demo { if (textField != null) { string actualText = textField.Text.ToString (); int start = textField.SelStart == -1 ? textField.CursorPosition : textField.SelStart; - string newText = actualText.Substring (0, start) + + string newText = actualText.Substring (0, start) + Clipboard.Contents?.ToString() + actualText.Substring (start + textField.SelLength, actualText.Length - start - textField.SelLength); textField.Text = newText; @@ -449,6 +450,7 @@ static class Demo { new MenuItem ("_Open", "", Open), new MenuItem ("_Hex", "", () => ShowHex (top)), new MenuItem ("_Close", "", () => Close ()), + new MenuItem ("_Disabled", "", () => { }, () => false), null, new MenuItem ("_Quit", "", () => { if (Quit ()) top.Running = false; }) }), diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs index 23f24ab7f..778c55635 100644 --- a/Terminal.Gui/Core.cs +++ b/Terminal.Gui/Core.cs @@ -68,7 +68,7 @@ namespace Terminal.Gui { /// /// If the view is focused, gives the view a - /// chance to process the keystroke. + /// chance to process the keystroke. /// /// /// @@ -83,7 +83,7 @@ namespace Terminal.Gui { /// /// /// The View implementation does nothing but return false, - /// so it is not necessary to call base.ProcessKey if you + /// so it is not necessary to call base.ProcessKey if you /// derive directly from View, but you should if you derive /// other View subclasses. /// @@ -134,7 +134,7 @@ namespace Terminal.Gui { /// /// Determines the LayoutStyle for a view, if Absolute, during LayoutSubviews, the - /// value from the Frame will be used, if the value is Computer, then the Frame + /// value from the Frame will be used, if the value is Computer, then the Frame /// will be updated from the X, Y Pos objets and the Width and Heigh Dim objects. /// public enum LayoutStyle { @@ -161,27 +161,27 @@ namespace Terminal.Gui { /// /// Views can either be created with an absolute position, by calling the constructor that takes a /// Rect parameter to specify the absolute position and size (the Frame of the View) or by setting the - /// X, Y, Width and Height properties on the view. Both approaches use coordinates that are relative + /// X, Y, Width and Height properties on the view. Both approaches use coordinates that are relative /// to the container they are being added to. /// /// - /// When you do not specify a Rect frame you can use the more flexible - /// Dim and Pos objects that can dynamically update the position of a view. + /// When you do not specify a Rect frame you can use the more flexible + /// Dim and Pos objects that can dynamically update the position of a view. /// The X and Y properties are of type /// and you can use either absolute positions, percentages or anchor - /// points. The Width and Height properties are of type - /// and can use absolute position, + /// points. The Width and Height properties are of type + /// and can use absolute position, /// percentages and anchors. These are useful as they will take /// care of repositioning your views if your view's frames are resized /// or if the terminal size changes. /// /// - /// When you specify the Rect parameter to a view, you are setting the LayoutStyle to Absolute, and the - /// view will always stay in the position that you placed it. To change the position change the + /// When you specify the Rect parameter to a view, you are setting the LayoutStyle to Absolute, and the + /// view will always stay in the position that you placed it. To change the position change the /// Frame property to the new position. /// /// - /// Subviews can be added to a View by calling the Add method. The container of a view is the + /// Subviews can be added to a View by calling the Add method. The container of a view is the /// Superview. /// /// @@ -192,7 +192,7 @@ namespace Terminal.Gui { /// Views have a ColorScheme property that defines the default colors that subviews /// should use for rendering. This ensures that the views fit in the context where /// they are being used, and allows for themes to be plugged in. For example, the - /// default colors for windows and toplevels uses a blue background, while it uses + /// default colors for windows and toplevels uses a blue background, while it uses /// a white background for dialog boxes and a red background for errors. /// /// @@ -208,7 +208,7 @@ namespace Terminal.Gui { /// /// Views that are focusable should implement the PositionCursor to make sure that /// the cursor is placed in a location that makes sense. Unix terminals do not have - /// a way of hiding the cursor, so it can be distracting to have the cursor left at + /// a way of hiding the cursor, so it can be distracting to have the cursor left at /// the last focused view. So views should make sure that they place the cursor /// in a visually sensible place. /// @@ -249,7 +249,7 @@ namespace Terminal.Gui { static IList empty = new List (0).AsReadOnly (); - // This is null, and allocated on demand. + // This is null, and allocated on demand. List subviews; /// @@ -284,7 +284,7 @@ namespace Terminal.Gui { /// /// The frame. /// - /// Altering the Frame of a view will trigger the redrawing of the + /// Altering the Frame of a view will trigger the redrawing of the /// view as well as the redrawing of the affected regions in the superview. /// public virtual Rect Frame { @@ -414,7 +414,7 @@ namespace Terminal.Gui { /// /// Initializes a new instance of the class and sets the - /// view up for Computed layout, which will use the values in X, Y, Width and Height to + /// view up for Computed layout, which will use the values in X, Y, Width and Height to /// compute the View's Frame. /// public View () @@ -1222,8 +1222,8 @@ namespace Terminal.Gui { } /// - /// This virtual method is invoked when a view starts executing or - /// when the dimensions of the view have changed, for example in + /// This virtual method is invoked when a view starts executing or + /// when the dimensions of the view have changed, for example in /// response to the container view or terminal resizing. /// public virtual void LayoutSubviews () @@ -1291,23 +1291,23 @@ namespace Terminal.Gui { /// new toplevel. /// /// - /// TopLevels can also opt-in to more sophisticated initialization - /// by implementing . When they do - /// so, the and - /// methods will be called + /// TopLevels can also opt-in to more sophisticated initialization + /// by implementing . When they do + /// so, the and + /// methods will be called /// before running the view. - /// If first-run-only initialization is preferred, the - /// can be implemented too, in which case the - /// methods will only be called if - /// is . This allows proper View inheritance hierarchies - /// to override base class layout code optimally by doing so only on first run, + /// If first-run-only initialization is preferred, the + /// can be implemented too, in which case the + /// methods will only be called if + /// is . 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. /// /// public class Toplevel : View { /// /// This flag is checked on each iteration of the mainloop and it continues - /// running until this flag is set to false. + /// running until this flag is set to false. /// public bool Running; @@ -1344,8 +1344,8 @@ namespace Terminal.Gui { } /// - /// Determines whether the is modal or not. - /// Causes to propagate keys upwards + /// Determines whether the is modal or not. + /// Causes to propagate keys upwards /// by default unless set to . /// public bool Modal { get; set; } @@ -1467,7 +1467,7 @@ namespace Terminal.Gui { int padding; /// /// Initializes a new instance of the with - /// the specified frame for its location, with the specified border + /// the specified frame for its location, with the specified border /// an optional title. /// /// Frame. @@ -1485,7 +1485,7 @@ namespace Terminal.Gui { /// /// Initializes a new instance of the with - /// the specified frame for its location, with the specified border + /// the specified frame for its location, with the specified border /// an optional title. /// /// Number of characters to use for padding of the drawn frame. @@ -1580,15 +1580,15 @@ namespace Terminal.Gui { } #if true - // + // // It does not look like the event is raised on clicked-drag // need to figure that out. // Point? dragPosition; public override bool MouseEvent(MouseEvent mouseEvent) { - // The code is currently disabled, because the - // Driver.UncookMouse does not seem to have an effect if there is + // The code is currently disabled, because the + // Driver.UncookMouse does not seem to have an effect if there is // a pending mouse event activated. if (true) return false; @@ -1648,7 +1648,7 @@ namespace Terminal.Gui { /// /// /// - /// You can hook up to the Iteration event to have your method + /// You can hook up to the Iteration event to have your method /// invoked on each iteration of the mainloop. /// /// @@ -1688,7 +1688,7 @@ namespace Terminal.Gui { /// /// This event is raised on each iteration of the - /// main loop. + /// main loop. /// /// /// See also @@ -1940,7 +1940,7 @@ namespace Terminal.Gui { /// Toplevel to prepare execution for. /// /// This method prepares the provided toplevel for running with the focus, - /// it adds this to the list of toplevels, sets up the mainloop to process the + /// it adds this to the list of toplevels, sets up the mainloop to process the /// event, lays out the subviews, focuses the first element, and draws the /// toplevel in the screen. This is usually followed by executing /// the method, and then the method upon termination which will @@ -1953,7 +1953,7 @@ namespace Terminal.Gui { var rs = new RunState (toplevel); Init (); - if (toplevel is ISupportInitializeNotification initializableNotification && + if (toplevel is ISupportInitializeNotification initializableNotification && !initializableNotification.IsInitialized) { initializableNotification.BeginInit(); initializableNotification.EndInit(); @@ -2040,7 +2040,7 @@ namespace Terminal.Gui { /// /// /// Use the wait parameter to control whether this is a - /// blocking or non-blocking call. + /// blocking or non-blocking call. /// /// The state returned by the Begin method. /// By default this is true which will execute the runloop waiting for events, if you pass false, you can use this method to run a single iteration of the events. @@ -2131,7 +2131,7 @@ namespace Terminal.Gui { /// returned value, and then calling end on the return value. /// /// - /// Alternatively, if your program needs to control the main loop and needs to + /// Alternatively, if your program needs to control the main loop and needs to /// process events manually, you can invoke Begin to set things up manually and then /// repeatedly call RunLoop with the wait parameter set to false. By doing this /// the RunLoop method will only process any pending events, timers, idle handlers and diff --git a/Terminal.Gui/Dialogs/FileDialog.cs b/Terminal.Gui/Dialogs/FileDialog.cs index e673c1394..23aa1793b 100644 --- a/Terminal.Gui/Dialogs/FileDialog.cs +++ b/Terminal.Gui/Dialogs/FileDialog.cs @@ -77,6 +77,7 @@ namespace Terminal.Gui { bool shiftOnWheel; public override bool MouseEvent (MouseEvent me) { + System.Diagnostics.Debug.WriteLine ($"Flags: {me.Flags}"); if ((me.Flags & (MouseFlags.Button1Clicked | MouseFlags.Button1DoubleClicked | MouseFlags.WheeledUp | MouseFlags.WheeledDown)) == 0) return false; diff --git a/Terminal.Gui/Drivers/ConsoleDriver.cs b/Terminal.Gui/Drivers/ConsoleDriver.cs index fffb90ee4..99e839667 100644 --- a/Terminal.Gui/Drivers/ConsoleDriver.cs +++ b/Terminal.Gui/Drivers/ConsoleDriver.cs @@ -155,16 +155,13 @@ namespace Terminal.Gui { private Attribute _focus; private Attribute _hotNormal; private Attribute _hotFocus; + private Attribute _disabled; /// /// The default color for text, when the view is not focused. /// public Attribute Normal { get { return _normal; } set { _normal = SetAttribute (value); } } - /// - /// The default color for text, when the view is disabled. - /// - public Attribute Disabled; /// /// The color for text when the view has the focus. /// @@ -180,6 +177,11 @@ namespace Terminal.Gui { /// public Attribute HotFocus { get { return _hotFocus; } set { _hotFocus = SetAttribute (value); } } + /// + /// The default color for text, when the view is disabled. + /// + public Attribute Disabled { get { return _disabled; } set { _disabled = SetAttribute (value); } } + public string Caller = ""; private bool preparingScheme = false; @@ -220,6 +222,7 @@ namespace Terminal.Gui { if (Focus.background != attribute.background) Focus = Application.Driver.MakeAttribute (attribute.foreground, Focus.background); HotNormal = Application.Driver.MakeAttribute (HotNormal.foreground, attribute.background); + Disabled = Application.Driver.MakeAttribute (Disabled.foreground, attribute.background); break; case "Focus": Normal = Application.Driver.MakeAttribute (attribute.foreground, Normal.background); @@ -229,12 +232,20 @@ namespace Terminal.Gui { if (Focus.background != attribute.background) HotFocus = Application.Driver.MakeAttribute (attribute.foreground, HotFocus.background); Normal = Application.Driver.MakeAttribute (Normal.foreground, attribute.background); + Disabled = Application.Driver.MakeAttribute (Disabled.foreground, attribute.background); break; case "HotFocus": HotNormal = Application.Driver.MakeAttribute (attribute.foreground, HotNormal.background); if (Focus.foreground != attribute.background) Focus = Application.Driver.MakeAttribute (Focus.foreground, attribute.background); break; + case "Disabled": + if (Focus.background != attribute.background) + HotFocus = Application.Driver.MakeAttribute (attribute.foreground, HotFocus.background); + Normal = Application.Driver.MakeAttribute (Normal.foreground, attribute.background); + HotNormal = Application.Driver.MakeAttribute (HotNormal.foreground, attribute.background); + break; + } break; @@ -374,7 +385,7 @@ namespace Terminal.Gui { RightTee, /// - /// Top tee + /// Top tee /// TopTee, @@ -416,7 +427,7 @@ namespace Terminal.Gui { /// Rune to add. public abstract void AddRune (Rune rune); /// - /// Adds the specified + /// Adds the specified /// /// String. public abstract void AddStr (ustring str); @@ -454,7 +465,7 @@ namespace Terminal.Gui { // Advanced uses - set colors to any pre-set pairs, you would need to init_color // that independently with the R, G, B values. /// - /// Advanced uses - set colors to any pre-set pairs, you would need to init_color + /// Advanced uses - set colors to any pre-set pairs, you would need to init_color /// that independently with the R, G, B values. /// /// Foreground color identifier. @@ -608,7 +619,7 @@ namespace Terminal.Gui { public Rune RightTee; /// - /// Top tee + /// Top tee /// public Rune TopTee; diff --git a/Terminal.Gui/Drivers/CursesDriver.cs b/Terminal.Gui/Drivers/CursesDriver.cs index 0b9ce8cde..73966586e 100644 --- a/Terminal.Gui/Drivers/CursesDriver.cs +++ b/Terminal.Gui/Drivers/CursesDriver.cs @@ -255,7 +255,7 @@ namespace Terminal.Gui { Colors.Base.HotNormal = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_BLUE); Colors.Base.HotFocus = Curses.A_BOLD | MakeColor (Curses.COLOR_YELLOW, Curses.COLOR_CYAN); - // Focused, + // Focused, // Selected, Hot: Yellow on Black // Selected, text: white on black // Unselected, hot: yellow on cyan @@ -411,7 +411,7 @@ namespace Terminal.Gui { suspendSignal = 18; break; case "Linux": - // TODO: should fetch the machine name and + // TODO: should fetch the machine name and // if it is MIPS return 24 suspendSignal = 20; break; diff --git a/Terminal.Gui/Drivers/NetDriver.cs b/Terminal.Gui/Drivers/NetDriver.cs index aec15a73c..0b5217910 100644 --- a/Terminal.Gui/Drivers/NetDriver.cs +++ b/Terminal.Gui/Drivers/NetDriver.cs @@ -135,7 +135,7 @@ namespace Terminal.Gui { Colors.Base.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Blue); Colors.Base.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan); - // Focused, + // Focused, // Selected, Hot: Yellow on Black // Selected, text: white on black // Unselected, hot: yellow on cyan @@ -349,7 +349,7 @@ namespace Terminal.Gui { } // - // These are for the .NET driver, but running natively on Windows, wont run + // These are for the .NET driver, but running natively on Windows, wont run // on the Mono emulation // diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs b/Terminal.Gui/Drivers/WindowsDriver.cs index 50f757ddd..b5a5a39fe 100644 --- a/Terminal.Gui/Drivers/WindowsDriver.cs +++ b/Terminal.Gui/Drivers/WindowsDriver.cs @@ -1,5 +1,5 @@ // -// WindowsDriver.cs: Windows specific driver +// WindowsDriver.cs: Windows specific driver // // Authors: // Miguel de Icaza (miguel@gnome.org) @@ -13,10 +13,10 @@ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -520,7 +520,7 @@ namespace Terminal.Gui { } finally { eventReady.Reset(); } - Debug.WriteLine("Events ready"); + //Debug.WriteLine("Events ready"); if (!tokenSource.IsCancellationRequested) return result != null; @@ -572,9 +572,11 @@ namespace Terminal.Gui { } private WindowsConsole.ButtonState? LastMouseButtonPressed = null; + private bool IsButtonReleased = false; private MouseEvent ToDriverMouse (WindowsConsole.MouseEventRecord mouseEvent) { + // MouseFlags.AllEvents have a behavior on double click with a extra click. MouseFlags mouseFlag = 0; @@ -584,12 +586,14 @@ namespace Terminal.Gui { // be fired with it's bit set to 0. So when the button is up ButtonState will be 0. // To map to the correct driver events we save the last pressed mouse button so we can // map to the correct clicked event. - if (LastMouseButtonPressed != null && mouseEvent.ButtonState != 0) { + if ((LastMouseButtonPressed != null || IsButtonReleased) && mouseEvent.ButtonState != 0) { LastMouseButtonPressed = null; + IsButtonReleased = false; } - - if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null || - mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved && mouseEvent.ButtonState != 0) { + Debug.WriteLine ($"ToDriverMouse: {mouseEvent}"); + if ((mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null) || + (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved && + mouseEvent.ButtonState != 0)) { switch (mouseEvent.ButtonState) { case WindowsConsole.ButtonState.Button1Pressed: mouseFlag = MouseFlags.Button1Pressed; @@ -603,8 +607,27 @@ namespace Terminal.Gui { mouseFlag = MouseFlags.Button3Pressed; break; } + + if (mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) + mouseFlag |= MouseFlags.ReportMousePosition; LastMouseButtonPressed = mouseEvent.ButtonState; - } else if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed != null) { + } else if (mouseEvent.EventFlags == 0 && LastMouseButtonPressed != null && !IsButtonReleased) { + switch (LastMouseButtonPressed) { + case WindowsConsole.ButtonState.Button1Pressed: + mouseFlag = MouseFlags.Button1Released; + break; + + case WindowsConsole.ButtonState.Button2Pressed: + mouseFlag = MouseFlags.Button2Released; + break; + + case WindowsConsole.ButtonState.RightmostButtonPressed: + mouseFlag = MouseFlags.Button3Released; + break; + } + IsButtonReleased = true; + } else if ((mouseEvent.EventFlags == 0 || mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) && + IsButtonReleased) { switch (LastMouseButtonPressed) { case WindowsConsole.ButtonState.Button1Pressed: mouseFlag = MouseFlags.Button1Clicked; @@ -619,6 +642,7 @@ namespace Terminal.Gui { break; } LastMouseButtonPressed = null; + IsButtonReleased = false; switch (mouseEvent.ControlKeyState) { case WindowsConsole.ControlKeyState.RightControlPressed: @@ -669,6 +693,7 @@ namespace Terminal.Gui { mouseFlag = MouseFlags.ReportMousePosition; } + Debug.WriteLine ($"MouseFlags: {mouseFlag}"); return new MouseEvent () { X = mouseEvent.MousePosition.X, Y = mouseEvent.MousePosition.Y, @@ -816,7 +841,7 @@ namespace Terminal.Gui { Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan); 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.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black); Colors.Menu.Disabled = MakeColor(ConsoleColor.DarkGray, ConsoleColor.Cyan); Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); @@ -961,6 +986,7 @@ namespace Terminal.Gui { }; winConsole.SetCursorPosition(position); } + public override void End () { winConsole.Cleanup(); diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index 43295c5b8..4fbc4746b 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -164,7 +164,7 @@ namespace Terminal.Gui { if (idx < first) continue; var cols = Rune.ColumnWidth (rune); - System.Diagnostics.Debug.WriteLine ($"SelStart: {SelStart}, SelLength: {SelLength} SelText: {SelText}"); + //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)); @@ -422,10 +422,13 @@ namespace Terminal.Gui { bool selResetNeeded; int start, length; + //bool isButtonReleased; public override bool MouseEvent (MouseEvent ev) { - if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked) && !ev.Flags.HasFlag (MouseFlags.Button1Pressed)) + System.Diagnostics.Debug.WriteLine ($"Flags: {ev.Flags}"); + if (!ev.Flags.HasFlag (MouseFlags.Button1Clicked) && !ev.Flags.HasFlag (MouseFlags.Button1Pressed) && + !ev.Flags.HasFlag (MouseFlags.Button1Released)) return false; if (!HasFocus) @@ -442,22 +445,28 @@ namespace Terminal.Gui { if (ev.Flags.HasFlag (MouseFlags.Button1Clicked) && SelStart > -1) selResetNeeded = true; else if (ev.Flags.HasFlag (MouseFlags.Button1Pressed)) { + //isButtonReleased = false; 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) : ""; - } + PrepareSelection (ev); } SetNeedsDisplay (); return true; } - void ClearAllSelection () + private void PrepareSelection (MouseEvent ev) + { + 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) : ""; + } + } + + public void ClearAllSelection () { SelStart = -1; SelLength = 0;