-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6953 from Gillibald/feature/textBlockInlines
Add TextBlock inlines support
- Loading branch information
Showing
22 changed files
with
786 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/Avalonia.Base/Metadata/TrimSurroundingWhitespaceAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System; | ||
|
||
namespace Avalonia.Metadata | ||
{ | ||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] | ||
public class TrimSurroundingWhitespaceAttribute : Attribute | ||
{ | ||
|
||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
src/Avalonia.Base/Metadata/WhitespaceSignificantCollectionAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
namespace Avalonia.Metadata | ||
{ | ||
/// <summary> | ||
/// Indicates that a collection type should be processed as being whitespace significant by a XAML processor. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] | ||
public class WhitespaceSignificantCollectionAttribute : Attribute | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using Avalonia.Media; | ||
|
||
namespace Avalonia.Controls.Documents | ||
{ | ||
/// <summary> | ||
/// Bold element - markup helper for indicating bolded content. | ||
/// Equivalent to a Span with FontWeight property set to FontWeights.Bold. | ||
/// Can contain other inline elements. | ||
/// </summary> | ||
public sealed class Bold : Span | ||
{ | ||
static Bold() | ||
{ | ||
FontWeightProperty.OverrideDefaultValue<Bold>(FontWeight.Bold); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using Avalonia.Media; | ||
using Avalonia.Media.TextFormatting; | ||
using Avalonia.Utilities; | ||
|
||
namespace Avalonia.Controls.Documents | ||
{ | ||
/// <summary> | ||
/// Inline element. | ||
/// </summary> | ||
public abstract class Inline : TextElement | ||
{ | ||
/// <summary> | ||
/// AvaloniaProperty for <see cref="TextDecorations" /> property. | ||
/// </summary> | ||
public static readonly StyledProperty<TextDecorationCollection> TextDecorationsProperty = | ||
AvaloniaProperty.Register<Inline, TextDecorationCollection>( | ||
nameof(TextDecorations)); | ||
|
||
/// <summary> | ||
/// AvaloniaProperty for <see cref="BaselineAlignment" /> property. | ||
/// </summary> | ||
public static readonly StyledProperty<BaselineAlignment> BaselineAlignmentProperty = | ||
AvaloniaProperty.Register<Inline, BaselineAlignment>( | ||
nameof(BaselineAlignment), | ||
BaselineAlignment.Baseline); | ||
|
||
/// <summary> | ||
/// The TextDecorations property specifies decorations that are added to the text of an element. | ||
/// </summary> | ||
public TextDecorationCollection TextDecorations | ||
{ | ||
get { return GetValue(TextDecorationsProperty); } | ||
set { SetValue(TextDecorationsProperty, value); } | ||
} | ||
|
||
/// <summary> | ||
/// Describes how the baseline for a text-based element is positioned on the vertical axis, | ||
/// relative to the established baseline for text. | ||
/// </summary> | ||
public BaselineAlignment BaselineAlignment | ||
{ | ||
get { return GetValue(BaselineAlignmentProperty); } | ||
set { SetValue(BaselineAlignmentProperty, value); } | ||
} | ||
|
||
internal abstract int BuildRun(StringBuilder stringBuilder, IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex); | ||
|
||
internal abstract int AppendText(StringBuilder stringBuilder); | ||
|
||
protected TextRunProperties CreateTextRunProperties() | ||
{ | ||
return new GenericTextRunProperties(new Typeface(FontFamily, FontStyle, FontWeight), FontSize, | ||
TextDecorations, Foreground, Background, BaselineAlignment); | ||
} | ||
|
||
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) | ||
{ | ||
base.OnPropertyChanged(change); | ||
|
||
switch (change.Property.Name) | ||
{ | ||
case nameof(TextDecorations): | ||
case nameof(BaselineAlignment): | ||
Invalidate(); | ||
break; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using System; | ||
using System.Text; | ||
using Avalonia.Collections; | ||
using Avalonia.LogicalTree; | ||
using Avalonia.Metadata; | ||
|
||
namespace Avalonia.Controls.Documents | ||
{ | ||
/// <summary> | ||
/// A collection of <see cref="Inline"/>s. | ||
/// </summary> | ||
[WhitespaceSignificantCollection] | ||
public class InlineCollection : AvaloniaList<Inline> | ||
{ | ||
private string? _text = string.Empty; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="InlineCollection"/> class. | ||
/// </summary> | ||
public InlineCollection(ILogical parent) : base(0) | ||
{ | ||
ResetBehavior = ResetBehavior.Remove; | ||
|
||
this.ForEachItem( | ||
x => | ||
{ | ||
((ISetLogicalParent)x).SetParent(parent); | ||
x.Invalidated += Invalidate; | ||
Invalidate(); | ||
}, | ||
x => | ||
{ | ||
((ISetLogicalParent)x).SetParent(null); | ||
x.Invalidated -= Invalidate; | ||
Invalidate(); | ||
}, | ||
() => throw new NotSupportedException()); | ||
} | ||
|
||
public bool HasComplexContent => Count > 0; | ||
|
||
/// <summary> | ||
/// Gets or adds the text held by the inlines collection. | ||
/// <remarks> | ||
/// Can be null for complex content. | ||
/// </remarks> | ||
/// </summary> | ||
public string? Text | ||
{ | ||
get | ||
{ | ||
if (!HasComplexContent) | ||
{ | ||
return _text; | ||
} | ||
|
||
var builder = new StringBuilder(); | ||
|
||
foreach(var inline in this) | ||
{ | ||
inline.AppendText(builder); | ||
} | ||
|
||
return builder.ToString(); | ||
} | ||
set | ||
{ | ||
if (HasComplexContent) | ||
{ | ||
Add(new Run(value)); | ||
} | ||
else | ||
{ | ||
_text = value; | ||
} | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Add a text segment to the collection. | ||
/// <remarks> | ||
/// For non complex content this appends the text to the end of currently held text. | ||
/// For complex content this adds a <see cref="Run"/> to the collection. | ||
/// </remarks> | ||
/// </summary> | ||
/// <param name="text"></param> | ||
public void Add(string text) | ||
{ | ||
if (HasComplexContent) | ||
{ | ||
Add(new Run(text)); | ||
} | ||
else | ||
{ | ||
_text += text; | ||
} | ||
} | ||
|
||
public override void Add(Inline item) | ||
{ | ||
if (!HasComplexContent) | ||
{ | ||
base.Add(new Run(_text)); | ||
|
||
_text = string.Empty; | ||
} | ||
|
||
base.Add(item); | ||
} | ||
|
||
/// <summary> | ||
/// Raised when an inline in the collection changes. | ||
/// </summary> | ||
public event EventHandler? Invalidated; | ||
|
||
/// <summary> | ||
/// Raises the <see cref="Invalidated"/> event. | ||
/// </summary> | ||
protected void Invalidate() => Invalidated?.Invoke(this, EventArgs.Empty); | ||
|
||
private void Invalidate(object? sender, EventArgs e) => Invalidate(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using Avalonia.Media; | ||
|
||
namespace Avalonia.Controls.Documents | ||
{ | ||
/// <summary> | ||
/// Italic element - markup helper for indicating italicized content. | ||
/// Equivalent to a Span with FontStyle property set to FontStyles.Italic. | ||
/// Can contain other inline elements. | ||
/// </summary> | ||
public sealed class Italic : Span | ||
{ | ||
static Italic() | ||
{ | ||
FontStyleProperty.OverrideDefaultValue<Italic>(FontStyle.Italic); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using Avalonia.Media.TextFormatting; | ||
using Avalonia.Metadata; | ||
using Avalonia.Utilities; | ||
|
||
namespace Avalonia.Controls.Documents | ||
{ | ||
/// <summary> | ||
/// LineBreak element that forces a line breaking. | ||
/// </summary> | ||
[TrimSurroundingWhitespace] | ||
public class LineBreak : Inline | ||
{ | ||
/// <summary> | ||
/// Creates a new LineBreak instance. | ||
/// </summary> | ||
public LineBreak() | ||
{ | ||
} | ||
|
||
internal override int BuildRun(StringBuilder stringBuilder, | ||
IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex) | ||
{ | ||
var length = AppendText(stringBuilder); | ||
|
||
textStyleOverrides.Add(new ValueSpan<TextRunProperties>(firstCharacterIndex, length, | ||
CreateTextRunProperties())); | ||
|
||
return length; | ||
} | ||
|
||
internal override int AppendText(StringBuilder stringBuilder) | ||
{ | ||
var text = Environment.NewLine; | ||
|
||
stringBuilder.Append(text); | ||
|
||
return text.Length; | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.