Browse Source

Add SelectionForegroundBrush to SelectableTextBlock (#13618)

pull/13795/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
1689bfe5b1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs
  2. 2
      src/Avalonia.Controls/Presenters/TextPresenter.cs
  3. 74
      src/Avalonia.Controls/SelectableTextBlock.cs
  4. 23
      src/Avalonia.Controls/TextBlock.cs

2
src/Avalonia.Base/Media/TextFormatting/FormattedTextSource.cs

@ -48,7 +48,7 @@ namespace Avalonia.Media.TextFormatting
/// <returns>
/// The created text style run.
/// </returns>
private static ValueSpan<TextRunProperties> CreateTextStyleRun(ReadOnlySpan<char> text, int firstTextSourceIndex,
internal static ValueSpan<TextRunProperties> CreateTextStyleRun(ReadOnlySpan<char> text, int firstTextSourceIndex,
TextRunProperties defaultProperties, IReadOnlyList<ValueSpan<TextRunProperties>>? textModifier)
{
if (textModifier == null || textModifier.Count == 0)

2
src/Avalonia.Controls/Presenters/TextPresenter.cs

@ -105,7 +105,7 @@ namespace Avalonia.Controls.Presenters
static TextPresenter()
{
AffectsRender<TextPresenter>(CaretBrushProperty, SelectionBrushProperty, TextElement.ForegroundProperty);
AffectsRender<TextPresenter>(CaretBrushProperty, SelectionBrushProperty, SelectionForegroundBrushProperty, TextElement.ForegroundProperty);
}
public TextPresenter() { }

74
src/Avalonia.Controls/SelectableTextBlock.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Avalonia.Controls.Documents;
using Avalonia.Controls.Utils;
@ -32,6 +33,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBrush?> SelectionBrushProperty =
TextBox.SelectionBrushProperty.AddOwner<SelectableTextBlock>();
public static readonly StyledProperty<IBrush?> SelectionForegroundBrushProperty =
TextBox.SelectionForegroundBrushProperty.AddOwner<SelectableTextBlock>();
public static readonly DirectProperty<SelectableTextBlock, bool> CanCopyProperty =
TextBox.CanCopyProperty.AddOwner<SelectableTextBlock>(o => o.CanCopy);
@ -63,6 +67,15 @@ namespace Avalonia.Controls
set => SetValue(SelectionBrushProperty, value);
}
/// <summary>
/// Gets or sets a brush that is used for the foreground of selected text
/// </summary>
public IBrush? SelectionForegroundBrush
{
get => GetValue(SelectionForegroundBrushProperty);
set => SetValue(SelectionForegroundBrushProperty, value);
}
/// <summary>
/// Gets or sets a character index for the beginning of the current selection.
/// </summary>
@ -167,6 +180,58 @@ namespace Avalonia.Controls
UpdateCommandStates();
}
protected override TextLayout CreateTextLayout(string? text)
{
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
var defaultProperties = new GenericTextRunProperties(
typeface,
FontSize,
TextDecorations,
Foreground);
var paragraphProperties = new GenericTextParagraphProperties(FlowDirection, TextAlignment, true, false,
defaultProperties, TextWrapping, LineHeight, 0, LetterSpacing)
{
LineSpacing = LineSpacing
};
IReadOnlyList<ValueSpan<TextRunProperties>>? textStyleOverrides = null;
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
var start = Math.Min(selectionStart, selectionEnd);
var length = Math.Max(selectionStart, selectionEnd) - start;
if (length > 0 && SelectionForegroundBrush != null)
{
textStyleOverrides = new[]
{
new ValueSpan<TextRunProperties>(start, length,
new GenericTextRunProperties(typeface, FontSize,
foregroundBrush: SelectionForegroundBrush))
};
}
ITextSource textSource;
if (_textRuns != null)
{
textSource = new InlinesTextSource(_textRuns, textStyleOverrides);
}
else
{
textSource = new FormattedTextSource(text ?? "", defaultProperties, textStyleOverrides);
}
return new TextLayout(
textSource,
paragraphProperties,
TextTrimming,
_constraint.Width,
_constraint.Height,
MaxLines);
}
protected override void RenderTextLayout(DrawingContext context, Point origin)
{
var selectionStart = SelectionStart;
@ -220,10 +285,17 @@ namespace Avalonia.Controls
{
base.OnPropertyChanged(change);
if (change.Property == SelectionStartProperty || change.Property == SelectionEndProperty)
if (change.Property == SelectionStartProperty ||
change.Property == SelectionEndProperty)
{
RaisePropertyChanged(SelectedTextProperty, "", "");
UpdateCommandStates();
InvalidateTextLayout();
}
if(change.Property == SelectionForegroundBrushProperty)
{
InvalidateTextLayout();
}
}

23
src/Avalonia.Controls/TextBlock.cs

@ -7,6 +7,7 @@ using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;
using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Controls
{
@ -155,8 +156,8 @@ namespace Avalonia.Controls
nameof(Inlines), t => t.Inlines, (t, v) => t.Inlines = v);
private TextLayout? _textLayout;
private Size _constraint;
private IReadOnlyList<TextRun>? _textRuns;
protected Size _constraint;
protected IReadOnlyList<TextRun>? _textRuns;
private InlineCollection? _inlines;
/// <summary>
@ -846,7 +847,7 @@ namespace Avalonia.Controls
InvalidateTextLayout();
}
private readonly record struct SimpleTextSource : ITextSource
protected readonly record struct SimpleTextSource : ITextSource
{
private readonly string _text;
private readonly TextRunProperties _defaultProperties;
@ -875,13 +876,17 @@ namespace Avalonia.Controls
}
}
private readonly struct InlinesTextSource : ITextSource
#pragma warning disable CA1815 // Equals und Gleichheitsoperator für Werttypen außer Kraft setzen
protected readonly struct InlinesTextSource : ITextSource
#pragma warning restore CA1815 // Equals und Gleichheitsoperator für Werttypen außer Kraft setzen
{
private readonly IReadOnlyList<TextRun> _textRuns;
private readonly IReadOnlyList<ValueSpan<TextRunProperties>>? _textModifier;
public InlinesTextSource(IReadOnlyList<TextRun> textRuns)
public InlinesTextSource(IReadOnlyList<TextRun> textRuns, IReadOnlyList<ValueSpan<TextRunProperties>>? textModifier = null)
{
_textRuns = textRuns;
_textModifier = textModifier;
}
public IReadOnlyList<TextRun> TextRuns => _textRuns;
@ -904,11 +909,13 @@ namespace Avalonia.Controls
continue;
}
if (textRun is TextCharacters)
if (textRun is TextCharacters textCharacters)
{
var skip = Math.Max(0, textSourceIndex - currentPosition);
return new TextCharacters(textRun.Text.Slice(skip), textRun.Properties!);
var textStyleRun = FormattedTextSource.CreateTextStyleRun(textRun.Text.Slice(skip).Span, textSourceIndex, textCharacters.Properties, _textModifier);
return new TextCharacters(textRun.Text.Slice(skip, textStyleRun.Length), textStyleRun.Value);
}
return textRun;
@ -916,6 +923,6 @@ namespace Avalonia.Controls
return new TextEndOfParagraph();
}
}
}
}
}

Loading…
Cancel
Save