diff --git a/Terminal.Gui/Core/SearchCollectionNavigator.cs b/Terminal.Gui/Core/CollectionNavigator.cs
similarity index 94%
rename from Terminal.Gui/Core/SearchCollectionNavigator.cs
rename to Terminal.Gui/Core/CollectionNavigator.cs
index c87865b6e..cc3b1124f 100644
--- a/Terminal.Gui/Core/SearchCollectionNavigator.cs
+++ b/Terminal.Gui/Core/CollectionNavigator.cs
@@ -15,17 +15,17 @@ namespace Terminal.Gui {
/// If the user pauses keystrokes for a short time (250ms), the search string is cleared.
///
///
- public class SearchCollectionNavigator {
+ public class CollectionNavigator {
///
- /// Constructs a new SearchCollectionNavigator.
+ /// Constructs a new CollectionNavigator.
///
- public SearchCollectionNavigator () { }
+ public CollectionNavigator () { }
///
- /// Constructs a new SearchCollectionNavigator for the given collection.
+ /// Constructs a new CollectionNavigator for the given collection.
///
///
- public SearchCollectionNavigator (IEnumerable collection) => Collection = collection;
+ public CollectionNavigator (IEnumerable collection) => Collection = collection;
DateTime lastKeystroke = DateTime.Now;
internal int TypingDelay { get; set; } = 250;
@@ -41,7 +41,7 @@ namespace Terminal.Gui {
public IEnumerable Collection { get; set; }
///
- /// Event arguments for the event.
+ /// Event arguments for the event.
///
public class KeystrokeNavigatorEventArgs {
///
@@ -162,7 +162,7 @@ namespace Terminal.Gui {
/// Set to to stop the search on the first match
/// if there are multiple matches for .
/// e.g. "ca" + 'r' should stay on "car" and not jump to "cart". If (the default),
- /// the next matching item will be returned, even if it is above in the collection.
+ /// the next matching item will be returned, even if it is above in the collection.
///
/// The index of the next matching item or if no match was found.
internal int GetNextMatchingItem (int currentIndex, string search, bool minimizeMovement = false)
diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index 39d2e1ff2..79d2e4121 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -23,7 +23,7 @@
-
+ $(RestoreSources);..\..\NStack\NStack\bin\Debug;https://api.nuget.org/v3/index.json
diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs
index 388def50a..957216837 100644
--- a/Terminal.Gui/Views/ListView.cs
+++ b/Terminal.Gui/Views/ListView.cs
@@ -110,7 +110,7 @@ namespace Terminal.Gui {
get => source;
set {
source = value;
- Navigator.Collection = source?.ToList ()?.Cast ();
+ KeystrokeNavigator.Collection = source?.ToList ()?.Cast ();
top = 0;
selected = 0;
lastSelectedItem = -1;
@@ -383,7 +383,7 @@ namespace Terminal.Gui {
Driver.SetAttribute (current);
}
if (allowsMarking) {
- Driver.AddRune (source.IsMarked (item) ? (AllowsMultipleSelection ? Driver.Checked : Driver.Selected) :
+ Driver.AddRune (source.IsMarked (item) ? (AllowsMultipleSelection ? Driver.Checked : Driver.Selected) :
(AllowsMultipleSelection ? Driver.UnChecked : Driver.UnSelected));
Driver.AddRune (' ');
}
@@ -408,9 +408,10 @@ namespace Terminal.Gui {
public event Action RowRender;
///
- /// Gets the that is used to navigate the when searching.
+ /// Gets the that searches the collection as
+ /// the user types.
///
- public SearchCollectionNavigator Navigator { get; private set; } = new SearchCollectionNavigator ();
+ public CollectionNavigator KeystrokeNavigator { get; private set; } = new CollectionNavigator ();
///
public override bool ProcessKey (KeyEvent kb)
@@ -423,10 +424,10 @@ namespace Terminal.Gui {
if (result != null) {
return (bool)result;
}
-
+
// Enable user to find & select an item by typing text
- if (SearchCollectionNavigator.IsCompatibleKey(kb)) {
- var newItem = Navigator?.GetNextMatchingItem (SelectedItem, (char)kb.KeyValue);
+ if (CollectionNavigator.IsCompatibleKey (kb)) {
+ var newItem = KeystrokeNavigator?.GetNextMatchingItem (SelectedItem, (char)kb.KeyValue);
if (newItem is int && newItem != -1) {
SelectedItem = (int)newItem;
EnsuresVisibilitySelectedItem ();
@@ -840,13 +841,13 @@ namespace Terminal.Gui {
if (src == null || src?.Count == 0) {
return 0;
}
-
+
int maxLength = 0;
for (int i = 0; i < src.Count; i++) {
var t = src [i];
int l;
if (t is ustring u) {
- l = u.RuneCount;
+ l = TextFormatter.GetTextWidth (u);
} else if (t is string s) {
l = s.Length;
} else {
@@ -863,18 +864,10 @@ namespace Terminal.Gui {
void RenderUstr (ConsoleDriver driver, ustring ustr, int col, int line, int width, int start = 0)
{
- int byteLen = ustr.Length;
- int used = 0;
- for (int i = start; i < byteLen;) {
- (var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
- var count = Rune.ColumnWidth (rune);
- if (used + count > width)
- break;
- driver.AddRune (rune);
- used += count;
- i += size;
- }
- for (; used < width; used++) {
+ var u = TextFormatter.ClipAndJustify (ustr, width, TextAlignment.Left);
+ driver.AddStr (u);
+ width -= TextFormatter.GetTextWidth (u);
+ while (width-- > 0) {
driver.AddRune (' ');
}
}
@@ -924,7 +917,7 @@ namespace Terminal.Gui {
if (src == null || src?.Count == 0) {
return -1;
}
-
+
for (int i = 0; i < src.Count; i++) {
var t = src [i];
if (t is ustring u) {
@@ -932,7 +925,7 @@ namespace Terminal.Gui {
return i;
}
} else if (t is string s) {
- if (s.ToUpperInvariant().StartsWith (search.ToUpperInvariant())) {
+ if (s.ToUpperInvariant ().StartsWith (search.ToUpperInvariant ())) {
return i;
}
}
diff --git a/Terminal.Gui/Views/TreeView.cs b/Terminal.Gui/Views/TreeView.cs
index 5ccf8b8c1..baab64642 100644
--- a/Terminal.Gui/Views/TreeView.cs
+++ b/Terminal.Gui/Views/TreeView.cs
@@ -547,7 +547,7 @@ namespace Terminal.Gui {
cachedLineMap = new ReadOnlyCollection> (toReturn);
// Update the collection used for search-typing
- Navigator.Collection = cachedLineMap.Select (b => AspectGetter (b.Model)).ToArray ();
+ KeystrokeNavigator.Collection = cachedLineMap.Select (b => AspectGetter (b.Model)).ToArray ();
return cachedLineMap;
}
@@ -565,10 +565,10 @@ namespace Terminal.Gui {
}
///
- /// Gets the that is used to navigate the
- /// when searching with the keyboard.
+ /// Gets the that searches the collection as
+ /// the user types.
///
- public SearchCollectionNavigator Navigator { get; private set; } = new SearchCollectionNavigator ();
+ public CollectionNavigator KeystrokeNavigator { get; private set; } = new CollectionNavigator ();
///
public override bool ProcessKey (KeyEvent keyEvent)
@@ -585,7 +585,7 @@ namespace Terminal.Gui {
}
// If not a keybinding, is the key a searchable key press?
- if (SearchCollectionNavigator.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation) {
+ if (CollectionNavigator.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation) {
IReadOnlyCollection> map;
// If there has been a call to InvalidateMap since the last time
@@ -594,7 +594,7 @@ namespace Terminal.Gui {
// Find the current selected object within the tree
var current = map.IndexOf (b => b.Model == SelectedObject);
- var newIndex = Navigator?.GetNextMatchingItem (current, (char)keyEvent.KeyValue);
+ var newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent.KeyValue);
if (newIndex is int && newIndex != -1) {
SelectedObject = map.ElementAt ((int)newIndex).Model;
diff --git a/UICatalog/Properties/launchSettings.json b/UICatalog/Properties/launchSettings.json
index e1f2b1db2..ec419ec20 100644
--- a/UICatalog/Properties/launchSettings.json
+++ b/UICatalog/Properties/launchSettings.json
@@ -45,7 +45,7 @@
"commandName": "WSL2",
"distributionName": ""
},
- "SearchCollectionNavigatorTester": {
+ "CollectionNavigatorTester": {
"commandName": "Project",
"commandLineArgs": "\"Search Collection Nav\""
}
diff --git a/UICatalog/Scenario.cs b/UICatalog/Scenario.cs
index c747829e3..30767e190 100644
--- a/UICatalog/Scenario.cs
+++ b/UICatalog/Scenario.cs
@@ -233,7 +233,7 @@ namespace UICatalog {
}
///
- /// Returns an instance of each defined in the project.
+ /// Returns a list of all instanaces defined in the project, sorted by .
/// https://stackoverflow.com/questions/5411694/get-all-inherited-classes-of-an-abstract-class
///
public static List GetScenarios ()
@@ -245,7 +245,7 @@ namespace UICatalog {
objects.Add (scenario);
_maxScenarioNameLen = Math.Max (_maxScenarioNameLen, scenario.GetName ().Length + 1);
}
- return objects;
+ return objects.OrderBy (s => s.GetName ()).ToList ();
}
protected virtual void Dispose (bool disposing)
diff --git a/UICatalog/Scenarios/SearchCollectionNavigatorTester.cs b/UICatalog/Scenarios/CollectionNavigatorTester.cs
similarity index 87%
rename from UICatalog/Scenarios/SearchCollectionNavigatorTester.cs
rename to UICatalog/Scenarios/CollectionNavigatorTester.cs
index 74dde8aef..d97f6890c 100644
--- a/UICatalog/Scenarios/SearchCollectionNavigatorTester.cs
+++ b/UICatalog/Scenarios/CollectionNavigatorTester.cs
@@ -6,13 +6,13 @@ using Terminal.Gui.Trees;
namespace UICatalog.Scenarios {
- [ScenarioMetadata (Name: "Search Collection Nav", Description: "Demonstrates & tests SearchCollectionNavigator.")]
- [ScenarioCategory ("Controls"),
- ScenarioCategory ("ListView"),
- ScenarioCategory ("TreeView"),
+ [ScenarioMetadata (Name: "Collection Navigator", Description: "Demonstrates keyboard navigation in ListView & TreeView (CollectionNavigator).")]
+ [ScenarioCategory ("Controls"),
+ ScenarioCategory ("ListView"),
+ ScenarioCategory ("TreeView"),
ScenarioCategory ("Text and Formatting"),
ScenarioCategory ("Mouse and Keyboard")]
- public class SearchCollectionNavigatorTester : Scenario {
+ public class CollectionNavigatorTester : Scenario {
// Don't create a Window, just return the top-level view
public override void Init (Toplevel top, ColorScheme colorScheme)
@@ -70,6 +70,9 @@ namespace UICatalog.Scenarios {
"egg",
"candle",
" <- space",
+ "\t<- tab",
+ "\n<- newline",
+ "\r<- formfeed",
"q",
"quit",
"quitter"
@@ -141,7 +144,7 @@ namespace UICatalog.Scenarios {
_listView.SetSource (_items);
- _listView.Navigator.SearchStringChanged += (state) => {
+ _listView.KeystrokeNavigator.SearchStringChanged += (state) => {
label.Text = $"ListView: {state.SearchString}";
};
}
@@ -169,16 +172,16 @@ namespace UICatalog.Scenarios {
};
Top.Add (_treeView);
- var root = new TreeNode ("Alpha examples");
+ var root = new TreeNode ("IsLetterOrDigit examples");
root.Children = _items.Where (i => char.IsLetterOrDigit (i [0])).Select (i => new TreeNode (i)).Cast ().ToList ();
_treeView.AddObject (root);
- root = new TreeNode ("Non-Alpha examples");
+ root = new TreeNode ("Non-IsLetterOrDigit examples");
root.Children = _items.Where (i => !char.IsLetterOrDigit (i [0])).Select (i => new TreeNode (i)).Cast ().ToList ();
_treeView.AddObject (root);
_treeView.ExpandAll ();
_treeView.GoToFirst ();
- _treeView.Navigator.SearchStringChanged += (state) => {
+ _treeView.KeystrokeNavigator.SearchStringChanged += (state) => {
label.Text = $"TreeView: {state.SearchString}";
};
}
diff --git a/UICatalog/Scenarios/ListViewWithSelection.cs b/UICatalog/Scenarios/ListViewWithSelection.cs
index bd1afc40b..c132cf8f5 100644
--- a/UICatalog/Scenarios/ListViewWithSelection.cs
+++ b/UICatalog/Scenarios/ListViewWithSelection.cs
@@ -21,7 +21,7 @@ namespace UICatalog.Scenarios {
public override void Setup ()
{
- _scenarios = Scenario.GetScenarios ().OrderBy (s => s.GetName ()).ToList ();
+ _scenarios = Scenario.GetScenarios ();
_customRenderCB = new CheckBox ("Use custom rendering") {
X = 0,
diff --git a/UnitTests/SearchCollectionNavigatorTests.cs b/UnitTests/CollectionNavigatorTests.cs
similarity index 94%
rename from UnitTests/SearchCollectionNavigatorTests.cs
rename to UnitTests/CollectionNavigatorTests.cs
index b7e0a4df8..06ebc0000 100644
--- a/UnitTests/SearchCollectionNavigatorTests.cs
+++ b/UnitTests/CollectionNavigatorTests.cs
@@ -2,7 +2,7 @@
using Xunit;
namespace Terminal.Gui.Core {
- public class SearchCollectionNavigatorTests {
+ public class CollectionNavigatorTests {
static string [] simpleStrings = new string []{
"appricot", // 0
"arm", // 1
@@ -14,7 +14,7 @@ namespace Terminal.Gui.Core {
[Fact]
public void ShouldAcceptNegativeOne ()
{
- var n = new SearchCollectionNavigator (simpleStrings);
+ var n = new CollectionNavigator (simpleStrings);
// Expect that index of -1 (i.e. no selection) should work correctly
// and select the first entry of the letter 'b'
@@ -23,7 +23,7 @@ namespace Terminal.Gui.Core {
[Fact]
public void OutOfBoundsShouldBeIgnored ()
{
- var n = new SearchCollectionNavigator (simpleStrings);
+ var n = new CollectionNavigator (simpleStrings);
// Expect saying that index 500 is the current selection should not cause
// error and just be ignored (treated as no selection)
@@ -33,7 +33,7 @@ namespace Terminal.Gui.Core {
[Fact]
public void Cycling ()
{
- var n = new SearchCollectionNavigator (simpleStrings);
+ var n = new CollectionNavigator (simpleStrings);
Assert.Equal (2, n.GetNextMatchingItem (0, 'b'));
Assert.Equal (3, n.GetNextMatchingItem (2, 'b'));
@@ -55,7 +55,7 @@ namespace Terminal.Gui.Core {
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (2, current = n.GetNextMatchingItem (current, 'b')); // match bat
Assert.Equal (4, current = n.GetNextMatchingItem (current, 'b')); // match bbfish
@@ -77,7 +77,7 @@ namespace Terminal.Gui.Core {
"candle"
};
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (2, n.GetNextMatchingItem (0, 't'));
// should match "te" in "text"
@@ -104,7 +104,7 @@ namespace Terminal.Gui.Core {
"candle"
};
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (3, n.GetNextMatchingItem (0, '丗'));
// 丗丙业丞 is as good a match as 丗丙丛
@@ -135,7 +135,7 @@ namespace Terminal.Gui.Core {
"candle"
};
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (3, n.GetNextMatchingItem (0, '@'));
Assert.Equal (3, n.GetNextMatchingItem (3, 'b'));
Assert.Equal (4, n.GetNextMatchingItem (3, 'b'));
@@ -153,7 +153,7 @@ namespace Terminal.Gui.Core {
"candle"
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (strings.IndexOf ("bat"), current = n.GetNextMatchingItem (current, 'b')); // match bat
Assert.Equal (strings.IndexOf ("bat"), current = n.GetNextMatchingItem (current, 'a')); // match bat
Assert.Equal (strings.IndexOf ("bat"), current = n.GetNextMatchingItem (current, 't')); // match bat
@@ -178,7 +178,7 @@ namespace Terminal.Gui.Core {
"appricot"
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (strings.IndexOf ("appricot"), current = n.GetNextMatchingItem (current, 'a'));
Assert.Equal ("a", n.SearchString);
@@ -221,7 +221,7 @@ namespace Terminal.Gui.Core {
"appricot"
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
// No delay
Assert.Equal (strings.IndexOf ("appricot"), current = n.GetNextMatchingItem (current, 'a'));
@@ -271,7 +271,7 @@ namespace Terminal.Gui.Core {
"cart",
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (strings.IndexOf ("$$"), current = n.GetNextMatchingItem (current, "$$", false));
Assert.Equal (strings.IndexOf ("$100.00"), current = n.GetNextMatchingItem (current, "$", false));
Assert.Equal (strings.IndexOf ("$$"), current = n.GetNextMatchingItem (current, "$$", false)); // back to top
@@ -317,7 +317,7 @@ namespace Terminal.Gui.Core {
"cart",
};
int current = 0;
- var n = new SearchCollectionNavigator (strings);
+ var n = new CollectionNavigator (strings);
Assert.Equal (strings.IndexOf ("$$"), current = n.GetNextMatchingItem (current, "$$", true));
Assert.Equal (strings.IndexOf ("$$"), current = n.GetNextMatchingItem (current, "$", true));
Assert.Equal (strings.IndexOf ("$$"), current = n.GetNextMatchingItem (current, "$$", true)); // back to top