Quellcode durchsuchen

Merge branch 'master' of tig:migueldeicaza/gui.cs

Charlie Kindel vor 5 Jahren
Ursprung
Commit
c5cb08b77f
3 geänderte Dateien mit 308 neuen und 0 gelöschten Zeilen
  1. 24 0
      Example/demo.cs
  2. 227 0
      Terminal.Gui/Views/ComboBox.cs
  3. 57 0
      UICatalog/Scenarios/ListsAndCombos.cs

+ 24 - 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,27 @@ static class Demo {
 		}
 		MessageBox.Query (60, 10, "Selected Animals", result == "" ? "No animals selected" : result, "Ok");
 	}
+
+	static void ComboBoxDemo ()
+	{
+		IList<string> items = new List<string> ();
+		foreach (var dir in new [] { "/etc", @"\windows\System32" }) {
+			if (Directory.Exists (dir)) {
+				items = Directory.GetFiles (dir)
+				.Select (Path.GetFileName)
+				.Where (x => char.IsLetterOrDigit (x [0]))
+				.Distinct ()
+				.OrderBy (x => x).ToList ();
+			}
+		}
+		var list = new ComboBox (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.ToString() == "" ? "Nothing selected" : list.Text.ToString(), "Ok");
+	}
 	#endregion
 
 
@@ -540,6 +563,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", "", ComboBoxDemo)
 			}),
 			new MenuBarItem ("A_ssorted", new MenuItem [] {
 				new MenuItem ("_Show text alignments", "", () => ShowTextAlignments ()),

+ 227 - 0
Terminal.Gui/Views/ComboBox.cs

@@ -0,0 +1,227 @@
+//
+// ComboBox.cs: ComboBox control
+//
+// Authors:
+//   Ross Ferguson ([email protected])
+//
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using NStack;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// ComboBox control
+	/// </summary>
+	public class ComboBox : 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;
+		bool autoHide = true;
+
+		/// <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 ComboBox(int x, int y, int w, int h, IList<string> source)
+		{
+			listsource = new List<string>(source);
+			height = h;
+			width = w;
+			search = new TextField(x, y, w, "");
+			search.Changed += Search_Changed;
+
+			listview = new ListView(new Rect(x, y + 1, w, 0), listsource.ToList())
+			{
+				LayoutStyle = LayoutStyle.Computed,
+			};
+			listview.SelectedChanged += (object sender, ListViewItemEventArgs e) => {
+				if(searchset.Count > 0)
+					SetValue (searchset [listview.SelectedItem]);
+			};
+
+			Application.Loaded += (object sender, Application.ResizedEventArgs e) => {
+				// Determine if this view is hosted inside a dialog
+				for (View view = this.SuperView; view != null; view = view.SuperView) {
+					if (view is Dialog) {
+						autoHide = false;
+						break;
+					}
+				}
+
+				searchset = autoHide ? new List<string> () : listsource;
+
+				// Needs to be re-applied for LayoutStyle.Computed
+				listview.X = x;
+				listview.Y = y + 1;
+				listview.Width = CalculateWidth();
+				listview.Height = CalculatetHeight ();
+
+				if (autoHide)
+					listview.ColorScheme = Colors.Menu;
+				else
+					search.ColorScheme = Colors.Menu;
+			};
+
+			this.Add(listview);
+			this.Add(search);
+			this.SetFocus(search);
+		}
+
+		///<inheritdoc cref="OnEnter"/>
+		public override bool OnEnter ()
+		{
+			if (!search.HasFocus)
+				this.SetFocus (search);
+
+			search.CursorPosition = search.Text.Length;
+
+			return true;
+		}
+
+		///<inheritdoc cref="ProcessKey"/>
+		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 && listview.HasFocus) {
+				if (listview.Source.Count == 0 || searchset.Count == 0) {
+					text = "";
+					return true;
+				}
+
+				SetValue( searchset [listview.SelectedItem]);
+				search.CursorPosition = search.Text.Length;
+				Search_Changed (search, search.Text);
+				Changed?.Invoke (this, text);
+
+				searchset.Clear();
+				listview.SetSource(new List<string> ());
+				listview.Height = 0;
+				this.SetFocus(search);
+
+				return true;
+			}
+
+			if (e.Key == Key.CursorDown && search.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) { // jump to list
+				this.SetFocus (listview);
+				SetValue (searchset [listview.SelectedItem]);
+				return true;
+			}
+
+			if (e.Key == Key.CursorUp && listview.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) // jump back to search
+			{
+				search.CursorPosition = search.Text.Length;
+				this.SetFocus (search);
+				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)
+			{
+				Reset();
+				return true;
+			}
+
+			return base.ProcessKey(e);
+		}
+
+		/// <summary>
+		/// The currenlty selected list item
+		/// </summary>
+		public ustring Text
+		{
+			get
+			{
+				return text;
+			}
+			set {
+				search.Text = text = value;
+			}
+		}
+
+		private void SetValue(ustring text)
+		{
+			search.Changed -= Search_Changed;
+			this.text = search.Text = text;
+			search.CursorPosition = 0;
+			search.Changed += Search_Changed;
+		}
+
+		/// <summary>
+		/// Reset to full original list
+		/// </summary>
+		private void Reset()
+		{
+			search.Text = text = "";
+			Changed?.Invoke (this, search.Text);
+			searchset = autoHide ? new List<string> () : listsource;
+
+			listview.SetSource(searchset.ToList());
+			listview.Height = CalculatetHeight ();
+
+			this.SetFocus(search);
+		}
+
+		private void Search_Changed (object sender, ustring text)
+		{
+			if (string.IsNullOrEmpty (search.Text.ToString()))
+				searchset = autoHide ? new List<string> () : listsource;
+			else
+				searchset = listsource.Where (x => x.StartsWith (search.Text.ToString (), StringComparison.CurrentCultureIgnoreCase)).ToList ();
+
+			listview.SetSource (searchset.ToList ());
+			listview.Height = CalculatetHeight ();
+
+			listview.Redraw (new Rect (0, 0, width, height)); // for any view behind this
+			this.SuperView?.BringSubviewToFront (this);
+		}
+
+		/// <summary>
+		/// Internal height of dynamic search list
+		/// </summary>
+		/// <returns></returns>
+		private int CalculatetHeight ()
+		{
+			return Math.Min (height, searchset.Count);
+		}
+
+		/// <summary>
+		/// Internal width
+		/// </summary>
+		/// <returns></returns>
+		private int CalculateWidth()
+		{
+			return autoHide? Math.Max (1, width - 1) : width;
+		}
+	}
+}

+ 57 - 0
UICatalog/Scenarios/ListsAndCombos.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Linq;
+using System.IO;
+using System.Collections.Generic;
+using Terminal.Gui;
+using NStack;
+
+namespace UICatalog.Scenarios {
+	[ScenarioMetadata (Name: "Lists", Description: "Demonstrates list selections")]
+	[ScenarioCategory ("Controls")]
+	class ListsAndCombos : Scenario {
+
+		public override void Setup ()
+		{
+			List<string> items = new List<string> ();
+			foreach (var dir in new [] { "/etc", @"\windows\System32" }) {
+				if (Directory.Exists (dir)) {
+					items = Directory.GetFiles (dir)
+					.Select (Path.GetFileName)
+					.Where (x => char.IsLetterOrDigit (x [0]))
+					.Distinct ()
+					.OrderBy (x => x).ToList ();
+				}
+			}
+
+			// ListView
+			var lbListView = new Label ("Listview") {
+				ColorScheme = Colors.TopLevel,
+				X = 0,
+				Width = 30
+			};
+
+			var listview = new ListView (items) {
+				X = 0,
+				Y = Pos.Bottom (lbListView) + 1,
+				Width = 30
+			};
+			listview.OpenSelectedItem += (object sender, ListViewItemEventArgs e) => lbListView.Text = items [listview.SelectedItem];
+			Win.Add (lbListView, listview);
+
+			// ComboBox
+			var lbComboBox = new Label ("ComboBox") {
+				ColorScheme = Colors.TopLevel,
+				X = Pos.Right (lbListView) + 1,
+				Width = 30
+			};
+
+			var comboBox = new ComboBox (0, 0, 30, 10, items) {
+				X = Pos.Right(listview) + 1 , 
+				Y = Pos.Bottom (lbListView) +1,
+				Width = 30
+			};
+			comboBox.Changed += (object sender, ustring text) => lbComboBox.Text = text;
+			Win.Add (lbComboBox, comboBox);
+		}
+	}
+}