Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
TextBlock.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Diagnostics;
5 using System.Text;
6 
7 using SiliconStudio.Core;
8 using SiliconStudio.Core.Mathematics;
9 using SiliconStudio.Paradox.Graphics;
11 
12 namespace SiliconStudio.Paradox.UI.Controls
13 {
14  /// <summary>
15  /// Provides a lightweight control for displaying small amounts of text.
16  /// </summary>
17  [DebuggerDisplay("TextBlock - Name={Name}")]
18  public class TextBlock : UIElement
19  {
20  /// <summary>
21  /// The key to the Font dependency property.
22  /// </summary>
23  public readonly static PropertyKey<SpriteFont> FontPropertyKey = new PropertyKey<SpriteFont>("FontKey", typeof(TextBlock), DefaultValueMetadata.Static<SpriteFont>(null), ObjectInvalidationMetadata.New<SpriteFont>(InvalidateFont));
24 
25  /// <summary>
26  /// The key to the TextColor dependency property.
27  /// </summary>
28  public readonly static PropertyKey<Color> TextColorPropertyKey = new PropertyKey<Color>("TextColorKey", typeof(TextBlock), DefaultValueMetadata.Static(Color.FromAbgr(0xF0F0F0FF)));
29 
30  private static void InvalidateFont(object propertyOwner, PropertyKey propertyKey, object propertyOldValue)
31  {
32  var element = (TextBlock)propertyOwner;
33  element.InvalidateMeasure();
34  }
35 
36  private string text;
37 
38  private bool wrapText;
39 
40  private string wrappedText;
41 
42  private float? textSize;
43 
44  private bool synchronousCharacterGeneration;
45 
46  /// <summary>
47  /// Create a new instance of <see cref="TextBlock"/>.
48  /// </summary>
49  public TextBlock()
50  {
51  SnapText = true;
52  }
53 
54  /// <summary>
55  /// Method triggered when the <see cref="Text"/> changes.
56  /// Can be overridden in inherited class to changed the default behavior.
57  /// </summary>
58  protected virtual void OnTextChanged()
59  {
60  InvalidateMeasure();
61  }
62 
63  /// <summary>
64  /// Returns the text to display during the draw call.
65  /// </summary>
66  public virtual string TextToDisplay
67  {
68  get { return WrapText? wrappedText: Text; }
69  }
70 
71  /// <summary>
72  /// Gets or sets the font of the text block
73  /// </summary>
74  public SpriteFont Font
75  {
76  get { return DependencyProperties.Get(FontPropertyKey); }
77  set { DependencyProperties.Set(FontPropertyKey, value); }
78  }
79 
80  /// <summary>
81  /// Gets or sets the text of the text block
82  /// </summary>
83  public string Text
84  {
85  get { return text; }
86  set
87  {
88  text = value;
89  OnTextChanged();
90  }
91  }
92 
93  /// <summary>
94  /// Gets or sets the text of the text block
95  /// </summary>
96  public Color TextColor
97  {
98  get { return DependencyProperties.Get(TextColorPropertyKey); }
99  set { DependencyProperties.Set(TextColorPropertyKey, value); }
100  }
101 
102  /// <summary>
103  /// Gets or sets the size of the text in virtual pixels unit
104  /// </summary>
105  public float TextSize
106  {
107  get
108  {
109  if (textSize.HasValue)
110  return textSize.Value;
111 
112  if (Font != null)
113  return Font.Size;
114 
115  return 0;
116  }
117  set
118  {
119  textSize = Math.Max(0, Math.Min(float.MaxValue, value));
120 
121  InvalidateMeasure();
122  }
123  }
124 
125  /// <summary>
126  /// Gets or sets the value indicating if the <see cref="Text"/> of the <see cref="TextBlock"/>
127  /// should automatically return to the beginning of the line when it is too big for the line width.
128  /// </summary>
129  public bool WrapText
130  {
131  get { return wrapText; }
132  set
133  {
134  if(wrapText == value)
135  return;
136 
137  wrapText = value;
138 
139  InvalidateMeasure();
140  }
141  }
142 
143  /// <summary>
144  /// Gets or sets the value indicating if the text block should generate <see cref="DynamicSpriteFont"/> characters synchronously or asynchronously.
145  /// </summary>
146  /// <remarks>If synchronous generation is activated, the game will be block until all the characters have finished to be generate.
147  /// If asynchronous generation is activated, some characters can appears with one or two frames of delay.</remarks>
148  public bool SynchronousCharacterGeneration
149  {
150  get { return synchronousCharacterGeneration; }
151  set
152  {
153  if(synchronousCharacterGeneration == value)
154  return;
155 
156  synchronousCharacterGeneration = value;
157 
158  if (IsMeasureValid && synchronousCharacterGeneration)
159  CalculateTextSize();
160  }
161  }
162 
163  /// <summary>
164  /// Gets or sets the alignment of the text to display.
165  /// </summary>
166  public TextAlignment TextAlignment { get; set; }
167 
168  /// <summary>
169  /// Gets or sets the value indicating if the <see cref="Text"/> of the <see cref="TextBlock"/> must be aligned to the closest screen pixel.
170  /// </summary>
171  public bool SnapText { get; set; }
172 
173  /// <summary>
174  /// Calculate and returns the size of the <see cref="Text"/> in virtual pixels size.
175  /// </summary>
176  /// <returns>The size of the Text in virtual pixels.</returns>
178  {
179  return CalculateTextSize(TextToDisplay);
180  }
181 
182  /// <summary>
183  /// Calculate and returns the size of the provided <paramref name="textToMeasure"/>"/> in virtual pixels size.
184  /// </summary>
185  /// <param name="textToMeasure">The text to measure</param>
186  /// <returns>The size of the text in virtual pixels</returns>
187  protected Vector2 CalculateTextSize(string textToMeasure)
188  {
189  if (textToMeasure == null)
190  return Vector2.Zero;
191 
192  return CalculateTextSize(new SpriteFont.StringProxy(textToMeasure));
193  }
194 
195  private Vector2 CalculateTextSize(StringBuilder textToMeasure)
196  {
197  return CalculateTextSize(new SpriteFont.StringProxy(textToMeasure));
198  }
199 
200  private Vector2 CalculateTextSize(SpriteFont.StringProxy textToMeasure)
201  {
202  if (Font == null)
203  return Vector2.Zero;
204 
205  var sizeRatio = RealSizeVirtualResolutionRatio;
206  var measureFontSize = TextSize * sizeRatio;
207  var realSize = Font.MeasureString(ref textToMeasure, ref measureFontSize);
208 
209  // force pre-generation if synchronous generation is required
210  if(SynchronousCharacterGeneration)
211  Font.PreGenerateGlyphs(ref textToMeasure, ref measureFontSize);
212 
213  if (Font.IsDynamic)
214  {
215  // rescale the real size to the virtual size
216  realSize.X /= sizeRatio.X;
217  realSize.Y /= sizeRatio.Y;
218  }
219 
220  return realSize;
221  }
222 
223  protected override Vector3 MeasureOverride(Vector3 availableSizeWithoutMargins)
224  {
225  if (WrapText)
226  UpdateWrappedText(availableSizeWithoutMargins);
227 
228  return new Vector3(CalculateTextSize(), 0);
229  }
230 
231  protected override Vector3 ArrangeOverride(Vector3 finalSizeWithoutMargins)
232  {
233  if (WrapText)
234  UpdateWrappedText(finalSizeWithoutMargins);
235 
236  return base.ArrangeOverride(finalSizeWithoutMargins);
237  }
238 
239  private void UpdateWrappedText(Vector3 availableSpace)
240  {
241  var availableWidth = availableSpace.X;
242  var currentLine = new StringBuilder(text.Length);
243  var currentText = new StringBuilder(2 * text.Length);
244 
245  var indexOfNewLine = 0;
246  while (true)
247  {
248  float lineCurrentSize;
249  var indexNextCharacter = 0;
250  var indexOfLastSpace = -1;
251 
252  while (true)
253  {
254  lineCurrentSize = CalculateTextSize(currentLine).X;
255 
256  if (lineCurrentSize > availableWidth || indexOfNewLine + indexNextCharacter >= text.Length)
257  break;
258 
259  var currentCharacter = text[indexOfNewLine + indexNextCharacter];
260 
261  if (currentCharacter == '\n')
262  {
263  indexOfNewLine += indexNextCharacter + 1;
264  goto AppendLine;
265  }
266 
267  currentLine.Append(currentCharacter);
268 
269  if (char.IsWhiteSpace(currentCharacter))
270  indexOfLastSpace = indexNextCharacter;
271 
272  ++indexNextCharacter;
273 
274  }
275 
276  if (lineCurrentSize <= availableWidth) // we reached the end of the text.
277  {
278  // append the final part of the text and quit the main loop
279  currentText.Append(currentLine);
280  break;
281  }
282 
283  // we reached the end of the line.
284  if (indexOfLastSpace < 0) // no space in the line
285  {
286  // remove last extra character
287  currentLine.Remove(currentLine.Length - 1, 1);
288  indexOfNewLine += indexNextCharacter - 1;
289  }
290  else // at least one white space in the line
291  {
292  // remove all extra characters until last space (included)
293  if(indexNextCharacter > indexOfLastSpace)
294  currentLine.Remove(indexOfLastSpace, indexNextCharacter - indexOfLastSpace);
295  indexOfNewLine += indexOfLastSpace + 1;
296  }
297 
298  AppendLine:
299 
300  // add the next line to the current text
301  currentLine.Append('\n');
302  currentText.Append(currentLine);
303 
304  // reset current line
305  currentLine.Clear();
306  }
307 
308  wrappedText = currentText.ToString();
309  }
310  }
311 }
Provides a base class for all the User Interface elements in Paradox applications.
Definition: UIElement.cs:21
Represents a two dimensional mathematical vector.
Definition: Vector2.cs:42
TextAlignment
Specify the available text alignment when rendering text.
Definition: TextAlignment.cs:8
virtual void OnTextChanged()
Method triggered when the Text changes. Can be overridden in inherited class to changed the default b...
Definition: TextBlock.cs:58
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
SharpDX.DirectWrite.Font Font
override Vector3 ArrangeOverride(Vector3 finalSizeWithoutMargins)
When overridden in a derived class, positions possible child elements and determines a size for a UIE...
Definition: TextBlock.cs:231
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Definition: SpriteFont.cs:26
Represents a 32-bit color (4 bytes) in the form of RGBA (in byte order: R, G, B, A).
Definition: Color.cs:16
Vector2 CalculateTextSize(string textToMeasure)
Calculate and returns the size of the provided textToMeasure "/> in virtual pixels size...
Definition: TextBlock.cs:187
Vector2 CalculateTextSize()
Calculate and returns the size of the Text in virtual pixels size.
Definition: TextBlock.cs:177
SiliconStudio.Core.Mathematics.Vector3 Vector3
Provides a lightweight control for displaying small amounts of text.
Definition: TextBlock.cs:18
override Vector3 MeasureOverride(Vector3 availableSizeWithoutMargins)
When overridden in a derived class, measures the size in layout required for possible child elements ...
Definition: TextBlock.cs:223
A class that represents a tag propety.
Definition: PropertyKey.cs:17
TextBlock()
Create a new instance of TextBlock.
Definition: TextBlock.cs:49