ViewText.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System.Text;
  2. using System;
  3. namespace Terminal.Gui {
  4. public partial class View {
  5. string _text;
  6. /// <summary>
  7. /// The text displayed by the <see cref="View"/>.
  8. /// </summary>
  9. /// <remarks>
  10. /// <para>
  11. /// The text will be drawn before any subviews are drawn.
  12. /// </para>
  13. /// <para>
  14. /// The text will be drawn starting at the view origin (0, 0) and will be formatted according
  15. /// to <see cref="TextAlignment"/> and <see cref="TextDirection"/>.
  16. /// </para>
  17. /// <para>
  18. /// The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
  19. /// is 1, the text will be clipped.
  20. /// </para>
  21. /// <para>
  22. /// Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set <see cref="HotKeySpecifier"/> to
  23. /// <c>(Rune)0xffff</c>.
  24. /// </para>
  25. /// </remarks>
  26. public virtual string Text {
  27. get => _text;
  28. set {
  29. _text = value;
  30. SetHotKey ();
  31. UpdateTextFormatterText ();
  32. //TextFormatter.Format ();
  33. OnResizeNeeded ();
  34. #if DEBUG
  35. if (_text != null && string.IsNullOrEmpty (Id)) {
  36. Id = _text;
  37. }
  38. #endif
  39. }
  40. }
  41. /// <summary>
  42. /// Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
  43. /// </summary>
  44. public TextFormatter TextFormatter { get; set; }
  45. /// <summary>
  46. /// Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
  47. /// different format than the default.
  48. /// </summary>
  49. protected virtual void UpdateTextFormatterText ()
  50. {
  51. if (TextFormatter != null) {
  52. TextFormatter.Text = _text;
  53. }
  54. }
  55. /// <summary>
  56. /// Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
  57. /// or not when <see cref="TextFormatter.WordWrap"/> is enabled.
  58. /// If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when
  59. /// <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
  60. /// </summary>
  61. public virtual bool PreserveTrailingSpaces {
  62. get => TextFormatter.PreserveTrailingSpaces;
  63. set {
  64. if (TextFormatter.PreserveTrailingSpaces != value) {
  65. TextFormatter.PreserveTrailingSpaces = value;
  66. TextFormatter.NeedsFormat = true;
  67. }
  68. }
  69. }
  70. /// <summary>
  71. /// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will redisplay the <see cref="View"/>.
  72. /// </summary>
  73. /// <value>The text alignment.</value>
  74. public virtual TextAlignment TextAlignment {
  75. get => TextFormatter.Alignment;
  76. set {
  77. TextFormatter.Alignment = value;
  78. UpdateTextFormatterText ();
  79. OnResizeNeeded ();
  80. }
  81. }
  82. /// <summary>
  83. /// Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will redisplay the <see cref="View"/>.
  84. /// </summary>
  85. /// <value>The text alignment.</value>
  86. public virtual VerticalTextAlignment VerticalTextAlignment {
  87. get => TextFormatter.VerticalAlignment;
  88. set {
  89. TextFormatter.VerticalAlignment = value;
  90. SetNeedsDisplay ();
  91. }
  92. }
  93. /// <summary>
  94. /// Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the <see cref="View"/>.
  95. /// </summary>
  96. /// <value>The text alignment.</value>
  97. public virtual TextDirection TextDirection {
  98. get => TextFormatter.Direction;
  99. set {
  100. UpdateTextDirection (value);
  101. TextFormatter.Direction = value;
  102. }
  103. }
  104. private void UpdateTextDirection (TextDirection newDirection)
  105. {
  106. var directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
  107. != TextFormatter.IsHorizontalDirection (newDirection);
  108. TextFormatter.Direction = newDirection;
  109. var isValidOldAutoSize = AutoSize && IsValidAutoSize (out var _);
  110. UpdateTextFormatterText ();
  111. if ((!ForceValidatePosDim && directionChanged && AutoSize)
  112. || (ForceValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize)) {
  113. OnResizeNeeded ();
  114. } else if (directionChanged && IsAdded) {
  115. ResizeBoundsToFit (Bounds.Size);
  116. // BUGBUG: I think this call is redundant.
  117. SetBoundsToFitFrame ();
  118. } else {
  119. SetBoundsToFitFrame ();
  120. }
  121. TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
  122. SetNeedsDisplay ();
  123. }
  124. /// <summary>
  125. /// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters
  126. /// in the <see cref="Text"/> property.
  127. /// </summary>
  128. /// <remarks>
  129. /// Only the first hotkey specifier found in <see cref="Text"/> is supported.
  130. /// </remarks>
  131. /// <param name="isWidth">If <see langword="true"/> (the default) the width required for the hotkey specifier is returned. Otherwise the height is returned.</param>
  132. /// <returns>The number of characters required for the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>. If the text direction specified
  133. /// by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.</returns>
  134. public int GetHotKeySpecifierLength (bool isWidth = true)
  135. {
  136. if (isWidth) {
  137. return TextFormatter.IsHorizontalDirection (TextDirection) &&
  138. TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
  139. ? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
  140. } else {
  141. return TextFormatter.IsVerticalDirection (TextDirection) &&
  142. TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
  143. ? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
  144. }
  145. }
  146. /// <summary>
  147. /// Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>.
  148. /// </summary>
  149. /// <returns></returns>
  150. public Size GetSizeNeededForTextWithoutHotKey ()
  151. {
  152. return new Size (TextFormatter.Size.Width - GetHotKeySpecifierLength (),
  153. TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
  154. }
  155. /// <summary>
  156. /// Gets the dimensions required for <see cref="Text"/> accounting for a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> .
  157. /// </summary>
  158. /// <returns></returns>
  159. public Size GetTextFormatterSizeNeededForTextAndHotKey ()
  160. {
  161. if (string.IsNullOrEmpty (TextFormatter.Text)) {
  162. if (!IsInitialized) return Size.Empty;
  163. return Bounds.Size;
  164. }
  165. // BUGBUG: This IGNORES what Text is set to, using on only the current View size. This doesn't seem to make sense.
  166. // BUGBUG: This uses Frame; in v2 it should be Bounds
  167. return new Size (Bounds.Size.Width + GetHotKeySpecifierLength (),
  168. Bounds.Size.Height + GetHotKeySpecifierLength (false));
  169. }
  170. }
  171. }