Browse Source

Feature/TextFieldAutoComplete

Ross Ferguson 5 years ago
parent
commit
e04cbf2b97
2 changed files with 152 additions and 0 deletions
  1. 15 0
      Example/demo.cs
  2. 137 0
      Terminal.Gui/Views/TextFieldAutoComplete.cs

+ 15 - 0
Example/demo.cs

@@ -1,5 +1,7 @@
 using Terminal.Gui;
 using System;
+using System.Linq;
+using System.IO;
 using Mono.Terminal;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -410,6 +412,18 @@ static class Demo {
 		}
 		MessageBox.Query (60, 10, "Selected Animals", result == "" ? "No animals selected" : result, "Ok");
 	}
+
+	static void TextFieldAutoCompleteDemo ()
+	{
+		var items = Directory.GetFiles (@"..\..\..\Terminal.Gui", "*.cs", SearchOption.AllDirectories).Select (x => Path.GetFileName (x)).ToList ();
+		var list = new TextFieldAutoComplete (0, 0, 36, 7, items);
+		list.Changed += (object sender, ustring text) => { Application.RequestStop (); };
+
+		var d = new Dialog ("Select source file", 40, 12) { list };
+		Application.Run (d);
+
+		MessageBox.Query (60, 10, "Selected file", list.Text == null ? "Nothing selected" : list.Text, "Ok");
+	}
 	#endregion
 
 
@@ -540,6 +554,7 @@ static class Demo {
 			new MenuBarItem ("_List Demos", new MenuItem [] {
 				new MenuItem ("Select _Multiple Items", "", () => ListSelectionDemo (true)),
 				new MenuItem ("Select _Single Item", "", () => ListSelectionDemo (false)),
+				new MenuItem ("Search Single Item", "", TextFieldAutoCompleteDemo)
 			}),
 			new MenuBarItem ("A_ssorted", new MenuItem [] {
 				new MenuItem ("_Show text alignments", "", () => ShowTextAlignments ()),

+ 137 - 0
Terminal.Gui/Views/TextFieldAutoComplete.cs

@@ -0,0 +1,137 @@
+//
+// TextFieldAutoComplete.cs: TextField with AutoComplete
+//
+// Author:
+//   Ross Ferguson ([email protected])
+//
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using NStack;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// TextField with AutoComplete
+	/// </summary>
+	public class TextFieldAutoComplete : View {
+		public event EventHandler<ustring> Changed;
+
+		readonly IList<string> listsource;
+		IList<string> searchset;
+		readonly TextField search;
+		readonly ListView listview;
+		readonly int height;
+
+		/// <summary>
+		/// Public constructor
+		/// </summary>
+		/// <param name="x">The x coordinate</param>
+		/// <param name="y">The y coordinate</param>
+		/// <param name="w">The width</param>		
+		/// <param name="h">The height</param>
+		/// <param name="source">Auto completetion source</param>
+		public TextFieldAutoComplete(int x, int y, int w, int h, IList<string> source) : base()
+		{
+			listsource = searchset = source;
+			height = h;
+			search = new TextField(x, y, w, "");
+			search.Changed += Search_Changed;
+
+			listview = new ListView(new Rect(x, y + 1, w, Math.Min(height, searchset.Count())), listsource.ToList())
+			{ 
+				//LayoutStyle = LayoutStyle.Computed,
+			};
+			
+			this.Add(listview);
+			this.Add(search);
+			this.SetFocus(search);
+
+			this.OnEnter += (object sender, EventArgs e) => { this.SetFocus(search); };
+		}
+
+		public override bool ProcessKey(KeyEvent e)
+		{
+			if (e.Key == Key.Tab)
+			{
+				base.ProcessKey(e);
+				return false; // allow tab-out to next control
+			}
+		
+			if (e.Key == Key.Enter)
+			{
+				if (Text == null)
+					return false; // allow tab-out to next control
+
+				search.Text = Text;
+				search.CursorPosition = search.Text.Length;
+				searchset.Clear();
+				listview.Clear();
+				this.SetFocus(search);
+
+				Changed?.Invoke(this, search.Text);
+
+				return true;
+			}
+		
+			if (e.Key == Key.CursorDown && search.HasFocus) // jump to list
+			{
+				this.SetFocus(listview);
+				listview.SelectedItem = 0;
+				return true;
+			}
+
+			if(e.Key == Key.CursorUp && listview.SelectedItem == 0 && listview.HasFocus) // jump back to search
+			{
+				this.SetFocus(search);
+				return true;
+			}
+
+			// Unix emulation
+			if (e.Key == Key.ControlU || e.Key == Key.Esc)
+			{
+				Reset();
+				return true;
+			}
+
+			return base.ProcessKey(e);
+		}
+
+		/// <summary>
+		/// The currenlty selected list item
+		/// </summary>
+		public string Text
+		{
+			get
+			{
+				if (listview.Source.Count == 0 || searchset.Count() == 0)
+					return search.Text.ToString();
+
+				return searchset.ToList()[listview.SelectedItem] as string;				
+			}
+		}
+
+		/// <summary>
+		/// Reset to full original list
+		/// </summary>
+		private void Reset()
+		{
+			search.Text = "";
+			searchset = listsource;
+			listview.SetSource(searchset.ToList());
+			this.SetFocus(search);
+		}
+
+		private void Search_Changed(object sender, ustring e)
+		{
+			
+		   if (string.IsNullOrEmpty(search.Text.ToString()))
+				searchset = listsource;
+			else
+				searchset = listsource.Where(x => x.ToLower().Contains(search.Text.ToString().ToLower())).ToList();
+
+			listview.SetSource(searchset.ToList());
+			listview.Height = Math.Min(height,  searchset.Count());
+		}
+	}
+}