Skip to content

Commit

Permalink
fix caret cursor (#212)
Browse files Browse the repository at this point in the history
* changed CaretControl template to output a Rectangle 
* Changed DrawRectangle to detect MoveCaret brushes
* Refactored DrawLine to detect MoveCaret Brushes.
  • Loading branch information
tomlm authored Dec 17, 2024
1 parent 8d96b05 commit 1fb603b
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 47 deletions.
12 changes: 12 additions & 0 deletions src/Consolonia.Core/Drawing/CaretStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Consolonia.Core.Drawing
{
public enum CaretStyle
{
BlinkingBar,
SteadyBar,
BlinkingBlock,
SteadyBlock,
BlinkingUnderline,
SteadyUnderline
}
}
27 changes: 20 additions & 7 deletions src/Consolonia.Core/Drawing/DrawingContextImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,17 @@ public void DrawGeometry(IBrush brush, IPen pen, IGeometryImpl geometry)
if (sceneBrushContent != null) sceneBrushContent.Render(this, Matrix.Identity);
return;
}
case MoveConsoleCaretToPositionBrush moveBrush:
{
Point head = r.TopLeft.Transform(Transform);
_pixelBuffer.CaretStyle = moveBrush.CaretStyle;
CurrentClip.ExecuteWithClipping(head,
() =>
{
_pixelBuffer.Set((PixelBufferCoordinate)head, pixel => pixel.Blend(new Pixel(true)));
});
return;
}
}

FillRectangleWithBrush(brush, pen, r);
Expand Down Expand Up @@ -458,6 +469,15 @@ private void DrawLineInternal(IPen pen, Line line)
return;
}

if (pen.Brush is MoveConsoleCaretToPositionBrush moveBrush)
{
_pixelBuffer.CaretStyle = moveBrush.CaretStyle;
Point head = line.PStart.Transform(Transform);
CurrentClip.ExecuteWithClipping(head,
() => { _pixelBuffer.Set((PixelBufferCoordinate)head, pixel => pixel.Blend(new Pixel(true))); });
return;
}

DrawBoxLineInternal(pen, line, RectangleLinePosition.Unknown);
}

Expand Down Expand Up @@ -532,13 +552,6 @@ private void DrawBoxLineInternal(IPen pen, Line line, RectangleLinePosition line

Point head = line.PStart;

if (pen.Brush is MoveConsoleCaretToPositionBrush)
{
CurrentClip.ExecuteWithClipping(head,
() => { _pixelBuffer.Set((PixelBufferCoordinate)head, pixel => pixel.Blend(new Pixel(true))); });
return;
}

var extractColorCheckPlatformSupported = ExtractColorOrNullWithPlatformCheck(pen, out var lineStyle);
if (extractColorCheckPlatformSupported == null)
return;
Expand Down
14 changes: 13 additions & 1 deletion src/Consolonia.Core/Drawing/MoveConsoleCaretToPositionBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@

namespace Consolonia.Core.Drawing
{
public class MoveConsoleCaretToPositionBrush : IImmutableBrush
public class MoveConsoleCaretToPositionBrush : AvaloniaObject, IImmutableBrush
{
public static readonly StyledProperty<CaretStyle> CaretStyleProperty =
AvaloniaProperty.Register<MoveConsoleCaretToPositionBrush, CaretStyle>(nameof(CaretStyle));

/// <summary>
/// style of caret
/// </summary>
public CaretStyle CaretStyle
{
get => GetValue(CaretStyleProperty);
set => SetValue(CaretStyleProperty, value);
}

//todo: Search for B75ABC91-2CDD-4557-9201-16AC483C8D7B
public double Opacity => 1;
public ITransform Transform => null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public PixelBuffer(ushort width, ushort height)
public ushort Width { get; }
public ushort Height { get; }

public CaretStyle CaretStyle { get; set; } = CaretStyle.BlinkingBar;

// ReSharper disable once UnusedMember.Global
[JsonIgnore]
public Pixel this[int i]
Expand Down
13 changes: 13 additions & 0 deletions src/Consolonia.Core/Drawing/RenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Avalonia.Platform;
using Consolonia.Core.Drawing.PixelBufferImplementation;
using Consolonia.Core.Infrastructure;
using Consolonia.Core.Text;

namespace Consolonia.Core.Drawing
{
Expand Down Expand Up @@ -141,11 +142,23 @@ private void RenderToDevice()
if (caretPosition != null)
{
_console.SetCaretPosition((PixelBufferCoordinate)caretPosition);
_console.WriteText(pixelBuffer.CaretStyle switch
{
CaretStyle.BlinkingBar => Esc.BlinkingBarCursor,
CaretStyle.SteadyBar => Esc.SteadyBarCursor,
CaretStyle.BlinkingBlock => Esc.BlinkingBlockCursor,
CaretStyle.SteadyBlock => Esc.SteadyBlockCursor,
CaretStyle.BlinkingUnderline => Esc.BlinkingUnderlineCursor,
CaretStyle.SteadyUnderline => Esc.SteadyUnderlineCursor,
_ => throw new ArgumentOutOfRangeException()
});
_console.WriteText(Esc.ShowCursor);
_console.CaretVisible = true;
}
else
{
_console.CaretVisible = false;
_console.WriteText(Esc.HideCursor);
}
}

Expand Down
14 changes: 1 addition & 13 deletions src/Consolonia.Core/Infrastructure/InputLessDefaultNetConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ namespace Consolonia.Core.Infrastructure
public abstract class InputLessDefaultNetConsole : IConsole
{
private const string TestEmoji = "👨‍👩‍👧‍👦";
private bool _caretVisible;
private PixelBufferCoordinate _headBufferPoint;

private bool? _supportEmoji;
Expand All @@ -32,18 +31,7 @@ protected InputLessDefaultNetConsole()

protected Task PauseTask { get; private set; }

public bool CaretVisible
{
get => _caretVisible;
#pragma warning disable CA1303 // Do not pass literals as localized parameters
set
{
if (_caretVisible == value) return;
WriteText(value ? Esc.ShowCursor : Esc.HideCursor);
_caretVisible = value;
}
#pragma warning restore CA1303 // Do not pass literals as localized parameters
}
public bool CaretVisible { get; set; }

public PixelBufferSize Size { get; private set; }

Expand Down
8 changes: 8 additions & 0 deletions src/Consolonia.Core/Text/Esc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ internal static class Esc
public const string HideCursor = "\u001b[?25l";
public const string ShowCursor = "\u001b[?25h";

// cursor shape
public const string BlinkingBlockCursor = "\u001b[1 q";
public const string SteadyBlockCursor = "\u001b[2 q";
public const string BlinkingUnderlineCursor = "\u001b[3 q";
public const string SteadyUnderlineCursor = "\u001b[4 q";
public const string BlinkingBarCursor = "\u001b[5 q";
public const string SteadyBarCursor = "\u001b[6 q";

// move cursor
public static string MoveCursorUp(int n)
{
Expand Down
38 changes: 12 additions & 26 deletions src/Consolonia.Themes/Templates/Controls/CaretControl.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,23 @@
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}">
<TextBlock Width="1"
Height="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsHitTestVisible="False"
Background="{DynamicResource ThemeActionBackgroundBrush}"
IsVisible="{TemplateBinding IsCaretShown}"
Margin="{TemplateBinding Padding}"
Tag="This TextBlock is a hack. Otherwise Line below does not get redrawn in CheckBox">
<!--<TextBlock.Background>
<drawing:ConsoleBrush Mode="Transparent"/>
</TextBlock.Background>-->
</TextBlock>
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
<Line Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Name="PART_CaretLine"
Width="1"
Height="1"
IsHitTestVisible="False"
IsVisible="{TemplateBinding IsCaretShown}"
StrokeThickness="1">
<Line.Stroke>
<drawing:MoveConsoleCaretToPositionBrush />
</Line.Stroke>
</Line>
<!-- Caret should be drawn last so it is overlayed on top of any chars in the content -->
<Rectangle Name="PART_CaretLine"
Width="1"
Height="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
IsHitTestVisible="False"
IsVisible="{TemplateBinding IsCaretShown}">
<Rectangle.Fill>
<drawing:MoveConsoleCaretToPositionBrush CaretStyle="{TemplateBinding CaretStyle}" />
</Rectangle.Fill>
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Consolonia.Core.Drawing;

namespace Consolonia.Themes.Templates.Controls.Helpers
{
Expand All @@ -9,13 +10,21 @@ public class CaretControl : ContentControl
public static readonly StyledProperty<bool> IsCaretShownProperty =
AvaloniaProperty.Register<CaretControl, bool>(nameof(IsCaretShown));

public static readonly StyledProperty<CaretStyle> CaretStyleProperty =
AvaloniaProperty.Register<CaretControl, CaretStyle>(nameof(CaretStyle));

public bool IsCaretShown
{
get => GetValue(IsCaretShownProperty);
set => SetValue(IsCaretShownProperty, value);
}

public CaretStyle CaretStyle
{
get => GetValue(CaretStyleProperty);
set => SetValue(CaretStyleProperty, value);
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Expand Down

0 comments on commit 1fb603b

Please sign in to comment.