//
// ListView.cs: ListView control
//
// Authors:
// Miguel de Icaza (miguel@gnome.org)
//
using System;
using System.Collections;
using System.Collections.Generic;
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;
}
}
}