From 4d2ddcf45fea49fcd05a3173676b7d15100707ae Mon Sep 17 00:00:00 2001 From: Ross Ferguson Date: Wed, 3 Jun 2020 17:30:19 +0100 Subject: [PATCH] ComboBox. Support parameterless constructor. Update scenario demo --- Terminal.Gui/Views/ComboBox.cs | 121 +++++++++++++++++++++----- UICatalog/Scenarios/ListsAndCombos.cs | 8 +- 2 files changed, 103 insertions(+), 26 deletions(-) diff --git a/Terminal.Gui/Views/ComboBox.cs b/Terminal.Gui/Views/ComboBox.cs index 5eaad25cb..64d62a95b 100644 --- a/Terminal.Gui/Views/ComboBox.cs +++ b/Terminal.Gui/Views/ComboBox.cs @@ -24,15 +24,28 @@ namespace Terminal.Gui { /// public event EventHandler Changed; - readonly IList listsource; + IList listsource; IList searchset; ustring text = ""; - readonly TextField search; - readonly ListView listview; - readonly int height; - readonly int width; + TextField search; + ListView listview; + int x; + int y; + int height; + int width; bool autoHide = true; + /// + /// Public constructor + /// + public ComboBox () : base() + { + search = new TextField ("") { LayoutStyle = LayoutStyle.Computed }; + listview = new ListView () { LayoutStyle = LayoutStyle.Computed, CanFocus = true /* why? */ }; + + Initialize (); + } + /// /// Public constructor /// @@ -41,24 +54,34 @@ namespace Terminal.Gui { /// The width /// The height /// Auto completion source - public ComboBox(int x, int y, int w, int h, IList source) + public ComboBox (int x, int y, int w, int h, IList source) { - listsource = new List(source); + SetSource (source); + this.x = x; + this.y = y; 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()) - { + search = new TextField (x, y, w, ""); + + listview = new ListView (new Rect (x, y + 1, w, 0), listsource.ToList ()) { LayoutStyle = LayoutStyle.Computed, }; + + Initialize (); + } + + private void Initialize() + { + search.Changed += Search_Changed; + listview.SelectedChanged += (object sender, ListViewItemEventArgs e) => { if(searchset.Count > 0) SetValue (searchset [listview.SelectedItem]); }; - LayoutComplete += (sender, a) => { + // TODO: LayoutComplete event breaks cursor up/down. Revert to Application.Loaded + Application.Loaded += (sender, a) => { // Determine if this view is hosted inside a dialog for (View view = this.SuperView; view != null; view = view.SuperView) { if (view is Dialog) { @@ -70,10 +93,31 @@ namespace Terminal.Gui { searchset = autoHide ? new List () : listsource; // Needs to be re-applied for LayoutStyle.Computed - listview.X = x; - listview.Y = y + 1; - listview.Width = CalculateWidth(); - listview.Height = CalculatetHeight (); + // If Dim or Pos are null, these are the from the parametrized constructor + if (X == null) + listview.X = x; + + if (Y == null) + listview.Y = y + 1; + else + listview.Y = Pos.Bottom (search); + + if (Width == null) + listview.Width = CalculateWidth (); + else { + width = GetDimAsInt (Width); + listview.Width = CalculateWidth (); + } + + if (Height == null) + listview.Height = CalculatetHeight (); + else { + height = GetDimAsInt (Height); + listview.Height = CalculatetHeight (); + } + + if (this.Text != null) + Search_Changed (search, Text); if (autoHide) listview.ColorScheme = Colors.Menu; @@ -83,17 +127,24 @@ namespace Terminal.Gui { search.MouseClick += Search_MouseClick; - this.Add(listview); - this.Add(search); + this.Add(listview, search); this.SetFocus(search); } + /// + /// Set search list source + /// + public void SetSource(IList source) + { + listsource = new List (source); + } + private void Search_MouseClick (object sender, MouseEventEventArgs e) { if (e.MouseEvent.Flags != MouseFlags.Button1Clicked) return; - SuperView.SetFocus (((View)sender)); + SuperView.SetFocus ((View)sender); } /// @@ -128,7 +179,7 @@ namespace Terminal.Gui { Changed?.Invoke (this, text); searchset.Clear(); - listview.SetSource(new List ()); + listview.Clear (); listview.Height = 0; this.SetFocus(search); @@ -141,6 +192,9 @@ namespace Terminal.Gui { return true; } + if (e.Key == Key.CursorUp && search.HasFocus) // stop odd behavior on KeyUp when search has focus + return true; + if (e.Key == Key.CursorUp && listview.HasFocus && listview.SelectedItem == 0 && searchset.Count > 0) // jump back to search { search.CursorPosition = search.Text.Length; @@ -204,6 +258,9 @@ namespace Terminal.Gui { private void Search_Changed (object sender, ustring text) { + if (listsource == null) // Object initialization + return; + if (string.IsNullOrEmpty (search.Text.ToString())) searchset = autoHide ? new List () : listsource; else @@ -226,12 +283,30 @@ namespace Terminal.Gui { } /// - /// Internal width + /// Internal width of search list /// /// - private int CalculateWidth() + private int CalculateWidth () { - return autoHide? Math.Max (1, width - 1) : width; + return autoHide ? Math.Max (1, width - 1) : width; + } + + /// + /// Get DimAbsolute as integer value + /// + /// + /// + private int GetDimAsInt(Dim dim) + { + if (!(dim is Dim.DimAbsolute)) + throw new ArgumentException ("Dim must be an absolute value"); + + // Anchor in the case of DimAbsolute returns absolute value. No documentation on what Anchor() does so not sure if this will change in the future. + // + // TODO: Does Dim need:- + // public static implicit operator int (Dim d) + // + return dim.Anchor (0); } } } diff --git a/UICatalog/Scenarios/ListsAndCombos.cs b/UICatalog/Scenarios/ListsAndCombos.cs index 62b5f38d7..bd41c70d5 100644 --- a/UICatalog/Scenarios/ListsAndCombos.cs +++ b/UICatalog/Scenarios/ListsAndCombos.cs @@ -15,10 +15,9 @@ namespace UICatalog.Scenarios { List items = new List (); foreach (var dir in new [] { "/etc", @"\windows\System32" }) { if (Directory.Exists (dir)) { - items = Directory.GetFiles (dir) + items = Directory.GetFiles (dir).Union(Directory.GetDirectories(dir)) .Select (Path.GetFileName) .Where (x => char.IsLetterOrDigit (x [0])) - .Distinct () .OrderBy (x => x).ToList (); } } @@ -45,11 +44,14 @@ namespace UICatalog.Scenarios { Width = 30 }; - var comboBox = new ComboBox (0, 0, 30, 10, items) { + var comboBox = new ComboBox() { X = Pos.Right(listview) + 1 , Y = Pos.Bottom (lbListView) +1, + Height = 10, Width = 30 }; + comboBox.SetSource (items); + comboBox.Changed += (object sender, ustring text) => lbComboBox.Text = text; Win.Add (lbComboBox, comboBox); }