mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
@@ -87,8 +87,8 @@ public class TreeTableSource<T> : IEnumerableTableSource<T>, IDisposable where T
|
|||||||
Branch<T> branch = RowToBranch (row);
|
Branch<T> branch = RowToBranch (row);
|
||||||
|
|
||||||
// Everything on line before the expansion run and branch text
|
// Everything on line before the expansion run and branch text
|
||||||
Rune [] prefix = branch.GetLinePrefix (Application.Driver).ToArray ();
|
Rune [] prefix = branch.GetLinePrefix ().ToArray ();
|
||||||
Rune expansion = branch.GetExpandableSymbol (Application.Driver);
|
Rune expansion = branch.GetExpandableSymbol ();
|
||||||
string lineBody = _tree.AspectGetter (branch.Model) ?? "";
|
string lineBody = _tree.AspectGetter (branch.Model) ?? "";
|
||||||
|
|
||||||
var sb = new StringBuilder ();
|
var sb = new StringBuilder ();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
namespace Terminal.Gui;
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Terminal.Gui;
|
||||||
|
|
||||||
internal class Branch<T> where T : class
|
internal class Branch<T> where T : class
|
||||||
{
|
{
|
||||||
private readonly TreeView<T> tree;
|
private readonly TreeView<T> _tree;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Declares a new branch of <paramref name="tree"/> in which the users object <paramref name="model"/> is
|
/// Declares a new branch of <paramref name="tree"/> in which the users object <paramref name="model"/> is
|
||||||
@@ -11,9 +13,9 @@ internal class Branch<T> where T : class
|
|||||||
/// <param name="tree">The UI control in which the branch resides.</param>
|
/// <param name="tree">The UI control in which the branch resides.</param>
|
||||||
/// <param name="parentBranchIfAny">Pass null for root level branches, otherwise pass the parent.</param>
|
/// <param name="parentBranchIfAny">Pass null for root level branches, otherwise pass the parent.</param>
|
||||||
/// <param name="model">The user's object that should be displayed.</param>
|
/// <param name="model">The user's object that should be displayed.</param>
|
||||||
public Branch (TreeView<T> tree, Branch<T> parentBranchIfAny, T model)
|
public Branch (TreeView<T> tree, Branch<T>? parentBranchIfAny, T model)
|
||||||
{
|
{
|
||||||
this.tree = tree;
|
_tree = tree;
|
||||||
Model = model;
|
Model = model;
|
||||||
|
|
||||||
if (parentBranchIfAny is { })
|
if (parentBranchIfAny is { })
|
||||||
@@ -27,7 +29,7 @@ internal class Branch<T> where T : class
|
|||||||
/// The children of the current branch. This is null until the first call to <see cref="FetchChildren"/> to avoid
|
/// The children of the current branch. This is null until the first call to <see cref="FetchChildren"/> to avoid
|
||||||
/// enumerating the entire underlying hierarchy.
|
/// enumerating the entire underlying hierarchy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<T, Branch<T>> ChildBranches { get; set; }
|
public List<Branch<T>>? ChildBranches { get; set; }
|
||||||
|
|
||||||
/// <summary>The depth of the current branch. Depth of 0 indicates root level branches.</summary>
|
/// <summary>The depth of the current branch. Depth of 0 indicates root level branches.</summary>
|
||||||
public int Depth { get; }
|
public int Depth { get; }
|
||||||
@@ -39,7 +41,7 @@ internal class Branch<T> where T : class
|
|||||||
public T Model { get; private set; }
|
public T Model { get; private set; }
|
||||||
|
|
||||||
/// <summary>The parent <see cref="Branch{T}"/> or null if it is a root.</summary>
|
/// <summary>The parent <see cref="Branch{T}"/> or null if it is a root.</summary>
|
||||||
public Branch<T> Parent { get; }
|
public Branch<T>? Parent { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if the current branch can be expanded according to the <see cref="TreeBuilder{T}"/> or cached
|
/// Returns true if the current branch can be expanded according to the <see cref="TreeBuilder{T}"/> or cached
|
||||||
@@ -52,13 +54,13 @@ internal class Branch<T> where T : class
|
|||||||
if (ChildBranches is null)
|
if (ChildBranches is null)
|
||||||
{
|
{
|
||||||
//if there is a rapid method for determining whether there are children
|
//if there is a rapid method for determining whether there are children
|
||||||
if (tree.TreeBuilder.SupportsCanExpand)
|
if (_tree.TreeBuilder.SupportsCanExpand)
|
||||||
{
|
{
|
||||||
return tree.TreeBuilder.CanExpand (Model);
|
return _tree.TreeBuilder.CanExpand (Model);
|
||||||
}
|
}
|
||||||
|
|
||||||
//there is no way of knowing whether we can expand without fetching the children
|
//there is no way of knowing whether we can expand without fetching the children
|
||||||
FetchChildren ();
|
ChildBranches = FetchChildren ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//we fetched or already know the children, so return whether we have any
|
//we fetched or already know the children, so return whether we have any
|
||||||
@@ -69,32 +71,30 @@ internal class Branch<T> where T : class
|
|||||||
public void Collapse () { IsExpanded = false; }
|
public void Collapse () { IsExpanded = false; }
|
||||||
|
|
||||||
/// <summary>Renders the current <see cref="Model"/> on the specified line <paramref name="y"/>.</summary>
|
/// <summary>Renders the current <see cref="Model"/> on the specified line <paramref name="y"/>.</summary>
|
||||||
/// <param name="driver"></param>
|
|
||||||
/// <param name="colorScheme"></param>
|
|
||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <param name="availableWidth"></param>
|
/// <param name="availableWidth"></param>
|
||||||
public virtual void Draw (IConsoleDriver driver, ColorScheme colorScheme, int y, int availableWidth)
|
public virtual void Draw (int y, int availableWidth)
|
||||||
{
|
{
|
||||||
List<Cell> cells = new ();
|
List<Cell> cells = new ();
|
||||||
int? indexOfExpandCollapseSymbol = null;
|
int? indexOfExpandCollapseSymbol = null;
|
||||||
int indexOfModelText;
|
int indexOfModelText;
|
||||||
|
|
||||||
// true if the current line of the tree is the selected one and control has focus
|
// true if the current line of the tree is the selected one and control has focus
|
||||||
bool isSelected = tree.IsSelected (Model);
|
bool isSelected = _tree.IsSelected (Model);
|
||||||
|
|
||||||
Attribute textColor =
|
Attribute textColor =
|
||||||
isSelected ? tree.HasFocus ? colorScheme.Focus : colorScheme.HotNormal : colorScheme.Normal;
|
isSelected ? _tree.HasFocus ? _tree.GetFocusColor () : _tree.GetHotNormalColor () : _tree.GetNormalColor ();
|
||||||
Attribute symbolColor = tree.Style.HighlightModelTextOnly ? colorScheme.Normal : textColor;
|
Attribute symbolColor = _tree.Style.HighlightModelTextOnly ? _tree.GetNormalColor () : textColor;
|
||||||
|
|
||||||
// Everything on line before the expansion run and branch text
|
// Everything on line before the expansion run and branch text
|
||||||
Rune [] prefix = GetLinePrefix (driver).ToArray ();
|
Rune [] prefix = GetLinePrefix ().ToArray ();
|
||||||
Rune expansion = GetExpandableSymbol (driver);
|
Rune expansion = GetExpandableSymbol ();
|
||||||
string lineBody = tree.AspectGetter (Model) ?? "";
|
string lineBody = _tree.AspectGetter (Model) ?? "";
|
||||||
|
|
||||||
tree.Move (0, y);
|
_tree.Move (0, y);
|
||||||
|
|
||||||
// if we have scrolled to the right then bits of the prefix will have disappeared off the screen
|
// if we have scrolled to the right then bits of the prefix will have disappeared off the screen
|
||||||
int toSkip = tree.ScrollOffsetHorizontal;
|
int toSkip = _tree.ScrollOffsetHorizontal;
|
||||||
Attribute attr = symbolColor;
|
Attribute attr = symbolColor;
|
||||||
|
|
||||||
// Draw the line prefix (all parallel lanes or whitespace and an expand/collapse/leaf symbol)
|
// Draw the line prefix (all parallel lanes or whitespace and an expand/collapse/leaf symbol)
|
||||||
@@ -112,20 +112,20 @@ internal class Branch<T> where T : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pick color for expanded symbol
|
// pick color for expanded symbol
|
||||||
if (tree.Style.ColorExpandSymbol || tree.Style.InvertExpandSymbolColors)
|
if (_tree.Style.ColorExpandSymbol || _tree.Style.InvertExpandSymbolColors)
|
||||||
{
|
{
|
||||||
Attribute color = symbolColor;
|
Attribute color;
|
||||||
|
|
||||||
if (tree.Style.ColorExpandSymbol)
|
if (_tree.Style.ColorExpandSymbol)
|
||||||
{
|
{
|
||||||
if (isSelected)
|
if (isSelected)
|
||||||
{
|
{
|
||||||
color = tree.Style.HighlightModelTextOnly ? colorScheme.HotNormal :
|
color = _tree.Style.HighlightModelTextOnly ? _tree.GetHotNormalColor () :
|
||||||
tree.HasFocus ? tree.ColorScheme.HotFocus : tree.ColorScheme.HotNormal;
|
_tree.HasFocus ? _tree.GetHotFocusColor () : _tree.GetHotNormalColor ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
color = tree.ColorScheme.HotNormal;
|
color = _tree.GetHotNormalColor ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -133,9 +133,9 @@ internal class Branch<T> where T : class
|
|||||||
color = symbolColor;
|
color = symbolColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree.Style.InvertExpandSymbolColors)
|
if (_tree.Style.InvertExpandSymbolColors)
|
||||||
{
|
{
|
||||||
color = new Attribute (color.Background, color.Foreground);
|
color = new (color.Background, color.Foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = color;
|
attr = color;
|
||||||
@@ -177,10 +177,10 @@ internal class Branch<T> where T : class
|
|||||||
if (lineBody.EnumerateRunes ().Sum (l => l.GetColumns ()) > availableWidth)
|
if (lineBody.EnumerateRunes ().Sum (l => l.GetColumns ()) > availableWidth)
|
||||||
{
|
{
|
||||||
// remaining space is zero and truncate the line
|
// remaining space is zero and truncate the line
|
||||||
lineBody = new string (
|
lineBody = new (
|
||||||
lineBody.TakeWhile (c => (availableWidth -= ((Rune)c).GetColumns ()) >= 0)
|
lineBody.TakeWhile (c => (availableWidth -= ((Rune)c).GetColumns ()) >= 0)
|
||||||
.ToArray ()
|
.ToArray ()
|
||||||
);
|
);
|
||||||
availableWidth = 0;
|
availableWidth = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -194,9 +194,9 @@ internal class Branch<T> where T : class
|
|||||||
Attribute modelColor = textColor;
|
Attribute modelColor = textColor;
|
||||||
|
|
||||||
// if custom color delegate invoke it
|
// if custom color delegate invoke it
|
||||||
if (tree.ColorGetter is { })
|
if (_tree.ColorGetter is { })
|
||||||
{
|
{
|
||||||
ColorScheme modelScheme = tree.ColorGetter (Model);
|
ColorScheme modelScheme = _tree.ColorGetter (Model);
|
||||||
|
|
||||||
// if custom color scheme is defined for this Model
|
// if custom color scheme is defined for this Model
|
||||||
if (modelScheme is { })
|
if (modelScheme is { })
|
||||||
@@ -206,12 +206,12 @@ internal class Branch<T> where T : class
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modelColor = new Attribute ();
|
modelColor = new ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = modelColor;
|
attr = modelColor;
|
||||||
cells.AddRange (lineBody.Select (r => NewCell (attr, new Rune (r))));
|
cells.AddRange (lineBody.Select (r => NewCell (attr, new (r))));
|
||||||
|
|
||||||
if (availableWidth > 0)
|
if (availableWidth > 0)
|
||||||
{
|
{
|
||||||
@@ -219,7 +219,7 @@ internal class Branch<T> where T : class
|
|||||||
|
|
||||||
cells.AddRange (
|
cells.AddRange (
|
||||||
Enumerable.Repeat (
|
Enumerable.Repeat (
|
||||||
NewCell (attr, new Rune (' ')),
|
NewCell (attr, new (' ')),
|
||||||
availableWidth
|
availableWidth
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -230,32 +230,29 @@ internal class Branch<T> where T : class
|
|||||||
Model = Model,
|
Model = Model,
|
||||||
Y = y,
|
Y = y,
|
||||||
Cells = cells,
|
Cells = cells,
|
||||||
Tree = tree,
|
Tree = _tree,
|
||||||
IndexOfExpandCollapseSymbol =
|
IndexOfExpandCollapseSymbol =
|
||||||
indexOfExpandCollapseSymbol,
|
indexOfExpandCollapseSymbol,
|
||||||
IndexOfModelText = indexOfModelText
|
IndexOfModelText = indexOfModelText
|
||||||
};
|
};
|
||||||
tree.OnDrawLine (e);
|
_tree.OnDrawLine (e);
|
||||||
|
|
||||||
if (!e.Handled && driver != null)
|
if (!e.Handled)
|
||||||
{
|
{
|
||||||
foreach (Cell cell in cells)
|
foreach (Cell cell in cells)
|
||||||
{
|
{
|
||||||
driver.SetAttribute ((Attribute)cell.Attribute!);
|
_tree.SetAttribute ((Attribute)cell.Attribute!);
|
||||||
driver.AddRune (cell.Rune);
|
_tree.AddRune (cell.Rune);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
driver?.SetAttribute (colorScheme.Normal);
|
_tree.SetAttribute (_tree.GetNormalColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Expands the current branch if possible.</summary>
|
/// <summary>Expands the current branch if possible.</summary>
|
||||||
public void Expand ()
|
public void Expand ()
|
||||||
{
|
{
|
||||||
if (ChildBranches is null)
|
ChildBranches ??= FetchChildren ();
|
||||||
{
|
|
||||||
FetchChildren ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ChildBranches.Any ())
|
if (ChildBranches.Any ())
|
||||||
{
|
{
|
||||||
@@ -264,45 +261,44 @@ internal class Branch<T> where T : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Fetch the children of this branch. This method populates <see cref="ChildBranches"/>.</summary>
|
/// <summary>Fetch the children of this branch. This method populates <see cref="ChildBranches"/>.</summary>
|
||||||
public virtual void FetchChildren ()
|
private List<Branch<T>> FetchChildren ()
|
||||||
{
|
{
|
||||||
if (tree.TreeBuilder is null)
|
if (_tree.TreeBuilder is null)
|
||||||
{
|
{
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<T> children;
|
IEnumerable<T> children;
|
||||||
|
|
||||||
if (Depth >= tree.MaxDepth)
|
if (Depth >= _tree.MaxDepth)
|
||||||
{
|
{
|
||||||
children = Enumerable.Empty<T> ();
|
children = [];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
children = tree.TreeBuilder.GetChildren (Model) ?? Enumerable.Empty<T> ();
|
children = _tree.TreeBuilder.GetChildren (Model) ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
ChildBranches = children.ToDictionary (k => k, val => new Branch<T> (tree, this, val));
|
return children.Select (o => new Branch<T> (_tree, this, o)).ToList ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an appropriate symbol for displaying next to the string representation of the <see cref="Model"/>
|
/// Returns an appropriate symbol for displaying next to the string representation of the <see cref="Model"/>
|
||||||
/// object to indicate whether it <see cref="IsExpanded"/> or not (or it is a leaf).
|
/// object to indicate whether it <see cref="IsExpanded"/> or not (or it is a leaf).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="driver"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Rune GetExpandableSymbol (IConsoleDriver driver)
|
public Rune GetExpandableSymbol ()
|
||||||
{
|
{
|
||||||
Rune leafSymbol = tree.Style.ShowBranchLines ? Glyphs.HLine : (Rune)' ';
|
Rune leafSymbol = _tree.Style.ShowBranchLines ? Glyphs.HLine : (Rune)' ';
|
||||||
|
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
return tree.Style.CollapseableSymbol ?? leafSymbol;
|
return _tree.Style.CollapseableSymbol ?? leafSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanExpand ())
|
if (CanExpand ())
|
||||||
{
|
{
|
||||||
return tree.Style.ExpandableSymbol ?? leafSymbol;
|
return _tree.Style.ExpandableSymbol ?? leafSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
return leafSymbol;
|
return leafSymbol;
|
||||||
@@ -313,10 +309,10 @@ internal class Branch<T> where T : class
|
|||||||
/// line body).
|
/// line body).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual int GetWidth (IConsoleDriver driver)
|
public virtual int GetWidth ()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
GetLinePrefix (driver).Sum (r => r.GetColumns ()) + GetExpandableSymbol (driver).GetColumns () + (tree.AspectGetter (Model) ?? "").Length;
|
GetLinePrefix ().Sum (r => r.GetColumns ()) + GetExpandableSymbol ().GetColumns () + (_tree.AspectGetter (Model) ?? "").Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Refreshes cached knowledge in this branch e.g. what children an object has.</summary>
|
/// <summary>Refreshes cached knowledge in this branch e.g. what children an object has.</summary>
|
||||||
@@ -333,41 +329,46 @@ internal class Branch<T> where T : class
|
|||||||
//if we don't know about any children yet just use the normal method
|
//if we don't know about any children yet just use the normal method
|
||||||
if (ChildBranches is null)
|
if (ChildBranches is null)
|
||||||
{
|
{
|
||||||
FetchChildren ();
|
ChildBranches = FetchChildren ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we already knew about some children so preserve the state of the old children
|
// we already knew about some children so preserve the state of the old children
|
||||||
|
|
||||||
// first gather the new Children
|
// first gather the new Children
|
||||||
IEnumerable<T> newChildren = tree.TreeBuilder?.GetChildren (Model) ?? Enumerable.Empty<T> ();
|
T [] newChildren = _tree.TreeBuilder?.GetChildren (Model).ToArray () ?? [];
|
||||||
|
|
||||||
// Children who no longer appear need to go
|
// Children who no longer appear need to go
|
||||||
foreach (T toRemove in ChildBranches.Keys.Except (newChildren).ToArray ())
|
foreach (Branch<T> toRemove in ChildBranches.Where (b => !newChildren.Contains (b.Model)).ToArray ())
|
||||||
{
|
{
|
||||||
ChildBranches.Remove (toRemove);
|
ChildBranches.Remove (toRemove);
|
||||||
|
|
||||||
//also if the user has this node selected (its disappearing) so lets change selection to us (the parent object) to be helpful
|
//also if the user has this node selected (its disappearing) so lets change selection to us (the parent object) to be helpful
|
||||||
if (Equals (tree.SelectedObject, toRemove))
|
if (Equals (_tree.SelectedObject, toRemove.Model))
|
||||||
{
|
{
|
||||||
tree.SelectedObject = Model;
|
_tree.SelectedObject = Model;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New children need to be added
|
// New children need to be added
|
||||||
foreach (T newChild in newChildren)
|
foreach (T newChild in newChildren)
|
||||||
{
|
{
|
||||||
|
Branch<T>? existingBranch = ChildBranches.FirstOrDefault (b => b.Model.Equals (newChild));
|
||||||
|
|
||||||
// If we don't know about the child, yet we need a new branch
|
// If we don't know about the child, yet we need a new branch
|
||||||
if (!ChildBranches.ContainsKey (newChild))
|
if (existingBranch == null)
|
||||||
{
|
{
|
||||||
ChildBranches.Add (newChild, new Branch<T> (tree, this, newChild));
|
ChildBranches.Add (new (_tree, this, newChild));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//we already have this object but update the reference anyway in case Equality match but the references are new
|
//we already have this object but update the reference anyway in case Equality match but the references are new
|
||||||
ChildBranches [newChild].Model = newChild;
|
existingBranch.Model = newChild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Order the list
|
||||||
|
ChildBranches = ChildBranches.OrderBy (b => newChildren.IndexOf (b.Model)).ToList ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,9 +382,9 @@ internal class Branch<T> where T : class
|
|||||||
|
|
||||||
if (ChildBranches is { })
|
if (ChildBranches is { })
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<T, Branch<T>> child in ChildBranches)
|
foreach (Branch<T> child in ChildBranches)
|
||||||
{
|
{
|
||||||
child.Value.CollapseAll ();
|
child.CollapseAll ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,9 +396,9 @@ internal class Branch<T> where T : class
|
|||||||
|
|
||||||
if (ChildBranches is { })
|
if (ChildBranches is { })
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<T, Branch<T>> child in ChildBranches)
|
foreach (Branch<T> child in ChildBranches)
|
||||||
{
|
{
|
||||||
child.Value.ExpandAll ();
|
child.ExpandAll ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,16 +407,15 @@ internal class Branch<T> where T : class
|
|||||||
/// Gets all characters to render prior to the current branches line. This includes indentation whitespace and
|
/// Gets all characters to render prior to the current branches line. This includes indentation whitespace and
|
||||||
/// any tree branches (if enabled).
|
/// any tree branches (if enabled).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="driver"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal IEnumerable<Rune> GetLinePrefix (IConsoleDriver driver)
|
internal IEnumerable<Rune> GetLinePrefix ()
|
||||||
{
|
{
|
||||||
// If not showing line branches or this is a root object.
|
// If not showing line branches or this is a root object.
|
||||||
if (!tree.Style.ShowBranchLines)
|
if (!_tree.Style.ShowBranchLines)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < Depth; i++)
|
for (var i = 0; i < Depth; i++)
|
||||||
{
|
{
|
||||||
yield return new Rune (' ');
|
yield return new (' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
yield break;
|
yield break;
|
||||||
@@ -426,14 +426,14 @@ internal class Branch<T> where T : class
|
|||||||
{
|
{
|
||||||
if (cur.IsLast ())
|
if (cur.IsLast ())
|
||||||
{
|
{
|
||||||
yield return new Rune (' ');
|
yield return new (' ');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
yield return Glyphs.VLine;
|
yield return Glyphs.VLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new Rune (' ');
|
yield return new (' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsLast ())
|
if (IsLast ())
|
||||||
@@ -462,15 +462,15 @@ internal class Branch<T> where T : class
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if we could theoretically expand
|
// if we could theoretically expand
|
||||||
if (!IsExpanded && tree.Style.ExpandableSymbol != default (Rune?))
|
if (!IsExpanded && _tree.Style.ExpandableSymbol != default (Rune?))
|
||||||
{
|
{
|
||||||
return x == GetLinePrefix (driver).Count ();
|
return x == GetLinePrefix ().Count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we could theoretically collapse
|
// if we could theoretically collapse
|
||||||
if (IsExpanded && tree.Style.CollapseableSymbol != default (Rune?))
|
if (IsExpanded && _tree.Style.CollapseableSymbol != default (Rune?))
|
||||||
{
|
{
|
||||||
return x == GetLinePrefix (driver).Count ();
|
return x == GetLinePrefix ().Count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -487,9 +487,9 @@ internal class Branch<T> where T : class
|
|||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
// if we are expanded we need to update the visible children
|
// if we are expanded we need to update the visible children
|
||||||
foreach (KeyValuePair<T, Branch<T>> child in ChildBranches)
|
foreach (Branch<T> child in ChildBranches)
|
||||||
{
|
{
|
||||||
child.Value.Rebuild ();
|
child.Rebuild ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -504,7 +504,7 @@ internal class Branch<T> where T : class
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private IEnumerable<Branch<T>> GetParentBranches ()
|
private IEnumerable<Branch<T>> GetParentBranches ()
|
||||||
{
|
{
|
||||||
Branch<T> cur = Parent;
|
Branch<T>? cur = Parent;
|
||||||
|
|
||||||
while (cur is { })
|
while (cur is { })
|
||||||
{
|
{
|
||||||
@@ -523,11 +523,13 @@ internal class Branch<T> where T : class
|
|||||||
{
|
{
|
||||||
if (Parent is null)
|
if (Parent is null)
|
||||||
{
|
{
|
||||||
return this == tree.roots.Values.LastOrDefault ();
|
return this == _tree.roots.Values.LastOrDefault ();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Parent.ChildBranches.Values.LastOrDefault () == this;
|
Parent.ChildBranches ??= Parent.FetchChildren ();
|
||||||
|
|
||||||
|
return Parent.ChildBranches.LastOrDefault () == this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Cell NewCell (Attribute attr, Rune r) { return new Cell { Rune = r, Attribute = new (attr) }; }
|
private static Cell NewCell (Attribute attr, Rune r) { return new() { Rune = r, Attribute = new (attr) }; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -847,7 +847,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
|||||||
return new T [0];
|
return new T [0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return branch.ChildBranches?.Values?.Select (b => b.Model)?.ToArray () ?? new T [0];
|
return branch.ChildBranches?.Select (b => b.Model)?.ToArray () ?? new T [0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns the maximum width line in the tree including prefix and expansion symbols.</summary>
|
/// <summary>Returns the maximum width line in the tree including prefix and expansion symbols.</summary>
|
||||||
@@ -879,10 +879,10 @@ public class TreeView<T> : View, ITreeView where T : class
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.Skip (ScrollOffsetVertical).Take (Viewport.Height).Max (b => b.GetWidth (Driver));
|
return map.Skip (ScrollOffsetVertical).Take (Viewport.Height).Max (b => b.GetWidth ());
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.Max (b => b.GetWidth (Driver));
|
return map.Max (b => b.GetWidth ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1171,7 +1171,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
|||||||
if (idxToRender < map.Count)
|
if (idxToRender < map.Count)
|
||||||
{
|
{
|
||||||
// Render the line
|
// Render the line
|
||||||
map.ElementAt (idxToRender).Draw (Driver, ColorScheme, line, Viewport.Width);
|
map.ElementAt (idxToRender).Draw (line, Viewport.Width);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1488,7 +1488,7 @@ public class TreeView<T> : View, ITreeView where T : class
|
|||||||
|
|
||||||
if (currentBranch.IsExpanded)
|
if (currentBranch.IsExpanded)
|
||||||
{
|
{
|
||||||
foreach (Branch<T> subBranch in currentBranch.ChildBranches.Values)
|
foreach (Branch<T> subBranch in currentBranch.ChildBranches)
|
||||||
{
|
{
|
||||||
foreach (Branch<T> sub in AddToLineMap (subBranch, weMatch, out bool childMatch))
|
foreach (Branch<T> sub in AddToLineMap (subBranch, weMatch, out bool childMatch))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests.Parallelizable",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerminalGuiFluentTesting", "TerminalGuiFluentTesting\TerminalGuiFluentTesting.csproj", "{2DBA7BDC-17AE-474B-A507-00807D087607}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerminalGuiFluentTesting", "TerminalGuiFluentTesting\TerminalGuiFluentTesting.csproj", "{2DBA7BDC-17AE-474B-A507-00807D087607}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerminalGuiFluentTesting.Xunit", "TerminalGuiFluentTesting.Xunit\TerminalGuiFluentTesting.Xunit.csproj", "{231B9723-10F3-46DB-8EAE-50C0C0375AD3}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -123,6 +125,10 @@ Global
|
|||||||
{2DBA7BDC-17AE-474B-A507-00807D087607}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{2DBA7BDC-17AE-474B-A507-00807D087607}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2DBA7BDC-17AE-474B-A507-00807D087607}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{2DBA7BDC-17AE-474B-A507-00807D087607}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2DBA7BDC-17AE-474B-A507-00807D087607}.Release|Any CPU.Build.0 = Release|Any CPU
|
{2DBA7BDC-17AE-474B-A507-00807D087607}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{231B9723-10F3-46DB-8EAE-50C0C0375AD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{231B9723-10F3-46DB-8EAE-50C0C0375AD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{231B9723-10F3-46DB-8EAE-50C0C0375AD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{231B9723-10F3-46DB-8EAE-50C0C0375AD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\TerminalGuiFluentTesting\TerminalGuiFluentTesting.csproj" />
|
||||||
|
<PackageReference Include="xunit" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
25
TerminalGuiFluentTesting.Xunit/XunitContextExtensions.cs
Normal file
25
TerminalGuiFluentTesting.Xunit/XunitContextExtensions.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace TerminalGuiFluentTesting;
|
||||||
|
|
||||||
|
public static class XunitContextExtensions
|
||||||
|
{
|
||||||
|
public static GuiTestContext AssertTrue (this GuiTestContext context, bool? condition)
|
||||||
|
{
|
||||||
|
context.Then (
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Assert.True (condition);
|
||||||
|
});
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
public static GuiTestContext AssertEqual (this GuiTestContext context, object? expected, object? actual)
|
||||||
|
{
|
||||||
|
context.Then (
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Assert.Equal (expected,actual);
|
||||||
|
});
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -243,7 +243,18 @@ public class GuiTestContext : IDisposable
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public GuiTestContext Then (Action doAction)
|
public GuiTestContext Then (Action doAction)
|
||||||
{
|
{
|
||||||
doAction ();
|
try
|
||||||
|
{
|
||||||
|
doAction ();
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
Stop ();
|
||||||
|
_hardStop.Cancel();
|
||||||
|
|
||||||
|
throw;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -360,6 +371,7 @@ public class GuiTestContext : IDisposable
|
|||||||
{
|
{
|
||||||
SendNetKey (k);
|
SendNetKey (k);
|
||||||
}
|
}
|
||||||
|
WaitIteration ();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException ();
|
throw new ArgumentOutOfRangeException ();
|
||||||
@@ -550,4 +562,25 @@ public class GuiTestContext : IDisposable
|
|||||||
|
|
||||||
WaitIteration ();
|
WaitIteration ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the input focus to the given <see cref="View"/>.
|
||||||
|
/// Throws <see cref="ArgumentException"/> if focus did not change due to system
|
||||||
|
/// constraints e.g. <paramref name="toFocus"/>
|
||||||
|
/// <see cref="View.CanFocus"/> is <see langword="false"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="toFocus"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentException"></exception>
|
||||||
|
public GuiTestContext Focus (View toFocus)
|
||||||
|
{
|
||||||
|
toFocus.FocusDeepest (NavigationDirection.Forward, TabBehavior.TabStop);
|
||||||
|
|
||||||
|
if (!toFocus.HasFocus)
|
||||||
|
{
|
||||||
|
throw new ArgumentException ("Failed to set focus, FocusDeepest did not result in HasFocus becoming true. Ensure view is added and focusable");
|
||||||
|
}
|
||||||
|
|
||||||
|
return WaitIteration ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Text;
|
using Terminal.Gui;
|
||||||
using Terminal.Gui;
|
|
||||||
using TerminalGuiFluentTesting;
|
using TerminalGuiFluentTesting;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
@@ -9,17 +8,6 @@ public class BasicFluentAssertionTests
|
|||||||
{
|
{
|
||||||
private readonly TextWriter _out;
|
private readonly TextWriter _out;
|
||||||
|
|
||||||
public class TestOutputWriter : TextWriter
|
|
||||||
{
|
|
||||||
private readonly ITestOutputHelper _output;
|
|
||||||
|
|
||||||
public TestOutputWriter (ITestOutputHelper output) { _output = output; }
|
|
||||||
|
|
||||||
public override void WriteLine (string? value) { _output.WriteLine (value ?? string.Empty); }
|
|
||||||
|
|
||||||
public override Encoding Encoding => Encoding.UTF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicFluentAssertionTests (ITestOutputHelper outputHelper) { _out = new TestOutputWriter (outputHelper); }
|
public BasicFluentAssertionTests (ITestOutputHelper outputHelper) { _out = new TestOutputWriter (outputHelper); }
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|||||||
15
Tests/IntegrationTests/FluentTests/TestOutputWriter.cs
Normal file
15
Tests/IntegrationTests/FluentTests/TestOutputWriter.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace IntegrationTests.FluentTests;
|
||||||
|
|
||||||
|
public class TestOutputWriter : TextWriter
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
|
||||||
|
public TestOutputWriter (ITestOutputHelper output) { _output = output; }
|
||||||
|
|
||||||
|
public override void WriteLine (string? value) { _output.WriteLine (value ?? string.Empty); }
|
||||||
|
|
||||||
|
public override Encoding Encoding => Encoding.UTF8;
|
||||||
|
}
|
||||||
162
Tests/IntegrationTests/FluentTests/TreeViewFluentTests.cs
Normal file
162
Tests/IntegrationTests/FluentTests/TreeViewFluentTests.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
using Terminal.Gui;
|
||||||
|
using TerminalGuiFluentTesting;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace IntegrationTests.FluentTests;
|
||||||
|
|
||||||
|
public class TreeViewFluentTests
|
||||||
|
{
|
||||||
|
private readonly TextWriter _out;
|
||||||
|
|
||||||
|
public TreeViewFluentTests (ITestOutputHelper outputHelper) { _out = new TestOutputWriter (outputHelper); }
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[ClassData (typeof (V2TestDrivers))]
|
||||||
|
public void TreeView_AllowReOrdering (V2TestDriver d)
|
||||||
|
{
|
||||||
|
var tv = new TreeView
|
||||||
|
{
|
||||||
|
Width = Dim.Fill (),
|
||||||
|
Height = Dim.Fill ()
|
||||||
|
};
|
||||||
|
|
||||||
|
TreeNode car;
|
||||||
|
TreeNode lorry;
|
||||||
|
TreeNode bike;
|
||||||
|
|
||||||
|
var root = new TreeNode ("Root")
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
[
|
||||||
|
car = new ("Car"),
|
||||||
|
lorry = new ("Lorry"),
|
||||||
|
bike = new ("Bike")
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
tv.AddObject (root);
|
||||||
|
|
||||||
|
using GuiTestContext context =
|
||||||
|
With.A<Window> (40, 10, d)
|
||||||
|
.Add (tv)
|
||||||
|
.Focus (tv)
|
||||||
|
.WaitIteration ()
|
||||||
|
.ScreenShot ("Before expanding", _out)
|
||||||
|
.AssertEqual (root, tv.GetObjectOnRow (0))
|
||||||
|
.Then (() => Assert.Null (tv.GetObjectOnRow (1)))
|
||||||
|
.Right ()
|
||||||
|
.ScreenShot ("After expanding", _out)
|
||||||
|
.AssertEqual (root, tv.GetObjectOnRow (0))
|
||||||
|
.AssertEqual (car, tv.GetObjectOnRow (1))
|
||||||
|
.AssertEqual (lorry, tv.GetObjectOnRow (2))
|
||||||
|
.AssertEqual (bike, tv.GetObjectOnRow (3))
|
||||||
|
.Then (
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
// Re order
|
||||||
|
root.Children = [bike, car, lorry];
|
||||||
|
tv.RefreshObject (root);
|
||||||
|
})
|
||||||
|
.WaitIteration ()
|
||||||
|
.ScreenShot ("After re-order", _out)
|
||||||
|
.AssertEqual (root, tv.GetObjectOnRow (0))
|
||||||
|
.AssertEqual (bike, tv.GetObjectOnRow (1))
|
||||||
|
.AssertEqual (car, tv.GetObjectOnRow (2))
|
||||||
|
.AssertEqual (lorry, tv.GetObjectOnRow (3))
|
||||||
|
.WriteOutLogs (_out);
|
||||||
|
|
||||||
|
context.Stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[ClassData (typeof (V2TestDrivers))]
|
||||||
|
public void TreeViewReOrder_PreservesExpansion (V2TestDriver d)
|
||||||
|
{
|
||||||
|
var tv = new TreeView
|
||||||
|
{
|
||||||
|
Width = Dim.Fill (),
|
||||||
|
Height = Dim.Fill ()
|
||||||
|
};
|
||||||
|
|
||||||
|
TreeNode car;
|
||||||
|
TreeNode lorry;
|
||||||
|
TreeNode bike;
|
||||||
|
|
||||||
|
TreeNode mrA;
|
||||||
|
TreeNode mrB;
|
||||||
|
|
||||||
|
TreeNode mrC;
|
||||||
|
|
||||||
|
TreeNode mrD;
|
||||||
|
TreeNode mrE;
|
||||||
|
|
||||||
|
var root = new TreeNode ("Root")
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
[
|
||||||
|
car = new ("Car")
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
[
|
||||||
|
mrA = new ("Mr A"),
|
||||||
|
mrB = new ("Mr B")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
lorry = new ("Lorry")
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
[
|
||||||
|
mrC = new ("Mr C")
|
||||||
|
]
|
||||||
|
},
|
||||||
|
bike = new ("Bike")
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
[
|
||||||
|
mrD = new ("Mr D"),
|
||||||
|
mrE = new ("Mr E")
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
tv.AddObject (root);
|
||||||
|
tv.ExpandAll ();
|
||||||
|
|
||||||
|
using GuiTestContext context =
|
||||||
|
With.A<Window> (40, 13, d)
|
||||||
|
.Add (tv)
|
||||||
|
.WaitIteration ()
|
||||||
|
.ScreenShot ("Initial State", _out)
|
||||||
|
.AssertEqual (root, tv.GetObjectOnRow (0))
|
||||||
|
.AssertEqual (car, tv.GetObjectOnRow (1))
|
||||||
|
.AssertEqual (mrA, tv.GetObjectOnRow (2))
|
||||||
|
.AssertEqual (mrB, tv.GetObjectOnRow (3))
|
||||||
|
.AssertEqual (lorry, tv.GetObjectOnRow (4))
|
||||||
|
.AssertEqual (mrC, tv.GetObjectOnRow (5))
|
||||||
|
.AssertEqual (bike, tv.GetObjectOnRow (6))
|
||||||
|
.AssertEqual (mrD, tv.GetObjectOnRow (7))
|
||||||
|
.AssertEqual (mrE, tv.GetObjectOnRow (8))
|
||||||
|
.Then (
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
// Re order
|
||||||
|
root.Children = [bike, car, lorry];
|
||||||
|
tv.RefreshObject (root);
|
||||||
|
})
|
||||||
|
.WaitIteration ()
|
||||||
|
.ScreenShot ("After re-order", _out)
|
||||||
|
.AssertEqual (root, tv.GetObjectOnRow (0))
|
||||||
|
.AssertEqual (bike, tv.GetObjectOnRow (1))
|
||||||
|
.AssertEqual (mrD, tv.GetObjectOnRow (2))
|
||||||
|
.AssertEqual (mrE, tv.GetObjectOnRow (3))
|
||||||
|
.AssertEqual (car, tv.GetObjectOnRow (4))
|
||||||
|
.AssertEqual (mrA, tv.GetObjectOnRow (5))
|
||||||
|
.AssertEqual (mrB, tv.GetObjectOnRow (6))
|
||||||
|
.AssertEqual (lorry, tv.GetObjectOnRow (7))
|
||||||
|
.AssertEqual (mrC, tv.GetObjectOnRow (8))
|
||||||
|
.WriteOutLogs (_out);
|
||||||
|
|
||||||
|
context.Stop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
|
<ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
|
||||||
|
<ProjectReference Include="..\..\TerminalGuiFluentTesting.Xunit\TerminalGuiFluentTesting.Xunit.csproj" />
|
||||||
<ProjectReference Include="..\..\TerminalGuiFluentTesting\TerminalGuiFluentTesting.csproj" />
|
<ProjectReference Include="..\..\TerminalGuiFluentTesting\TerminalGuiFluentTesting.csproj" />
|
||||||
<ProjectReference Include="..\..\UICatalog\UICatalog.csproj" />
|
<ProjectReference Include="..\..\UICatalog\UICatalog.csproj" />
|
||||||
<ProjectReference Include="..\UnitTests\UnitTests.csproj" />
|
<ProjectReference Include="..\UnitTests\UnitTests.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user