Skip to content

Commit

Permalink
Merge branch 'master' into fix-276
Browse files Browse the repository at this point in the history
  • Loading branch information
danipen authored Oct 25, 2022
2 parents 883007b + cf278a3 commit f939891
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 122 deletions.
1 change: 1 addition & 0 deletions src/AvaloniaEdit.Demo/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ToggleButton Name="viewTabs" Content="View tabs" IsChecked="{Binding #Editor.Options.ShowTabs}" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<ToggleButton Name="viewSpaces" Content="View spaces" IsChecked="{Binding #Editor.Options.ShowSpaces}" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<ToggleButton Name="viewEOL" Content="View EOL" IsChecked="{Binding #Editor.Options.ShowEndOfLine}" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<ToggleButton Name="viewColumnRules" Content="View columns rulers" IsChecked="{Binding #Editor.Options.ShowColumnRulers}" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<Button Name="addControlBtn" Content="Add Button" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<Button Name="clearControlBtn" Content="Clear Buttons" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
<ComboBox Name="syntaxModeCombo" VerticalAlignment="Stretch" VerticalContentAlignment="Center"/>
Expand Down
3 changes: 2 additions & 1 deletion src/AvaloniaEdit.Demo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public MainWindow()
_textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered;
_textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering;
_textEditor.Options.ShowBoxForControlCharacters = true;
_textEditor.Options.ColumnRulerPositions = new List<int>() { 80, 100 };
_textEditor.TextArea.IndentationStrategy = new Indentation.CSharp.CSharpIndentationStrategy(_textEditor.Options);
_textEditor.TextArea.Caret.PositionChanged += Caret_PositionChanged;
_textEditor.TextArea.RightClickMovesCaret = true;
Expand All @@ -68,7 +69,7 @@ public MainWindow()
_addControlButton.Click += AddControlButton_Click;

_clearControlButton = this.FindControl<Button>("clearControlBtn");
_clearControlButton.Click += ClearControlButton_Click; ;
_clearControlButton.Click += ClearControlButton_Click;

_changeThemeButton = this.FindControl<Button>("changeThemeBtn");
_changeThemeButton.Click += ChangeThemeButton_Click;
Expand Down
84 changes: 45 additions & 39 deletions src/AvaloniaEdit/Rendering/ColumnRulerRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,62 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;

using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Immutable;

using AvaloniaEdit.Utils;

namespace AvaloniaEdit.Rendering
{
/// <summary>
/// Renders a ruler at a certain column.
/// </summary>
internal sealed class ColumnRulerRenderer : IBackgroundRenderer
{
private IPen _pen;
private int _column;
private readonly TextView _textView;
/// <summary>
/// Renders a ruler at a certain column.
/// </summary>
internal sealed class ColumnRulerRenderer : IBackgroundRenderer
{
private IPen _pen;
private IEnumerable<int> _columns;
private readonly TextView _textView;

public static readonly Color DefaultForeground = Colors.LightGray;

public static readonly Color DefaultForeground = Colors.LightGray;
public ColumnRulerRenderer(TextView textView)
{
_pen = new ImmutablePen(new ImmutableSolidColorBrush(DefaultForeground), 1);
_textView = textView ?? throw new ArgumentNullException(nameof(textView));
_textView.BackgroundRenderers.Add(this);
}

public ColumnRulerRenderer(TextView textView)
{
_pen = new ImmutablePen(new ImmutableSolidColorBrush(DefaultForeground), 1);
_textView = textView ?? throw new ArgumentNullException(nameof(textView));
_textView.BackgroundRenderers.Add(this);
}
public KnownLayer Layer => KnownLayer.Background;

public KnownLayer Layer => KnownLayer.Background;
public void SetRuler(IEnumerable<int> columns, IPen pen)
{
_columns = columns;
_pen = pen;
_textView.InvalidateLayer(Layer);
}

public void SetRuler(int column, IPen pen)
{
if (_column != column) {
_column = column;
_textView.InvalidateLayer(Layer);
}
if (_pen != pen) {
_pen = pen;
_textView.InvalidateLayer(Layer);
}
}
public void Draw(TextView textView, DrawingContext drawingContext)
{
if (_columns == null)
return;

public void Draw(TextView textView, DrawingContext drawingContext)
{
if (_column < 1) return;
var offset = textView.WideSpaceWidth * _column;
var pixelSize = PixelSnapHelpers.GetPixelSize(textView);
var markerXPos = PixelSnapHelpers.PixelAlign(offset, pixelSize.Width);
markerXPos -= textView.ScrollOffset.X;
var start = new Point(markerXPos, 0);
var end = new Point(markerXPos, Math.Max(textView.DocumentHeight, textView.Bounds.Height));
foreach (int column in _columns)
{
var offset = textView.WideSpaceWidth * column;
var pixelSize = PixelSnapHelpers.GetPixelSize(textView);
var markerXPos = PixelSnapHelpers.PixelAlign(offset, pixelSize.Width);
markerXPos -= textView.ScrollOffset.X;
var start = new Point(markerXPos, 0);
var end = new Point(markerXPos, Math.Max(textView.DocumentHeight, textView.Bounds.Height));

drawingContext.DrawLine(_pen, start, end);
}
}
drawingContext.DrawLine(
_pen,
start.SnapToDevicePixels(textView),
end.SnapToDevicePixels(textView));
}
}
}
}
48 changes: 30 additions & 18 deletions src/AvaloniaEdit/Rendering/SingleCharacterElementGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,27 +99,39 @@ public override int GetFirstInterestedOffset(int startOffset)
return -1;
}

public override VisualLineElement ConstructElement(int offset)
{
var c = CurrentContext.Document.GetCharAt(offset);

if (ShowSpaces && c == ' ') {
return new SpaceTextElement(CurrentContext.TextView.CachedElements.GetTextForNonPrintableCharacter("\u00B7", CurrentContext));
} else if (ShowTabs && c == '\t') {
return new TabTextElement(CurrentContext.TextView.CachedElements.GetTextForNonPrintableCharacter("\u00BB", CurrentContext));
} else if (ShowBoxForControlCharacters && char.IsControl(c)) {
var p = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties);
p.SetForegroundBrush(Brushes.White);
var textFormatter = TextFormatterFactory.Create(CurrentContext.TextView);
var text = FormattedTextElement.PrepareText(textFormatter,
TextUtilities.GetControlCharacterName(c), p);
return new SpecialCharacterBoxElement(text);
}
public override VisualLineElement ConstructElement(int offset)
{
var c = CurrentContext.Document.GetCharAt(offset);

if (ShowSpaces && c == ' ')
{
var runProperties = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties);
runProperties.SetForegroundBrush(CurrentContext.TextView.NonPrintableCharacterBrush);
return new SpaceTextElement(CurrentContext.TextView.CachedElements.GetTextForNonPrintableCharacter(
CurrentContext.TextView.Options.ShowSpacesGlyph,
runProperties));
}
else if (ShowTabs && c == '\t')
{
var runProperties = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties);
runProperties.SetForegroundBrush(CurrentContext.TextView.NonPrintableCharacterBrush);
return new TabTextElement(CurrentContext.TextView.CachedElements.GetTextForNonPrintableCharacter(
CurrentContext.TextView.Options.ShowTabsGlyph,
runProperties));
}
else if (ShowBoxForControlCharacters && char.IsControl(c))
{
var runProperties = new VisualLineElementTextRunProperties(CurrentContext.GlobalTextRunProperties);
runProperties.SetForegroundBrush(Brushes.White);
var textFormatter = TextFormatterFactory.Create(CurrentContext.TextView);
var text = FormattedTextElement.PrepareText(textFormatter, TextUtilities.GetControlCharacterName(c), runProperties);
return new SpecialCharacterBoxElement(text);
}

return null;
}
}

private sealed class SpaceTextElement : FormattedTextElement
private sealed class SpaceTextElement : FormattedTextElement
{
public SpaceTextElement(TextLine textLine) : base(textLine, 1)
{
Expand Down
14 changes: 7 additions & 7 deletions src/AvaloniaEdit/Rendering/TextView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ protected virtual void OnOptionChanged(PropertyChangedEventArgs e)
{
OptionChanged?.Invoke(this, e);

if (Options.ShowColumnRuler)
_columnRulerRenderer.SetRuler(Options.ColumnRulerPosition, ColumnRulerPen);
if (Options.ShowColumnRulers)
_columnRulerRenderer.SetRuler(Options.ColumnRulerPositions, ColumnRulerPen);
else
_columnRulerRenderer.SetRuler(-1, ColumnRulerPen);
_columnRulerRenderer.SetRuler(null, ColumnRulerPen);

UpdateBuiltinElementGeneratorsFromOptions();
Redraw();
Expand Down Expand Up @@ -1928,7 +1928,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
}
if (change.Property == ColumnRulerPenProperty)
{
_columnRulerRenderer.SetRuler(Options.ColumnRulerPosition, ColumnRulerPen);
_columnRulerRenderer.SetRuler(Options.ColumnRulerPositions, ColumnRulerPen);
}
if (change.Property == CurrentLineBorderProperty)
{
Expand All @@ -1942,10 +1942,10 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang

/// <summary>
/// The pen used to draw the column ruler.
/// <seealso cref="TextEditorOptions.ShowColumnRuler"/>
/// <seealso cref="TextEditorOptions.ShowColumnRulers"/>
/// </summary>
public static readonly StyledProperty<IPen> ColumnRulerPenProperty =
AvaloniaProperty.Register<TextView, IPen>("ColumnRulerBrush", CreateFrozenPen(Brushes.LightGray));
AvaloniaProperty.Register<TextView, IPen>("ColumnRulerBrush", CreateFrozenPen(new SolidColorBrush(Color.FromArgb(90, 128, 128, 128))));

private static ImmutablePen CreateFrozenPen(IBrush brush)
{
Expand Down Expand Up @@ -1988,7 +1988,7 @@ void ILogicalScrollable.RaiseScrollInvalidated(EventArgs e)

/// <summary>
/// Gets/Sets the pen used to draw the column ruler.
/// <seealso cref="TextEditorOptions.ShowColumnRuler"/>
/// <seealso cref="TextEditorOptions.ShowColumnRulers"/>
/// </summary>
public IPen ColumnRulerPen
{
Expand Down
25 changes: 6 additions & 19 deletions src/AvaloniaEdit/Rendering/TextViewCachedElements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,22 @@

namespace AvaloniaEdit.Rendering
{
internal sealed class TextViewCachedElements /*: IDisposable*/
internal sealed class TextViewCachedElements
{
private TextFormatter _formatter;
private Dictionary<string, TextLine> _nonPrintableCharacterTexts;

public TextLine GetTextForNonPrintableCharacter(string text, ITextRunConstructionContext context)
public TextLine GetTextForNonPrintableCharacter(string text, TextRunProperties properties)
{
if (_nonPrintableCharacterTexts == null)
_nonPrintableCharacterTexts = new Dictionary<string, TextLine>();

TextLine textLine;
if (!_nonPrintableCharacterTexts.TryGetValue(text, out textLine)) {
var p = new VisualLineElementTextRunProperties(context.GlobalTextRunProperties);
p.SetForegroundBrush(context.TextView.NonPrintableCharacterBrush);
if (_formatter == null)
_formatter = TextFormatter.Current;//TextFormatterFactory.Create(context.TextView);
textLine = FormattedTextElement.PrepareText(_formatter, text, p);
if (!_nonPrintableCharacterTexts.TryGetValue(text, out textLine))
{
textLine = FormattedTextElement.PrepareText(TextFormatter.Current, text, properties);
_nonPrintableCharacterTexts[text] = textLine;
}
return textLine;
}

/*public void Dispose()
{
if (nonPrintableCharacterTexts != null) {
foreach (TextLine line in nonPrintableCharacterTexts.Values)
line.Dispose();
}
if (formatter != null)
formatter.Dispose();
}*/
}
}
48 changes: 28 additions & 20 deletions src/AvaloniaEdit/Rendering/VisualLineTextSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

using System;
using System.Diagnostics;

using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Utilities;
using AvaloniaEdit.Document;
Expand Down Expand Up @@ -74,30 +76,36 @@ public TextRun GetTextRun(int textSourceCharacterIndex)
}
}

private TextRun CreateTextRunForNewLine()
{
string newlineText = "";
DocumentLine lastDocumentLine = VisualLine.LastDocumentLine;
if (lastDocumentLine.DelimiterLength == 2) {
newlineText = "";
} else if (lastDocumentLine.DelimiterLength == 1) {
char newlineChar = Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
if (newlineChar == '\r')
newlineText = "\\r";
else if (newlineChar == '\n')
newlineText = "\\n";
else
newlineText = "?";
}
private TextRun CreateTextRunForNewLine()
{
string newlineText = "";
DocumentLine lastDocumentLine = VisualLine.LastDocumentLine;
if (lastDocumentLine.DelimiterLength == 2)
{
newlineText = TextView.Options.EndOfLineCRLFGlyph;
}
else if (lastDocumentLine.DelimiterLength == 1)
{
char newlineChar = Document.GetCharAt(lastDocumentLine.Offset + lastDocumentLine.Length);
if (newlineChar == '\r')
newlineText = TextView.Options.EndOfLineCRGlyph;
else if (newlineChar == '\n')
newlineText = TextView.Options.EndOfLineLFGlyph;
else
newlineText = "?";
}

var textElement = new FormattedTextElement(TextView.CachedElements.GetTextForNonPrintableCharacter(newlineText, this), 0);
var p = new VisualLineElementTextRunProperties(GlobalTextRunProperties);
p.SetForegroundBrush(TextView.NonPrintableCharacterBrush);
p.SetFontRenderingEmSize(GlobalTextRunProperties.FontRenderingEmSize - 2);
var textElement = new FormattedTextElement(TextView.CachedElements.GetTextForNonPrintableCharacter(newlineText, p), 0);

textElement.RelativeTextOffset = lastDocumentLine.Offset + lastDocumentLine.Length;
textElement.RelativeTextOffset = lastDocumentLine.Offset + lastDocumentLine.Length;

return new FormattedTextRun(textElement, GlobalTextRunProperties);
}
return new FormattedTextRun(textElement, GlobalTextRunProperties);
}

public ReadOnlySlice<char> GetPrecedingText(int textSourceCharacterIndexLimit)
public ReadOnlySlice<char> GetPrecedingText(int textSourceCharacterIndexLimit)
{
try {
foreach (VisualLineElement element in VisualLine.Elements) {
Expand Down
Loading

0 comments on commit f939891

Please sign in to comment.