Frame.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using NStack;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Xml.Linq;
  6. using Terminal.Gui.Graphs;
  7. namespace Terminal.Gui {
  8. /// <summary>
  9. /// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
  10. /// enabling borders, menus, etc...
  11. /// </summary>
  12. public class Frame : View {
  13. /// <summary>
  14. /// Frames are a special form of <see cref="View"/> that act as adornments; they appear outside of the <see cref="View.Bounds"/>
  15. /// enabling borders, menus, etc...
  16. /// </summary>
  17. public Frame ()
  18. {
  19. }
  20. /// <summary>
  21. /// The Parent of this Frame.
  22. /// </summary>
  23. public View Parent { get; set; }
  24. /// <summary>
  25. /// Frames cannot be used as sub-views, so this method always throws an <see cref="InvalidOperationException"/>.
  26. /// TODO: Are we sure?
  27. /// </summary>
  28. public override View SuperView {
  29. get {
  30. return null;
  31. }
  32. set {
  33. throw new NotImplementedException ();
  34. }
  35. }
  36. /// <inheritdoc/>
  37. public override void ViewToScreen (int col, int row, out int rcol, out int rrow, bool clipped = true)
  38. {
  39. // Frames are children of a View, not SubViews. Thus ViewToScreen will not work.
  40. // To get the screen-relative coordinates of a Frame, we need to know who
  41. // the Parent is
  42. // Computes the real row, col relative to the screen.
  43. var inner = Parent?.Bounds ?? Bounds;
  44. rrow = row - inner.Y;
  45. rcol = col - inner.X;
  46. Parent?.ViewToScreen (rcol, rrow, out rcol, out rrow, clipped);
  47. }
  48. /// <summary>
  49. ///
  50. /// </summary>
  51. /// <param name="clipRect"></param>
  52. public virtual void OnDrawSubViews (Rect clipRect)
  53. {
  54. // if (Subviews == null) {
  55. // return;
  56. // }
  57. // foreach (var view in Subviews) {
  58. // // BUGBUG: v2 - shouldn't this be !view.LayoutNeeded? Why draw if layout is going to happen and we'll just draw again?
  59. // if (view.LayoutNeeded) {
  60. // view.LayoutSubviews ();
  61. // }
  62. // if ((view.Visible && !view.NeedDisplay.IsEmpty && view.Frame.Width > 0 && view.Frame.Height > 0) || view.ChildNeedsDisplay) {
  63. // view.Redraw (view.Bounds);
  64. // view.NeedDisplay = Rect.Empty;
  65. // // BUGBUG - v2 why does this need to be set to false?
  66. // // Shouldn't it be set when the subviews draw?
  67. // view.ChildNeedsDisplay = false;
  68. // }
  69. // }
  70. }
  71. /// <inheritdoc/>
  72. public override void OnDrawContent (Rect viewport)
  73. {
  74. if (!ustring.IsNullOrEmpty (TextFormatter.Text)) {
  75. Clear (viewport);
  76. SetChildNeedsDisplay ();
  77. // Draw any Text
  78. if (TextFormatter != null) {
  79. TextFormatter.NeedsFormat = true;
  80. Rect containerBounds = GetContainerBounds ();
  81. TextFormatter?.Draw (ViewToScreen (viewport), HasFocus ? ColorScheme.Focus : GetNormalColor (),
  82. HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled,
  83. containerBounds);
  84. }
  85. }
  86. }
  87. /// <summary>
  88. /// Redraws the Frames that comprise the <see cref="Frame"/>.
  89. /// </summary>
  90. /// <param name="clipRect"></param>
  91. public override void Redraw (Rect clipRect)
  92. {
  93. //OnDrawContent (bounds);
  94. //OnDrawSubViews (bounds);
  95. //OnDrawContentComplete (bounds);
  96. if (ColorScheme != null) {
  97. Driver.SetAttribute (ColorScheme.Normal);
  98. }
  99. var screenBounds = ViewToScreen (Frame);
  100. Thickness.Draw (screenBounds, (string)Data);
  101. //OnDrawContent (bounds);
  102. if (BorderStyle != BorderStyle.None) {
  103. var lc = new LineCanvas ();
  104. lc.AddLine (screenBounds.Location, Frame.Width - 1, Orientation.Horizontal, BorderStyle);
  105. lc.AddLine (screenBounds.Location, Frame.Height - 1, Orientation.Vertical, BorderStyle);
  106. lc.AddLine (new Point (screenBounds.X, screenBounds.Y + screenBounds.Height - 1), screenBounds.Width - 1, Orientation.Horizontal, BorderStyle);
  107. lc.AddLine (new Point (screenBounds.X + screenBounds.Width - 1, screenBounds.Y), screenBounds.Height - 1, Orientation.Vertical, BorderStyle);
  108. foreach (var p in lc.GenerateImage (screenBounds)) {
  109. Driver.Move (p.Key.X, p.Key.Y);
  110. Driver.AddRune (p.Value);
  111. }
  112. if (!ustring.IsNullOrEmpty (Parent?.Title)) {
  113. Driver.DrawWindowTitle (screenBounds, Parent?.Title, 0, 0, 0, 0);
  114. }
  115. }
  116. }
  117. //public Label DiagnosticsLabel { get; set; }
  118. // TODO: v2 = This is teporary; need to also enable (or not) simple way of setting
  119. // other border properties
  120. // TOOD: v2 - Missing 3D effect
  121. /// <summary>
  122. ///
  123. /// </summary>
  124. public BorderStyle BorderStyle { get; set; } = BorderStyle.None;
  125. /// <summary>
  126. /// Defines the rectangle that the <see cref="Frame"/> will use to draw its content.
  127. /// </summary>
  128. public Thickness Thickness { get; set; }
  129. // TODO: v2 - This is confusing. It is a read-only property and actually only returns a size, so
  130. // should not be a Rect. However, it may make sense to keep it a Rect and support negative Location
  131. // for scrolling. Still noodling this.
  132. /// <summary>
  133. /// Gets the rectangle that describes the inner area of the frame. The Location is always 0, 0.
  134. /// </summary>
  135. public override Rect Bounds {
  136. get {
  137. if (Thickness == null) {
  138. return new Rect (Point.Empty, Frame.Size);
  139. }
  140. // Return the frame-relative bounds
  141. return Thickness.GetInnerRect (new Rect (Point.Empty, Frame.Size));
  142. }
  143. set {
  144. throw new InvalidOperationException ("It makes no sense to explicitly set Bounds.");
  145. }
  146. }
  147. }
  148. }