2014-12-17 21:38:28 +01:00
|
|
|
|
using System.Windows;
|
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
|
|
|
|
|
|
|
namespace WpfApplication
|
|
|
|
|
|
{
|
|
|
|
|
|
public class OutlinedText : FrameworkElement
|
|
|
|
|
|
{
|
|
|
|
|
|
private GlyphRun glyphRun;
|
|
|
|
|
|
private Geometry outline;
|
|
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty TextProperty = TextBlock.TextProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty FontSizeProperty = TextBlock.FontSizeProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty FontFamilyProperty = TextBlock.FontFamilyProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty FontStyleProperty = TextBlock.FontStyleProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty FontWeightProperty = TextBlock.FontWeightProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty FontStretchProperty = TextBlock.FontStretchProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty ForegroundProperty = TextBlock.ForegroundProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata((o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty BackgroundProperty = TextBlock.BackgroundProperty.AddOwner(
|
2017-08-08 21:24:51 +02:00
|
|
|
|
typeof(OutlinedText), new FrameworkPropertyMetadata(Brushes.White, (o, e) => ((OutlinedText)o).glyphRun = null) { AffectsMeasure = true });
|
2014-12-17 21:38:28 +01:00
|
|
|
|
|
|
|
|
|
|
public static readonly DependencyProperty OutlineThicknessProperty = DependencyProperty.Register(
|
|
|
|
|
|
"OutlineThickness", typeof(double), typeof(OutlinedText),
|
|
|
|
|
|
new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsMeasure, (o, e) => ((OutlinedText)o).glyphRun = null));
|
|
|
|
|
|
|
|
|
|
|
|
public string Text
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (string)GetValue(TextProperty); }
|
|
|
|
|
|
set { SetValue(TextProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public double FontSize
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (double)GetValue(FontSizeProperty); }
|
|
|
|
|
|
set { SetValue(FontSizeProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public FontFamily FontFamily
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (FontFamily)GetValue(FontFamilyProperty); }
|
|
|
|
|
|
set { SetValue(FontFamilyProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public FontStyle FontStyle
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (FontStyle)GetValue(FontStyleProperty); }
|
|
|
|
|
|
set { SetValue(FontStyleProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public FontWeight FontWeight
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (FontWeight)GetValue(FontWeightProperty); }
|
|
|
|
|
|
set { SetValue(FontWeightProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public FontStretch FontStretch
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (FontStretch)GetValue(FontStretchProperty); }
|
|
|
|
|
|
set { SetValue(FontStretchProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Brush Foreground
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (Brush)GetValue(ForegroundProperty); }
|
|
|
|
|
|
set { SetValue(ForegroundProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Brush Background
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (Brush)GetValue(BackgroundProperty); }
|
|
|
|
|
|
set { SetValue(BackgroundProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public double OutlineThickness
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return (double)GetValue(OutlineThicknessProperty); }
|
|
|
|
|
|
set { SetValue(OutlineThicknessProperty, value); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
|
|
|
|
{
|
|
|
|
|
|
return CheckGlyphRun() ? outline.Bounds.Size : new Size();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override void OnRender(DrawingContext drawingContext)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (CheckGlyphRun())
|
|
|
|
|
|
{
|
|
|
|
|
|
var location = outline.Bounds.Location;
|
|
|
|
|
|
drawingContext.PushTransform(new TranslateTransform(-location.X, -location.Y));
|
|
|
|
|
|
drawingContext.DrawGeometry(Background, null, outline);
|
|
|
|
|
|
drawingContext.DrawGlyphRun(Foreground, glyphRun);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool CheckGlyphRun()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (glyphRun == null)
|
|
|
|
|
|
{
|
2015-03-15 10:11:19 +01:00
|
|
|
|
if (string.IsNullOrEmpty(Text))
|
2014-12-17 21:38:28 +01:00
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
|
|
|
|
|
|
GlyphTypeface glyphTypeface;
|
|
|
|
|
|
|
|
|
|
|
|
if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var glyphIndices = new ushort[Text.Length];
|
|
|
|
|
|
var advanceWidths = new double[Text.Length];
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Text.Length; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[i]];
|
|
|
|
|
|
glyphIndices[i] = glyphIndex;
|
|
|
|
|
|
advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * FontSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
glyphRun = new GlyphRun(glyphTypeface, 0, false, FontSize, glyphIndices, new Point(), advanceWidths, null, null, null, null, null, null);
|
|
|
|
|
|
|
|
|
|
|
|
outline = glyphRun.BuildGeometry().GetWidenedPathGeometry(new Pen(null, OutlineThickness * 2d));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|