Browse Source

Limit InlineUIContainer to available width (#19651)

* Limit InlineUIContainer to available width

* Unit test for InlineUIContainer maximum width

* Invalidate InlineUIContainer's host

* Better InlineUIContainer visual children management

* OnInlineHostChanged also handled by InlineUIContainer

---------

Co-authored-by: Jan Kučera <miloush@users.noreply.github.com>
Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>
fix/avnview-hittest
Jan Kučera 5 months ago
committed by GitHub
parent
commit
912f916c10
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/Avalonia.Controls/Documents/Inline.cs
  2. 19
      src/Avalonia.Controls/Documents/InlineCollection.cs
  3. 20
      src/Avalonia.Controls/Documents/InlineUIContainer.cs
  4. 2
      src/Avalonia.Controls/Documents/LineBreak.cs
  5. 4
      src/Avalonia.Controls/Documents/Run.cs
  6. 4
      src/Avalonia.Controls/Documents/Span.cs
  7. 4
      src/Avalonia.Controls/TextBlock.cs
  8. 27
      tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

2
src/Avalonia.Controls/Documents/Inline.cs

@ -66,7 +66,7 @@ namespace Avalonia.Controls.Documents
control.SetValue(TextDecorationsProperty, value); control.SetValue(TextDecorationsProperty, value);
} }
internal abstract void BuildTextRun(IList<TextRun> textRuns); internal abstract void BuildTextRun(IList<TextRun> textRuns, Size blockSize);
internal abstract void AppendText(StringBuilder stringBuilder); internal abstract void AppendText(StringBuilder stringBuilder);

19
src/Avalonia.Controls/Documents/InlineCollection.cs

@ -160,15 +160,6 @@ namespace Avalonia.Controls.Documents
foreach (var child in this) foreach (var child in this)
{ {
child.InlineHost = newValue; child.InlineHost = newValue;
if (child is not InlineUIContainer container)
{
continue;
}
oldValue?.VisualChildren.Remove(container.Child);
newValue?.VisualChildren.Add(container.Child);
} }
Invalidate(); Invalidate();
@ -180,11 +171,6 @@ namespace Avalonia.Controls.Documents
LogicalChildren?.Add(inline); LogicalChildren?.Add(inline);
if (inline is InlineUIContainer container)
{
InlineHost?.VisualChildren.Add(container.Child);
}
Invalidate(); Invalidate();
} }
@ -192,11 +178,6 @@ namespace Avalonia.Controls.Documents
{ {
LogicalChildren?.Remove(inline); LogicalChildren?.Remove(inline);
if (inline is InlineUIContainer container)
{
InlineHost?.VisualChildren.Remove(container.Child);
}
inline.InlineHost = null; inline.InlineHost = null;
Invalidate(); Invalidate();

20
src/Avalonia.Controls/Documents/InlineUIContainer.cs

@ -18,6 +18,8 @@ namespace Avalonia.Controls.Documents
public static readonly StyledProperty<Control> ChildProperty = public static readonly StyledProperty<Control> ChildProperty =
AvaloniaProperty.Register<InlineUIContainer, Control>(nameof(Child)); AvaloniaProperty.Register<InlineUIContainer, Control>(nameof(Child));
private double _measuredWidth = double.NaN;
/// <summary> /// <summary>
/// Initializes a new instance of InlineUIContainer element. /// Initializes a new instance of InlineUIContainer element.
/// </summary> /// </summary>
@ -51,11 +53,12 @@ namespace Avalonia.Controls.Documents
set => SetValue(ChildProperty, value); set => SetValue(ChildProperty, value);
} }
internal override void BuildTextRun(IList<TextRun> textRuns) internal override void BuildTextRun(IList<TextRun> textRuns, Size blockSize)
{ {
if(!Child.IsMeasureValid) if (_measuredWidth != blockSize.Width || !Child.IsMeasureValid)
{ {
Child.Measure(Size.Infinity); Child.Measure(new Size(blockSize.Width, double.PositiveInfinity));
_measuredWidth = blockSize.Width;
} }
textRuns.Add(new EmbeddedControlRun(Child, CreateTextRunProperties())); textRuns.Add(new EmbeddedControlRun(Child, CreateTextRunProperties()));
@ -74,13 +77,24 @@ namespace Avalonia.Controls.Documents
if(change.OldValue is Control oldChild) if(change.OldValue is Control oldChild)
{ {
LogicalChildren.Remove(oldChild); LogicalChildren.Remove(oldChild);
InlineHost?.VisualChildren.Remove(oldChild);
} }
if(change.NewValue is Control newChild) if(change.NewValue is Control newChild)
{ {
LogicalChildren.Add(newChild); LogicalChildren.Add(newChild);
InlineHost?.VisualChildren.Add(newChild);
} }
InlineHost?.Invalidate();
} }
} }
internal override void OnInlineHostChanged(IInlineHost? oldValue, IInlineHost? newValue)
{
var child = Child;
oldValue?.VisualChildren.Remove(child);
newValue?.VisualChildren.Add(child);
}
} }
} }

2
src/Avalonia.Controls/Documents/LineBreak.cs

@ -19,7 +19,7 @@ namespace Avalonia.Controls.Documents
{ {
} }
internal override void BuildTextRun(IList<TextRun> textRuns) internal override void BuildTextRun(IList<TextRun> textRuns, Size blockSize)
{ {
var text = Environment.NewLine; var text = Environment.NewLine;

4
src/Avalonia.Controls/Documents/Run.cs

@ -50,7 +50,7 @@ namespace Avalonia.Controls.Documents
set => SetValue(TextProperty, value); set => SetValue(TextProperty, value);
} }
internal override void BuildTextRun(IList<TextRun> textRuns) internal override void BuildTextRun(IList<TextRun> textRuns, Size blockSize)
{ {
var text = Text ?? ""; var text = Text ?? "";
@ -59,7 +59,7 @@ namespace Avalonia.Controls.Documents
return; return;
} }
var textRunProperties = CreateTextRunProperties(); var textRunProperties = CreateTextRunProperties();
var textCharacters = new TextCharacters(text, textRunProperties); var textCharacters = new TextCharacters(text, textRunProperties);

4
src/Avalonia.Controls/Documents/Span.cs

@ -38,11 +38,11 @@ namespace Avalonia.Controls.Documents
set => SetValue(InlinesProperty, value); set => SetValue(InlinesProperty, value);
} }
internal override void BuildTextRun(IList<TextRun> textRuns) internal override void BuildTextRun(IList<TextRun> textRuns, Size blockSize)
{ {
foreach (var inline in Inlines) foreach (var inline in Inlines)
{ {
inline.BuildTextRun(textRuns); inline.BuildTextRun(textRuns, blockSize);
} }
} }

4
src/Avalonia.Controls/TextBlock.cs

@ -730,7 +730,7 @@ namespace Avalonia.Controls
_textLayout = null; _textLayout = null;
_constraint = deflatedSize; _constraint = deflatedSize;
//Force arrange so text will be properly alligned. //Force arrange so text will be properly aligned.
InvalidateArrange(); InvalidateArrange();
} }
@ -742,7 +742,7 @@ namespace Avalonia.Controls
foreach (var inline in inlines!) foreach (var inline in inlines!)
{ {
inline.BuildTextRun(textRuns); inline.BuildTextRun(textRuns, deflatedSize);
} }
_textRuns = textRuns; _textRuns = textRuns;

27
tests/Avalonia.Controls.UnitTests/TextBlockTests.cs

@ -348,7 +348,7 @@ namespace Avalonia.Controls.UnitTests
} }
[Fact] [Fact]
public void InlineUIContainer_Child_Schould_Be_Arranged() public void InlineUIContainer_Child_Should_Be_Arranged()
{ {
using (UnitTestApplication.Start(TestServices.StyledWindow)) using (UnitTestApplication.Start(TestServices.StyledWindow))
{ {
@ -382,6 +382,31 @@ namespace Avalonia.Controls.UnitTests
} }
} }
[Fact]
public void InlineUIContainer_Child_Should_Be_Constrained()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var target = new TextBlock();
GeometryDrawing drawing = new GeometryDrawing();
drawing.Geometry = new RectangleGeometry(new Rect(0, 0, 500, 500));
DrawingImage image = new DrawingImage(drawing);
Image imageControl = new Image { Source = image };
InlineUIContainer container = new InlineUIContainer(imageControl);
target.Inlines.Add(new Run("The child should not be limited by position on line."));
target.Inlines.Add(container);
target.Measure(new Size(100, 100));
target.Arrange(new Rect(target.DesiredSize));
Assert.True(imageControl.IsMeasureValid);
Assert.Equal(100, imageControl.Bounds.Width);
}
}
[Fact] [Fact]
public void Setting_Text_Should_Reset_Inlines() public void Setting_Text_Should_Reset_Inlines()
{ {

Loading…
Cancel
Save