FrameView.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // Authors:
  3. // Miguel de Icaza ([email protected])
  4. //
  5. // NOTE: FrameView is functionally identical to Window with the following exceptions.
  6. // - Is not a Toplevel
  7. // - Does not support mouse dragging
  8. // - Does not support padding (but should)
  9. // - Does not support IEnumerable
  10. // Any udpates done here should probably be done in Window as well; TODO: Merge these classes
  11. using System.Linq;
  12. using NStack;
  13. namespace Terminal.Gui {
  14. /// <summary>
  15. /// The FrameView is a container frame that draws a frame around the contents. It is similar to
  16. /// a GroupBox in Windows.
  17. /// </summary>
  18. public class FrameView : View {
  19. View contentView;
  20. ustring title;
  21. /// <summary>
  22. /// The title to be displayed for this <see cref="FrameView"/>.
  23. /// </summary>
  24. /// <value>The title.</value>
  25. public ustring Title {
  26. get => title;
  27. set {
  28. title = value;
  29. SetNeedsDisplay ();
  30. }
  31. }
  32. /// <summary>
  33. /// ContentView is an internal implementation detail of Window. It is used to host Views added with <see cref="Add(View)"/>.
  34. /// Its ONLY reason for being is to provide a simple way for Window to expose to those SubViews that the Window's Bounds
  35. /// are actually deflated due to the border.
  36. /// </summary>
  37. class ContentView : View {
  38. public ContentView (Rect frame) : base (frame) { }
  39. public ContentView () : base () { }
  40. }
  41. /// <summary>
  42. /// Initializes a new instance of the <see cref="Gui.FrameView"/> class using <see cref="LayoutStyle.Absolute"/> layout.
  43. /// </summary>
  44. /// <param name="frame">Frame.</param>
  45. /// <param name="title">Title.</param>
  46. public FrameView (Rect frame, ustring title = null) : base (frame)
  47. {
  48. var cFrame = new Rect (1, 1, frame.Width - 2, frame.Height - 2);
  49. this.title = title;
  50. contentView = new ContentView (cFrame);
  51. Initialize ();
  52. }
  53. /// <summary>
  54. /// Initializes a new instance of the <see cref="Gui.FrameView"/> class using <see cref="LayoutStyle.Computed"/> layout.
  55. /// </summary>
  56. /// <param name="frame">Frame.</param>
  57. /// <param name="title">Title.</param>
  58. /// /// <param name="views">Views.</param>
  59. public FrameView (Rect frame, ustring title, View [] views) : this (frame, title)
  60. {
  61. foreach (var view in views) {
  62. contentView.Add (view);
  63. }
  64. Initialize ();
  65. }
  66. /// <summary>
  67. /// Initializes a new instance of the <see cref="Gui.FrameView"/> class using <see cref="LayoutStyle.Computed"/> layout.
  68. /// </summary>
  69. /// <param name="title">Title.</param>
  70. public FrameView (ustring title)
  71. {
  72. this.title = title;
  73. contentView = new ContentView () {
  74. X = 1,
  75. Y = 1,
  76. Width = Dim.Fill (1),
  77. Height = Dim.Fill (1)
  78. };
  79. Initialize ();
  80. }
  81. /// <summary>
  82. /// Initializes a new instance of the <see cref="Gui.FrameView"/> class using <see cref="LayoutStyle.Computed"/> layout.
  83. /// </summary>
  84. public FrameView () : this (title: string.Empty) { }
  85. void Initialize ()
  86. {
  87. if (Subviews?.Count == 0) {
  88. base.Add (contentView);
  89. contentView.Text = base.Text;
  90. }
  91. }
  92. void DrawFrame ()
  93. {
  94. DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), 0, fill: true);
  95. }
  96. /// <summary>
  97. /// Add the specified <see cref="View"/> to this container.
  98. /// </summary>
  99. /// <param name="view"><see cref="View"/> to add to this container</param>
  100. public override void Add (View view)
  101. {
  102. contentView.Add (view);
  103. if (view.CanFocus)
  104. CanFocus = true;
  105. }
  106. /// <summary>
  107. /// Removes a <see cref="View"/> from this container.
  108. /// </summary>
  109. /// <remarks>
  110. /// </remarks>
  111. public override void Remove (View view)
  112. {
  113. if (view == null)
  114. return;
  115. SetNeedsDisplay ();
  116. var touched = view.Frame;
  117. contentView.Remove (view);
  118. if (contentView.InternalSubviews.Count < 1)
  119. this.CanFocus = false;
  120. }
  121. /// <summary>
  122. /// Removes all <see cref="View"/>s from this container.
  123. /// </summary>
  124. /// <remarks>
  125. /// </remarks>
  126. public override void RemoveAll ()
  127. {
  128. contentView.RemoveAll ();
  129. }
  130. ///<inheritdoc/>
  131. public override void Redraw (Rect bounds)
  132. {
  133. var padding = 0;
  134. var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
  135. if (!NeedDisplay.IsEmpty) {
  136. Driver.SetAttribute (ColorScheme.Normal);
  137. Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: true);
  138. }
  139. var savedClip = ClipToBounds ();
  140. contentView.Redraw (contentView.Bounds);
  141. Driver.Clip = savedClip;
  142. ClearNeedsDisplay ();
  143. Driver.SetAttribute (ColorScheme.Normal);
  144. Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: false);
  145. if (HasFocus)
  146. Driver.SetAttribute (ColorScheme.HotNormal);
  147. Driver.DrawWindowTitle (scrRect, Title, padding, padding, padding, padding);
  148. Driver.SetAttribute (ColorScheme.Normal);
  149. }
  150. /// <summary>
  151. /// The text displayed by the <see cref="Label"/>.
  152. /// </summary>
  153. public override ustring Text {
  154. get => contentView.Text;
  155. set {
  156. base.Text = value;
  157. if (contentView != null) {
  158. contentView.Text = value;
  159. }
  160. }
  161. }
  162. /// <summary>
  163. /// Controls the text-alignment property of the label, changing it will redisplay the <see cref="Label"/>.
  164. /// </summary>
  165. /// <value>The text alignment.</value>
  166. public override TextAlignment TextAlignment {
  167. get => contentView.TextAlignment;
  168. set {
  169. base.TextAlignment = contentView.TextAlignment = value;
  170. }
  171. }
  172. ///<inheritdoc/>
  173. public override bool OnEnter (View view)
  174. {
  175. if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus)) {
  176. Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
  177. }
  178. return base.OnEnter (view);
  179. }
  180. }
  181. }