Frame.cs 5.4 KB

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