diff --git a/workers/unity/Packages/io.improbable.gdk.debug/.codegen/Source/Generators/DebugExtensions/FieldTypeHandler.cs b/workers/unity/Packages/io.improbable.gdk.debug/.codegen/Source/Generators/DebugExtensions/FieldTypeHandler.cs index d6a392adb7..c6b95556c4 100644 --- a/workers/unity/Packages/io.improbable.gdk.debug/.codegen/Source/Generators/DebugExtensions/FieldTypeHandler.cs +++ b/workers/unity/Packages/io.improbable.gdk.debug/.codegen/Source/Generators/DebugExtensions/FieldTypeHandler.cs @@ -43,8 +43,18 @@ public string ToFieldDeclaration(UnityFieldDetails fieldDetails) var element = optionFieldType.IsNullable ? "NullableVisualElement" : "OptionVisualElement"; return $"private readonly {element}<{innerUiType}, {optionFieldType.ContainedType.FqnType}> {fieldDetails.CamelCaseName}Field;"; + case ListFieldType listFieldType: + var innerListType = GetUiFieldType(listFieldType.ContainedType); + + if (innerListType == "") + { + // TODO: Eliminate this case by supporting 'Entity'. + return ""; + } + + return $"private readonly PaginatedListView<{innerListType}, {listFieldType.ContainedType.FqnType}> {fieldDetails.CamelCaseName}Field;"; default: - // TODO: Lists and maps. + // TODO: Maps. return ""; } } @@ -105,8 +115,40 @@ public IEnumerable ToFieldInitialisation(UnityFieldDetails fieldDetails, $"{fieldDetails.CamelCaseName}Field = new {element}<{innerUiType}, {optionFieldType.ContainedType.FqnType}>(\"{Formatting.SnakeCaseToHumanReadable(fieldDetails.Name)}\", {fieldDetails.CamelCaseName}InnerField, (element, data) => {{ {ContainedTypeToUiFieldUpdate(optionFieldType.ContainedType, "element", "data")} }});"; yield return $"{parentContainer}.Add({fieldDetails.CamelCaseName}Field);"; break; + case ListFieldType listFieldType: + var innerListType = GetUiFieldType(listFieldType.ContainedType); + + if (innerListType == "") + { + // TODO: Eliminate this case by supporting 'Entity'. + yield break; + } + + yield return + $"{fieldDetails.CamelCaseName}Field = new PaginatedListView<{innerListType}, {listFieldType.ContainedType.FqnType}>(\"{Formatting.SnakeCaseToHumanReadable(fieldDetails.Name)}\", () => {{ var inner = new {innerListType}(\"\");"; + + // These lines are part of the func to create an inner list item. + if (listFieldType.ContainedType.Category != ValueType.Type) + { + yield return "inner.SetEnabled(false);"; + } + + if (listFieldType.ContainedType.Category == ValueType.Enum) + { + yield return $"inner.Init(default({listFieldType.ContainedType.FqnType}));"; + } + + yield return "return inner; }, (index, data, element) => {"; + + // These lines are part of the binding. + var labelBinding = listFieldType.ContainedType.Category == ValueType.Type ? "Label" : "label"; + yield return $"element.{labelBinding} = $\"Item {{index + 1}}\";"; + yield return ContainedTypeToUiFieldUpdate(listFieldType.ContainedType, "element", "data"); + yield return "});"; + yield return $"{parentContainer}.Add({fieldDetails.CamelCaseName}Field);"; + break; default: - // TODO: Lists and maps. + // TODO: Maps. yield break; } } @@ -125,9 +167,17 @@ public string ToUiFieldUpdate(UnityFieldDetails fieldDetails, string fieldParent return ""; } + return $"{uiElementName}.Update({fieldParent}.{fieldDetails.PascalCaseName});"; + case ListFieldType listFieldType: + if (GetUiFieldType(listFieldType.ContainedType) == "") + { + // TODO: Eliminate this case by supporting 'Entity'. + return ""; + } + return $"{uiElementName}.Update({fieldParent}.{fieldDetails.PascalCaseName});"; default: - // TODO: Lists and maps. + // TODO: Maps. return ""; } } diff --git a/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs new file mode 100644 index 0000000000..d42e52dbea --- /dev/null +++ b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Improbable.Gdk.Debug.WorkerInspector.Codegen.EditmodeTests")] diff --git a/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs.meta b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs.meta new file mode 100644 index 0000000000..b78753c81a --- /dev/null +++ b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: af24913a485043009e9bf180b2f1aca8 +timeCreated: 1592324281 \ No newline at end of file diff --git a/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/PaginatedListView.cs b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/PaginatedListView.cs new file mode 100644 index 0000000000..5c43191e3b --- /dev/null +++ b/workers/unity/Packages/io.improbable.gdk.debug/WorkerInspector/Codegen/PaginatedListView.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Improbable.Gdk.Debug.WorkerInspector.Codegen +{ + public class PaginatedListView : VisualElement + where TElement : VisualElement + { + private const string UxmlPath = + "Packages/io.improbable.gdk.debug/WorkerInspector/Templates/PaginatedListView.uxml"; + + private List data; + + private readonly Action bindElement; + private readonly VisualElement container; + private readonly ElementPool elementPool; + private readonly int elementsPerPage; + + private readonly VisualElement controlsContainer; + private readonly Button forwardButton; + private readonly Button backButton; + private readonly Label pageCounter; + + private int currentPage = 0; + private int numPages = 0; + + public PaginatedListView(string label, Func makeElement, Action bindElement, int elementsPerPage = 5) + { + this.bindElement = bindElement; + this.elementsPerPage = elementsPerPage; + + var template = AssetDatabase.LoadAssetAtPath(UxmlPath); + template.CloneTree(this); + + this.Q