2
0
Эх сурвалжийг харах

ComboBox. Supports Unicode. Add dropdown arrow from @BDisp. Support PageUp / PageDown

Ross Ferguson 5 жил өмнө
parent
commit
ef3c020c22

+ 79 - 87
Terminal.Gui/Views/ComboBox.cs

@@ -8,8 +8,6 @@
 using System;
 using System;
 using System.Collections;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Linq;
-
 using NStack;
 using NStack;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
@@ -30,8 +28,11 @@ namespace Terminal.Gui {
 			get => source;
 			get => source;
 			set {
 			set {
 				source = value;
 				source = value;
-				Search_Changed ("");
-				SetNeedsDisplay ();
+
+				if(isAdded) { 
+					Search_Changed ("");
+					SetNeedsDisplay ();
+				}
 			}
 			}
 		}
 		}
 
 
@@ -64,9 +65,8 @@ namespace Terminal.Gui {
 		ustring text = "";
 		ustring text = "";
 		readonly TextField search;
 		readonly TextField search;
 		readonly ListView listview;
 		readonly ListView listview;
-		int height;
-		int width;
 		bool autoHide = true;
 		bool autoHide = true;
+		bool isAdded;
 
 
 		/// <summary>
 		/// <summary>
 		/// Public constructor
 		/// Public constructor
@@ -99,10 +99,7 @@ namespace Terminal.Gui {
 		/// <param name="source"></param>
 		/// <param name="source"></param>
 		public ComboBox (Rect rect, IList source) : base (rect)
 		public ComboBox (Rect rect, IList source) : base (rect)
 		{
 		{
-			this.height = rect.Height;
-			this.width = rect.Width;
-
-			search = new TextField ("") { Width = width };
+			search = new TextField ("") { Width = rect.Width };
 			listview = new ListView (rect, source) { LayoutStyle = LayoutStyle.Computed };
 			listview = new ListView (rect, source) { LayoutStyle = LayoutStyle.Computed };
 
 
 			Initialize ();
 			Initialize ();
@@ -119,8 +116,14 @@ namespace Terminal.Gui {
 			ColorScheme = Colors.Base;
 			ColorScheme = Colors.Base;
 
 
 			search.TextChanged += Search_Changed;
 			search.TextChanged += Search_Changed;
+			search.MouseClick += Search_MouseClick;
+
+			listview.Y = Pos.Bottom (search);
 			listview.OpenSelectedItem += (ListViewItemEventArgs a) => Selected ();
 			listview.OpenSelectedItem += (ListViewItemEventArgs a) => Selected ();
 
 
+			this.Add (listview, search);
+			this.SetFocus (search);
+
 			// On resize
 			// On resize
 			LayoutComplete += (LayoutEventArgs a) => {
 			LayoutComplete += (LayoutEventArgs a) => {
 				search.Width = Bounds.Width;
 				search.Width = Bounds.Width;
@@ -131,11 +134,18 @@ namespace Terminal.Gui {
 			listview.SelectedItemChanged += (ListViewItemEventArgs e) => {
 			listview.SelectedItemChanged += (ListViewItemEventArgs e) => {
 
 
 				if (searchset.Count > 0) {
 				if (searchset.Count > 0) {
-					SetValue ((ustring)searchset [listview.SelectedItem]);
+					SetValue (searchset [listview.SelectedItem]);
 				}
 				}
 			};
 			};
 
 
+			// This is needed in addition to 'Adding' to trigger the capture the Bounds.Width & Height
 			Application.Loaded += (Application.ResizedEventArgs a) => {
 			Application.Loaded += (Application.ResizedEventArgs a) => {
+				SetNeedsLayout ();
+				Search_Changed (Text);
+			};
+
+			Adding += (View v) => {
+
 				// Determine if this view is hosted inside a dialog
 				// Determine if this view is hosted inside a dialog
 				for (View view = this.SuperView; view != null; view = view.SuperView) {
 				for (View view = this.SuperView; view != null; view = view.SuperView) {
 					if (view is Dialog) {
 					if (view is Dialog) {
@@ -144,70 +154,43 @@ namespace Terminal.Gui {
 					}
 					}
 				}
 				}
 
 
-				ResetSearchSet ();
-
 				ColorScheme = autoHide ? Colors.Base : ColorScheme = null;
 				ColorScheme = autoHide ? Colors.Base : ColorScheme = null;
 
 
-				listview.Y = Pos.Bottom (search);
-
-				if (Width != null && width == 0) { // new ComboBox() { Width = 
-					width = Bounds.Width;
-				}
-
-				search.Width = width;
-				listview.Width = CalculateWidth ();
-
-				if (Height != null && height == 0) { // new ComboBox() { Height = 
-					height = Bounds.Height;
-				}
-
-				listview.Height = CalculatetHeight ();
-
 				SetNeedsLayout ();
 				SetNeedsLayout ();
-
-				if (this.Text != null) {
-					Search_Changed (Text);
-				}
+				Search_Changed (Text);
 
 
 				if (autoHide) {
 				if (autoHide) {
 					listview.ColorScheme = Colors.Menu;
 					listview.ColorScheme = Colors.Menu;
 				} else {
 				} else {
 					search.ColorScheme = Colors.Menu;
 					search.ColorScheme = Colors.Menu;
 				}
 				}
-			};
-
-			search.MouseClick += Search_MouseClick;
 
 
-			this.Add (listview, search);
-			this.SetFocus (search);
+				isAdded = true;
+			};
 		}
 		}
 
 
-#if COMBO_FEATURE
 		bool isShow = false;
 		bool isShow = false;
-#endif
 
 
 		private void Search_MouseClick (MouseEventArgs me)
 		private void Search_MouseClick (MouseEventArgs me)
 		{
 		{
-#if !COMBO_FEATURE
-
-			if (me.MouseEvent.Flags != MouseFlags.Button1Clicked)
-				return;
-#else
 			if (me.MouseEvent.X == Bounds.Right - 1 && me.MouseEvent.Y == Bounds.Top && me.MouseEvent.Flags == MouseFlags.Button1Pressed
 			if (me.MouseEvent.X == Bounds.Right - 1 && me.MouseEvent.Y == Bounds.Top && me.MouseEvent.Flags == MouseFlags.Button1Pressed
-			&&  search.Text == "" && autoHide) {
+			&& search.Text == "" && autoHide) {
 
 
 				if (isShow) {
 				if (isShow) {
 					HideList ();
 					HideList ();
 					isShow = false;
 					isShow = false;
 				} else {
 				} else {
-					searchset = Source.ToList().Cast<object>().ToList(); // force deep copy
+					// force deep copy
+					foreach (var item in Source.ToList()) { 
+						searchset.Add (item);
+					}
+
 					ShowList ();
 					ShowList ();
 					isShow = true;
 					isShow = true;
 				}
 				}
+			} else { 
+				SuperView.SetFocus (search);
 			}
 			}
-			else
-#endif
-			SuperView.SetFocus (search);
 		}
 		}
 
 
 		///<inheritdoc/>
 		///<inheritdoc/>
@@ -235,7 +218,6 @@ namespace Terminal.Gui {
 			return true;
 			return true;
 		}
 		}
 
 
-#if COMBO_FEATURE
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		public override void Redraw (Rect bounds)
 		{
 		{
@@ -248,7 +230,7 @@ namespace Terminal.Gui {
 			Move (Bounds.Right - 1, 0);
 			Move (Bounds.Right - 1, 0);
 			Driver.AddRune (Driver.DownArrow);
 			Driver.AddRune (Driver.DownArrow);
 		}
 		}
-#endif
+
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override bool ProcessKey (KeyEvent e)
 		public override bool ProcessKey (KeyEvent e)
 		{
 		{
@@ -262,9 +244,9 @@ namespace Terminal.Gui {
 				return true;
 				return true;
 			}
 			}
 
 
-			if (e.Key == Key.CursorDown && search.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) { // jump to list
+			if (e.Key == Key.CursorDown && search.HasFocus && searchset.Count > 0) { // jump to list
 				this.SetFocus (listview);
 				this.SetFocus (listview);
-				SetValue ((ustring)searchset [listview.SelectedItem]);
+				SetValue (searchset [listview.SelectedItem]);
 				return true;
 				return true;
 			}
 			}
 
 
@@ -279,6 +261,16 @@ namespace Terminal.Gui {
 				return true;
 				return true;
 			}
 			}
 
 
+			if(e.Key == Key.PageDown) { 
+				listview.MovePageDown ();
+				return true;
+			}
+
+			if (e.Key == Key.PageUp) { 
+				listview.MovePageUp ();
+				return true;
+			}
+
 			if (e.Key == Key.Esc) {
 			if (e.Key == Key.Esc) {
 				this.SetFocus (search);
 				this.SetFocus (search);
 				search.Text = text = "";
 				search.Text = text = "";
@@ -298,8 +290,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// The currently selected list item
 		/// The currently selected list item
 		/// </summary>
 		/// </summary>
-		public new ustring Text
-		{
+		public new ustring Text {
 			get {
 			get {
 				return text;
 				return text;
 			}
 			}
@@ -308,10 +299,10 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
-		private void SetValue (ustring text)
+		private void SetValue (object text)
 		{
 		{
 			search.TextChanged -= Search_Changed;
 			search.TextChanged -= Search_Changed;
-			this.text = search.Text = text;
+			this.text = search.Text = text.ToString();
 			search.CursorPosition = 0;
 			search.CursorPosition = 0;
 			search.TextChanged += Search_Changed;
 			search.TextChanged += Search_Changed;
 		}
 		}
@@ -323,9 +314,10 @@ namespace Terminal.Gui {
 				return;
 				return;
 			}
 			}
 
 
-			SetValue ((ustring)searchset [listview.SelectedItem]);
-			search.CursorPosition = search.Text.Length;
+			SetValue (searchset [listview.SelectedItem]);
+			search.CursorPosition = search.Text.RuneCount;
 			Search_Changed (search.Text);
 			Search_Changed (search.Text);
+			OnSelectedChanged ();
 			Reset (keepSearchText: true);
 			Reset (keepSearchText: true);
 		}
 		}
 
 
@@ -338,7 +330,6 @@ namespace Terminal.Gui {
 				search.Text = text = "";
 				search.Text = text = "";
 			}
 			}
 
 
-			OnSelectedChanged ();
 			ResetSearchSet ();
 			ResetSearchSet ();
 
 
 			listview.SetSource (searchset);
 			listview.SetSource (searchset);
@@ -347,16 +338,20 @@ namespace Terminal.Gui {
 			this.SetFocus (search);
 			this.SetFocus (search);
 		}
 		}
 
 
-		private void ResetSearchSet ()
+		private void ResetSearchSet (bool noCopy = false)
 		{
 		{
-			if (autoHide) {
-				if (searchset == null) {
-					searchset = new List<string> ();
-				} else {
-					searchset.Clear ();
-				}
-			} else {
-				searchset = source.ToList ();
+			if (searchset == null) {
+				searchset = new List<object> ();
+			} else { 
+				searchset.Clear ();
+			}
+
+			if (autoHide || noCopy)
+				return;
+
+			// force deep copy
+			foreach (var item in Source.ToList ()) {
+				searchset.Add (item);
 			}
 			}
 		}
 		}
 
 
@@ -366,10 +361,16 @@ namespace Terminal.Gui {
 				return;
 				return;
 			}
 			}
 
 
-			if (string.IsNullOrEmpty (search.Text.ToString ())) {
+			if (ustring.IsNullOrEmpty (search.Text)) {
 				ResetSearchSet ();
 				ResetSearchSet ();
 			} else {
 			} else {
-				searchset = source.ToList ().Cast<object> ().Where (x => x.ToString ().StartsWith (search.Text.ToString (), StringComparison.CurrentCultureIgnoreCase)).ToList ();
+				ResetSearchSet (noCopy: true);
+
+				foreach (var item in source.ToList ()) { // Iterate to preserver object type and force deep copy
+					if (item.ToString().StartsWith (search.Text.ToString(), StringComparison.CurrentCultureIgnoreCase)) { 
+						searchset.Add (item);
+					}
+				}
 			}
 			}
 
 
 			ShowList ();
 			ShowList ();
@@ -380,14 +381,12 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		/// 
 		/// 
 		/// Consider making public
 		/// Consider making public
-		private void ShowList()
+		private void ShowList ()
 		{
 		{
 			listview.SetSource (searchset);
 			listview.SetSource (searchset);
 			listview.Height = CalculatetHeight ();
 			listview.Height = CalculatetHeight ();
-
-			listview.Redraw (new Rect (0, 0, width, height)); // for any view behind this
+			listview.Redraw (new Rect (0, 0, Bounds.Width, Bounds.Height)); // Ensure list shrinks in Dialog
 			this.SuperView?.BringSubviewToFront (this);
 			this.SuperView?.BringSubviewToFront (this);
-
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -395,28 +394,21 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		/// 
 		/// 
 		/// Consider making public
 		/// Consider making public
-		private void HideList()
+		private void HideList ()
 		{
 		{
 			Reset ();
 			Reset ();
 		}
 		}
 
 
-		/// <summary>
-		/// Internal width of search list
-		/// </summary>
-		/// <returns></returns>
-		private int CalculateWidth ()
-		{
-			return autoHide ? Math.Max (1, width - 1) : width;
-		}
-
 		/// <summary>
 		/// <summary>
 		/// Internal height of dynamic search list
 		/// Internal height of dynamic search list
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
 		private int CalculatetHeight ()
 		private int CalculatetHeight ()
 		{
 		{
-			var h = (Height is Dim.DimAbsolute) ? height : Bounds.Height;
-			return Math.Min (Math.Max (0, h - 1), searchset?.Count ?? 0);
+			if (Bounds.Height == 0)
+				return 0;
+
+			return Math.Min (Bounds.Height - 1, searchset?.Count ?? 0);
 		}
 		}
 	}
 	}
 }
 }

+ 1 - 1
UICatalog/Scenarios/AllViewsTester.cs

@@ -369,7 +369,7 @@ namespace UICatalog {
 
 
 			// If the view supports a Source property, set it so we have something to look at
 			// If the view supports a Source property, set it so we have something to look at
 			if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType().GetProperty("Source").PropertyType == typeof(Terminal.Gui.IListDataSource)) {
 			if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType().GetProperty("Source").PropertyType == typeof(Terminal.Gui.IListDataSource)) {
-				var source = new ListWrapper (new List<ustring> () { ustring.Make ("List Item #1"), ustring.Make ("List Item #2"), ustring.Make ("List Item #3")});
+				var source = new ListWrapper (new List<ustring> () { ustring.Make ("Test Text #1"), ustring.Make ("Test Text #2"), ustring.Make ("Test Text #3") });
 				view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
 				view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
 			}
 			}