Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

203-selectabletextblock-does-not-work #219

Merged
merged 7 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Consolonia.Core/Dummy/DummyConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
Size = new PixelBufferSize(width, height);
}

public PixelBufferSize Size { get; set; }

Check notice on line 27 in src/Consolonia.Core/Dummy/DummyConsole.cs

View workflow job for this annotation

GitHub Actions / build

"[AutoPropertyCanBeMadeGetOnly.Global] Auto-property can be made get-only" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Dummy/DummyConsole.cs(27,44)

public bool CaretVisible
{
Expand All @@ -34,6 +34,8 @@

public bool SupportsComplexEmoji => true;
public bool SupportsAltSolo => false;
public bool SupportsMouse => false;
public bool SupportsMouseMove => false;

public void ClearOutput()
{
Expand Down
2 changes: 2 additions & 0 deletions src/Consolonia.Core/Infrastructure/DefaultNetConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 2 additions & 0 deletions src/Consolonia.Core/Infrastructure/IConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public interface IConsole : IDisposable
bool SupportsComplexEmoji { get; }

bool SupportsAltSolo { get; }
bool SupportsMouse { get; }
bool SupportsMouseMove { get; }

void SetTitle(string title);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
FontWeight="Bold"
Background="DarkMagenta"
Foreground="Chartreuse" />
<SelectableTextBlock SelectionStart="17"
SelectionEnd="26">
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
</SelectableTextBlock>

<StackPanel Orientation="Vertical"
Margin="0"
Expand Down
2 changes: 2 additions & 0 deletions src/Consolonia.NUnit/UnitTestConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public void Dispose()

public bool SupportsComplexEmoji => true;
public bool SupportsAltSolo => true;
public bool SupportsMouse => false;
public bool SupportsMouseMove => false;

public void SetTitle(string title)
{
Expand Down
14 changes: 8 additions & 6 deletions src/Consolonia.PlatformSupport/CursesConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ private static readonly FlagTranslator<Key, ConsoleKey>
(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),
Expand All @@ -116,6 +116,8 @@ public CursesConsole()
}

public override bool SupportsAltSolo => false;
public override bool SupportsMouse => true;
public override bool SupportsMouseMove => false;

private void StartEventLoop()
{
Expand Down
2 changes: 2 additions & 0 deletions src/Consolonia.PlatformSupport/WindowsConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions src/Consolonia.Themes/Templates/Controls/AllControls.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<MergeResourceInclude Source="/Templates/Controls/TextBlock.axaml" />
<MergeResourceInclude Source="/Templates/Controls/SelectableTextBlock.axaml" />
<MergeResourceInclude Source="/Templates/Controls/Window.axaml" />
<MergeResourceInclude Source="/Templates/Controls/Button.axaml" />
<MergeResourceInclude Source="/Templates/Controls/TextBox.axaml" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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<bool> SelectOnMouseLeftUpProperty =
AvaloniaProperty.RegisterAttached<SelectableTextBlock, bool>(CommonInternalHelper.GetStyledPropertyName(),
typeof(SelectTextWithPointerUpExtension));

static SelectTextWithPointerUpExtension()
{
var console = AvaloniaLocator.Current.GetService<IConsole>();
bool supportsMouse = console.SupportsMouse;
bool supportsMouseMove = console.SupportsMouseMove;
if (!supportsMouse || supportsMouseMove)
return;

SelectOnMouseLeftUpProperty.Changed.SubscribeAction(OnPropertyChanged);
}

private static void OnPropertyChanged(AvaloniaPropertyChangedEventArgs<bool> args)
{
if (args.Sender is not SelectableTextBlock selectableTextBlock) return;

selectableTextBlock.PointerReleased -= OnPointerReleased;

if (args.GetNewValue<bool>()) 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);
}
}
}
11 changes: 11 additions & 0 deletions src/Consolonia.Themes/Templates/Controls/SelectableTextBlock.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helpers="clr-namespace:Consolonia.Themes.Templates.Controls.Helpers">
<ControlTheme x:Key="{x:Type SelectableTextBlock}"
TargetType="SelectableTextBlock">
<Setter Property="SelectionBrush"
Value="{DynamicResource ThemeActionBackgroundBrush}" />
<Setter Property="helpers:SelectTextWithPointerUpExtension.SelectOnMouseLeftUp"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

next level magic.

I haven't ever created a mixin extension like this. Xaml is so freaking powerful as a model.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. Its supposed to be simpler with "behaviours", they manage lifetime etc, but Avalonia does not have them builtin, i dont want to include that assembly to core level packages of consolonia.

Value="True" />
</ControlTheme>
</ResourceDictionary>
Loading