AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.96k stars 2.25k forks source link

Text aligned to top instead of center when changing LineSpacing on TextBlock #17193

Open kuiperzone opened 1 month ago

kuiperzone commented 1 month ago

Describe the bug

Ref #13873

It seems that the problem remains with LineSpacing, rather than LineHeight.

See screenshots.

LineSpacing

LineHeight

To Reproduce

private static Grid CreateSample2()
{
    const double LineSpacing = 16; // 0;
    const double LineHeight = double.NaN; // 32;

    var grid = new Grid();
    grid.Background = new SolidColorBrush(Colors.DarkGray);
    grid.ShowGridLines = true;
    grid.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top;
    grid.HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch;

    grid.RowDefinitions.Add(new RowDefinition());

    grid.ColumnDefinitions.Add(new ColumnDefinition());
    grid.ColumnDefinitions.Add(new ColumnDefinition());
    grid.ColumnDefinitions.Add(new ColumnDefinition());

    var block = new TextBlock();
    block.LineSpacing = LineSpacing;
    block.LineHeight = LineHeight;
    block.Inlines.Add(new Run("Col 0"));
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 2") { FontSize = 24 });
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 3") { FontSize = 24 });
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 4"));
    grid.Children.Add(block);
    Grid.SetColumn(block, 0);

    block = new TextBlock();
    block.LineSpacing = LineSpacing;
    block.LineHeight = LineHeight;
    block.Inlines.Add(new Run("Col 1"));
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 2"));
    grid.Children.Add(block);
    Grid.SetColumn(block, 1);

    block = new TextBlock();
    block.LineSpacing = LineSpacing;
    block.LineHeight = LineHeight;
    block.Inlines.Add(new Run("Col 1"));
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 2"));
    block.Inlines.Add(new Run("\n"));
    block.Inlines.Add(new Run("Line 3"));
    grid.Children.Add(block);
    Grid.SetColumn(block, 2);

    return grid;
}

Expected behavior

LineSpacing behaves sames as LineHeight with regard vertical alignment

Avalonia version

11.1.3

OS

Linux

Additional context

No response

kuiperzone commented 1 month ago

On second thoughts, I wonder if the correct behaviour is that LineSpacing should refer to line-spacing BETWEEN LINES. In other words, it should indeed align to the Top, but should should have zero spacing at the bottom line.

See the screenshot which shows a test output of mine. The LineSpacing is 1.2 (16 1.2 px), except for one item which is 2.0 (16 2.0 px). You can see that it bottom pads everything, which I don't think is best.

Unsaved Image 2

Gillibald commented 1 month ago

So you think we should add the spacing to the top instead of the bottom?

kuiperzone commented 1 month ago

No, only between lines, so the Top and bottom would be 0. Think it appropriate to define what is meant by LineSpacing and the difference between it and the behaviour of LineHeight. It might be worth seeing what CSS does.

kuiperzone commented 1 month ago

It looks like there is only a CSS "line-height", which you already appear to handle in the same way CSS does as per Ref https://github.com/AvaloniaUI/Avalonia/issues/13873

So I guess you are free to do whatever you wish with LineSpacing, including leaving it as it is. However, if you agree, I would suggest that it refers to the space between lines.

kuiperzone commented 1 month ago

PS. I noted there doesn't appear to be a LineSpacing in WPF. I quite like LineSpacing because it should handle text with different font-sizes well, whereas LineHeight does not.

Gillibald commented 1 month ago

Currently, we add extra space to the bottom of a text line. We can do the opposite but must leave out the first line. This is doable.

kuiperzone commented 1 month ago

Thank you for your replies.

I realise now that this issue needs a little thought. Your LineHeight property is analogous to the CSS line-height, except that it handles only pixels. I think LineSpacing is actually quite useful, but it wasn't immediately clear what this is and how it differs to LineHeight. I guess I should leave it is an open question as to what it should do in terms of top-bottom spacing, but don't think it should pad just the bottom line as does currently. Either it should behave like LineHeight, or pad only between lines. Are there any use cases which would prefer one above the other? Either would be acceptable, on reflection.