TextFieldAutoComplete.cs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //
  2. // TextFieldAutoComplete.cs: TextField with AutoComplete
  3. //
  4. // Author:
  5. // Ross Ferguson ([email protected])
  6. //
  7. using System;
  8. using System.Linq;
  9. using System.Collections.Generic;
  10. using NStack;
  11. namespace Terminal.Gui {
  12. /// <summary>
  13. /// TextField with AutoComplete
  14. /// </summary>
  15. public class TextFieldAutoComplete : View {
  16. public event EventHandler<ustring> Changed;
  17. readonly IList<string> listsource;
  18. IList<string> searchset;
  19. readonly TextField search;
  20. readonly ListView listview;
  21. readonly int height;
  22. /// <summary>
  23. /// Public constructor
  24. /// </summary>
  25. /// <param name="x">The x coordinate</param>
  26. /// <param name="y">The y coordinate</param>
  27. /// <param name="w">The width</param>
  28. /// <param name="h">The height</param>
  29. /// <param name="source">Auto completetion source</param>
  30. public TextFieldAutoComplete(int x, int y, int w, int h, IList<string> source) : base()
  31. {
  32. listsource = searchset = source;
  33. height = h;
  34. search = new TextField(x, y, w, "");
  35. search.Changed += Search_Changed;
  36. listview = new ListView(new Rect(x, y + 1, w, Math.Min(height, searchset.Count())), listsource.ToList())
  37. {
  38. //LayoutStyle = LayoutStyle.Computed,
  39. };
  40. this.Add(listview);
  41. this.Add(search);
  42. this.SetFocus(search);
  43. this.OnEnter += (object sender, EventArgs e) => { this.SetFocus(search); };
  44. }
  45. public override bool ProcessKey(KeyEvent e)
  46. {
  47. if (e.Key == Key.Tab)
  48. {
  49. base.ProcessKey(e);
  50. return false; // allow tab-out to next control
  51. }
  52. if (e.Key == Key.Enter)
  53. {
  54. if (Text == null)
  55. return false; // allow tab-out to next control
  56. search.Text = Text;
  57. search.CursorPosition = search.Text.Length;
  58. searchset.Clear();
  59. listview.Clear();
  60. this.SetFocus(search);
  61. Changed?.Invoke(this, search.Text);
  62. return true;
  63. }
  64. if (e.Key == Key.CursorDown && search.HasFocus) // jump to list
  65. {
  66. this.SetFocus(listview);
  67. listview.SelectedItem = 0;
  68. return true;
  69. }
  70. if(e.Key == Key.CursorUp && listview.SelectedItem == 0 && listview.HasFocus) // jump back to search
  71. {
  72. this.SetFocus(search);
  73. return true;
  74. }
  75. // Unix emulation
  76. if (e.Key == Key.ControlU || e.Key == Key.Esc)
  77. {
  78. Reset();
  79. return true;
  80. }
  81. return base.ProcessKey(e);
  82. }
  83. /// <summary>
  84. /// The currenlty selected list item
  85. /// </summary>
  86. public string Text
  87. {
  88. get
  89. {
  90. if (listview.Source.Count == 0 || searchset.Count() == 0)
  91. return search.Text.ToString();
  92. return searchset.ToList()[listview.SelectedItem] as string;
  93. }
  94. }
  95. /// <summary>
  96. /// Reset to full original list
  97. /// </summary>
  98. private void Reset()
  99. {
  100. search.Text = "";
  101. searchset = listsource;
  102. listview.SetSource(searchset.ToList());
  103. this.SetFocus(search);
  104. }
  105. private void Search_Changed(object sender, ustring e)
  106. {
  107. if (string.IsNullOrEmpty(search.Text.ToString()))
  108. searchset = listsource;
  109. else
  110. searchset = listsource.Where(x => x.ToLower().Contains(search.Text.ToString().ToLower())).ToList();
  111. listview.SetSource(searchset.ToList());
  112. listview.Height = Math.Min(height, searchset.Count());
  113. }
  114. }
  115. }