From 1dc0cc6fac98c4eb2529c83422e3597fed9ebb15 Mon Sep 17 00:00:00 2001 From: Ross Ferguson Date: Fri, 15 May 2020 06:04:38 +0100 Subject: [PATCH] Use LayoutStyle.Computed. Add Text setter --- Example/demo.cs | 2 +- Terminal.Gui/Views/TextFieldAutoComplete.cs | 118 +++++++++++++++----- 2 files changed, 91 insertions(+), 29 deletions(-) diff --git a/Example/demo.cs b/Example/demo.cs index 76e24ddbc..0fc148508 100644 --- a/Example/demo.cs +++ b/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 diff --git a/Terminal.Gui/Views/TextFieldAutoComplete.cs b/Terminal.Gui/Views/TextFieldAutoComplete.cs index 3c8c1f210..57befd95c 100644 --- a/Terminal.Gui/Views/TextFieldAutoComplete.cs +++ b/Terminal.Gui/Views/TextFieldAutoComplete.cs @@ -4,6 +4,9 @@ // Author: // Ross Ferguson (ross.c.ferguson@btinternet.com) // +// 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 /// public class TextFieldAutoComplete : View { + /// + /// Changed event, raised when the selection has been confirmed. + /// + /// + /// Client code can hook up to this event, it is + /// raised when the selection has been confirmed. + /// public event EventHandler Changed; readonly IList listsource; IList searchset; + ustring text = ""; readonly TextField search; readonly ListView listview; readonly int height; + readonly int width; /// /// Public constructor @@ -31,23 +43,34 @@ namespace Terminal.Gui { /// The width /// The height /// Auto completetion source - public TextFieldAutoComplete(int x, int y, int w, int h, IList source) : base() + public TextFieldAutoComplete(int x, int y, int w, int h, IList 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 { /// /// The currenlty selected list item /// - 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 { /// 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)); + } + + /// + /// Internal height of dynamic search list + /// + /// + private int CalculatetHeight () + { + return Math.Min (height, searchset.Count); + } + + /// + /// Determine if this view is hosted inside a dialog + /// + /// + private bool IsDialogHosted() + { + for (View v = this.SuperView; v != null; v = v.SuperView) { + + if (v.GetType () == typeof (Dialog)) + return true; + } + return false; } } }