diff --git a/src/Consolonia.Core/Dummy/DummyConsole.cs b/src/Consolonia.Core/Dummy/DummyConsole.cs index f3fc6efc..883fc56f 100644 --- a/src/Consolonia.Core/Dummy/DummyConsole.cs +++ b/src/Consolonia.Core/Dummy/DummyConsole.cs @@ -34,6 +34,8 @@ public bool CaretVisible public bool SupportsComplexEmoji => true; public bool SupportsAltSolo => false; + public bool SupportsMouse => false; + public bool SupportsMouseMove => false; public void ClearOutput() { diff --git a/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs b/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs index 3437cd57..ffffbc18 100644 --- a/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs +++ b/src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs @@ -48,6 +48,8 @@ public DefaultNetConsole() } public override bool SupportsAltSolo => false; + public override bool SupportsMouse => false; + public override bool SupportsMouseMove => false; protected override void Dispose(bool disposing) { diff --git a/src/Consolonia.Core/Infrastructure/IConsole.cs b/src/Consolonia.Core/Infrastructure/IConsole.cs index d4975340..d9f94b3b 100644 --- a/src/Consolonia.Core/Infrastructure/IConsole.cs +++ b/src/Consolonia.Core/Infrastructure/IConsole.cs @@ -22,6 +22,8 @@ public interface IConsole : IDisposable bool SupportsComplexEmoji { get; } bool SupportsAltSolo { get; } + bool SupportsMouse { get; } + bool SupportsMouseMove { get; } void SetTitle(string title); diff --git a/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs b/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs index dff6c716..d5c39dab 100644 --- a/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs +++ b/src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs @@ -37,6 +37,8 @@ protected InputLessDefaultNetConsole() public bool SupportsComplexEmoji => _supportEmoji ?? false; public abstract bool SupportsAltSolo { get; } + public abstract bool SupportsMouse { get; } + public abstract bool SupportsMouseMove { get; } public void SetTitle(string title) { diff --git a/src/Consolonia.Core/InternalHelpers/CommonInternalHelper.cs b/src/Consolonia.Core/InternalHelpers/CommonInternalHelper.cs index dc15318f..3a0658f3 100644 --- a/src/Consolonia.Core/InternalHelpers/CommonInternalHelper.cs +++ b/src/Consolonia.Core/InternalHelpers/CommonInternalHelper.cs @@ -3,7 +3,7 @@ namespace Consolonia.Core.InternalHelpers { - internal static class CommonInternalHelper + public static class CommonInternalHelper { public static bool IsNearlyEqual(this double value, double compareTo) { diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml index b0899a84..1d20256c 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml @@ -20,6 +20,10 @@ FontWeight="Bold" Background="DarkMagenta" Foreground="Chartreuse" /> + + Selectable text: Loreum ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis + true; public bool SupportsAltSolo => true; + public bool SupportsMouse => false; + public bool SupportsMouseMove => false; public void SetTitle(string title) { diff --git a/src/Consolonia.PlatformSupport/CursesConsole.cs b/src/Consolonia.PlatformSupport/CursesConsole.cs index 809fed4b..78c8fcfc 100644 --- a/src/Consolonia.PlatformSupport/CursesConsole.cs +++ b/src/Consolonia.PlatformSupport/CursesConsole.cs @@ -93,12 +93,12 @@ private static readonly FlagTranslator (Curses.Event.Button1Pressed, RawPointerEventType.LeftButtonDown), (Curses.Event.Button1Clicked, RawPointerEventType.LeftButtonDown), (Curses.Event.Button1Released, RawPointerEventType.LeftButtonUp), - (Curses.Event.Button2Pressed, RawPointerEventType.RightButtonDown), - (Curses.Event.Button2Clicked, RawPointerEventType.RightButtonDown), - (Curses.Event.Button2Released, RawPointerEventType.RightButtonUp), - (Curses.Event.Button3Pressed, RawPointerEventType.MiddleButtonDown), - (Curses.Event.Button3Clicked, RawPointerEventType.MiddleButtonDown), - (Curses.Event.Button3Released, RawPointerEventType.MiddleButtonUp), + (Curses.Event.Button2Pressed, RawPointerEventType.MiddleButtonDown), + (Curses.Event.Button2Clicked, RawPointerEventType.MiddleButtonDown), + (Curses.Event.Button2Released, RawPointerEventType.MiddleButtonUp), + (Curses.Event.Button3Pressed, RawPointerEventType.RightButtonDown), + (Curses.Event.Button3Clicked, RawPointerEventType.RightButtonDown), + (Curses.Event.Button3Released, RawPointerEventType.RightButtonUp), (Curses.Event.Button4Pressed, RawPointerEventType.XButton1Down), (Curses.Event.Button4Clicked, RawPointerEventType.XButton1Down), (Curses.Event.Button4Released, RawPointerEventType.XButton1Up), @@ -116,6 +116,8 @@ public CursesConsole() } public override bool SupportsAltSolo => false; + public override bool SupportsMouse => true; + public override bool SupportsMouseMove => false; private void StartEventLoop() { diff --git a/src/Consolonia.PlatformSupport/WindowsConsole.cs b/src/Consolonia.PlatformSupport/WindowsConsole.cs index 596e37db..283756b1 100644 --- a/src/Consolonia.PlatformSupport/WindowsConsole.cs +++ b/src/Consolonia.PlatformSupport/WindowsConsole.cs @@ -62,6 +62,8 @@ public Win32Console() } public override bool SupportsAltSolo => true; + public override bool SupportsMouse => true; + public override bool SupportsMouseMove => true; public override void PauseIO(Task task) { diff --git a/src/Consolonia.Themes/Templates/Controls/AllControls.axaml b/src/Consolonia.Themes/Templates/Controls/AllControls.axaml index a7236e04..91f4ec93 100644 --- a/src/Consolonia.Themes/Templates/Controls/AllControls.axaml +++ b/src/Consolonia.Themes/Templates/Controls/AllControls.axaml @@ -4,6 +4,7 @@ + diff --git a/src/Consolonia.Themes/Templates/Controls/Helpers/SelectTextWithPointerUpExtension.cs b/src/Consolonia.Themes/Templates/Controls/Helpers/SelectTextWithPointerUpExtension.cs new file mode 100644 index 00000000..a3ae2634 --- /dev/null +++ b/src/Consolonia.Themes/Templates/Controls/Helpers/SelectTextWithPointerUpExtension.cs @@ -0,0 +1,60 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Media; +using Avalonia.Utilities; +using Consolonia.Core.Helpers; +using Consolonia.Core.Infrastructure; +using Consolonia.Core.InternalHelpers; + +namespace Consolonia.Themes.Templates.Controls.Helpers +{ + internal static class SelectTextWithPointerUpExtension + { + public static readonly AttachedProperty SelectOnMouseLeftUpProperty = + AvaloniaProperty.RegisterAttached(CommonInternalHelper.GetStyledPropertyName(), + typeof(SelectTextWithPointerUpExtension)); + + static SelectTextWithPointerUpExtension() + { + var console = AvaloniaLocator.Current.GetService(); + bool supportsMouse = console.SupportsMouse; + bool supportsMouseMove = console.SupportsMouseMove; + if (!supportsMouse || supportsMouseMove) + return; + + SelectOnMouseLeftUpProperty.Changed.SubscribeAction(OnPropertyChanged); + } + + private static void OnPropertyChanged(AvaloniaPropertyChangedEventArgs args) + { + if (args.Sender is not SelectableTextBlock selectableTextBlock) return; + + selectableTextBlock.PointerReleased -= OnPointerReleased; + + if (args.GetNewValue()) selectableTextBlock.PointerReleased += OnPointerReleased; + } + + private static void OnPointerReleased(object sender, PointerReleasedEventArgs e) + { + // simplified copy of SelectableTextBlock.PointerMove + var tb = (SelectableTextBlock)sender; + + if (e.InitialPressMouseButton != MouseButton.Left) + return; + + Thickness padding = tb.Padding; + + Point point = e.GetPosition(tb) - new Point(padding.Left, padding.Top); + + point = new Point( + MathUtilities.Clamp(point.X, 0, Math.Max(tb.TextLayout.WidthIncludingTrailingWhitespace, 0)), + MathUtilities.Clamp(point.Y, 0, Math.Max(tb.TextLayout.Height, 0))); + + TextHitTestResult hit = tb.TextLayout.HitTestPoint(point); + int textPosition = hit.TextPosition; + tb.SetCurrentValue(SelectableTextBlock.SelectionEndProperty, textPosition); + } + } +} \ No newline at end of file diff --git a/src/Consolonia.Themes/Templates/Controls/SelectableTextBlock.axaml b/src/Consolonia.Themes/Templates/Controls/SelectableTextBlock.axaml new file mode 100644 index 00000000..492dd575 --- /dev/null +++ b/src/Consolonia.Themes/Templates/Controls/SelectableTextBlock.axaml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file