Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
EditText.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.Games;
10 using SiliconStudio.Paradox.Graphics;
12 using SiliconStudio.Paradox.UI.Events;
13 
14 namespace SiliconStudio.Paradox.UI.Controls
15 {
16  /// <summary>
17  /// Represent an edit text where the user can enter text.
18  /// </summary>
19  [DebuggerDisplay("EditText - Name={Name}")]
20  public partial class EditText : Control
21  {
22  private float? textSize;
23 
24  private InputTypeFlags inputType;
25 
26  private const char PasswordHidingCharacter = '*';
27 
28  private string text = "";
29  private string textToDisplay = "";
30 
31  private int selectionStart;
32  private int selectionStop;
33  private bool caretAtStart;
34 
35  private float caretWith;
36  private float caretFrequency;
37  private bool caretHided;
38  private float accumulatedTime;
39 
40  private bool synchronousCharacterGeneration;
41 
42  private readonly StringBuilder builder = new StringBuilder();
43 
44  [Flags]
45  public enum InputTypeFlags
46  {
47  /// <summary>
48  /// No specific input type for the <see cref="EditText"/>
49  /// </summary>
50  None,
51 
52  /// <summary>
53  /// An password input type. Password text is hided while editing.
54  /// </summary>
55  Password,
56  }
57 
58  #region Dependency Properties
59 
60  /// <summary>
61  /// The key to the IsReadOnly dependency property.
62  /// </summary>
63  public readonly static PropertyKey<bool> IsReadOnlyPropertyKey = new PropertyKey<bool>("IsReadOnlyKey", typeof(EditText), DefaultValueMetadata.Static(false), ObjectInvalidationMetadata.New<bool>(InvalidateIsReadOnly));
64 
65  /// <summary>
66  /// The key to the Font dependency property.
67  /// </summary>
68  public readonly static PropertyKey<SpriteFont> FontPropertyKey = new PropertyKey<SpriteFont>("FontKey", typeof(EditText), DefaultValueMetadata.Static<SpriteFont>(null), ObjectInvalidationMetadata.New<SpriteFont>(InvalidateFont));
69 
70  /// <summary>
71  /// The key to the TextColor dependency property.
72  /// </summary>
73  public readonly static PropertyKey<Color> TextColorPropertyKey = new PropertyKey<Color>("TextColorKey", typeof(EditText), DefaultValueMetadata.Static(Color.FromAbgr(0xF0F0F0FF)));
74 
75  /// <summary>
76  /// The key to the SelectionColor dependency property.
77  /// </summary>
78  public readonly static PropertyKey<Color> SelectionColorPropertyKey = new PropertyKey<Color>("SelectionColorKey", typeof(EditText), DefaultValueMetadata.Static(Color.FromAbgr(0x623574FF)));
79 
80  /// <summary>
81  /// The key to the SelectionColor dependency property.
82  /// </summary>
83  public readonly static PropertyKey<Color> CaretColorPropertyKey = new PropertyKey<Color>("CaretColorKey", typeof(EditText), DefaultValueMetadata.Static(Color.FromAbgr(0xF0F0F0FF)));
84 
85  /// <summary>
86  /// The key to the MaxLength dependency property.
87  /// </summary>
88  public readonly static PropertyKey<int> MaxLengthPropertyKey = new PropertyKey<int>("MaxLengthKey", typeof(EditText),
89  DefaultValueMetadata.Static(int.MaxValue), ValidateValueMetadata.New<int>(CheckStrictlyPositive), ObjectInvalidationMetadata.New<int>(InvalidateMaxLength));
90 
91  /// <summary>
92  /// The key to the MaxLength dependency property.
93  /// </summary>
94  public readonly static PropertyKey<int> MaxLinesPropertyKey = new PropertyKey<int>("MaxLinesKey", typeof(EditText),
95  DefaultValueMetadata.Static(int.MaxValue), ValidateValueMetadata.New<int>(CheckStrictlyPositive), ObjectInvalidationMetadata.New<int>(InvalidateMaxLines));
96 
97  /// <summary>
98  /// The key to the MaxLength dependency property.
99  /// </summary>
100  public readonly static PropertyKey<int> MinLinesPropertyKey = new PropertyKey<int>("MinLinesKey", typeof(EditText),
101  DefaultValueMetadata.Static(1), ValidateValueMetadata.New<int>(CheckStrictlyPositive), ObjectInvalidationMetadata.New<int>(InvalidateMinLines));
102 
103  /// <summary>
104  /// The key to the ActiveImage dependency property.
105  /// </summary>
106  public static readonly PropertyKey<UIImage> ActiveImagePropertyKey = new PropertyKey<UIImage>("EditActiveImageKey", typeof(EditText), DefaultValueMetadata.Static<UIImage>(null));
107 
108  /// <summary>
109  /// The key to the InactiveImage dependency property.
110  /// </summary>
111  public static readonly PropertyKey<UIImage> InactiveImagePropertyKey = new PropertyKey<UIImage>("EditInactiveImageKey", typeof(EditText), DefaultValueMetadata.Static<UIImage>(null));
112 
113  /// <summary>
114  /// The key to the MouseOverImage dependency property.
115  /// </summary>
116  public static readonly PropertyKey<UIImage> MouseOverImagePropertyKey = new PropertyKey<UIImage>("MouseOverImageModeKey", typeof(EditText), DefaultValueMetadata.Static<UIImage>(null));
117 
118  private static void CheckStrictlyPositive(ref int value)
119  {
120  if (value < 1)
121  throw new ArgumentOutOfRangeException("value");
122  }
123 
124  private static void InvalidateFont(object propertyOwner, PropertyKey<SpriteFont> propertyKey, SpriteFont propertyOldValue)
125  {
126  var element = (UIElement)propertyOwner;
127  element.InvalidateMeasure();
128  }
129 
130 
131  private static void InvalidateIsReadOnly(object propertyOwner, PropertyKey<bool> propertykey, bool propertyoldvalue)
132  {
133  var editText = (EditText)propertyOwner;
134 
135  editText.OnIsReadOnlyChanged();
136  }
137 
138  private static void InvalidateMaxLength(object propertyOwner, PropertyKey<int> propertyKey, int propertyOldValue)
139  {
140  var editText = (EditText)propertyOwner;
141 
142  editText.OnMaxLengthChanged();
143  }
144 
145  private static void InvalidateMaxLines(object propertyOwner, PropertyKey<int> propertyKey, int propertyOldValue)
146  {
147  var editText = (EditText)propertyOwner;
148 
149  editText.OnMaxLinesChanged();
150  }
151 
152  private static void InvalidateMinLines(object propertyOwner, PropertyKey<int> propertyKey, int propertyOldValue)
153  {
154  var editText = (EditText)propertyOwner;
155 
156  editText.OnMinLinesChanged();
157  }
158 
159  /// <summary>
160  /// Function triggered when the value of <see cref="IsReadOnly"/> changed.
161  /// </summary>
162  protected virtual void OnIsReadOnlyChanged()
163  {
164  IsSelectionActive = false;
165  }
166 
167  /// <summary>
168  /// Function triggered when the value of <see cref="MaxLength"/> changed.
169  /// </summary>
170  protected virtual void OnMaxLengthChanged()
171  {
172  var previousCaret = CaretPosition;
173  var previousSelectionStart = SelectionStart;
174  var previousSelectionLength = SelectionLength;
175 
176  Text = text;
177 
178  CaretPosition = previousCaret;
179  Select(previousSelectionStart, previousSelectionLength);
180  }
181 
182  /// <summary>
183  /// Function triggered when the value of <see cref="MaxLines"/> changed.
184  /// </summary>
185  protected virtual void OnMaxLinesChanged()
186  {
187  OnMaxLinesChangedImpl();
188  InvalidateMeasure();
189  }
190 
191  /// <summary>
192  /// Function triggered when the value of <see cref="MinLines"/> changed.
193  /// </summary>
194  protected virtual void OnMinLinesChanged()
195  {
196  OnMinLinesChangedImpl();
197  InvalidateMeasure();
198  }
199 
200  #endregion
201 
202  static EditText()
203  {
204  EventManager.RegisterClassHandler(typeof(EditText), TextChangedEvent, TextChangedClassHandler);
205 
206  InitializeStaticImpl();
207  }
208 
209  /// <summary>
210  /// Create a new instance of <see cref="EditText"/>.
211  /// </summary>
212  /// <param name="services">The game services</param>
213  /// <exception cref="ArgumentNullException"><paramref name="services"/> is null</exception>
214  /// <exception cref="ArgumentException"><paramref name="services"/> does not contain an <see cref="IGame"/> service.</exception>
215  public EditText(IServiceRegistry services)
216  {
217  if (services == null)
218  throw new ArgumentNullException("services");
219 
220  game = services.GetService(typeof(IGame)) as GameBase;
221  if(game == null)
222  throw new ArgumentException("Provided services need to contain a provider for the IGame interface.");
223 
224  InitializeImpl();
225 
226  SnapText = true;
227  CanBeHitByUser = true;
228  IsSelectionActive = false;
229  Padding = new Thickness(8,4,0,8,8,0);
230  DrawLayerNumber += 4; // ( 1: image, 2: selection, 3: Text, 4:Cursor)
231  CaretWidth = 1f;
232  CaretFrequency = 1f;
233  }
234 
235  private bool isSelectionActive;
236 
237  // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
238  private readonly GameBase game;
239 
240  private Func<char, bool> characterFilterPredicate;
241 
242  /// <summary>
243  /// Gets a value that indicates whether the text box has focus and selected text.
244  /// </summary>
245  public bool IsSelectionActive
246  {
247  get { return isSelectionActive; }
248  set
249  {
250  if (isSelectionActive == value)
251  return;
252 
253  if(IsReadOnly && value) // prevent selection when the Edit is read only
254  return;
255 
256  isSelectionActive = value;
257 
258  if (IsSelectionActive)
259  {
260  var previousEditText = FocusedElement as EditText;
261  if (previousEditText != null)
262  previousEditText.IsSelectionActive = false;
263 
264  FocusedElement = this;
265  ActivateEditTextImpl();
266  }
267  else
268  {
269  DeactivateEditTextImpl();
270  }
271  }
272  }
273 
274  public override bool IsEnabled
275  {
276  set
277  {
278  if (!value && IsSelectionActive)
279  IsSelectionActive = false;
280 
281  base.IsEnabled = value;
282  }
283  }
284 
285  /// <summary>
286  /// Gets or sets the value indicating if the text block should generate <see cref="DynamicSpriteFont"/> characters synchronously or asynchronously.
287  /// </summary>
288  /// <remarks>If synchronous generation is activated, the game will be block until all the characters have finished to be generate.
289  /// If asynchronous generation is activated, some characters can appears with one or two frames of delay.</remarks>
290  public bool SynchronousCharacterGeneration
291  {
292  get { return synchronousCharacterGeneration; }
293  set
294  {
295  if (synchronousCharacterGeneration == value)
296  return;
297 
298  synchronousCharacterGeneration = value;
299 
300  if (IsMeasureValid && synchronousCharacterGeneration)
301  CalculateTextSize();
302  }
303  }
304 
305  /// <summary>
306  /// Gets a value indicating if the text should be hided when displayed.
307  /// </summary>
308  protected bool ShouldHideText { get { return (inputType & InputTypeFlags.Password) != 0; } }
309 
310  /// <summary>
311  /// Gets or sets the padding inside a control.
312  /// </summary>
313  public bool IsReadOnly
314  {
315  get { return DependencyProperties.Get(IsReadOnlyPropertyKey); }
316  set { DependencyProperties.Set(IsReadOnlyPropertyKey, value); }
317  }
318 
319  /// <summary>
320  /// Gets or sets the font of the text block
321  /// </summary>
322  public SpriteFont Font
323  {
324  get { return DependencyProperties.Get(FontPropertyKey); }
325  set { DependencyProperties.Set(FontPropertyKey, value); }
326  }
327 
328  /// <summary>
329  /// Gets or sets the color of the text
330  /// </summary>
331  public Color TextColor
332  {
333  get { return DependencyProperties.Get(TextColorPropertyKey); }
334  set { DependencyProperties.Set(TextColorPropertyKey, value); }
335  }
336 
337  /// <summary>
338  /// Gets or sets the color of the selection
339  /// </summary>
340  public Color SelectionColor
341  {
342  get { return DependencyProperties.Get(SelectionColorPropertyKey); }
343  set { DependencyProperties.Set(SelectionColorPropertyKey, value); }
344  }
345 
346  /// <summary>
347  /// Gets or sets the color of the selection
348  /// </summary>
349  public Color CaretColor
350  {
351  get { return DependencyProperties.Get(CaretColorPropertyKey); }
352  set { DependencyProperties.Set(CaretColorPropertyKey, value); }
353  }
354 
355  /// <summary>
356  /// Gets or sets the maximum number of characters that can be manually entered into the text box.
357  /// </summary>
358  /// <exception cref="ArgumentOutOfRangeException">The provided value must be strictly positive</exception>
359  public int MaxLength
360  {
361  get { return DependencyProperties.Get(MaxLengthPropertyKey); }
362  set { DependencyProperties.Set(MaxLengthPropertyKey, value); }
363  }
364 
365  /// <summary>
366  /// Gets or sets the maximum number of visible lines.
367  /// </summary>
368  /// <exception cref="ArgumentOutOfRangeException">The provided value must be strictly positive</exception>
369  public int MaxLines
370  {
371  get { return DependencyProperties.Get(MaxLinesPropertyKey); }
372  set { DependencyProperties.Set(MaxLinesPropertyKey, value); }
373  }
374 
375  /// <summary>
376  /// Gets or sets the minimum number of visible lines.
377  /// </summary>
378  /// <exception cref="ArgumentOutOfRangeException">The provided value must be strictly positive</exception>
379  public int MinLines
380  {
381  get { return DependencyProperties.Get(MinLinesPropertyKey); }
382  set { DependencyProperties.Set(MinLinesPropertyKey, value); }
383  }
384 
385  /// <summary>
386  /// Gets or sets the image that is displayed in background when the edit is active
387  /// </summary>
388  public UIImage ActiveImage
389  {
390  get { return DependencyProperties.Get(ActiveImagePropertyKey); }
391  set { DependencyProperties.Set(ActiveImagePropertyKey, value); }
392  }
393 
394  /// <summary>
395  /// Gets or sets the image that is displayed in background when the edit is inactive
396  /// </summary>
397  public UIImage InactiveImage
398  {
399  get { return DependencyProperties.Get(InactiveImagePropertyKey); }
400  set { DependencyProperties.Set(InactiveImagePropertyKey, value); }
401  }
402 
403  /// <summary>
404  /// Gets or sets the image that the button displays when the mouse is over it
405  /// </summary>
406  public UIImage MouseOverImage
407  {
408  get { return DependencyProperties.Get(MouseOverImagePropertyKey); }
409  set { DependencyProperties.Set(MouseOverImagePropertyKey, value); }
410  }
411 
412  /// <summary>
413  /// Gets or sets the value indicating if the <see cref="Text"/> of the <see cref="TextBlock"/> must be aligned to the closest screen pixel.
414  /// </summary>
415  public bool SnapText { get; set; }
416 
417  /// <summary>
418  /// Gets or sets the caret position in the <see cref="EditText"/>'s text.
419  /// </summary>
420  public int CaretPosition
421  {
422  get
423  {
424  UpdateSelectionFromEditImpl();
425 
426  return caretAtStart? selectionStart: selectionStop;
427  }
428  set { Select(value, 0); }
429  }
430 
431  /// <summary>
432  /// Gets or sets the width of the edit text's cursor (in virtual pixels).
433  /// </summary>
434  /// <remarks>The value is trunked between [0, infinity-1]</remarks>
435  public float CaretWidth
436  {
437  get { return caretWith; }
438  set { caretWith = Math.Max(0, Math.Min(float.MaxValue, value));}
439  }
440 
441  /// <summary>
442  /// Gets or sets the caret blinking frequency.
443  /// </summary>
444  /// <remarks>The value is trunked between [0, infinity-1]</remarks>
445  public float CaretFrequency
446  {
447  get { return caretFrequency; }
448  set { caretFrequency = Math.Max(0, Math.Min(float.MaxValue, value)); }
449  }
450 
451  /// <summary>
452  /// Gets the value indicating if the blinking caret is currently visible or not.
453  /// </summary>
454  public bool IsCaretVisible { get { return IsSelectionActive && !caretHided; } }
455 
456  private void ResetCaretVisibility()
457  {
458  caretHided = false;
459  accumulatedTime = 0f;
460  }
461 
462  protected override void Update(GameTime time)
463  {
464  base.Update(time);
465 
466  if (IsSelectionActive)
467  {
468  accumulatedTime += (float)time.Elapsed.TotalSeconds;
469  var displayTime = Math.Min(float.MaxValue, Math.Max(MathUtil.ZeroTolerance, 1 / (2 * CaretFrequency)));
470  while (accumulatedTime > displayTime)
471  {
472  accumulatedTime -= displayTime;
473  caretHided = !caretHided;
474  }
475  }
476  else
477  {
478  ResetCaretVisibility();
479  }
480  }
481 
482  /// <summary>
483  /// Gets or sets the edit text input type by setting a combination of <see cref="InputTypeFlags"/>.
484  /// </summary>
485  public InputTypeFlags InputType
486  {
487  get { return inputType; }
488  set
489  {
490  if(inputType == value)
491  return;
492 
493  inputType = value;
494 
495  UpdateTextToDisplay();
496 
497  UpdateInputTypeImpl();
498  }
499  }
500 
501  /// <summary>
502  /// Gets or sets the size of the text in virtual pixels unit
503  /// </summary>
504  public float TextSize
505  {
506  get
507  {
508  if (textSize.HasValue)
509  return textSize.Value;
510 
511  if (Font != null)
512  return Font.Size;
513 
514  return 0;
515  }
516  set
517  {
518  textSize = Math.Max(0, Math.Min(float.MaxValue, value));
519 
520  InvalidateMeasure();
521  }
522  }
523 
524  /// <summary>
525  /// Gets the total number of lines in the text box.
526  /// </summary>
527  public int LineCount
528  {
529  get { return GetLineCountImpl(); }
530  }
531 
532  /// <summary>
533  /// Gets or sets the alignment of the text to display.
534  /// </summary>
535  public TextAlignment TextAlignment { get; set; }
536 
537  /// <summary>
538  /// Gets or sets the filter used to determine whether the inputed characters are valid or not.
539  /// Accepted character are characters that the provided predicate function returns <value>true</value>.
540  /// </summary>
541  /// <remarks>If <see cref="CharacterFilterPredicate"/> is not set all characters are accepted.</remarks>
542  public Func<char, bool> CharacterFilterPredicate
543  {
544  get
545  {
546  return characterFilterPredicate;
547  }
548  set
549  {
550  if(characterFilterPredicate == value)
551  return;
552 
553  characterFilterPredicate = value;
554 
555  Text = text;
556  }
557  }
558 
559  /// <summary>
560  /// Gets or sets the content of the current selection in the text box.
561  /// </summary>
562  /// <exception cref="ArgumentNullException">The provided string value is null</exception>
563  public string SelectedText
564  {
565  get { return Text.Substring(SelectionStart, SelectionLength); }
566  set
567  {
568  if(value == null)
569  throw new ArgumentNullException("value");
570 
571  var stringBfr = Text.Substring(0, SelectionStart);
572  var stringAft = Text.Substring(SelectionStart + SelectionLength);
573 
574  Text = stringBfr + value + stringAft;
575  CaretPosition = stringBfr.Length + value.Length;
576 
577  InvalidateMeasure();
578  }
579  }
580 
581  /// <summary>
582  /// Gets or sets a value indicating the number of characters in the current selection in the text box.
583  /// </summary>
584  /// <remarks>If the provided length of the selection is too big, the selection is extended until the end of the current text</remarks>
585  public int SelectionLength
586  {
587  get
588  {
589  UpdateSelectionFromEditImpl();
590 
591  return selectionStop - selectionStart;
592  }
593  set
594  {
595  Select(SelectionStart, value);
596  }
597  }
598 
599  /// <summary>
600  /// Gets or sets a character index for the beginning of the current selection.
601  /// </summary>
602  /// <remarks>If the provided selection start index is too big, the caret is placed at the end of the current text</remarks>
603  public int SelectionStart
604  {
605  get
606  {
607  UpdateSelectionFromEditImpl();
608 
609  return selectionStart;
610  }
611  set
612  {
613  Select(value, SelectionLength);
614  }
615  }
616 
617  /// <summary>
618  /// Gets or sets the text contents of the text box.
619  /// </summary>
620  /// <remarks>Setting explicitly the text sets the cursor at the end of the new text.</remarks>
621  public string Text
622  {
623  get
624  {
625  return text;
626  }
627  set
628  {
629  if (value == null)
630  throw new ArgumentNullException("value");
631 
632  SetTextInternal(value, true);
633 
634  // remove all not valid characters
635  builder.Clear();
636  var predicate = CharacterFilterPredicate;
637  foreach (var character in value)
638  {
639  if (predicate == null || predicate(character))
640  builder.Append(character);
641  }
642 
643  SetTextInternal(builder.ToString(), true);
644  }
645  }
646 
647  private void SetTextInternal(string newText, bool updateNativeEdit)
648  {
649  var truncatedText = newText;
650  if (truncatedText.Length > MaxLength)
651  truncatedText = truncatedText.Substring(0, MaxLength);
652 
653  var oldText = text;
654  text = truncatedText;
655 
656  if (updateNativeEdit)
657  UpdateTextToEditImpl();
658 
659  // early exit if text did not changed
660  if (text == oldText)
661  return;
662 
663  UpdateTextToDisplay();
664 
665  Select(text.Length, 0);
666 
667  RaiseEvent(new RoutedEventArgs(TextChangedEvent));
668 
669  InvalidateMeasure();
670  }
671 
672  private void UpdateTextToDisplay()
673  {
674  textToDisplay = ShouldHideText ? new string(PasswordHidingCharacter, text.Length) : text;
675  }
676 
677  /// <summary>
678  /// The actual text to show into the edit text.
679  /// </summary>
680  public string TextToDisplay
681  {
682  get { return textToDisplay; }
683  }
684 
685  /// <summary>
686  /// Appends a string to the contents of a text control.
687  /// </summary>
688  /// <param name="textData">A string that specifies the text to append to the current contents of the text control.</param>
689  public void AppendText(string textData)
690  {
691  if (textData == null)
692  throw new ArgumentNullException("textData");
693 
694  Text += textData;
695  }
696 
697  /// <summary>
698  /// Selects all the contents of the text editing control.
699  /// </summary>
700  /// <param name="caretAtBeginning">Indicate if the caret should be at the beginning or the end of the selection</param>
701  public void SelectAll(bool caretAtBeginning = false)
702  {
703  Select(0, Text.Length, caretAtBeginning);
704  }
705 
706  /// <summary>
707  /// Clears all the content from the text box.
708  /// </summary>
709  public void Clear()
710  {
711  Text = "";
712  }
713 
714  /// <summary>
715  /// Selects a range of text in the text box.
716  /// </summary>
717  /// <param name="start">The zero-based character index of the first character in the selection.</param>
718  /// <param name="length">The length of the selection, in characters.</param>
719  /// <param name="caretAtBeginning">Indicate if the caret should be at the beginning or the end of the selection</param>
720  /// <remarks>If the value of start is too big the caret is positioned at the end of the current text.
721  /// If the value of length is too big the selection is extended to the end current text.</remarks>
722  public void Select(int start, int length, bool caretAtBeginning = false)
723  {
724  var truncatedStart = Math.Max(0, Math.Min(start, Text.Length));
725  var truncatedStop = Math.Max(truncatedStart, Math.Min(Text.Length, truncatedStart + Math.Max(0, length)));
726 
727  selectionStart = truncatedStart;
728  selectionStop = truncatedStop;
729  caretAtStart = caretAtBeginning;
730 
731  ResetCaretVisibility(); // force caret not to blink when modifying selection/caret position.
732 
733  UpdateSelectionToEditImpl();
734  }
735 
736  /// <summary>
737  /// Calculate and returns the size of the <see cref="Text"/> in virtual pixels size.
738  /// </summary>
739  /// <returns>The size of the Text in virtual pixels.</returns>
741  {
742  return CalculateTextSize(TextToDisplay);
743  }
744 
745  /// <summary>
746  /// Calculate and returns the size of the provided <paramref name="textToMeasure"/>"/> in virtual pixels size.
747  /// </summary>
748  /// <param name="textToMeasure">The text to measure</param>
749  /// <returns>The size of the text in virtual pixels</returns>
750  protected Vector2 CalculateTextSize(string textToMeasure)
751  {
752  if (textToMeasure == null || Font == null)
753  return Vector2.Zero;
754 
755  var sizeRatio = RealSizeVirtualResolutionRatio;
756  var measureFontSize = TextSize * sizeRatio;
757  var realSize = Font.MeasureString(textToMeasure, measureFontSize);
758 
759  // force pre-generation if synchronous generation is required
760  if (SynchronousCharacterGeneration)
761  Font.PreGenerateGlyphs(textToMeasure, measureFontSize);
762 
763  if (Font.IsDynamic)
764  {
765  // rescale the real size to the virtual size
766  realSize.X /= sizeRatio.X;
767  realSize.Y /= sizeRatio.Y;
768  }
769 
770  return realSize;
771  }
772 
773  protected override Vector3 MeasureOverride(Vector3 availableSizeWithoutMargins)
774  {
775  var desiredSize = Vector3.Zero;
776  if (Font != null)
777  {
778  // take the maximum between the text size and the minimum visible line size as text desired size
779  var fontLineSpacing = Font.GetTotalLineSpacing(TextSize);
780  var currentTextSize = new Vector3(CalculateTextSize(), 0);
781  desiredSize = new Vector3(currentTextSize.X, Math.Min(Math.Max(currentTextSize.Y, fontLineSpacing * MinLines), fontLineSpacing * MaxLines), currentTextSize.Z);
782  }
783 
784  // add the padding to the text desired size
785  var desiredSizeWithPadding = CalculateSizeWithThickness(ref desiredSize, ref padding);
786 
787  return desiredSizeWithPadding;
788  }
789 
790  protected override Vector3 ArrangeOverride(Vector3 finalSizeWithoutMargins)
791  {
792  // get the maximum between the final size and the desired size
793  var returnSize = new Vector3(
794  Math.Max(finalSizeWithoutMargins.X, DesiredSize.X),
795  Math.Max(finalSizeWithoutMargins.Y, DesiredSize.Y),
796  Math.Max(finalSizeWithoutMargins.Z, DesiredSize.Z));
797 
798  return returnSize;
799  }
800 
801  #region Events
802 
803  /// <summary>
804  /// Occurs when the text selection has changed.
805  /// </summary>
806  /// <remarks>A click event is bubbling</remarks>
807  public event EventHandler<RoutedEventArgs> TextChanged
808  {
809  add { AddHandler(TextChangedEvent, value); }
810  remove { RemoveHandler(TextChangedEvent, value); }
811  }
812 
813  /// <summary>
814  /// Identifies the <see cref="TextChanged"/> routed event.
815  /// </summary>
816  public static readonly RoutedEvent<RoutedEventArgs> TextChangedEvent = EventManager.RegisterRoutedEvent<RoutedEventArgs>(
817  "TextChanged",
818  RoutingStrategy.Bubble,
819  typeof(EditText));
820 
821  private static void TextChangedClassHandler(object sender, RoutedEventArgs e)
822  {
823  var editText = (EditText)sender;
824 
825  editText.OnTextChanged(e);
826  }
827 
828  /// <summary>
829  /// The class handler of the event <see cref="TextChanged"/>.
830  /// This method can be overridden in inherited classes to perform actions common to all instances of a class.
831  /// </summary>
832  /// <param name="args">The arguments of the event</param>
833  protected virtual void OnTextChanged(RoutedEventArgs args)
834  {
835 
836  }
837 
838  protected override void OnTouchDown(TouchEventArgs args)
839  {
840  base.OnTouchDown(args);
841 
842  IsSelectionActive = !IsReadOnly;
843 
844  OnTouchDownImpl(args);
845  }
846 
847  protected override void OnTouchMove(TouchEventArgs args)
848  {
849  base.OnTouchMove(args);
850 
851  OnTouchMoveImpl(args);
852  }
853 
854  #endregion
855  }
856 }
virtual void OnMaxLengthChanged()
Function triggered when the value of MaxLength changed.
Definition: EditText.cs:170
void SelectAll(bool caretAtBeginning=false)
Selects all the contents of the text editing control.
Definition: EditText.cs:701
Provides a base class for all the User Interface elements in Paradox applications.
Definition: UIElement.cs:21
virtual void OnTextChanged(RoutedEventArgs args)
The class handler of the event TextChanged. This method can be overridden in inherited classes to per...
Definition: EditText.cs:833
Represents a two dimensional mathematical vector.
Definition: Vector2.cs:42
virtual void OnMinLinesChanged()
Function triggered when the value of MinLines changed.
Definition: EditText.cs:194
Represents the base class for user interface (UI) controls.
Definition: Control.cs:11
void AppendText(string textData)
Appends a string to the contents of a text control.
Definition: EditText.cs:689
TextAlignment
Specify the available text alignment when rendering text.
Definition: TextAlignment.cs:8
Contains state information and event data associated with a routed event.
float X
The X component of the vector.
Definition: Vector3.cs:78
const float ZeroTolerance
The value for which all absolute numbers smaller than are considered equal to zero.
Definition: MathUtil.cs:38
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
override Vector3 ArrangeOverride(Vector3 finalSizeWithoutMargins)
When overridden in a derived class, positions possible child elements and determines a size for a UIE...
Definition: EditText.cs:790
A service registry is a IServiceProvider that provides methods to register and unregister services...
Describes the thickness of a frame around a cuboid. Six float values describe the Left...
Definition: Thickness.cs:12
SharpDX.DirectWrite.Font Font
Flags
Enumeration of the new Assimp's flags.
void Clear()
Clears all the content from the text box.
Definition: EditText.cs:709
SpriteFont to use with SpriteBatch. See SpriteFont to learn how to use it.
Definition: SpriteFont.cs:26
Vector2 CalculateTextSize()
Calculate and returns the size of the Text in virtual pixels size.
Definition: EditText.cs:740
Current timing used for variable-step (real time) or fixed-step (game time) games.
Definition: GameTime.cs:31
void Select(int start, int length, bool caretAtBeginning=false)
Selects a range of text in the text box.
Definition: EditText.cs:722
Vector2 CalculateTextSize(string textToMeasure)
Calculate and returns the size of the provided textToMeasure "/> in virtual pixels size...
Definition: EditText.cs:750
Represents a 32-bit color (4 bytes) in the form of RGBA (in byte order: R, G, B, A).
Definition: Color.cs:16
Provides data for touch input events.
override void OnTouchMove(TouchEventArgs args)
The class handler of the event TouchMove. This method can be overridden in inherited classes to perfo...
Definition: EditText.cs:847
EditText(IServiceRegistry services)
Create a new instance of EditText.
Definition: EditText.cs:215
Represents and identifies a routed event and declares its characteristics.
Definition: RoutedEvent.cs:10
SiliconStudio.Core.Mathematics.Vector3 Vector3
virtual void OnIsReadOnlyChanged()
Function triggered when the value of IsReadOnly changed.
Definition: EditText.cs:162
Class holding all the data required to define an UI image.
Definition: UIImage.cs:15
TimeSpan Elapsed
Gets the elapsed game time since the last update
Definition: GameTime.cs:80
override void OnTouchDown(TouchEventArgs args)
The class handler of the event TouchDown. This method can be overridden in inherited classes to perfo...
Definition: EditText.cs:838
float Z
The Z component of the vector.
Definition: Vector3.cs:90
A class that represents a tag propety.
Definition: PropertyKey.cs:17
virtual void OnMaxLinesChanged()
Function triggered when the value of MaxLines changed.
Definition: EditText.cs:185
override Vector3 MeasureOverride(Vector3 availableSizeWithoutMargins)
When overridden in a derived class, measures the size in layout required for possible child elements ...
Definition: EditText.cs:773
override void Update(GameTime time)
Method called by IUIElementUpdate.Update. This method can be overridden by inherited classes to perfo...
Definition: EditText.cs:462
Represent an edit text where the user can enter text.
Definition: EditText.cs:20