From a467607e576e77e704762715e71f51b4038a7c60 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 13 Sep 2014 21:51:42 +0200 Subject: [PATCH] Correctly measure TextBlocks. --- Perspex.Direct2D1/TextService.cs | 63 ++++++++++++++++++++------------ Perspex/Controls/TextBlock.cs | 4 +- Perspex/Controls/TextBox.cs | 3 +- Perspex/Controls/TextBoxView.cs | 10 +++-- Perspex/Media/FormattedText.cs | 15 +++++--- Perspex/Platform/ITextService.cs | 8 ++-- 6 files changed, 64 insertions(+), 39 deletions(-) diff --git a/Perspex.Direct2D1/TextService.cs b/Perspex.Direct2D1/TextService.cs index 948d9efef2..ce6a22075d 100644 --- a/Perspex.Direct2D1/TextService.cs +++ b/Perspex.Direct2D1/TextService.cs @@ -7,6 +7,7 @@ namespace Perspex.Direct2D1 { using System; + using System.Linq; using Perspex.Media; using Perspex.Platform; using SharpDX.DirectWrite; @@ -28,46 +29,60 @@ namespace Perspex.Direct2D1 (float)text.FontSize); } - public TextLayout GetTextLayout(Factory factory, FormattedText text) + public TextLayout GetTextLayout(Factory factory, FormattedText text, Size constraint) { return new TextLayout( factory, text.Text, GetTextFormat(factory, text), - float.MaxValue, - float.MaxValue); + (float)constraint.Width, + (float)constraint.Height); } - public int GetCaretIndex(FormattedText text, Point point) + public int GetCaretIndex(FormattedText text, Point point, Size constraint) { - TextLayout layout = GetTextLayout(this.factory, text); - SharpDX.Bool isTrailingHit; - SharpDX.Bool isInside; + using (TextLayout layout = GetTextLayout(this.factory, text, constraint)) + { + SharpDX.Bool isTrailingHit; + SharpDX.Bool isInside; - HitTestMetrics result = layout.HitTestPoint( - (float)point.X, - (float)point.Y, - out isTrailingHit, - out isInside); + HitTestMetrics result = layout.HitTestPoint( + (float)point.X, + (float)point.Y, + out isTrailingHit, + out isInside); - return result.TextPosition + (isTrailingHit ? 1 : 0); + return result.TextPosition + (isTrailingHit ? 1 : 0); + } } - public Point GetCaretPosition(FormattedText text, int caretIndex) + public Point GetCaretPosition(FormattedText text, int caretIndex, Size constraint) { - TextLayout layout = GetTextLayout(this.factory, text); - float x; - float y; - layout.HitTestTextPosition(caretIndex, false, out x, out y); - return new Point(x, y); + using (TextLayout layout = GetTextLayout(this.factory, text, constraint)) + { + float x; + float y; + layout.HitTestTextPosition(caretIndex, false, out x, out y); + return new Point(x, y); + } } - public Size Measure(FormattedText text) + public double[] GetLineHeights(FormattedText text, Size constraint) { - TextLayout layout = GetTextLayout(this.factory, text); - return new Size( - layout.Metrics.WidthIncludingTrailingWhitespace, - layout.Metrics.Height); + using (TextLayout layout = GetTextLayout(this.factory, text, constraint)) + { + return layout.GetLineMetrics().Select(x => (double)x.Height).ToArray(); + } + } + + public Size Measure(FormattedText text, Size constraint) + { + using (TextLayout layout = GetTextLayout(this.factory, text, constraint)) + { + return new Size( + layout.Metrics.WidthIncludingTrailingWhitespace, + layout.Metrics.Height); + } } } } diff --git a/Perspex/Controls/TextBlock.cs b/Perspex/Controls/TextBlock.cs index e689866472..8d8d275b64 100644 --- a/Perspex/Controls/TextBlock.cs +++ b/Perspex/Controls/TextBlock.cs @@ -18,7 +18,7 @@ namespace Perspex.Controls static TextBlock() { - AffectsRender(TextProperty); + AffectsMeasure(TextProperty); } public string Text @@ -56,7 +56,7 @@ namespace Perspex.Controls { if (!string.IsNullOrEmpty(this.Text)) { - return this.FormattedText.Size; + return this.FormattedText.Measure(availableSize); } return new Size(); diff --git a/Perspex/Controls/TextBox.cs b/Perspex/Controls/TextBox.cs index b550365c95..adf102fdd2 100644 --- a/Perspex/Controls/TextBox.cs +++ b/Perspex/Controls/TextBox.cs @@ -126,7 +126,8 @@ namespace Perspex.Controls IPlatformRenderInterface platform = Locator.Current.GetService(); this.CaretIndex = platform.TextService.GetCaretIndex( this.textBoxView.FormattedText, - e.GetPosition(this.textBoxView)); + e.GetPosition(this.textBoxView), + this.ActualSize); } } } diff --git a/Perspex/Controls/TextBoxView.cs b/Perspex/Controls/TextBoxView.cs index ab09936c7e..d415e49748 100644 --- a/Perspex/Controls/TextBoxView.cs +++ b/Perspex/Controls/TextBoxView.cs @@ -79,7 +79,11 @@ namespace Perspex.Controls if (this.parent.IsFocused) { IPlatformRenderInterface platform = Locator.Current.GetService(); - Point caretPos = platform.TextService.GetCaretPosition(this.formattedText, this.parent.CaretIndex); + Point caretPos = platform.TextService.GetCaretPosition( + this.formattedText, + this.parent.CaretIndex, + this.ActualSize); + double[] lineHeights = platform.TextService.GetLineHeights(this.formattedText, this.ActualSize); Brush caretBrush = Brushes.Black; if (this.caretBlink) @@ -87,14 +91,14 @@ namespace Perspex.Controls context.DrawLine( new Pen(caretBrush, 1), caretPos, - new Point(caretPos.X, caretPos.Y + this.FormattedText.Size.Height)); + new Point(caretPos.X, caretPos.Y + lineHeights[0])); } } } protected override Size MeasureOverride(Size constraint) { - return new Size(this.FormattedText.Size.Width, this.FormattedText.Size.Height); + return this.FormattedText.Measure(constraint); } private FormattedText CreateFormattedText() diff --git a/Perspex/Media/FormattedText.cs b/Perspex/Media/FormattedText.cs index 8092d0a389..129e0f1243 100644 --- a/Perspex/Media/FormattedText.cs +++ b/Perspex/Media/FormattedText.cs @@ -17,13 +17,16 @@ namespace Perspex.Media public string Text { get; set; } - public Size Size + public double[] GetLineHeights(Size constraint) { - get - { - IPlatformRenderInterface factory = Locator.Current.GetService(); - return factory.TextService.Measure(this); - } + IPlatformRenderInterface factory = Locator.Current.GetService(); + return factory.TextService.GetLineHeights(this, constraint); + } + + public Size Measure(Size constraint) + { + IPlatformRenderInterface factory = Locator.Current.GetService(); + return factory.TextService.Measure(this, constraint); } } } diff --git a/Perspex/Platform/ITextService.cs b/Perspex/Platform/ITextService.cs index d9e05ce4c6..d4eadd7b91 100644 --- a/Perspex/Platform/ITextService.cs +++ b/Perspex/Platform/ITextService.cs @@ -10,10 +10,12 @@ namespace Perspex.Platform public interface ITextService { - Size Measure(FormattedText text); + int GetCaretIndex(FormattedText text, Point point, Size constraint); - int GetCaretIndex(FormattedText text, Point point); + Point GetCaretPosition(FormattedText text, int caretIndex, Size constraint); - Point GetCaretPosition(FormattedText text, int caretIndex); + double[] GetLineHeights(FormattedText text, Size constraint); + + Size Measure(FormattedText text, Size constraint); } }