Skip to content

Commit

Permalink
Merge pull request #280 from gui-cs/treeview-t-support
Browse files Browse the repository at this point in the history
TreeView<T> support
  • Loading branch information
tznind authored Jan 5, 2024
2 parents 7958413 + 5ddd5f6 commit ea3c0c4
Show file tree
Hide file tree
Showing 20 changed files with 533 additions and 36 deletions.
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
6 changes: 5 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,12 +152,15 @@ 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"),
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "System.Runtime.dll"),
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "System.Collections.dll"),
MetadataReference.CreateFromFile(coreDir.FullName + Path.DirectorySeparatorChar + "System.Data.Common.dll")
,
};

var options = new CSharpCompilationOptions(
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

0 comments on commit ea3c0c4

Please sign in to comment.