Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TreeView<T> support #280

Merged
merged 15 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions src/Design.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Xml.Linq;
using NLog;
using Terminal.Gui;
Expand Down Expand Up @@ -48,7 +49,6 @@ public class Design
typeof(TableView),
typeof(TabView),
typeof(TreeView),
typeof(TreeView<>),
typeof(Dialog),
};

Expand Down Expand Up @@ -794,7 +794,7 @@ private IEnumerable<Property> LoadDesignableProperties()
yield return this.CreateProperty(nameof(FrameView.Title));
}

if (this.View is TreeView tree)
if (this.View is ITreeView tree)
{
yield return this.CreateSubProperty(nameof(TreeStyle.CollapseableSymbol), nameof(TreeView<ITreeNode>.Style), tree.Style);
yield return this.CreateSubProperty(nameof(TreeStyle.ColorExpandSymbol), nameof(TreeView<ITreeNode>.Style), tree.Style);
Expand All @@ -803,6 +803,13 @@ private IEnumerable<Property> LoadDesignableProperties()
yield return this.CreateSubProperty(nameof(TreeStyle.LeaveLastRow), nameof(TreeView<ITreeNode>.Style), tree.Style);
yield return this.CreateSubProperty(nameof(TreeStyle.ShowBranchLines), nameof(TreeView<ITreeNode>.Style), tree.Style);
}

if (isGenericType && viewType.GetGenericTypeDefinition() == typeof(TreeView<>))
{
var prop = this.CreateTreeObjectsProperty(viewType);
if(((ITreeObjectsProperty)prop).IsSupported())
yield return prop;
}

if (this.View is TableView tv)
{
Expand Down Expand Up @@ -833,6 +840,23 @@ private IEnumerable<Property> LoadDesignableProperties()
}
}

private Property CreateTreeObjectsProperty(Type viewType)
{
if(viewType.GetGenericTypeDefinition() != typeof(TreeView<>))
{
throw new ArgumentException("Method should only be called for TreeView<T>");
}

var tType = viewType.GetGenericArguments()[0];
var propertyType = typeof(TreeObjectsProperty<>).MakeGenericType(tType);

var instance =
Activator.CreateInstance(propertyType, new object?[] { this })
?? throw new Exception($"Failed to construct {propertyType}");

return (Property)instance;
}

private bool ShowTextProperty()
{
// never show Text for root because it's almost certainly a container
Expand Down
4 changes: 2 additions & 2 deletions src/DesignState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public DesignState(Design design)
{
this.Design = design;
this.OriginalScheme = this.Design.View.GetExplicitColorScheme();
this.Design.View.DrawContent += this.DrawContent;
this.Design.View.DrawContentComplete += this.DrawContentComplete;
this.Design.View.Enter += this.Enter;
}

Expand All @@ -49,7 +49,7 @@ private void Enter(object? sender, FocusEventArgs obj)
}
}

private void DrawContent(object? sender, DrawEventArgs r)
private void DrawContentComplete(object? sender, DrawEventArgs r)
{
if (this.Design.View.IsBorderlessContainerView() && Editor.ShowBorders)
{
Expand Down
4 changes: 3 additions & 1 deletion src/FromCode/CodeToView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using NLog;
using Terminal.Gui;
using TerminalGuiDesigner.ToCode;
using static Terminal.Gui.SpinnerStyle;

namespace TerminalGuiDesigner.FromCode;

Expand Down Expand Up @@ -151,7 +152,8 @@ public Assembly CompileAssembly()
var references = new List<MetadataReference>()
{
MetadataReference.CreateFromFile(typeof(View).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Data.DataTable).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.IO.FileSystemInfo).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Linq.Enumerable).Assembly.Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(MarshalByValueComponent).Assembly.Location),
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "mscorlib.dll"),
Expand Down
2 changes: 1 addition & 1 deletion src/Operations/AddViewOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ protected override bool DoImpl()
{
if (selected.IsGenericType)
{
var allowedTTypes = ViewFactory.GetSupportedTTypesForGenericViewOfType(selected).ToArray();
var allowedTTypes = TTypes.GetSupportedTTypesForGenericViewOfType(selected).ToArray();

if(Modals.Get("Enter a Type for <T>", "Choose", true, allowedTTypes, this.TypeNameDelegate, false, null, out var selectedTType) && selectedTType != null)
{
Expand Down
57 changes: 57 additions & 0 deletions src/TTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.CodeDom;
using Terminal.Gui;
using TerminalGuiDesigner.ToCode;

namespace TerminalGuiDesigner
{
/// <summary>
/// Provides knowledge about how to handle different T types for generic
/// views e.g. <see cref="Slider{T}"/>, <see cref="TreeView{T}"/>
/// </summary>
public static class TTypes
{
/// <summary>
/// Returns <see cref="CodeObjectCreateExpression"/> or <see cref="CodePrimitiveExpression"/>
/// or similar that represents <paramref name="value"/>.
/// </summary>
/// <param name="args"></param>
/// <param name="design"></param>
/// <param name="value"></param>
/// <returns></returns>
public static CodeExpression ToCode(CodeDomArgs args, Design design, object? value)
{
if(value == null || value is string || value.GetType().IsValueType)
{
return value.ToCodePrimitiveExpression();
}

if(value is FileSystemInfo fsi)
{
return new CodeObjectCreateExpression(value.GetType(), fsi.ToString().ToCodePrimitiveExpression());
}

throw new NotSupportedException("Value Type ToCode not known" + value.GetType());
}

/// <summary>
/// Returns all Types which can be used with generic view of the given <paramref name="viewType"/>.
/// </summary>
/// <param name="viewType">A generic view type e.g. <see langword="typeof"/>(Slider&lt;&gt;)</param>
/// <returns></returns>
public static IEnumerable<Type> GetSupportedTTypesForGenericViewOfType(Type viewType)
{
if (viewType == typeof(Slider<>))
{
return new[] { typeof(int), typeof(string), typeof(float), typeof(double), typeof(bool) };
}

if (viewType == typeof(TreeView<>))
{
return new[] { typeof(object), typeof(FileSystemInfo) };
}

throw new NotSupportedException($"Generic View {viewType} is not yet supported");
}

}
}
64 changes: 58 additions & 6 deletions src/TerminalGuiDesigner.cd
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<Class Name="TerminalGuiDesigner.Design">
<Position X="3.75" Y="0.5" Width="2.25" />
<TypeIdentifier>
<HashCode>AhABQBACACKBADAHCAAAAEIQAECJhAAgARAABAAAgAg=</HashCode>
<HashCode>AxABQBACAiKBADAnCAAAAEIQAECJhAAgARAABAAAgAg=</HashCode>
<FileName>Design.cs</FileName>
</TypeIdentifier>
<ShowAsAssociation>
Expand All @@ -39,7 +39,7 @@
<Class Name="TerminalGuiDesigner.Operations.AddViewOperation" Collapsed="true" BaseTypeListCollapsed="true">
<Position X="10.75" Y="3.5" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAABAAAAAAAAIhBABAAAAAAAAAAAAACAAA=</HashCode>
<HashCode>AAAAAAAAAAAABAAAAAAAAIhBABABAAAAAAAAAAACAAA=</HashCode>
<FileName>Operations\AddViewOperation.cs</FileName>
</TypeIdentifier>
</Class>
Expand Down Expand Up @@ -84,14 +84,14 @@
<Class Name="TerminalGuiDesigner.UI.Editor">
<Position X="0.5" Y="0.5" Width="1.75" />
<TypeIdentifier>
<HashCode>IQRiB4gQACICNCQgCABAAAIBigMAQAgBEAFAIQAACAI=</HashCode>
<HashCode>IQRiB4gQACICJCQgKABAAAIBigMAQAgBAAEAIQAACAo=</HashCode>
<FileName>UI\Editor.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="TerminalGuiDesigner.ToCode.Property" Collapsed="true">
<Position X="6.5" Y="0.5" Width="1.75" />
<TypeIdentifier>
<HashCode>AAAAEAAAKAABChAEAAAAAAAAAABCAEABAAAAAAAAAAA=</HashCode>
<HashCode>AAAAEAAAKAABChAFAAAAAAEAAABCAEABAAAAAAAAAAA=</HashCode>
<FileName>ToCode\Property.cs</FileName>
</TypeIdentifier>
</Class>
Expand All @@ -112,7 +112,7 @@
<Class Name="TerminalGuiDesigner.ToCode.CodeDomArgs">
<Position X="17.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAgAAABAAAAIAAAAAAAAAAAQAEAACAAAAAAA=</HashCode>
<HashCode>AAAAAAAAAgAAABAAAAIEAAAAAAAAAAQAEAACAAAAAAA=</HashCode>
<FileName>ToCode\CodeDomArgs.cs</FileName>
</TypeIdentifier>
</Class>
Expand Down Expand Up @@ -192,10 +192,62 @@
<FileName>Operations\OperationFactory.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="TerminalGuiDesigner.TTypes">
<Position X="11.5" Y="7.75" Width="3.25" />
<TypeIdentifier>
<HashCode>AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAA=</HashCode>
<FileName>TTypes.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="TerminalGuiDesigner.ToCode.TreeObjectsProperty&lt;T&gt;">
<Position X="8.75" Y="7.75" Width="2.25" />
<Compartments>
<Compartment Name="Methods" Collapsed="true" />
</Compartments>
<InheritanceLine Type="TerminalGuiDesigner.ToCode.Property" ManuallyRouted="true">
<Path>
<Point X="7.375" Y="1.191" />
<Point X="7.375" Y="1.345" />
<Point X="8.398" Y="1.345" />
<Point X="8.398" Y="7.159" />
<Point X="9.875" Y="7.159" />
<Point X="9.875" Y="7.75" />
</Path>
</InheritanceLine>
<TypeIdentifier>
<HashCode>BgBAEAAAIAAAAgIEAAAAAAAAAABAAGAAAAAAAAAAAAA=</HashCode>
<FileName>ToCode\TreeObjectsProperty.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="TerminalGuiDesigner.UI.Windows.ArrayEditor" Collapsed="true">
<Position X="11.5" Y="9.25" Width="1.5" />
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
</Compartments>
<TypeIdentifier>
<HashCode>AAAAgAAAACQgAAEEgAggAAQDACBQBABAAIBAEAAAgAQ=</HashCode>
<FileName>UI\Windows\ArrayEditor.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="TerminalGuiDesigner.TypeExtensions">
<Position X="15" Y="7.75" Width="1.75" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAABAAAQAAAAAAAAAAAAAA=</HashCode>
<FileName>TypeExtensions.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="TerminalGuiDesigner.UI.ValueFactory">
<Position X="13" Y="9.25" Width="2.5" />
<TypeIdentifier>
<HashCode>AAAACAEAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAI=</HashCode>
<FileName>UI\ValueFactory.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="TerminalGuiDesigner.Operations.IOperation">
<Position X="10.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAABAAAAAAgABABCAAAAAAAACAAAAAACAA=</HashCode>
<HashCode>AAAAAAAAAQAABAAAAAAgABABCAAAAAAAACAAAAAACAA=</HashCode>
<FileName>Operations\IOperation.cs</FileName>
</TypeIdentifier>
</Interface>
Expand Down
20 changes: 20 additions & 0 deletions src/ToCode/ITreeObjectsProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace TerminalGuiDesigner.ToCode;

/// <summary>
/// Interface for generic class <see cref="TreeObjectsProperty{T}"/>
/// </summary>
public interface ITreeObjectsProperty
{
/// <summary>
/// Returns True if the T type the property was constructed with is well
/// supported by the designer (i.e. user can pick objects for their tree).
/// </summary>
/// <returns></returns>
bool IsSupported();

/// <summary>
/// Returns true if the collection currently held on the property is empty
/// </summary>
/// <returns></returns>
public bool IsEmpty();
}
Loading
Loading