diff --git a/samples/Sandbox/MainWindow.axaml b/samples/Sandbox/MainWindow.axaml index 6929f192c7..03f80d8fc7 100644 --- a/samples/Sandbox/MainWindow.axaml +++ b/samples/Sandbox/MainWindow.axaml @@ -1,4 +1,13 @@ + + This is a + TextBlock + with several + Span elements, + + using a variety of styles + . + diff --git a/src/Markup/Avalonia.Markup.Xaml/IAddChild.cs b/src/Avalonia.Base/Metadata/IAddChild.cs similarity index 61% rename from src/Markup/Avalonia.Markup.Xaml/IAddChild.cs rename to src/Avalonia.Base/Metadata/IAddChild.cs index 993eb6142d..8ef02912a6 100644 --- a/src/Markup/Avalonia.Markup.Xaml/IAddChild.cs +++ b/src/Avalonia.Base/Metadata/IAddChild.cs @@ -1,11 +1,11 @@ -namespace Avalonia.Markup.Xaml +namespace Avalonia.Metadata { public interface IAddChild { void AddChild(object child); } - public interface IAddChild : IAddChild + public interface IAddChild { void AddChild(T child); } diff --git a/src/Avalonia.Controls/Documents/Inline.cs b/src/Avalonia.Controls/Documents/Inline.cs index b400625903..47581e87f1 100644 --- a/src/Avalonia.Controls/Documents/Inline.cs +++ b/src/Avalonia.Controls/Documents/Inline.cs @@ -50,8 +50,38 @@ namespace Avalonia.Controls.Documents protected TextRunProperties CreateTextRunProperties() { - return new GenericTextRunProperties(new Typeface(FontFamily, FontStyle, FontWeight), FontSize, - TextDecorations, Foreground, Background, BaselineAlignment); + var textDecorations = TextDecorations; + var background = Background; + + if(Parent is Inline inline) + { + if(textDecorations == null) + { + textDecorations = inline.TextDecorations; + } + + if(background == null) + { + background = inline.Background; + } + } + + var fontStyle = FontStyle; + + if(Parent is Italic) + { + fontStyle = FontStyle.Italic; + } + + var fontWeight = FontWeight; + + if(Parent is Bold) + { + fontWeight = FontWeight.Bold; + } + + return new GenericTextRunProperties(new Typeface(FontFamily, fontStyle, fontWeight), FontSize, + textDecorations, Foreground, background, BaselineAlignment); } protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) diff --git a/src/Avalonia.Controls/Documents/InlineCollection.cs b/src/Avalonia.Controls/Documents/InlineCollection.cs index dc688fc359..3d7a4b58d1 100644 --- a/src/Avalonia.Controls/Documents/InlineCollection.cs +++ b/src/Avalonia.Controls/Documents/InlineCollection.cs @@ -14,7 +14,6 @@ namespace Avalonia.Controls.Documents { private ILogical? _parent; private IInlineHost? _inlineHost; - private string? _text = string.Empty; /// /// Initializes a new instance of the class. @@ -22,7 +21,7 @@ namespace Avalonia.Controls.Documents public InlineCollection() { ResetBehavior = ResetBehavior.Remove; - + this.ForEachItem( x => { @@ -36,16 +35,16 @@ namespace Avalonia.Controls.Documents x.InlineHost = InlineHost; Invalidate(); }, - () => throw new NotSupportedException()); + () => throw new NotSupportedException()); } - internal ILogical? Parent + internal ILogical? Parent { get => _parent; set { _parent = value; - + OnParentChanged(value); } } @@ -61,8 +60,6 @@ namespace Avalonia.Controls.Documents } } - public bool HasComplexContent => Count > 0; - /// /// Gets or adds the text held by the inlines collection. /// @@ -73,11 +70,6 @@ namespace Avalonia.Controls.Documents { get { - if (!HasComplexContent) - { - return _text; - } - var builder = new StringBuilder(); foreach (var inline in this) @@ -87,17 +79,7 @@ namespace Avalonia.Controls.Documents return builder.ToString(); } - set - { - if (HasComplexContent) - { - Add(new Run(value)); - } - else - { - _text = value; - } - } + } /// @@ -110,36 +92,12 @@ namespace Avalonia.Controls.Documents /// public void Add(string text) { - if (HasComplexContent) - { - Add(new Run(text)); - } - else - { - _text = text; - } + Add(new Run(text)); } public void Add(IControl child) { - var implicitRun = new InlineUIContainer(child); - - Add(implicitRun); - } - - public override void Add(Inline item) - { - if (!HasComplexContent) - { - if (!string.IsNullOrEmpty(_text)) - { - base.Add(new Run(_text)); - } - - _text = null; - } - - base.Add(item); + Add(new InlineUIContainer(child)); } /// @@ -152,7 +110,7 @@ namespace Avalonia.Controls.Documents /// protected void Invalidate() { - if(InlineHost != null) + if (InlineHost != null) { InlineHost.Invalidate(); } @@ -162,7 +120,7 @@ namespace Avalonia.Controls.Documents private void OnParentChanged(ILogical? parent) { - foreach(var child in this) + foreach (var child in this) { ((ISetLogicalParent)child).SetParent(parent); } diff --git a/src/Avalonia.Controls/Documents/Span.cs b/src/Avalonia.Controls/Documents/Span.cs index c7289dbc3f..3560996727 100644 --- a/src/Avalonia.Controls/Documents/Span.cs +++ b/src/Avalonia.Controls/Documents/Span.cs @@ -38,41 +38,17 @@ namespace Avalonia.Controls.Documents internal override void BuildTextRun(IList textRuns) { - if (Inlines.HasComplexContent) + foreach (var inline in Inlines) { - foreach (var inline in Inlines) - { - inline.BuildTextRun(textRuns); - } - } - else - { - if (Inlines.Text is string text) - { - var textRunProperties = CreateTextRunProperties(); - - var textCharacters = new TextCharacters(text.AsMemory(), textRunProperties); - - textRuns.Add(textCharacters); - } + inline.BuildTextRun(textRuns); } } internal override void AppendText(StringBuilder stringBuilder) { - if (Inlines.HasComplexContent) - { - foreach (var inline in Inlines) - { - inline.AppendText(stringBuilder); - } - } - else + foreach (var inline in Inlines) { - if (Inlines.Text is string text) - { - stringBuilder.Append(text); - } + inline.AppendText(stringBuilder); } } @@ -93,7 +69,7 @@ namespace Avalonia.Controls.Documents { base.OnInlineHostChanged(oldValue, newValue); - if(Inlines is not null) + if (Inlines is not null) { Inlines.InlineHost = newValue; } diff --git a/src/Avalonia.Controls/Documents/TextElement.cs b/src/Avalonia.Controls/Documents/TextElement.cs index 5bac3642ed..2034f05fc0 100644 --- a/src/Avalonia.Controls/Documents/TextElement.cs +++ b/src/Avalonia.Controls/Documents/TextElement.cs @@ -18,7 +18,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty FontFamilyProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(FontFamily), defaultValue: FontFamily.Default, inherits: true); @@ -27,7 +27,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty FontSizeProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(FontSize), defaultValue: 12, inherits: true); @@ -36,7 +36,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty FontStyleProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(FontStyle), inherits: true); @@ -44,7 +44,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty FontWeightProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(FontWeight), inherits: true, defaultValue: FontWeight.Normal); @@ -53,7 +53,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty FontStretchProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(FontStretch), inherits: true, defaultValue: FontStretch.Normal); @@ -62,7 +62,7 @@ namespace Avalonia.Controls.Documents /// Defines the property. /// public static readonly AttachedProperty ForegroundProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( nameof(Foreground), Brushes.Black, inherits: true); diff --git a/src/Avalonia.Controls/RichTextBlock.cs b/src/Avalonia.Controls/RichTextBlock.cs index 2b84113497..abd6e7e807 100644 --- a/src/Avalonia.Controls/RichTextBlock.cs +++ b/src/Avalonia.Controls/RichTextBlock.cs @@ -16,7 +16,7 @@ namespace Avalonia.Controls /// /// A control that displays a block of formatted text. /// - public class RichTextBlock : TextBlock, IInlineHost + public class RichTextBlock : TextBlock, IInlineHost, IAddChild, IAddChild, IAddChild { public static readonly StyledProperty IsTextSelectionEnabledProperty = AvaloniaProperty.Register(nameof(IsTextSelectionEnabled), false); @@ -148,7 +148,6 @@ namespace Avalonia.Controls /// /// Gets or sets the inlines. /// - [Content] public InlineCollection Inlines { get => GetValue(InlinesProperty); @@ -170,6 +169,8 @@ namespace Avalonia.Controls remove => RemoveHandler(CopyingToClipboardEvent, value); } + internal bool HasComplexContent => Inlines.Count > 0; + /// /// Copies the current selection to the Clipboard. /// @@ -251,25 +252,69 @@ namespace Avalonia.Controls SelectionEnd = SelectionStart; } - protected override string? GetText() + void IAddChild.AddChild(string text) { - return _text ?? Inlines.Text; + AddText(text); } - protected override void SetText(string? text) + void IAddChild.AddChild(Inline inline) { - var oldValue = _text ?? Inlines?.Text; + if (!HasComplexContent && !string.IsNullOrEmpty(_text)) + { + Inlines.Add(_text); + + _text = null; + } + + Inlines.Add(inline); + } - if (Inlines is not null && Inlines.HasComplexContent) + void IAddChild.AddChild(IControl child) + { + if (!HasComplexContent && !string.IsNullOrEmpty(_text)) { - Inlines.Text = text; + Inlines.Add(_text); _text = null; } - else + + Inlines.Add(new InlineUIContainer(child)); + } + + protected void AddText(string? text) + { + if (string.IsNullOrEmpty(text)) + { + return; + } + + if (!HasComplexContent && string.IsNullOrEmpty(_text)) { _text = text; } + else + { + if (!string.IsNullOrEmpty(_text)) + { + Inlines.Add(_text); + + _text = null; + } + + Inlines.Add(text); + } + } + + protected override string? GetText() + { + return _text ?? Inlines.Text; + } + + protected override void SetText(string? text) + { + var oldValue = _text ?? Inlines?.Text; + + AddText(text); RaisePropertyChanged(TextProperty, oldValue, text); } @@ -293,7 +338,7 @@ namespace Avalonia.Controls var inlines = Inlines; - if (inlines is not null && inlines.HasComplexContent) + if (HasComplexContent) { var textRuns = new List(); diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index 52261d1c76..8077c00faf 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -4,6 +4,7 @@ using Avalonia.Controls.Documents; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Media.TextFormatting; +using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Controls @@ -11,7 +12,7 @@ namespace Avalonia.Controls /// /// A control that displays a block of text. /// - public class TextBlock : Control + public class TextBlock : Control, IAddChild { /// /// Defines the property. @@ -473,11 +474,6 @@ namespace Avalonia.Controls control.SetValue(MaxLinesProperty, maxLines); } - public void Add(string text) - { - _text = text; - } - /// /// Renders the to a drawing context. /// @@ -512,6 +508,11 @@ namespace Avalonia.Controls TextLayout.Draw(context, new Point(padding.Left, top)); } + void IAddChild.AddChild(string text) + { + _text = text; + } + protected virtual string? GetText() { return _text; diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs index 54eac8f59e..c8fced515d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguage.cs @@ -70,8 +70,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions }, InnerServiceProviderFactoryMethod = runtimeHelpers.FindMethod(m => m.Name == "CreateInnerServiceProviderV1"), - IAddChild = typeSystem.GetType("Avalonia.Markup.Xaml.IAddChild"), - IAddChildOfT = typeSystem.GetType("Avalonia.Markup.Xaml.IAddChild`1") + IAddChild = typeSystem.GetType("Avalonia.Metadata.IAddChild"), + IAddChildOfT = typeSystem.GetType("Avalonia.Metadata.IAddChild`1") }; rv.CustomAttributeResolver = new AttributeResolver(typeSystem, rv); diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index c35cbc35c0..30d321426f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -15,7 +15,6 @@ -