Browse Source

Started refactoring of FormattedText.

pull/10/head
Steven Kirk 12 years ago
parent
commit
20a944013e
  1. 45
      Perspex.Controls/TextBlock.cs
  2. 1
      Perspex.Controls/TextBox.cs
  3. 67
      Perspex.Controls/TextBoxView.cs
  4. 55
      Perspex.SceneGraph/Media/FormattedText.cs
  5. 15
      Perspex.SceneGraph/Media/TextHitTestResult.cs
  6. 2
      Perspex.SceneGraph/Perspex.SceneGraph.csproj
  7. 29
      Perspex.SceneGraph/Platform/IFormattedTextImpl.cs
  8. 2
      Perspex.SceneGraph/Platform/ITextService.cs
  9. 2
      Windows/Perspex.Direct2D1/Direct2D1Platform.cs
  10. 182
      Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs
  11. 2
      Windows/Perspex.Direct2D1/Media/TextService.cs
  12. 3
      Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

45
Perspex.Controls/TextBlock.cs

@ -25,9 +25,27 @@ namespace Perspex.Controls
public static readonly PerspexProperty<string> TextProperty =
PerspexProperty.Register<TextBlock, string>("Text");
static TextBlock()
private FormattedText formattedText = new FormattedText();
public TextBlock()
{
Control.AffectsMeasure(TextProperty);
this.GetObservable(TextProperty).Subscribe(x =>
{
this.formattedText.Text = x;
this.InvalidateMeasure();
});
this.GetObservable(FontSizeProperty).Subscribe(x =>
{
this.formattedText.FontSize = x;
this.InvalidateMeasure();
});
this.GetObservable(FontStyleProperty).Subscribe(x =>
{
this.formattedText.FontStyle = x;
this.InvalidateMeasure();
});
}
public string Text
@ -48,20 +66,6 @@ namespace Perspex.Controls
set { this.SetValue(FontStyleProperty, value); }
}
private FormattedText FormattedText
{
get
{
return new FormattedText
{
FontFamilyName = "Segoe UI",
FontSize = this.FontSize,
FontStyle = this.FontStyle,
Text = this.Text,
};
}
}
public override void Render(IDrawingContext context)
{
Brush background = this.Background;
@ -71,15 +75,18 @@ namespace Perspex.Controls
context.FillRectange(background, new Rect(this.ActualSize));
}
context.DrawText(this.Foreground, new Rect(this.ActualSize), this.FormattedText);
context.DrawText(
this.Foreground,
new Rect(this.ActualSize),
this.formattedText);
}
protected override Size MeasureOverride(Size availableSize)
{
if (!string.IsNullOrEmpty(this.Text))
{
ITextService textService = Locator.Current.GetService<ITextService>();
return textService.Measure(this.FormattedText, availableSize);
this.formattedText.Constraint = availableSize;
return this.formattedText.Measure();
}
return new Size();

1
Perspex.Controls/TextBox.cs

@ -95,7 +95,6 @@ namespace Perspex.Controls
}
textContainer.Content = this.textBoxView = new TextBoxView(this);
this.GetObservable(TextProperty).Subscribe(_ => this.textBoxView.InvalidateText());
}
private void OnKeyDown(object sender, KeyEventArgs e)

67
Perspex.Controls/TextBoxView.cs

@ -24,6 +24,29 @@ namespace Perspex.Controls
public TextBoxView(TextBox parent)
{
this.FormattedText = new FormattedText();
// TODO: Implement TextBlock.FontFamilyName.
this.FormattedText.FontFamilyName = "Segoe UI";
parent.GetObservable(TextBox.TextProperty).Subscribe(x =>
{
this.FormattedText.Text = x;
this.InvalidateMeasure();
});
this.GetObservable(TextBlock.FontSizeProperty).Subscribe(x =>
{
this.FormattedText.FontSize = x;
this.InvalidateMeasure();
});
this.GetObservable(TextBlock.FontStyleProperty).Subscribe(x =>
{
this.FormattedText.FontStyle = x;
this.InvalidateMeasure();
});
this.caretTimer = new DispatcherTimer();
this.caretTimer.Interval = TimeSpan.FromMilliseconds(500);
this.caretTimer.Tick += this.CaretTimerTick;
@ -32,15 +55,8 @@ namespace Perspex.Controls
public FormattedText FormattedText
{
get
{
if (this.formattedText == null)
{
this.formattedText = this.CreateFormattedText();
}
return this.formattedText;
}
get;
private set;
}
public new void GotFocus()
@ -55,12 +71,6 @@ namespace Perspex.Controls
this.InvalidateVisual();
}
public void InvalidateText()
{
this.formattedText = null;
this.InvalidateMeasure();
}
public override void Render(IDrawingContext context)
{
Rect rect = new Rect(this.ActualSize);
@ -69,20 +79,12 @@ namespace Perspex.Controls
if (this.parent.IsFocused)
{
ITextService textService = Locator.Current.GetService<ITextService>();
Point caretPos = textService.GetCaretPosition(
this.formattedText,
this.parent.CaretIndex,
this.ActualSize);
double[] lineHeights = textService.GetLineHeights(this.formattedText, this.ActualSize);
var charPos = this.FormattedText.HitTestTextPosition(this.parent.CaretIndex);
Brush caretBrush = Brushes.Black;
if (this.caretBlink)
{
context.DrawLine(
new Pen(caretBrush, 1),
caretPos,
new Point(caretPos.X, caretPos.Y + lineHeights[0]));
context.DrawLine(new Pen(caretBrush, 1), charPos.TopLeft, charPos.BottomLeft);
}
}
}
@ -99,24 +101,13 @@ namespace Perspex.Controls
{
if (!string.IsNullOrEmpty(this.parent.Text))
{
ITextService textService = Locator.Current.GetService<ITextService>();
return textService.Measure(this.FormattedText, constraint);
this.FormattedText.Constraint = constraint;
return this.FormattedText.Measure();
}
return new Size();
}
private FormattedText CreateFormattedText()
{
return new FormattedText
{
FontFamilyName = "Segoe UI",
FontSize = this.GetValue(TextBlock.FontSizeProperty),
FontStyle = this.GetValue(TextBlock.FontStyleProperty),
Text = this.parent.Text,
};
}
private void CaretTimerTick(object sender, EventArgs e)
{
this.caretBlink = !this.caretBlink;

55
Perspex.SceneGraph/Media/FormattedText.cs

@ -6,6 +6,9 @@
namespace Perspex.Media
{
using Perspex.Platform;
using Splat;
public enum FontStyle
{
Normal,
@ -15,12 +18,56 @@ namespace Perspex.Media
public class FormattedText
{
public string FontFamilyName { get; set; }
private IFormattedTextImpl impl;
public FormattedText()
{
this.impl = Locator.Current.GetService<IFormattedTextImpl>();
}
public Size Constraint
{
get { return this.impl.Constraint; }
set { this.impl.Constraint = value; }
}
public string FontFamilyName
{
get { return this.impl.FontFamilyName; }
set { this.impl.FontFamilyName = value; }
}
public double FontSize
{
get { return this.impl.FontSize; }
set { this.impl.FontSize = value; }
}
public FontStyle FontStyle
{
get { return this.impl.FontStyle; }
set { this.impl.FontStyle = value; }
}
public string Text
{
get { return this.impl.Text; }
set { this.impl.Text = value; }
}
public double FontSize { get; set; }
public TextHitTestResult HitTestPoint(Point point)
{
return this.impl.HitTestPoint(point);
}
public FontStyle FontStyle { get; set; }
public Rect HitTestTextPosition(int index)
{
return this.impl.HitTestTextPosition(index);
}
public string Text { get; set; }
public Size Measure()
{
return this.impl.Measure();
}
}
}

15
Perspex.SceneGraph/Media/TextHitTestResult.cs

@ -0,0 +1,15 @@
// -----------------------------------------------------------------------
// <copyright file="TextHitTestResult.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Media
{
public class TextHitTestResult
{
public int TextPosition { get; set; }
public bool IsTrailing { get; set; }
}
}

2
Perspex.SceneGraph/Perspex.SceneGraph.csproj

@ -62,8 +62,10 @@
<Compile Include="Media\StreamGeometry.cs" />
<Compile Include="Media\StreamGeometryContext.cs" />
<Compile Include="Media\Stretch.cs" />
<Compile Include="Media\TextHitTestResult.cs" />
<Compile Include="Media\Transform.cs" />
<Compile Include="Origin.cs" />
<Compile Include="Platform\IFormattedTextImpl.cs" />
<Compile Include="Platform\IBitmapImpl.cs" />
<Compile Include="Platform\IGeometryImpl.cs" />
<Compile Include="Platform\IPlatformRenderInterface.cs" />

29
Perspex.SceneGraph/Platform/IFormattedTextImpl.cs

@ -0,0 +1,29 @@
// -----------------------------------------------------------------------
// <copyright file="IFormattedTextImpl.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Platform
{
using Perspex.Media;
public interface IFormattedTextImpl
{
Size Constraint { get; set; }
string FontFamilyName { get; set; }
double FontSize { get; set; }
FontStyle FontStyle { get; set; }
string Text { get; set; }
TextHitTestResult HitTestPoint(Point point);
Rect HitTestTextPosition(int index);
Size Measure();
}
}

2
Perspex.SceneGraph/Platform/ITextService.cs

@ -6,8 +6,10 @@
namespace Perspex.Platform
{
using System;
using Perspex.Media;
[Obsolete("Use methods on FormattedText instead.")]
public interface ITextService
{
int GetCaretIndex(FormattedText text, Point point, Size constraint);

2
Windows/Perspex.Direct2D1/Direct2D1Platform.cs

@ -33,10 +33,10 @@ namespace Perspex.Direct2D1
{
var locator = Locator.CurrentMutable;
locator.Register(() => instance, typeof(IPlatformRenderInterface));
locator.Register(() => textService, typeof(ITextService));
locator.Register(() => d2d1Factory, typeof(SharpDX.Direct2D1.Factory));
locator.Register(() => dwfactory, typeof(SharpDX.DirectWrite.Factory));
locator.Register(() => imagingFactory, typeof(SharpDX.WIC.ImagingFactory));
locator.Register(() => new FormattedTextImpl(), typeof(IFormattedTextImpl));
}
public IBitmapImpl CreateBitmap(int width, int height)

182
Windows/Perspex.Direct2D1/Media/FormattedTextImpl.cs

@ -0,0 +1,182 @@
// -----------------------------------------------------------------------
// <copyright file="TextService.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Direct2D1.Media
{
using System;
using Perspex.Media;
using Perspex.Platform;
using Splat;
using DWrite = SharpDX.DirectWrite;
public class FormattedTextImpl : IFormattedTextImpl
{
private string text;
private string fontFamilyName = "Ariel";
private double fontSize = 10;
private FontStyle fontStyle;
private DWrite.Factory factory;
private DWrite.TextLayout layout;
public FormattedTextImpl()
{
this.factory = Locator.Current.GetService<DWrite.Factory>();
}
public Size Constraint
{
get
{
return new Size(this.Layout.MaxWidth, this.Layout.MaxHeight);
}
set
{
this.Layout.MaxWidth = (float)value.Width;
this.Layout.MaxHeight = (float)value.Height;
}
}
public string FontFamilyName
{
get
{
return this.fontFamilyName;
}
set
{
if (this.fontFamilyName != value)
{
this.fontFamilyName = value;
this.DisposeLayout();
}
}
}
public double FontSize
{
get
{
return this.fontSize;
}
set
{
if (this.fontSize != value)
{
this.fontSize = value;
this.DisposeLayout();
}
}
}
public FontStyle FontStyle
{
get
{
return this.fontStyle;
}
set
{
if (this.fontStyle != value)
{
this.fontStyle = value;
this.DisposeLayout();
}
}
}
public string Text
{
get
{
return this.text;
}
set
{
if (this.text != value)
{
this.text = value;
this.DisposeLayout();
}
}
}
public DWrite.TextLayout Layout
{
get
{
if (this.layout == null)
{
this.layout = new DWrite.TextLayout(
this.factory,
this.text ?? string.Empty,
new DWrite.TextFormat(this.factory, this.fontFamilyName, (float)this.fontSize),
float.MaxValue,
float.MaxValue);
}
return this.layout;
}
}
public TextHitTestResult HitTestPoint(Point point)
{
SharpDX.Bool isTrailingHit;
SharpDX.Bool isInside;
DWrite.HitTestMetrics result = layout.HitTestPoint(
(float)point.X,
(float)point.Y,
out isTrailingHit,
out isInside);
return new TextHitTestResult
{
TextPosition = result.TextPosition,
IsTrailing = isTrailingHit,
};
}
public Rect HitTestTextPosition(int index)
{
float x;
float y;
DWrite.HitTestMetrics result = layout.HitTestTextPosition(
index,
false,
out x,
out y);
return new Rect(result.Left, result.Top, result.Width, result.Height);
}
public Size Measure()
{
return new Size(
layout.Metrics.WidthIncludingTrailingWhitespace,
layout.Metrics.Height);
}
private void DisposeLayout()
{
if (this.layout != null)
{
this.layout.Dispose();
this.layout = null;
}
}
}
}

2
Windows/Perspex.Direct2D1/TextService.cs → Windows/Perspex.Direct2D1/Media/TextService.cs

@ -4,7 +4,7 @@
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Direct2D1
namespace Perspex.Direct2D1.Media
{
using System;
using System.Linq;

3
Windows/Perspex.Direct2D1/Perspex.Direct2D1.csproj

@ -73,10 +73,11 @@
<Compile Include="Media\StreamGeometryContextImpl.cs" />
<Compile Include="Media\GeometryImpl.cs" />
<Compile Include="Media\StreamGeometryImpl.cs" />
<Compile Include="Media\FormattedTextImpl.cs" />
<Compile Include="PrimitiveExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Renderer.cs" />
<Compile Include="TextService.cs" />
<Compile Include="Media\TextService.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />

Loading…
Cancel
Save