committed by
GitHub
29 changed files with 799 additions and 382 deletions
@ -0,0 +1,10 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Avalonia.Metadata |
||||
|
{ |
||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] |
||||
|
public class TrimSurroundingWhitespaceAttribute : Attribute |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,86 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Data; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A terminal element in text flow hierarchy - contains a uniformatted run of unicode characters
|
||||
|
/// </summary>
|
||||
|
public class Run : Inline |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes an instance of Run class.
|
||||
|
/// </summary>
|
||||
|
public Run() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes an instance of Run class specifying its text content.
|
||||
|
/// </summary>
|
||||
|
/// <param name="text">
|
||||
|
/// Text content assigned to the Run.
|
||||
|
/// </param>
|
||||
|
public Run(string? text) |
||||
|
{ |
||||
|
Text = text; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Dependency property backing Text.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Note that when a TextRange that intersects with this Run gets modified (e.g. by editing
|
||||
|
/// a selection in RichTextBox), we will get two changes to this property since we delete
|
||||
|
/// and then insert when setting the content of a TextRange.
|
||||
|
/// </remarks>
|
||||
|
public static readonly StyledProperty<string?> TextProperty = AvaloniaProperty.Register<Run, string?> ( |
||||
|
nameof (Text), defaultBindingMode: BindingMode.TwoWay); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// The content spanned by this TextElement.
|
||||
|
/// </summary>
|
||||
|
[Content] |
||||
|
public string? Text { |
||||
|
get { return GetValue (TextProperty); } |
||||
|
set { SetValue (TextProperty, value); } |
||||
|
} |
||||
|
|
||||
|
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 = Text ?? ""; |
||||
|
|
||||
|
stringBuilder.Append(text); |
||||
|
|
||||
|
return text.Length; |
||||
|
} |
||||
|
|
||||
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
|
||||
|
switch (change.Property.Name) |
||||
|
{ |
||||
|
case nameof(Text): |
||||
|
Invalidate(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using Avalonia.Media.TextFormatting; |
||||
|
using Avalonia.Metadata; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Span element used for grouping other Inline elements.
|
||||
|
/// </summary>
|
||||
|
public class Span : Inline |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Inlines"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly DirectProperty<Span, InlineCollection> InlinesProperty = |
||||
|
AvaloniaProperty.RegisterDirect<Span, InlineCollection>( |
||||
|
nameof(Inlines), |
||||
|
o => o.Inlines); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of a Span element.
|
||||
|
/// </summary>
|
||||
|
public Span() |
||||
|
{ |
||||
|
Inlines = new InlineCollection(this); |
||||
|
|
||||
|
Inlines.Invalidated += (s, e) => Invalidate(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the inlines.
|
||||
|
/// </summary>
|
||||
|
[Content] |
||||
|
public InlineCollection Inlines { get; } |
||||
|
|
||||
|
internal override int BuildRun(StringBuilder stringBuilder, IList<ValueSpan<TextRunProperties>> textStyleOverrides, int firstCharacterIndex) |
||||
|
{ |
||||
|
var length = 0; |
||||
|
|
||||
|
if (Inlines.HasComplexContent) |
||||
|
{ |
||||
|
foreach (var inline in Inlines) |
||||
|
{ |
||||
|
var inlineLength = inline.BuildRun(stringBuilder, textStyleOverrides, firstCharacterIndex); |
||||
|
|
||||
|
firstCharacterIndex += inlineLength; |
||||
|
|
||||
|
length += inlineLength; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (Inlines.Text == null) |
||||
|
{ |
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
stringBuilder.Append(Inlines.Text); |
||||
|
|
||||
|
length = Inlines.Text.Length; |
||||
|
|
||||
|
textStyleOverrides.Add(new ValueSpan<TextRunProperties>(firstCharacterIndex, length, |
||||
|
CreateTextRunProperties())); |
||||
|
} |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
internal override int AppendText(StringBuilder stringBuilder) |
||||
|
{ |
||||
|
if (Inlines.HasComplexContent) |
||||
|
{ |
||||
|
var length = 0; |
||||
|
|
||||
|
foreach (var inline in Inlines) |
||||
|
{ |
||||
|
length += inline.AppendText(stringBuilder); |
||||
|
} |
||||
|
|
||||
|
return length; |
||||
|
} |
||||
|
|
||||
|
if (Inlines.Text == null) |
||||
|
{ |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
stringBuilder.Append(Inlines.Text); |
||||
|
|
||||
|
return Inlines.Text.Length; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,129 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// TextElement is an base class for content in text based controls.
|
||||
|
/// TextElements span other content, applying property values or providing structural information.
|
||||
|
/// </summary>
|
||||
|
public abstract class TextElement : StyledElement |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Background"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly StyledProperty<IBrush?> BackgroundProperty = |
||||
|
AvaloniaProperty.Register<TextElement, IBrush?>(nameof(Background), inherits: true); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontFamily"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontFamily> FontFamilyProperty = |
||||
|
TextBlock.FontFamilyProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontSize"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<double> FontSizeProperty = |
||||
|
TextBlock.FontSizeProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontStyle"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontStyle> FontStyleProperty = |
||||
|
TextBlock.FontStyleProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="FontWeight"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<FontWeight> FontWeightProperty = |
||||
|
TextBlock.FontWeightProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Defines the <see cref="Foreground"/> property.
|
||||
|
/// </summary>
|
||||
|
public static readonly AttachedProperty<IBrush?> ForegroundProperty = |
||||
|
TextBlock.ForegroundProperty.AddOwner<TextElement>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a brush used to paint the control's background.
|
||||
|
/// </summary>
|
||||
|
public IBrush? Background |
||||
|
{ |
||||
|
get { return GetValue(BackgroundProperty); } |
||||
|
set { SetValue(BackgroundProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font family.
|
||||
|
/// </summary>
|
||||
|
public FontFamily FontFamily |
||||
|
{ |
||||
|
get { return GetValue(FontFamilyProperty); } |
||||
|
set { SetValue(FontFamilyProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font size.
|
||||
|
/// </summary>
|
||||
|
public double FontSize |
||||
|
{ |
||||
|
get { return GetValue(FontSizeProperty); } |
||||
|
set { SetValue(FontSizeProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font style.
|
||||
|
/// </summary>
|
||||
|
public FontStyle FontStyle |
||||
|
{ |
||||
|
get { return GetValue(FontStyleProperty); } |
||||
|
set { SetValue(FontStyleProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the font weight.
|
||||
|
/// </summary>
|
||||
|
public FontWeight FontWeight |
||||
|
{ |
||||
|
get { return GetValue(FontWeightProperty); } |
||||
|
set { SetValue(FontWeightProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a brush used to paint the text.
|
||||
|
/// </summary>
|
||||
|
public IBrush? Foreground |
||||
|
{ |
||||
|
get { return GetValue(ForegroundProperty); } |
||||
|
set { SetValue(ForegroundProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raised when the visual representation of the text element changes.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler? Invalidated; |
||||
|
|
||||
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
||||
|
{ |
||||
|
base.OnPropertyChanged(change); |
||||
|
|
||||
|
switch (change.Property.Name) |
||||
|
{ |
||||
|
case nameof(Background): |
||||
|
case nameof(FontFamily): |
||||
|
case nameof(FontSize): |
||||
|
case nameof(FontStyle): |
||||
|
case nameof(FontWeight): |
||||
|
case nameof(Foreground): |
||||
|
Invalidate(); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raises the <see cref="Invalidate"/> event.
|
||||
|
/// </summary>
|
||||
|
protected void Invalidate() => Invalidated?.Invoke(this, EventArgs.Empty); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Avalonia.Controls.Documents |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Underline element - markup helper for indicating superscript content.
|
||||
|
/// Equivalent to a Span with TextDecorations property set to TextDecorations.Underlined.
|
||||
|
/// Can contain other inline elements.
|
||||
|
/// </summary>
|
||||
|
public sealed class Underline : Span |
||||
|
{ |
||||
|
static Underline() |
||||
|
{ |
||||
|
TextDecorationsProperty.OverrideDefaultValue<Underline>(Media.TextDecorations.Underline); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,344 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using Avalonia.Controls.Platform; |
|
||||
using Avalonia.Controls.Primitives.PopupPositioning; |
|
||||
using Avalonia.Input; |
|
||||
using Avalonia.Input.Raw; |
|
||||
using Avalonia.Input.TextInput; |
|
||||
using Avalonia.Platform; |
|
||||
using Avalonia.Rendering; |
|
||||
|
|
||||
namespace Avalonia.Controls; |
|
||||
|
|
||||
internal class ValidatingToplevelImpl : ITopLevelImpl, ITopLevelImplWithNativeControlHost, |
|
||||
ITopLevelImplWithNativeMenuExporter, ITopLevelImplWithTextInputMethod |
|
||||
{ |
|
||||
private readonly ITopLevelImpl _impl; |
|
||||
private bool _disposed; |
|
||||
|
|
||||
public ValidatingToplevelImpl(ITopLevelImpl impl) |
|
||||
{ |
|
||||
_impl = impl ?? throw new InvalidOperationException( |
|
||||
"Could not create TopLevel implementation: maybe no windowing subsystem was initialized?"); |
|
||||
} |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
_disposed = true; |
|
||||
_impl.Dispose(); |
|
||||
} |
|
||||
|
|
||||
protected void CheckDisposed() |
|
||||
{ |
|
||||
if (_disposed) |
|
||||
throw new ObjectDisposedException(_impl.GetType().FullName); |
|
||||
} |
|
||||
|
|
||||
protected ITopLevelImpl Inner |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
CheckDisposed(); |
|
||||
return _impl; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static ITopLevelImpl Wrap(ITopLevelImpl impl) |
|
||||
{ |
|
||||
#if DEBUG
|
|
||||
if (impl is ValidatingToplevelImpl) |
|
||||
return impl; |
|
||||
return new ValidatingToplevelImpl(impl); |
|
||||
#else
|
|
||||
return impl; |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
public Size ClientSize => Inner.ClientSize; |
|
||||
public Size? FrameSize => Inner.FrameSize; |
|
||||
public double RenderScaling => Inner.RenderScaling; |
|
||||
public IEnumerable<object> Surfaces => Inner.Surfaces; |
|
||||
|
|
||||
public Action<RawInputEventArgs>? Input |
|
||||
{ |
|
||||
get => Inner.Input; |
|
||||
set => Inner.Input = value; |
|
||||
} |
|
||||
|
|
||||
public Action<Rect>? Paint |
|
||||
{ |
|
||||
get => Inner.Paint; |
|
||||
set => Inner.Paint = value; |
|
||||
} |
|
||||
|
|
||||
public Action<Size, PlatformResizeReason>? Resized |
|
||||
{ |
|
||||
get => Inner.Resized; |
|
||||
set => Inner.Resized = value; |
|
||||
} |
|
||||
|
|
||||
public Action<double>? ScalingChanged |
|
||||
{ |
|
||||
get => Inner.ScalingChanged; |
|
||||
set => Inner.ScalingChanged = value; |
|
||||
} |
|
||||
|
|
||||
public Action<WindowTransparencyLevel>? TransparencyLevelChanged |
|
||||
{ |
|
||||
get => Inner.TransparencyLevelChanged; |
|
||||
set => Inner.TransparencyLevelChanged = value; |
|
||||
} |
|
||||
|
|
||||
public IRenderer CreateRenderer(IRenderRoot root) => Inner.CreateRenderer(root); |
|
||||
|
|
||||
public void Invalidate(Rect rect) => Inner.Invalidate(rect); |
|
||||
|
|
||||
public void SetInputRoot(IInputRoot inputRoot) => Inner.SetInputRoot(inputRoot); |
|
||||
|
|
||||
public Point PointToClient(PixelPoint point) => Inner.PointToClient(point); |
|
||||
|
|
||||
public PixelPoint PointToScreen(Point point) => Inner.PointToScreen(point); |
|
||||
|
|
||||
public void SetCursor(ICursorImpl? cursor) => Inner.SetCursor(cursor); |
|
||||
|
|
||||
public Action? Closed |
|
||||
{ |
|
||||
get => Inner.Closed; |
|
||||
set => Inner.Closed = value; |
|
||||
} |
|
||||
|
|
||||
public Action? LostFocus |
|
||||
{ |
|
||||
get => Inner.LostFocus; |
|
||||
set => Inner.LostFocus = value; |
|
||||
} |
|
||||
|
|
||||
// Exception: for some reason we are notifying platform mouse device from TopLevel.cs
|
|
||||
public IMouseDevice MouseDevice => _impl.MouseDevice; |
|
||||
public IPopupImpl? CreatePopup() => Inner.CreatePopup(); |
|
||||
|
|
||||
public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) => |
|
||||
Inner.SetTransparencyLevelHint(transparencyLevel); |
|
||||
|
|
||||
|
|
||||
public WindowTransparencyLevel TransparencyLevel => Inner.TransparencyLevel; |
|
||||
public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => Inner.AcrylicCompensationLevels; |
|
||||
public INativeControlHostImpl? NativeControlHost => (Inner as ITopLevelImplWithNativeControlHost)?.NativeControlHost; |
|
||||
|
|
||||
public ITopLevelNativeMenuExporter? NativeMenuExporter => |
|
||||
(Inner as ITopLevelImplWithNativeMenuExporter)?.NativeMenuExporter; |
|
||||
|
|
||||
public ITextInputMethodImpl? TextInputMethod => (Inner as ITopLevelImplWithTextInputMethod)?.TextInputMethod; |
|
||||
} |
|
||||
|
|
||||
internal class ValidatingWindowBaseImpl : ValidatingToplevelImpl, IWindowBaseImpl |
|
||||
{ |
|
||||
private readonly IWindowBaseImpl _impl; |
|
||||
|
|
||||
public ValidatingWindowBaseImpl(IWindowBaseImpl impl) : base(impl) |
|
||||
{ |
|
||||
_impl = impl; |
|
||||
} |
|
||||
|
|
||||
protected new IWindowBaseImpl Inner |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
CheckDisposed(); |
|
||||
return _impl; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static IWindowBaseImpl Wrap(IWindowBaseImpl impl) |
|
||||
{ |
|
||||
#if DEBUG
|
|
||||
if (impl is ValidatingToplevelImpl) |
|
||||
return impl; |
|
||||
return new ValidatingWindowBaseImpl(impl); |
|
||||
#else
|
|
||||
return impl; |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
public void Show(bool activate, bool isDialog) => Inner.Show(activate, isDialog); |
|
||||
|
|
||||
public void Hide() => Inner.Hide(); |
|
||||
|
|
||||
public double DesktopScaling => Inner.DesktopScaling; |
|
||||
public PixelPoint Position => Inner.Position; |
|
||||
|
|
||||
public Action<PixelPoint>? PositionChanged |
|
||||
{ |
|
||||
get => Inner.PositionChanged; |
|
||||
set => Inner.PositionChanged = value; |
|
||||
} |
|
||||
|
|
||||
public void Activate() => Inner.Activate(); |
|
||||
|
|
||||
public Action? Deactivated |
|
||||
{ |
|
||||
get => Inner.Deactivated; |
|
||||
set => Inner.Deactivated = value; |
|
||||
} |
|
||||
|
|
||||
public Action? Activated |
|
||||
{ |
|
||||
get => Inner.Activated; |
|
||||
set => Inner.Activated = value; |
|
||||
} |
|
||||
|
|
||||
public IPlatformHandle Handle => Inner.Handle; |
|
||||
public Size MaxAutoSizeHint => Inner.MaxAutoSizeHint; |
|
||||
public void SetTopmost(bool value) => Inner.SetTopmost(value); |
|
||||
public IScreenImpl Screen => Inner.Screen; |
|
||||
} |
|
||||
|
|
||||
internal class ValidatingWindowImpl : ValidatingWindowBaseImpl, IWindowImpl |
|
||||
{ |
|
||||
private readonly IWindowImpl _impl; |
|
||||
|
|
||||
public ValidatingWindowImpl(IWindowImpl impl) : base(impl) |
|
||||
{ |
|
||||
_impl = impl; |
|
||||
} |
|
||||
|
|
||||
protected new IWindowImpl Inner |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
CheckDisposed(); |
|
||||
return _impl; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static IWindowImpl Unwrap(IWindowImpl impl) |
|
||||
{ |
|
||||
if (impl is ValidatingWindowImpl v) |
|
||||
return v.Inner; |
|
||||
return impl; |
|
||||
} |
|
||||
|
|
||||
public static IWindowImpl Wrap(IWindowImpl impl) |
|
||||
{ |
|
||||
#if DEBUG
|
|
||||
if (impl is ValidatingToplevelImpl) |
|
||||
return impl; |
|
||||
return new ValidatingWindowImpl(impl); |
|
||||
#else
|
|
||||
return impl; |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
public WindowState WindowState |
|
||||
{ |
|
||||
get => Inner.WindowState; |
|
||||
set => Inner.WindowState = value; |
|
||||
} |
|
||||
|
|
||||
public Action<WindowState> WindowStateChanged |
|
||||
{ |
|
||||
get => Inner.WindowStateChanged; |
|
||||
set => Inner.WindowStateChanged = value; |
|
||||
} |
|
||||
|
|
||||
public void SetTitle(string? title) => Inner.SetTitle(title); |
|
||||
|
|
||||
public void SetParent(IWindowImpl parent) |
|
||||
{ |
|
||||
//Workaround. SetParent will cast IWindowImpl to WindowImpl but ValidatingWindowImpl isn't actual WindowImpl so it will fail with InvalidCastException.
|
|
||||
if (parent is ValidatingWindowImpl validatingToplevelImpl) |
|
||||
{ |
|
||||
Inner.SetParent(validatingToplevelImpl.Inner); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
Inner.SetParent(parent); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void SetEnabled(bool enable) => Inner.SetEnabled(enable); |
|
||||
|
|
||||
public Action GotInputWhenDisabled |
|
||||
{ |
|
||||
get => Inner.GotInputWhenDisabled; |
|
||||
set => Inner.GotInputWhenDisabled = value; |
|
||||
} |
|
||||
|
|
||||
public void SetSystemDecorations(SystemDecorations enabled) => Inner.SetSystemDecorations(enabled); |
|
||||
|
|
||||
public void SetIcon(IWindowIconImpl? icon) => Inner.SetIcon(icon); |
|
||||
|
|
||||
public void ShowTaskbarIcon(bool value) => Inner.ShowTaskbarIcon(value); |
|
||||
|
|
||||
public void CanResize(bool value) => Inner.CanResize(value); |
|
||||
|
|
||||
public Func<bool> Closing |
|
||||
{ |
|
||||
get => Inner.Closing; |
|
||||
set => Inner.Closing = value; |
|
||||
} |
|
||||
|
|
||||
public bool IsClientAreaExtendedToDecorations => Inner.IsClientAreaExtendedToDecorations; |
|
||||
|
|
||||
public Action<bool> ExtendClientAreaToDecorationsChanged |
|
||||
{ |
|
||||
get => Inner.ExtendClientAreaToDecorationsChanged; |
|
||||
set => Inner.ExtendClientAreaToDecorationsChanged = value; |
|
||||
} |
|
||||
|
|
||||
public bool NeedsManagedDecorations => Inner.NeedsManagedDecorations; |
|
||||
public Thickness ExtendedMargins => Inner.ExtendedMargins; |
|
||||
public Thickness OffScreenMargin => Inner.OffScreenMargin; |
|
||||
public void BeginMoveDrag(PointerPressedEventArgs e) => Inner.BeginMoveDrag(e); |
|
||||
|
|
||||
public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) => Inner.BeginResizeDrag(edge, e); |
|
||||
|
|
||||
public void Resize(Size clientSize, PlatformResizeReason reason) => |
|
||||
Inner.Resize(clientSize, reason); |
|
||||
|
|
||||
public void Move(PixelPoint point) => Inner.Move(point); |
|
||||
|
|
||||
public void SetMinMaxSize(Size minSize, Size maxSize) => Inner.SetMinMaxSize(minSize, maxSize); |
|
||||
|
|
||||
public void SetExtendClientAreaToDecorationsHint(bool extendIntoClientAreaHint) => |
|
||||
Inner.SetExtendClientAreaToDecorationsHint(extendIntoClientAreaHint); |
|
||||
|
|
||||
public void SetExtendClientAreaChromeHints(ExtendClientAreaChromeHints hints) => |
|
||||
Inner.SetExtendClientAreaChromeHints(hints); |
|
||||
|
|
||||
public void SetExtendClientAreaTitleBarHeightHint(double titleBarHeight) => |
|
||||
Inner.SetExtendClientAreaTitleBarHeightHint(titleBarHeight); |
|
||||
} |
|
||||
|
|
||||
internal class ValidatingPopupImpl : ValidatingWindowBaseImpl, IPopupImpl |
|
||||
{ |
|
||||
private readonly IPopupImpl _impl; |
|
||||
|
|
||||
public ValidatingPopupImpl(IPopupImpl impl) : base(impl) |
|
||||
{ |
|
||||
_impl = impl; |
|
||||
} |
|
||||
|
|
||||
protected new IPopupImpl Inner |
|
||||
{ |
|
||||
get |
|
||||
{ |
|
||||
CheckDisposed(); |
|
||||
return _impl; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public static IPopupImpl Wrap(IPopupImpl impl) |
|
||||
{ |
|
||||
#if DEBUG
|
|
||||
if (impl is ValidatingToplevelImpl) |
|
||||
return impl; |
|
||||
return new ValidatingPopupImpl(impl); |
|
||||
#else
|
|
||||
return impl; |
|
||||
#endif
|
|
||||
} |
|
||||
|
|
||||
public IPopupPositioner PopupPositioner => Inner.PopupPositioner; |
|
||||
public void SetWindowManagerAddShadowHint(bool enabled) => Inner.SetWindowManagerAddShadowHint(enabled); |
|
||||
} |
|
||||
Loading…
Reference in new issue