diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index cc5419151..099f29d2e 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -31,13 +31,13 @@
-
- ..\packages\NStack.Core.0.7.0\lib\netstandard1.5\NStack.dll
-
..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll
+
+ ..\packages\NStack.Core.0.8.0\lib\netstandard1.5\NStack.dll
+
diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs
index 587c20c44..522ab3ef9 100644
--- a/Terminal.Gui/Views/ListView.cs
+++ b/Terminal.Gui/Views/ListView.cs
@@ -12,15 +12,140 @@ using NStack;
namespace Terminal.Gui {
public interface IListDataSource {
int Count { get; }
-
+ void Render (int item, int col, int line, int width);
}
///
/// ListView widget renders a list of data.
///
+ ///
+ ///
public class ListView : View {
+ int top;
+ int selected;
+
+ class ListWrapper : IListDataSource {
+ IList src;
+ public ListView Container;
+ public ConsoleDriver Driver;
+
+ public ListWrapper (IList source)
+ {
+ this.src = source;
+ }
+
+ public int Count => src.Count;
+
+ void RenderUstr (ustring ustr, int col, int line, int width)
+ {
+ int byteLen = ustr.Length;
+ int used = 0;
+ for (int i = 0; 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++) {
+ Driver.AddRune (' ');
+ }
+ }
+
+ public void Render (int item, int col, int line, int width)
+ {
+ Container.Move (col, line);
+ var t = src [item];
+ if (t is ustring) {
+ RenderUstr (t as ustring, col, line, width);
+ } else if (t is string) {
+ RenderUstr (t as string, col, line, width);
+ } else
+ RenderUstr (((string)t).ToString (), col, line, width);
+ }
+ }
+
+ IListDataSource source;
+ ///
+ /// Gets or sets the IListDataSource backing this view.
+ ///
+ /// The source.
+ public IListDataSource Source {
+ get => source;
+ set {
+ if (value == null)
+ throw new ArgumentNullException ("value");
+ source = value;
+ top = 0;
+ selected = 0;
+ SetNeedsDisplay ();
+ }
+ }
+
+ bool allowsMarking;
+ ///
+ /// Gets or sets a value indicating whether this allows items to be marked.
+ ///
+ /// true if allows marking elements of the list; otherwise, false.
+ public bool AllowsMarking {
+ get => allowsMarking;
+ set {
+ allowsMarking = value;
+ SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// Gets or sets the item that is displayed at the top of the listview
+ ///
+ /// The top item.
+ public int TopItem {
+ get => top;
+ set {
+ if (top < 0 || top >= source.Count)
+ throw new ArgumentException ("value");
+ top = value;
+ SetNeedsDisplay ();
+ }
+ }
+
+ ///
+ /// Gets or sets the currently selecteded item.
+ ///
+ /// The selected item.
+ public int SelectedItem {
+ get => selected;
+ set {
+ if (selected < 0 || selected >= source.Count)
+ throw new ArgumentException ("value");
+ selected = value;
+ if (selected < top)
+ top = selected;
+ else if (selected >= top + Frame.Height)
+ top = selected;
+ }
+ }
+
+
+ static IListDataSource MakeWrapper (IList source)
+ {
+ return new ListWrapper (source);
+ }
+
+ public ListView (Rect rect, IList source, (ustring title, int width) [] headers = null) : this (rect, MakeWrapper (source), headers)
+ {
+ ((ListWrapper)(Source)).Container = this;
+ ((ListWrapper)(Source)).Driver = Driver;
+ }
+
public ListView (Rect rect, IListDataSource source, (ustring title, int width) [] headers = null) : base (rect)
{
+ if (source == null)
+ throw new ArgumentNullException (nameof (source));
+ Source = source;
}
+
}
}
diff --git a/Terminal.Gui/packages.config b/Terminal.Gui/packages.config
index 62939e85c..c86d262a1 100644
--- a/Terminal.Gui/packages.config
+++ b/Terminal.Gui/packages.config
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file