Window.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. //
  2. // Window.cs: Window is a TopLevel View with a frame
  3. //
  4. // Authors:
  5. // Miguel de Icaza ([email protected])
  6. //
  7. using System.Collections;
  8. using NStack;
  9. namespace Terminal.Gui {
  10. /// <summary>
  11. /// A <see cref="Toplevel"/> <see cref="View"/> that draws a frame around its region and has a "ContentView" subview where the contents are added.
  12. /// </summary>
  13. public class Window : Toplevel, IEnumerable {
  14. View contentView;
  15. ustring title;
  16. /// <summary>
  17. /// The title to be displayed for this window.
  18. /// </summary>
  19. /// <value>The title.</value>
  20. public ustring Title {
  21. get => title;
  22. set {
  23. title = value;
  24. SetNeedsDisplay ();
  25. }
  26. }
  27. class ContentView : View {
  28. public ContentView (Rect frame) : base (frame) { }
  29. public ContentView () : base () { }
  30. #if false
  31. public override void Redraw (Rect region)
  32. {
  33. Driver.SetAttribute (ColorScheme.Focus);
  34. for (int y = 0; y < Frame.Height; y++) {
  35. Move (0, y);
  36. for (int x = 0; x < Frame.Width; x++) {
  37. Driver.AddRune ('x');
  38. }
  39. }
  40. }
  41. #endif
  42. }
  43. /// <summary>
  44. /// Initializes a new instance of the <see cref="Gui.Window"/> class with an optional title and a set frame.
  45. /// </summary>
  46. /// <param name="frame">Frame.</param>
  47. /// <param name="title">Title.</param>
  48. public Window (Rect frame, ustring title = null) : this (frame, title, padding: 0)
  49. {
  50. }
  51. /// <summary>
  52. /// Initializes a new instance of the <see cref="Window"/> class with an optional title.
  53. /// </summary>
  54. /// <param name="title">Title.</param>
  55. public Window (ustring title = null) : this (title, padding: 0)
  56. {
  57. }
  58. int padding;
  59. /// <summary>
  60. /// Initializes a new instance of the <see cref="Window"/> with
  61. /// the specified frame for its location, with the specified border
  62. /// an optional title.
  63. /// </summary>
  64. /// <param name="frame">Frame.</param>
  65. /// <param name="padding">Number of characters to use for padding of the drawn frame.</param>
  66. /// <param name="title">Title.</param>
  67. public Window (Rect frame, ustring title = null, int padding = 0) : base (frame)
  68. {
  69. this.Title = title;
  70. int wb = 2 * (1 + padding);
  71. this.padding = padding;
  72. var cFrame = new Rect (1 + padding, 1 + padding, frame.Width - wb, frame.Height - wb);
  73. contentView = new ContentView (cFrame);
  74. base.Add (contentView);
  75. }
  76. /// <summary>
  77. /// Initializes a new instance of the <see cref="Window"/> with
  78. /// the specified frame for its location, with the specified border
  79. /// an optional title.
  80. /// </summary>
  81. /// <param name="padding">Number of characters to use for padding of the drawn frame.</param>
  82. /// <param name="title">Title.</param>
  83. public Window (ustring title = null, int padding = 0) : base ()
  84. {
  85. this.Title = title;
  86. int wb = 1 + padding;
  87. this.padding = padding;
  88. contentView = new ContentView () {
  89. X = wb,
  90. Y = wb,
  91. Width = Dim.Fill (wb),
  92. Height = Dim.Fill (wb)
  93. };
  94. base.Add (contentView);
  95. }
  96. /// <summary>
  97. /// Enumerates the various <see cref="View"/>s in the embedded <see cref="ContentView"/>.
  98. /// </summary>
  99. /// <returns>The enumerator.</returns>
  100. public new IEnumerator GetEnumerator ()
  101. {
  102. return contentView.GetEnumerator ();
  103. }
  104. void DrawFrame (bool fill = true)
  105. {
  106. DrawFrame (new Rect (0, 0, Frame.Width, Frame.Height), padding, fill: fill);
  107. }
  108. /// <summary>
  109. /// Add the specified view to the <see cref="ContentView"/>.
  110. /// </summary>
  111. /// <param name="view">View to add to the window.</param>
  112. public override void Add (View view)
  113. {
  114. contentView.Add (view);
  115. if (view.CanFocus)
  116. CanFocus = true;
  117. }
  118. /// <summary>
  119. /// Removes a widget from this container.
  120. /// </summary>
  121. /// <remarks>
  122. /// </remarks>
  123. public override void Remove (View view)
  124. {
  125. if (view == null)
  126. return;
  127. SetNeedsDisplay ();
  128. var touched = view.Frame;
  129. contentView.Remove (view);
  130. if (contentView.InternalSubviews.Count < 1)
  131. this.CanFocus = false;
  132. }
  133. /// <summary>
  134. /// Removes all widgets from this container.
  135. /// </summary>
  136. /// <remarks>
  137. /// </remarks>
  138. public override void RemoveAll ()
  139. {
  140. contentView.RemoveAll ();
  141. }
  142. ///<inheritdoc cref="Redraw"/>
  143. public override void Redraw (Rect bounds)
  144. {
  145. Application.CurrentView = this;
  146. if (NeedDisplay != null && !NeedDisplay.IsEmpty) {
  147. DrawFrameWindow ();
  148. }
  149. contentView.Redraw (contentView.Bounds);
  150. ClearNeedsDisplay ();
  151. DrawFrameWindow (false);
  152. void DrawFrameWindow (bool fill = true)
  153. {
  154. Driver.SetAttribute (ColorScheme.Normal);
  155. DrawFrame (fill);
  156. if (HasFocus)
  157. Driver.SetAttribute (ColorScheme.HotNormal);
  158. var width = Frame.Width - (padding + 2) * 2;
  159. if (Title != null && width > 4) {
  160. Move (1 + padding, padding);
  161. Driver.AddRune (' ');
  162. var str = Title.Length >= width ? Title [0, width - 2] : Title;
  163. Driver.AddStr (str);
  164. Driver.AddRune (' ');
  165. }
  166. Driver.SetAttribute (ColorScheme.Normal);
  167. }
  168. }
  169. //
  170. // FIXED:It does not look like the event is raised on clicked-drag
  171. // need to figure that out.
  172. //
  173. internal static Point? dragPosition;
  174. Point start;
  175. ///<inheritdoc cref="MouseEvent(Gui.MouseEvent)"/>
  176. public override bool MouseEvent (MouseEvent mouseEvent)
  177. {
  178. // FIXED:The code is currently disabled, because the
  179. // Driver.UncookMouse does not seem to have an effect if there is
  180. // a pending mouse event activated.
  181. int nx, ny;
  182. if ((mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) ||
  183. mouseEvent.Flags == MouseFlags.Button3Pressed)) {
  184. if (dragPosition.HasValue) {
  185. if (SuperView == null) {
  186. Application.Top.SetNeedsDisplay (Frame);
  187. Application.Top.Redraw (Frame);
  188. } else {
  189. SuperView.SetNeedsDisplay (Frame);
  190. }
  191. EnsureVisibleBounds (this, mouseEvent.X + mouseEvent.OfX - start.X,
  192. mouseEvent.Y + mouseEvent.OfY, out nx, out ny);
  193. dragPosition = new Point (nx, ny);
  194. Frame = new Rect (nx, ny, Frame.Width, Frame.Height);
  195. X = nx;
  196. Y = ny;
  197. //Demo.ml2.Text = $"{dx},{dy}";
  198. // FIXED: optimize, only SetNeedsDisplay on the before/after regions.
  199. SetNeedsDisplay ();
  200. return true;
  201. } else {
  202. // Only start grabbing if the user clicks on the title bar.
  203. if (mouseEvent.Y == 0) {
  204. start = new Point (mouseEvent.X, mouseEvent.Y);
  205. dragPosition = new Point ();
  206. nx = mouseEvent.X - mouseEvent.OfX;
  207. ny = mouseEvent.Y - mouseEvent.OfY;
  208. dragPosition = new Point (nx, ny);
  209. Application.GrabMouse (this);
  210. }
  211. //Demo.ml2.Text = $"Starting at {dragPosition}";
  212. return true;
  213. }
  214. }
  215. if (mouseEvent.Flags == MouseFlags.Button1Released && dragPosition.HasValue) {
  216. Application.UngrabMouse ();
  217. Driver.UncookMouse ();
  218. dragPosition = null;
  219. }
  220. //Demo.ml.Text = me.ToString ();
  221. return false;
  222. }
  223. }
  224. }