ListView.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. //
  2. // ListView.cs: ListView control
  3. //
  4. // Authors:
  5. // Miguel de Icaza ([email protected])
  6. //
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using NStack;
  11. namespace Terminal.Gui {
  12. public interface IListDataSource {
  13. int Count { get; }
  14. void Render (int item, int col, int line, int width);
  15. }
  16. /// <summary>
  17. /// ListView widget renders a list of data.
  18. /// </summary>
  19. /// <remarks>
  20. /// </remarks>
  21. public class ListView : View {
  22. int top;
  23. int selected;
  24. class ListWrapper : IListDataSource {
  25. IList src;
  26. public ListView Container;
  27. public ConsoleDriver Driver;
  28. public ListWrapper (IList source)
  29. {
  30. this.src = source;
  31. }
  32. public int Count => src.Count;
  33. void RenderUstr (ustring ustr, int col, int line, int width)
  34. {
  35. int byteLen = ustr.Length;
  36. int used = 0;
  37. for (int i = 0; i < byteLen;) {
  38. (var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
  39. var count = Rune.ColumnWidth (rune);
  40. if (used+count >= width)
  41. break;
  42. Driver.AddRune (rune);
  43. used += count;
  44. i += size;
  45. }
  46. for (; used < width; used++) {
  47. Driver.AddRune (' ');
  48. }
  49. }
  50. public void Render (int item, int col, int line, int width)
  51. {
  52. Container.Move (col, line);
  53. var t = src [item];
  54. if (t is ustring) {
  55. RenderUstr (t as ustring, col, line, width);
  56. } else if (t is string) {
  57. RenderUstr (t as string, col, line, width);
  58. } else
  59. RenderUstr (((string)t).ToString (), col, line, width);
  60. }
  61. }
  62. IListDataSource source;
  63. /// <summary>
  64. /// Gets or sets the IListDataSource backing this view.
  65. /// </summary>
  66. /// <value>The source.</value>
  67. public IListDataSource Source {
  68. get => source;
  69. set {
  70. if (value == null)
  71. throw new ArgumentNullException ("value");
  72. source = value;
  73. top = 0;
  74. selected = 0;
  75. SetNeedsDisplay ();
  76. }
  77. }
  78. bool allowsMarking;
  79. /// <summary>
  80. /// Gets or sets a value indicating whether this <see cref="T:Terminal.Gui.ListView"/> allows items to be marked.
  81. /// </summary>
  82. /// <value><c>true</c> if allows marking elements of the list; otherwise, <c>false</c>.</value>
  83. public bool AllowsMarking {
  84. get => allowsMarking;
  85. set {
  86. allowsMarking = value;
  87. SetNeedsDisplay ();
  88. }
  89. }
  90. /// <summary>
  91. /// Gets or sets the item that is displayed at the top of the listview
  92. /// </summary>
  93. /// <value>The top item.</value>
  94. public int TopItem {
  95. get => top;
  96. set {
  97. if (top < 0 || top >= source.Count)
  98. throw new ArgumentException ("value");
  99. top = value;
  100. SetNeedsDisplay ();
  101. }
  102. }
  103. /// <summary>
  104. /// Gets or sets the currently selecteded item.
  105. /// </summary>
  106. /// <value>The selected item.</value>
  107. public int SelectedItem {
  108. get => selected;
  109. set {
  110. if (selected < 0 || selected >= source.Count)
  111. throw new ArgumentException ("value");
  112. selected = value;
  113. if (selected < top)
  114. top = selected;
  115. else if (selected >= top + Frame.Height)
  116. top = selected;
  117. }
  118. }
  119. static IListDataSource MakeWrapper (IList source)
  120. {
  121. return new ListWrapper (source);
  122. }
  123. public ListView (Rect rect, IList source, (ustring title, int width) [] headers = null) : this (rect, MakeWrapper (source), headers)
  124. {
  125. ((ListWrapper)(Source)).Container = this;
  126. ((ListWrapper)(Source)).Driver = Driver;
  127. }
  128. public ListView (Rect rect, IListDataSource source, (ustring title, int width) [] headers = null) : base (rect)
  129. {
  130. if (source == null)
  131. throw new ArgumentNullException (nameof (source));
  132. Source = source;
  133. }
  134. }
  135. }