diff --git a/src/Design.cs b/src/Design.cs index fb9e63fa..8eef1d08 100644 --- a/src/Design.cs +++ b/src/Design.cs @@ -654,6 +654,7 @@ private IEnumerable LoadDesignableProperties() if (this.View is Toplevel) { yield return this.CreateProperty(nameof(Toplevel.Modal)); + yield return this.CreateProperty(nameof(Toplevel.IsMdiContainer)); } // Allow changing the FieldName on anything but root where @@ -673,6 +674,7 @@ private IEnumerable LoadDesignableProperties() { yield return this.CreateSubProperty(nameof(Border.BorderStyle), nameof(this.View.Border), this.View.Border); yield return this.CreateSubProperty(nameof(Border.BorderBrush), nameof(this.View.Border), this.View.Border); + yield return this.CreateSubProperty(nameof(Border.Background), nameof(this.View.Border), this.View.Border); yield return this.CreateSubProperty(nameof(Border.Effect3D), nameof(this.View.Border), this.View.Border); yield return this.CreateSubProperty(nameof(Border.Effect3DBrush), nameof(this.View.Border), this.View.Border); yield return this.CreateSubProperty(nameof(Border.DrawMarginFrame), nameof(this.View.Border), this.View.Border); diff --git a/src/FromCode/CodeToView.cs b/src/FromCode/CodeToView.cs index 27172ac7..c0a93a84 100644 --- a/src/FromCode/CodeToView.cs +++ b/src/FromCode/CodeToView.cs @@ -18,7 +18,7 @@ namespace TerminalGuiDesigner.FromCode; /// /// /// Compiling requires having the correct assembly references for dependencies. This is handled -/// by . Most references come from +/// by . Most references come from /// but also . /// public class CodeToView @@ -147,7 +147,7 @@ public Assembly CompileAssembly() var dd = typeof(Enumerable).GetTypeInfo().Assembly.Location; var coreDir = Directory.GetParent(dd) ?? throw new Exception($"Could not find parent directory of dotnet sdk. Sdk directory was {dd}"); - var references = new List(ReferenceAssemblies.Net60); + var references = new List(Net70.References.All); references.Add(MetadataReference.CreateFromFile(typeof(View).Assembly.Location)); references.Add(MetadataReference.CreateFromFile(typeof(ustring).Assembly.Location)); diff --git a/src/TerminalGuiDesigner.csproj b/src/TerminalGuiDesigner.csproj index 4b38cb80..db37e964 100644 --- a/src/TerminalGuiDesigner.csproj +++ b/src/TerminalGuiDesigner.csproj @@ -18,14 +18,14 @@ true TerminalGuiDesigner ./nupkg - net6.0 + net7.0 enable TerminalGuiDesigner 1.0.24 Thomas Nind enable MIT - Command line visual designer tool for creating Terminal.Gui C# applications. Create and edit Termianl.Gui views as easily as you could with the Windows Forms Designer. All generated code is contained in a seperate file (e.g. MyControl.Designer.cs). Run the tool by calling directly from the command line 'TerminalGuiDesigner' + Command line visual designer tool for creating Terminal.Gui C# applications. Create and edit Termianl.Gui views as easily as you could with the Windows Forms Designer. All generated code is contained in a separate file (e.g. MyControl.Designer.cs). Run the tool by calling directly from the command line 'TerminalGuiDesigner' Thomas Nind TerminalGuiDesigner does for Terminal.Gui what the Windows Forms Designer does for WinForms https://github.com/tznind/TerminalGuiDesigner/ @@ -134,17 +134,17 @@ - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/src/ToCode/Property.cs b/src/ToCode/Property.cs index 0c1e3c3e..323a52cb 100644 --- a/src/ToCode/Property.cs +++ b/src/ToCode/Property.cs @@ -188,6 +188,12 @@ public virtual void SetValue(object? value) /// Thrown if it is not possible to generate code for the current . public virtual void ToCode(CodeDomArgs args) { + // If property value is known default then do not emit in code gen + if(this.SkipToCode()) + { + return; + } + try { this.AddPropertyAssignment(args, this.GetLhs(), this.GetRhs()); @@ -198,6 +204,24 @@ public virtual void ToCode(CodeDomArgs args) } } + /// + /// Returns true if the value of the property is a known default for the API + /// and should not be included in generated code. Especially if the default is + /// odd (e.g. -1 Enum value) or assigning the default to a property breaks other things. + /// + /// True if should not take place. + private bool SkipToCode() + { + // Color does not contain a definition of -1 but it is used in shorthand to be 'no color' + if (this.PropertyInfo.PropertyType == typeof(Color)) + { + var val = this.GetValue(); + return val != null && (int)val == -1; + } + + return false; + } + /// /// Gets a CodeDOM code block for the right hand side of an assignment operation e.g.: /// "heya" diff --git a/tests/BorderColorTests.cs b/tests/BorderColorTests.cs new file mode 100644 index 00000000..f842f7b8 --- /dev/null +++ b/tests/BorderColorTests.cs @@ -0,0 +1,92 @@ +using NUnit.Framework; +using System.Linq; +using System.Reflection; +using Terminal.Gui; +using TerminalGuiDesigner; +using TerminalGuiDesigner.Operations; + +namespace UnitTests +{ + internal class BorderColorTests : Tests + { + [Test] + public void TestRoundTrip_BorderColors_NeverSet() + { + var result = RoundTrip((d, v) => + { + // Our view should not have any border color to start with + Assert.AreEqual(-1, (int)v.Border.BorderBrush); + Assert.AreEqual(-1, (int)v.Border.Background); + + }, out _); + + // Since there were no changes we would expect them to stay the same + // after reload + Assert.AreEqual(-1, (int)result.Border.BorderBrush); + Assert.AreEqual(-1, (int)result.Border.Background); + } + + [TestCase(true)] + [TestCase(false)] + public void TestCopyPasteContainer(bool alsoSelectSubElements) + { + RoundTrip((d, v) => + { + new AddViewOperation(new Label(), d, "lbl1").Do(); + new AddViewOperation(new Label(), d, "lbl2").Do(); + + Assert.AreEqual(2, v.GetActualSubviews().Count(), "Expected the FrameView to have 2 children (lbl1 and lbl2)"); + + Design[] toCopy; + + if (alsoSelectSubElements) + { + var lbl1Design = (Design)d.View.GetActualSubviews().First().Data; + Assert.AreEqual("lbl1", lbl1Design.FieldName); + + toCopy = new Design[] { d, lbl1Design }; + } + else + { + toCopy = new[] { d }; + } + + // copy the FrameView + Assert.IsTrue(new CopyOperation(toCopy).Do()); + + var rootDesign = d.GetRootDesign(); + + // paste the FrameView + Assert.IsTrue(new PasteOperation(rootDesign).Do()); + + var rootSubviews = rootDesign.View.GetActualSubviews(); + + Assert.AreEqual(2, rootSubviews.Count, "Expected root to have 2 FrameView now"); + Assert.IsTrue(rootSubviews.All(v => v is FrameView)); + + Assert.IsTrue( + rootSubviews.All(f => f.GetActualSubviews().Count() == 2), + "Expected both FrameView (copied and pasted) to have the full contents of 2 Labels"); + + // Since there were no changes we would expect them to stay the same + // after reload + foreach (var rsv in rootSubviews) + { + Assert.AreEqual(-1, (int)rsv.Border.BorderBrush); + Assert.AreEqual(-1, (int)rsv.Border.Background); + Assert.Null(GetFieldValue(rsv.Border, "borderBrush")); + Assert.Null(GetFieldValue(rsv.Border, "background")); + } + } + , out _); + } + + private T GetFieldValue(object obj, string name) + { + // Set the flags so that private and public fields from instances will be found + var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + var field = obj.GetType().GetField(name, bindingFlags); + return (T)field?.GetValue(obj)!; + } + } +} diff --git a/tests/UnitTests.csproj b/tests/UnitTests.csproj index ec223b28..f660728a 100644 --- a/tests/UnitTests.csproj +++ b/tests/UnitTests.csproj @@ -1,19 +1,19 @@ - net6.0 + net7.0 enable false true - + - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive