浏览代码

Use LayoutStyle.Computed. Add Text setter

Ross Ferguson 5 年之前
父节点
当前提交
1dc0cc6fac
共有 2 个文件被更改,包括 91 次插入29 次删除
  1. 1 1
      Example/demo.cs
  2. 90 28
      Terminal.Gui/Views/TextFieldAutoComplete.cs

+ 1 - 1
Example/demo.cs

@@ -422,7 +422,7 @@ static class Demo {
 		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");
+		MessageBox.Query (60, 10, "Selected file", list.Text.ToString() == "" ? "Nothing selected" : list.Text.ToString(), "Ok");
 	}
 	#endregion
 

+ 90 - 28
Terminal.Gui/Views/TextFieldAutoComplete.cs

@@ -4,6 +4,9 @@
 // Author:
 //   Ross Ferguson ([email protected])
 //
+// TODO:
+//   * Completion list auto appears when hosted directly in a Window as opposed to a dialog
+//
 
 using System;
 using System.Linq;
@@ -15,13 +18,22 @@ namespace Terminal.Gui {
 	/// TextField with AutoComplete
 	/// </summary>
 	public class TextFieldAutoComplete : View {
+		/// <summary>
+		///   Changed event, raised when the selection has been confirmed.
+		/// </summary>
+		/// <remarks>
+		///   Client code can hook up to this event, it is
+		///   raised when the selection has been confirmed.
+		/// </remarks>
 		public event EventHandler<ustring> Changed;
 
 		readonly IList<string> listsource;
 		IList<string> searchset;
+		ustring text = "";
 		readonly TextField search;
 		readonly ListView listview;
 		readonly int height;
+		readonly int width;
 
 		/// <summary>
 		/// Public constructor
@@ -31,23 +43,34 @@ namespace Terminal.Gui {
 		/// <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()
+		public TextFieldAutoComplete(int x, int y, int w, int h, IList<string> source)
 		{
 			listsource = searchset = source;
 			height = h;
+			width = w;
 			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,
+			listview = new ListView(new Rect(x, y + 1, w, CalculatetHeight()), listsource.ToList())
+			{
+				LayoutStyle = LayoutStyle.Computed,
+				ColorScheme = Colors.Dialog
 			};
-			
+
+			// Needs to be re-applied for LayoutStyle.Computed
+			listview.X = x;
+			listview.Y = y + 1;
+			listview.Width = w;
+			listview.Height = CalculatetHeight ();
+
 			this.Add(listview);
 			this.Add(search);
 			this.SetFocus(search);
 
-			this.OnEnter += (object sender, EventArgs e) => { this.SetFocus(search); };
+			this.OnEnter += (object sender, EventArgs e) => {
+				this.SetFocus(search);
+				search.CursorPosition = search.Text.Length;
+			};
 		}
 
 		public override bool ProcessKey(KeyEvent e)
@@ -57,23 +80,25 @@ namespace Terminal.Gui {
 				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;
+			if (e.Key == Key.Enter && listview.HasFocus) {
+
+				if (listview.Source.Count == 0 || searchset.Count == 0) {
+					text = "";
+					return true;
+				}
+
+				search.Text = text =  searchset [listview.SelectedItem];
 				search.CursorPosition = search.Text.Length;
+				Changed?.Invoke (this, text);
+
 				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);
@@ -87,8 +112,15 @@ namespace Terminal.Gui {
 				return true;
 			}
 
+			if (e.Key == Key.Esc) {
+				this.SetFocus (search);
+				search.Text = text = "";
+				Changed?.Invoke (this, search.Text);
+				return true;
+			}
+
 			// Unix emulation
-			if (e.Key == Key.ControlU || e.Key == Key.Esc)
+			if (e.Key == Key.ControlU)
 			{
 				Reset();
 				return true;
@@ -100,14 +132,14 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// The currenlty selected list item
 		/// </summary>
-		public string Text
+		public ustring Text
 		{
 			get
 			{
-				if (listview.Source.Count == 0 || searchset.Count() == 0)
-					return search.Text.ToString();
-
-				return searchset.ToList()[listview.SelectedItem] as string;				
+				return text;
+			}
+			set {
+				search.Text = text = value;
 			}
 		}
 
@@ -116,22 +148,52 @@ namespace Terminal.Gui {
 		/// </summary>
 		private void Reset()
 		{
-			search.Text = "";
+			search.Text = text = "";
+			Changed?.Invoke (this, search.Text);
 			searchset = listsource;
+
 			listview.SetSource(searchset.ToList());
+			listview.Height = CalculatetHeight ();
+			listview.Redraw (new Rect (0, 0, width, height));
+
 			this.SetFocus(search);
 		}
 
-		private void Search_Changed(object sender, ustring e)
+		private void Search_Changed (object sender, ustring text)
 		{
-			
-		   if (string.IsNullOrEmpty(search.Text.ToString()))
+			// Cannot use text argument as its old value (pre-change)
+			if (string.IsNullOrEmpty (search.Text.ToString())) {
 				searchset = listsource;
+			} 
 			else
-				searchset = listsource.Where(x => x.ToLower().Contains(search.Text.ToString().ToLower())).ToList();
+				searchset = listsource.Where (x => x.StartsWith (search.Text.ToString (), StringComparison.CurrentCultureIgnoreCase)).ToList ();
 
-			listview.SetSource(searchset.ToList());
-			listview.Height = Math.Min(height,  searchset.Count());
+			listview.SetSource (searchset.ToList ());
+			listview.Height = CalculatetHeight ();
+			listview.Redraw (new Rect (0, 0, width, height));
+		}
+
+		/// <summary>
+		/// Internal height of dynamic search list
+		/// </summary>
+		/// <returns></returns>
+		private int CalculatetHeight ()
+		{
+			return Math.Min (height, searchset.Count);
+		}
+
+		/// <summary>
+		/// Determine if this view is hosted inside a dialog
+		/// </summary>
+		/// <returns></returns>
+		private bool IsDialogHosted()
+		{
+			for (View v = this.SuperView; v != null; v = v.SuperView) {
+
+				if (v.GetType () == typeof (Dialog))
+					return true;
+			}
+			return false;
 		}
 	}
 }