Browse Source

Correctly measure TextBlocks.

pull/4/head
Steven Kirk 12 years ago
parent
commit
a467607e57
  1. 63
      Perspex.Direct2D1/TextService.cs
  2. 4
      Perspex/Controls/TextBlock.cs
  3. 3
      Perspex/Controls/TextBox.cs
  4. 10
      Perspex/Controls/TextBoxView.cs
  5. 15
      Perspex/Media/FormattedText.cs
  6. 8
      Perspex/Platform/ITextService.cs

63
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);
}
}
}
}

4
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();

3
Perspex/Controls/TextBox.cs

@ -126,7 +126,8 @@ namespace Perspex.Controls
IPlatformRenderInterface platform = Locator.Current.GetService<IPlatformRenderInterface>();
this.CaretIndex = platform.TextService.GetCaretIndex(
this.textBoxView.FormattedText,
e.GetPosition(this.textBoxView));
e.GetPosition(this.textBoxView),
this.ActualSize);
}
}
}

10
Perspex/Controls/TextBoxView.cs

@ -79,7 +79,11 @@ namespace Perspex.Controls
if (this.parent.IsFocused)
{
IPlatformRenderInterface platform = Locator.Current.GetService<IPlatformRenderInterface>();
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()

15
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<IPlatformRenderInterface>();
return factory.TextService.Measure(this);
}
IPlatformRenderInterface factory = Locator.Current.GetService<IPlatformRenderInterface>();
return factory.TextService.GetLineHeights(this, constraint);
}
public Size Measure(Size constraint)
{
IPlatformRenderInterface factory = Locator.Current.GetService<IPlatformRenderInterface>();
return factory.TextService.Measure(this, constraint);
}
}
}

8
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);
}
}

Loading…
Cancel
Save