浏览代码

refactored PropertyField creation and editor namespaces

/main
Steven Leal 4 年前
当前提交
fa7892b4
共有 40 个文件被更改,包括 646 次插入554 次删除
  1. 67
      com.unity.perception/Editor/Randomization/Editors/PerceptionEditorAnalytics.cs
  2. 28
      com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs
  3. 80
      com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs
  4. 5
      com.unity.perception/Editor/Randomization/PropertyDrawers/ColorHsvaDrawer.cs
  5. 4
      com.unity.perception/Editor/Randomization/PropertyDrawers/ParameterDrawer.cs
  6. 1
      com.unity.perception/Editor/Randomization/Uxml/Sampler/FloatRangeElement.uxml
  7. 7
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml
  8. 4
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml.meta
  9. 8
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/CategoricalOptionElement.cs
  10. 9
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ColorHsvaField.cs
  11. 37
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/DrawerParameterElement.cs
  12. 48
      com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs
  13. 166
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/AddRandomizerMenu.cs
  14. 12
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/DragToReorderManipulator.cs
  15. 72
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerElement.cs
  16. 34
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerList.cs
  17. 5
      com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerReorderingIndicator.cs
  18. 6
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/FloatRangeElement.cs
  19. 120
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs
  20. 14
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs.meta
  21. 2
      com.unity.perception/Runtime/Randomization/Randomizers/Randomizer.cs
  22. 2
      com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs
  23. 26
      com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs
  24. 3
      com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs.meta
  25. 28
      com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs
  26. 3
      com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs.meta
  27. 10
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml
  28. 3
      com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml.meta
  29. 89
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs
  30. 11
      com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs.meta
  31. 21
      com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs
  32. 95
      com.unity.perception/Editor/Randomization/Utilities/StaticData.cs
  33. 76
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs
  34. 3
      com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs.meta
  35. 101
      com.unity.perception/Editor/Randomization/StaticData.cs
  36. 0
      /com.unity.perception/Editor/Randomization/Utilities/StaticData.cs.meta
  37. 0
      /com.unity.perception/Editor/Randomization/Utilities.meta
  38. 0
      /com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs.meta

67
com.unity.perception/Editor/Randomization/Editors/PerceptionEditorAnalytics.cs


using System;
using JetBrains.Annotations;
using UnityEditor;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
const string k_VendorKey = "unity.perception";
const string k_RunInUnitySimulationName = "runinunitysimulation";
const string k_VendorKey = "unity.perception";
const string k_RunInUnitySimulationName = "runinunitysimulation";
static bool s_IsRegistered = false;
static bool s_IsRegistered;
static bool TryRegisterEvents()
{

bool success = true;
var success = true;
success &= EditorAnalytics.RegisterEventWithLimit(k_RunInUnitySimulationName, k_MaxEventsPerHour, k_MaxItems,
k_VendorKey) == AnalyticsResult.Ok;

enum RunStatus
{
Started,
Failed,
Succeeded
}
struct RunInUnitySimulationData
{
[UsedImplicitly]
public string runId;
[UsedImplicitly]
public int totalIterations;
[UsedImplicitly]
public int instanceCount;
[UsedImplicitly]
public string existingBuildId;
[UsedImplicitly]
public string errorMessage;
[UsedImplicitly]
public string runExecutionId;
[UsedImplicitly]
public string runStatus;
}
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
totalIterations = totalIterations,

if (!TryRegisterEvents())
return;
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
errorMessage = errorMessage,

if (!TryRegisterEvents())
return;
var data = new RunInUnitySimulationData()
var data = new RunInUnitySimulationData
{
runId = runId.ToString(),
runExecutionId = runExecutionId,

}
enum RunStatus
{
Started,
Failed,
Succeeded
}
struct RunInUnitySimulationData
{
[UsedImplicitly]
public string runId;
[UsedImplicitly]
public int totalIterations;
[UsedImplicitly]
public int instanceCount;
[UsedImplicitly]
public string existingBuildId;
[UsedImplicitly]
public string errorMessage;
[UsedImplicitly]
public string runExecutionId;
[UsedImplicitly]
public string runStatus;
}
}
}

28
com.unity.perception/Editor/Randomization/Editors/RunInUnitySimulationWindow.cs


using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Simulation.Client;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class RunInUnitySimulationWindow : EditorWindow
{

SysParamDefinition m_SysParam;
TextField m_RunNameField;
IntegerField m_TotalIterationsField;
ObjectField m_ScenarioField;
TextField m_RunNameField;
ObjectField m_ScenarioField;
SysParamDefinition m_SysParam;
IntegerField m_TotalIterationsField;
[MenuItem("Window/Run in Unity Simulation")]
static void ShowWindow()
{

}
/// <summary>
/// Enables a visual element to remember values between editor sessions
/// Enables a visual element to remember values between editor sessions
/// </summary>
/// <param name="element">The visual element to enable view data for</param>
static void SetViewDataKey(VisualElement element)

var sysParamDefinitions = API.GetSysParams();
var sysParamMenu = root.Q<ToolbarMenu>("sys-param");
foreach (var definition in sysParamDefinitions)
{
sysParamMenu.menu.AppendAction(
definition.description,
action =>

});
}
sysParamMenu.text = sysParamDefinitions[0].description;
m_SysParam = sysParamDefinitions[0];

runGuid,
m_TotalIterationsField.value,
m_InstanceCountField.value,
existingBuildId: null);
null);
try
{
ValidateSettings();

var constants = configuration["constants"];
constants["totalIterations"] = m_TotalIterationsField.value;
constants["instanceCount"]= m_InstanceCountField.value;
constants["instanceCount"] = m_InstanceCountField.value;
for (var i = 0; i < m_InstanceCountField.value; i++)
{

constants["instanceIndex"]= i;
constants["instanceIndex"] = i;
appParamIds.Add(new AppParam()
appParamIds.Add(new AppParam
{
id = appParamId,
name = appParamName,

Debug.Log("Run cancelled");
return;
}
Debug.Log($"Generated app-param ids: {appParams.Count}");
var runDefinitionId = API.UploadRunDefinition(new RunDefinition

80
com.unity.perception/Editor/Randomization/Editors/ScenarioBaseEditor.cs


using System.Collections;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.VisualElements;
using Object = UnityEngine.Object;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
class ScenarioBaseEditor : UnityEditor.Editor
class ScenarioBaseEditor : Editor
VisualElement m_ConstantsListVisualContainer;
VisualElement m_InspectorPropertiesContainer;
VisualElement m_RandomizerListPlaceholder;
VisualElement m_Root;
VisualElement m_Root;
VisualElement m_InspectorPropertiesContainer;
VisualElement m_ConstantsListVisualContainer;
VisualElement m_RandomizerListPlaceholder;
public override VisualElement CreateInspectorGUI()
{

m_ConstantsListVisualContainer = m_Root.Q<VisualElement>("constants-list");
m_ConstantsListVisualContainer.Clear();
var iterator = m_SerializedObject.GetIterator();
if (iterator.NextVisible(true))
var iterator = m_SerializedObject.GetIterator();
iterator.NextVisible(true);
iterator.NextVisible(false);
do
do
switch (iterator.name)
switch (iterator.name)
case "m_Randomizers":
m_RandomizerListPlaceholder.Add(new RandomizerList(iterator.Copy()));
break;
case "constants":
m_HasConstantsField = true;
UIElementsEditorUtilities.CreatePropertyFields(iterator.Copy(), m_ConstantsListVisualContainer);
break;
default:
case "m_Script":
break;
case "m_Randomizers":
m_RandomizerListPlaceholder.Add(new RandomizerList(iterator.Copy()));
break;
case "constants":
m_HasConstantsField = true;
CreateConstantsFieldsWithToolTips(iterator.Copy());
break;
default:
{
foundProperties = true;
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(m_SerializedObject);
m_InspectorPropertiesContainer.Add(propertyField);
break;
}
foundProperties = true;
var propertyField = UIElementsEditorUtilities.CreatePropertyField(iterator, m_Scenario.GetType());
m_InspectorPropertiesContainer.Add(propertyField);
break;
} while (iterator.NextVisible(false));
}
}
} while (iterator.NextVisible(false));
if (!foundProperties)
m_InspectorPropertiesContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);

m_InspectorPropertiesContainer.style.marginBottom = 0;
m_ConstantsListVisualContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
}
void CreateConstantsFieldsWithToolTips(SerializedProperty constantsProperty)
{
constantsProperty.NextVisible(true);
do
{
var constantsPropertyField = new PropertyField(constantsProperty.Copy());
constantsPropertyField.Bind(m_SerializedObject);
var originalField = target.GetType().GetField("constants").FieldType.GetField(constantsProperty.name);
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
constantsPropertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
m_ConstantsListVisualContainer.Add(constantsPropertyField);
} while (constantsProperty.NextVisible(true));
}
}
}

5
com.unity.perception/Editor/Randomization/PropertyDrawers/ColorHsvaDrawer.cs


using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor.PropertyDrawers
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(ColorHsva), true)]
class ColorHsvaDrawer : PropertyDrawer

4
com.unity.perception/Editor/Randomization/PropertyDrawers/ParameterDrawer.cs


using System;
using UnityEditor;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor.PropertyDrawers
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(Parameter), true)]
class ParameterDrawer : PropertyDrawer

1
com.unity.perception/Editor/Randomization/Uxml/Sampler/FloatRangeElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement>
<Style src="../../Uss/Styles.uss"/>
<VisualElement style="flex-direction: row; margin: 1px, 1px, 1px, 3px;">
<Label text="Range" class="unity-base-field__label" style="min-width: 147;"/>
<VisualElement class="sampler__float-range" style="flex-grow: 1; flex-direction: row;">

7
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="sampler-template" style="margin-bottom: 4px;">
<VisualElement style="margin-bottom: 4px;">
<VisualElement style="flex-direction: row; align-items: center;">
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/>
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler__type-menu"/>
</VisualElement>
<Label name="display-name" text="Sampler Name" class="unity-base-field__label"/>
<VisualElement name="fields-container" style="margin-left: 18px;"/>
</VisualElement>
</UXML>

4
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerElement.uxml.meta


fileFormatVersion: 2
guid: e91be9c80e944358b231c125be80a749
timeCreated: 1594847524
guid: a4752f9d99d8497e9a147942da225b5f
timeCreated: 1612043461

8
com.unity.perception/Editor/Randomization/VisualElements/Parameter/CategoricalOptionElement.cs


using System;
using UnityEditor;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
int m_Index;
int m_Index;
SerializedProperty m_ProbabilitiesProperty;
internal CategoricalOptionElement(

else
{
probability.SetEnabled(true);
probability.RegisterValueChangedCallback((evt) =>
probability.RegisterValueChangedCallback(evt =>
{
if (evt.newValue < 0f)
probability.value = 0f;

9
com.unity.perception/Editor/Randomization/VisualElements/Parameter/ColorHsvaField.cs


using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
SerializedProperty m_Property;
SerializedProperty m_A;
SerializedProperty m_Property;
SerializedProperty m_A;
public ColorHsvaField(SerializedProperty property)
{

37
com.unity.perception/Editor/Randomization/VisualElements/Parameter/DrawerParameterElement.cs


using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using System;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
Parameter m_Parameter;
const string k_CollapsedParameterClass = "collapsed";
const string k_CollapsedParameterClass = "collapsed";
bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
public DrawerParameterElement(SerializedProperty property)
{

var drawer = this.Q<VisualElement>("drawer");
drawer.Add(new ParameterElement(property));
}
bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
}
}

48
com.unity.perception/Editor/Randomization/VisualElements/Parameter/ParameterElement.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEngine.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class ParameterElement : VisualElement
{

Parameter parameter => (Parameter)StaticData.GetManagedReferenceValue(m_SerializedProperty);
CategoricalParameterBase categoricalParameter => (CategoricalParameterBase)parameter;
public ParameterElement(SerializedProperty property)
{
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(

m_PropertiesContainer = this.Q<VisualElement>("properties");
CreatePropertyFields();
}
Parameter parameter => (Parameter)StaticData.GetManagedReferenceValue(m_SerializedProperty);
CategoricalParameterBase categoricalParameter => (CategoricalParameterBase)parameter;
void CreatePropertyFields()
{

return;
}
var currentProperty = m_SerializedProperty.Copy();
var currentProperty = m_SerializedProperty.Copy();
{
if (currentProperty.type.Contains("managedReference") &&
currentProperty.managedReferenceFieldTypename == StaticData.samplerSerializedFieldType)
m_PropertiesContainer.Add(new SamplerElement(currentProperty.Copy(), parameter));
else
{
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(currentProperty.serializedObject);
m_PropertiesContainer.Add(propertyField);
}
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(currentProperty.serializedObject);
m_PropertiesContainer.Add(propertyField);
}
}
void CreateCategoricalParameterFields()

listView.style.flexGrow = 1.0f;
listView.style.height = new StyleLength(listView.itemHeight * 4);
VisualElement MakeItem() => new CategoricalOptionElement(
optionsProperty, probabilitiesProperty);
VisualElement MakeItem()
{
return new CategoricalOptionElement(
optionsProperty, probabilitiesProperty);
}
listView.makeItem = MakeItem;
void BindItem(VisualElement e, int i)

listView.Refresh();
};
}
listView.bindItem = BindItem;
var addOptionButton = template.Q<Button>("add-option");

var addFolderButton = template.Q<Button>("add-folder");
if (categoricalParameter.sampleType.IsSubclassOf(typeof(Object)))
{
addFolderButton.clicked += () =>
{
var folderPath = EditorUtility.OpenFolderPanel(

optionProperty.objectReferenceValue = categories[i];
probabilityProperty.floatValue = uniformProbability;
}
}
else
addFolderButton.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);

{
if (Mathf.Approximately(scrollView.verticalScroller.highValue, 0f))
return;
if ((scrollView.scrollOffset.y <= 0f && evt.delta.y < 0f) ||
if (scrollView.scrollOffset.y <= 0f && evt.delta.y < 0f ||
scrollView.scrollOffset.y >= scrollView.verticalScroller.highValue && evt.delta.y > 0f)
evt.StopImmediatePropagation();
});

if (Application.isPlaying)
uniformToggle.SetEnabled(false);
else
{
uniformToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
listView.ToggleInClassList("collapsed");

var probability = probabilitiesProperty.GetArrayElementAtIndex(i);
probability.floatValue = uniformProbabilityValue;
}
}
m_PropertiesContainer.Add(template);
}

if (!folderPath.StartsWith(Application.dataPath))
throw new ApplicationException("Selected folder is not an asset folder in this project");
var assetsPath = "Assets" + folderPath.Remove(0, Application.dataPath.Length);
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new []{assetsPath});
var assetIds = AssetDatabase.FindAssets($"t:{assetType.Name}", new[] { assetsPath });
var assets = new List<Object>();
foreach (var guid in assetIds)
assets.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), assetType));

166
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/AddRandomizerMenu.cs


using System.Collections.Generic;
using NUnit.Framework;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
VisualElement m_DirectoryChevron;
TextElement m_DirectoryLabelText;
Dictionary<string, HashSet<string>> m_MenuDirectories = new Dictionary<string, HashSet<string>>();
VisualElement m_MenuElements;
List<MenuItem> m_MenuItems = new List<MenuItem>();
Dictionary<string, List<MenuItem>> m_MenuItemsMap = new Dictionary<string, List<MenuItem>>();
RandomizerList m_RandomizerList;
string m_SearchString = string.Empty;
public AddRandomizerMenu(VisualElement parentElement, VisualElement button, RandomizerList randomizerList)
{
m_RandomizerList = randomizerList;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/AddRandomizerMenu.uxml");
template.CloneTree(this);
style.position = new StyleEnum<Position>(Position.Absolute);
var buttonPosition = button.worldBound.position;
var top = math.min(buttonPosition.y, parentElement.worldBound.height - 300);
style.top = top;
style.left = buttonPosition.x;
focusable = true;
RegisterCallback<FocusOutEvent>(evt =>
{
if (evt.relatedTarget == null || ((VisualElement)evt.relatedTarget).FindCommonAncestor(this) != this)
ExitMenu();
});
var directoryLabel = this.Q<VisualElement>("directory-label");
directoryLabel.RegisterCallback<MouseUpEvent>(evt => { AscendDirectory(); });
m_DirectoryLabelText = this.Q<TextElement>("directory-label-text");
m_DirectoryChevron = this.Q<VisualElement>("directory-chevron");
var searchBar = this.Q<TextField>("search-bar");
searchBar.schedule.Execute(() => searchBar.ElementAt(0).Focus());
searchBar.RegisterValueChangedCallback(evt => searchString = evt.newValue);
m_MenuElements = this.Q<VisualElement>("menu-options");
CreateMenuItems();
DrawDirectoryItems();
}
string currentPath
{
get => m_CurrentPath;

}
}
string m_SearchString = string.Empty;
string searchString
{
get => m_SearchString;

}
}
RandomizerList m_RandomizerList;
VisualElement m_MenuElements;
TextElement m_DirectoryLabelText;
VisualElement m_DirectoryChevron;
Dictionary<string, List<MenuItem>> m_MenuItemsMap = new Dictionary<string, List<MenuItem>>();
Dictionary<string, HashSet<string>> m_MenuDirectories = new Dictionary<string, HashSet<string>>();
List<MenuItem> m_MenuItems = new List<MenuItem>();
class MenuItem
{
public Type randomizerType;
public string itemName;
public MenuItem(Type randomizerType, string itemName)
{
this.randomizerType = randomizerType;
this.itemName = itemName;
}
}
sealed class MenuItemElement : TextElement
{
public MenuItemElement(MenuItem menuItem, AddRandomizerMenu menu)
{
text = menuItem.itemName;
AddToClassList("randomizer__add-menu-directory-item");
RegisterCallback<MouseUpEvent>(evt => menu.AddRandomizer(menuItem.randomizerType));
}
}
sealed class MenuDirectoryElement : VisualElement
{
public MenuDirectoryElement(string directory, AddRandomizerMenu menu)
{
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/MenuDirectoryElement.uxml").CloneTree(this);
var pathItems = directory.Split('/');
this.Q<TextElement>("directory").text = pathItems[pathItems.Length - 1];
RegisterCallback<MouseUpEvent>(evt => menu.currentPath = directory);
}
}
public AddRandomizerMenu(VisualElement parentElement, VisualElement button, RandomizerList randomizerList)
{
m_RandomizerList = randomizerList;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/AddRandomizerMenu.uxml");
template.CloneTree(this);
style.position = new StyleEnum<Position>(Position.Absolute);
var buttonPosition = button.worldBound.position;
var top = math.min(buttonPosition.y, parentElement.worldBound.height - 300);
style.top = top;
style.left = buttonPosition.x;
focusable = true;
RegisterCallback<FocusOutEvent>(evt =>
{
if (evt.relatedTarget == null || ((VisualElement)evt.relatedTarget).FindCommonAncestor(this) != this)
ExitMenu();
});
var directoryLabel = this.Q<VisualElement>("directory-label");
directoryLabel.RegisterCallback<MouseUpEvent>(evt => { AscendDirectory(); });
m_DirectoryLabelText = this.Q<TextElement>("directory-label-text");
m_DirectoryChevron = this.Q<VisualElement>("directory-chevron");
var searchBar = this.Q<TextField>("search-bar");
searchBar.schedule.Execute(() => searchBar.ElementAt(0).Focus());
searchBar.RegisterValueChangedCallback(evt => searchString = evt.newValue);
m_MenuElements = this.Q<VisualElement>("menu-options");
CreateMenuItems();
DrawDirectoryItems();
}
void ExitMenu()
{
parent.Remove(this);

var upperSearchString = searchString.ToUpper();
foreach (var menuItem in m_MenuItems)
{
}
}
void CreateMenuItems()

m_MenuDirectories.Add(path, new HashSet<string>());
m_MenuDirectories[path].Add(childPath);
}
path = childPath;
}

rootList.Add(new MenuItem(randomizerType, randomizerType.Name));
}
}
}
class MenuItem
{
public string itemName;
public Type randomizerType;
public MenuItem(Type randomizerType, string itemName)
{
this.randomizerType = randomizerType;
this.itemName = itemName;
}
}
sealed class MenuItemElement : TextElement
{
public MenuItemElement(MenuItem menuItem, AddRandomizerMenu menu)
{
text = menuItem.itemName;
AddToClassList("randomizer__add-menu-directory-item");
RegisterCallback<MouseUpEvent>(evt => menu.AddRandomizer(menuItem.randomizerType));
}
}
sealed class MenuDirectoryElement : VisualElement
{
public MenuDirectoryElement(string directory, AddRandomizerMenu menu)
{
AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Randomizer/MenuDirectoryElement.uxml").CloneTree(this);
var pathItems = directory.Split('/');
this.Q<TextElement>("directory").text = pathItems[pathItems.Length - 1];
RegisterCallback<MouseUpEvent>(evt => menu.currentPath = directory);
}
}
}
}

12
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/DragToReorderManipulator.cs


using UnityEngine.Experimental.Perception.Randomization.VisualElements;
using System;
using UnityEditor.Experimental.Perception.Randomization;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
VisualElement m_DragHandle;
VisualElement m_ParameterContainer;
VisualElement m_DragHandle;
VisualElement m_ParameterContainer;
protected override void RegisterCallbacksOnTarget()
{

var randomizerIndex = m_RandomizerElement.parent.IndexOf(m_RandomizerElement);
for (var i = 0; i < middlePoints.Length; i++)
{
}
ReorderParameter(randomizerIndex, middlePoints.Length);
}

72
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerElement.cs


using System;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Editor;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
const string k_CollapsedParameterClass = "collapsed";
SerializedProperty m_Property;
Randomizers.Randomizer randomizer => (Randomizers.Randomizer)StaticData.GetManagedReferenceValue(m_Property);
public Type randomizerType => randomizer.GetType();
const string k_CollapsedParameterClass = "collapsed";
public RandomizerList randomizerList { get; }
public bool collapsed
{
get => m_Collapsed.boolValue;
set
{
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
}
SerializedProperty m_Property;
public RandomizerElement(SerializedProperty property, RandomizerList randomizerList)
{

FillPropertiesContainer();
}
void FillPropertiesContainer()
{
m_PropertiesContainer.Clear();
var iterator = m_Property.Copy();
var nextSiblingProperty = m_Property.Copy();
nextSiblingProperty.NextVisible(false);
Randomizer randomizer => (Randomizer)StaticData.GetManagedReferenceValue(m_Property);
public Type randomizerType => randomizer.GetType();
public RandomizerList randomizerList { get; }
var foundProperties = false;
if (iterator.NextVisible(true))
public bool collapsed
{
get => m_Collapsed.boolValue;
set
do
{
if (SerializedProperty.EqualContents(iterator, nextSiblingProperty))
break;
if (iterator.name == "<enabled>k__BackingField")
continue;
foundProperties = true;
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(m_Property.serializedObject);
m_PropertiesContainer.Add(propertyField);
} while (iterator.NextVisible(false));
m_Collapsed.boolValue = value;
m_Property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (value)
AddToClassList(k_CollapsedParameterClass);
else
RemoveFromClassList(k_CollapsedParameterClass);
}
if (!foundProperties)
void FillPropertiesContainer()
{
m_PropertiesContainer.Clear();
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer);
if (m_PropertiesContainer.childCount == 0)
m_PropertiesContainer.style.display = new StyleEnum<DisplayStyle>(DisplayStyle.None);
}
}

34
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerList.cs


using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Editor;
namespace UnityEngine.Experimental.Perception.Randomization.VisualElements
namespace UnityEditor.Experimental.Perception.Randomization
SerializedProperty m_Property;
public ScenarioBase scenario => (ScenarioBase)m_Property.serializedObject.targetObject;
VisualElement inspectorContainer
{
get
{
var viewport = parent;
while (!viewport.ClassListContains("unity-inspector-main-container"))
viewport = viewport.parent;
return viewport;
}
}
SerializedProperty m_Property;
public RandomizerList(SerializedProperty property)
{

m_Property.serializedObject.Update();
RefreshList();
};
}
public ScenarioBase scenario => (ScenarioBase)m_Property.serializedObject.targetObject;
VisualElement inspectorContainer
{
get
{
var viewport = parent;
while (!viewport.ClassListContains("unity-inspector-main-container"))
viewport = viewport.parent;
return viewport;
}
}
void RefreshList()

5
com.unity.perception/Editor/Randomization/VisualElements/Randomizer/RandomizerReorderingIndicator.cs


using UnityEngine.UIElements;
using System;
using UnityEngine.UIElements;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class RandomizerReorderingIndicator : VisualElement
{

6
com.unity.perception/Editor/Randomization/VisualElements/Sampler/FloatRangeElement.cs


using UnityEngine;
using UnityEditor;
using System;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
{
class FloatRangeElement : VisualElement
{

120
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs


using System;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
namespace UnityEditor.Experimental.Perception.Randomization
Parameter m_Parameter;
ISampler m_Sampler;
SerializedProperty m_Property;
SerializedProperty m_RangeProperty;
VisualElement m_Properties;
ToolbarMenu m_SamplerTypeDropdown;
public SamplerElement(SerializedProperty property, Parameter parameter)
public SamplerElement(SerializedProperty property)
m_Property = property;
m_Parameter = parameter;
m_Sampler = GetSamplerFromSerializedObject();
if (m_Sampler == null)
CreateSampler(typeof(UniformSampler));
var samplerName = this.Q<Label>("sampler-name");
samplerName.text = UppercaseFirstLetter(m_Property.name);
m_Properties = this.Q<VisualElement>("fields-container");
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown");
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(m_Sampler.GetType());;
foreach (var samplerType in StaticData.samplerTypes)
{
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);;
m_SamplerTypeDropdown.menu.AppendAction(
displayName,
a => { ReplaceSampler(samplerType); },
a => DropdownMenuAction.Status.Normal);
}
CreatePropertyFields();
}
void ReplaceSampler(Type samplerType)
{
CreateSampler(samplerType);
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType);
CreatePropertyFields();
}
void CreateSampler(Type samplerType)
{
var newSampler = (ISampler)Activator.CreateInstance(samplerType);
CopyFloatRangeToNewSampler(newSampler);
m_Sampler = newSampler;
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
}
void CopyFloatRangeToNewSampler(ISampler newSampler)
{
if (m_RangeProperty == null)
return;
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name);
if (rangeField == null)
return;
var range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
rangeField.SetValue(newSampler, range);
}
void CreatePropertyFields()
{
m_RangeProperty = null;
m_Properties.Clear();
var currentProperty = m_Property.Copy();
var nextSiblingProperty = m_Property.Copy();
nextSiblingProperty.NextVisible(false);
if (currentProperty.NextVisible(true))
{
do
{
if (SerializedProperty.EqualContents(currentProperty, nextSiblingProperty))
break;
if (currentProperty.type == "FloatRange")
{
m_RangeProperty = currentProperty.Copy();
m_Properties.Add(new FloatRangeElement(m_RangeProperty));
}
else
{
var propertyField = new PropertyField(currentProperty.Copy());
propertyField.Bind(m_Property.serializedObject);
var originalField = m_Sampler.GetType().GetField(currentProperty.name);
var tooltipAttribute = originalField.GetCustomAttributes(true).ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
{
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
}
m_Properties.Add(propertyField);
}
}
while (currentProperty.NextVisible(false));
}
}
var displayName = this.Q<Label>("display-name");
displayName.text = property.displayName;
static string UppercaseFirstLetter(string s)
{
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1);
}
ISampler GetSamplerFromSerializedObject()
{
var configType = m_Parameter.GetType();
var field = configType.GetField(m_Property.name);
return (ISampler)field.GetValue(m_Parameter);
var fieldsContainer = this.Q<VisualElement>("fields-container");
UIElementsEditorUtilities.CreatePropertyFields(property, fieldsContainer);
}
}
}

14
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerElement.cs.meta


fileFormatVersion: 2
guid: 134b50014b9f4c0694a087d3529ea4c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: a5920440efa84756a581dda95394a14f
timeCreated: 1612042675

2
com.unity.perception/Runtime/Randomization/Randomizers/Randomizer.cs


/// <summary>
/// Enabled Randomizers are updated, disabled Randomizers are not.
/// </summary>
[field: SerializeField] public bool enabled { get; set; } = true;
[field: SerializeField, HideInInspector] public bool enabled { get; set; } = true;
/// <summary>
/// Returns the scenario containing this Randomizer

2
com.unity.perception/Runtime/Randomization/Samplers/ISampler.cs


using System;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
namespace UnityEngine.Experimental.Perception.Randomization.Samplers

26
com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(FloatRange))]
class FloatRangeDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return new FloatRangeElement(property);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

3
com.unity.perception/Editor/Randomization/PropertyDrawers/FloatRangeDrawer.cs.meta


fileFormatVersion: 2
guid: 2aaf69aad9c844a592283d36b3c14d8f
timeCreated: 1612042769

28
com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization.PropertyDrawers
{
[CustomPropertyDrawer(typeof(ISampler), true)]
class SamplerDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
return fieldInfo.FieldType.IsInterface
? new SamplerInterfaceElement(property) as VisualElement
: new SamplerElement(property);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property);
}
}
}

3
com.unity.perception/Editor/Randomization/PropertyDrawers/SamplerDrawer.cs.meta


fileFormatVersion: 2
guid: 87021ed3ca1241f8953af2ee975504c4
timeCreated: 1612040428

10
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml


<UXML xmlns="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements">
<VisualElement name="sampler-template" style="margin-bottom: 4px;">
<Style src="../../Uss/Styles.uss"/>
<VisualElement style="flex-direction: row; align-items: center;">
<Label name="sampler-name" text="Sampler Name" class="unity-base-field__label"/>
<editor:ToolbarMenu name="sampler-type-dropdown" text="Placeholder Sampler Type" class="sampler__type-menu"/>
</VisualElement>
<VisualElement name="fields-container" style="margin-left: 18px;"/>
</VisualElement>
</UXML>

3
com.unity.perception/Editor/Randomization/Uxml/Sampler/SamplerInterfaceElement.uxml.meta


fileFormatVersion: 2
guid: e91be9c80e944358b231c125be80a749
timeCreated: 1594847524

89
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs


using System;
using UnityEditor.UIElements;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
class SamplerInterfaceElement : VisualElement
{
VisualElement m_PropertiesContainer;
SerializedProperty m_Property;
SerializedProperty m_RangeProperty;
ToolbarMenu m_SamplerTypeDropdown;
public SamplerInterfaceElement(SerializedProperty property)
{
m_Property = property;
var template = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(
$"{StaticData.uxmlDir}/Sampler/SamplerInterfaceElement.uxml");
template.CloneTree(this);
if (sampler == null)
CreateSampler(typeof(UniformSampler));
var samplerName = this.Q<Label>("sampler-name");
samplerName.text = UppercaseFirstLetter(m_Property.name);
m_PropertiesContainer = this.Q<VisualElement>("fields-container");
m_SamplerTypeDropdown = this.Q<ToolbarMenu>("sampler-type-dropdown");
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(sampler.GetType());
;
foreach (var samplerType in StaticData.samplerTypes)
{
var displayName = SamplerUtility.GetSamplerDisplayName(samplerType);
;
m_SamplerTypeDropdown.menu.AppendAction(
displayName,
a => { ReplaceSampler(samplerType); },
a => DropdownMenuAction.Status.Normal);
}
CreatePropertyFields();
}
ISampler sampler => (ISampler)StaticData.GetManagedReferenceValue(m_Property);
void ReplaceSampler(Type samplerType)
{
CreateSampler(samplerType);
m_SamplerTypeDropdown.text = SamplerUtility.GetSamplerDisplayName(samplerType);
CreatePropertyFields();
}
void CreateSampler(Type samplerType)
{
var newSampler = (ISampler)Activator.CreateInstance(samplerType);
CopyFloatRangeToNewSampler(newSampler);
m_Property.managedReferenceValue = newSampler;
m_Property.serializedObject.ApplyModifiedProperties();
}
void CopyFloatRangeToNewSampler(ISampler newSampler)
{
if (m_RangeProperty == null)
return;
var rangeField = newSampler.GetType().GetField(m_RangeProperty.name);
if (rangeField == null)
return;
var range = new FloatRange(
m_RangeProperty.FindPropertyRelative("minimum").floatValue,
m_RangeProperty.FindPropertyRelative("maximum").floatValue);
rangeField.SetValue(newSampler, range);
}
void CreatePropertyFields()
{
m_RangeProperty = null;
m_PropertiesContainer.Clear();
UIElementsEditorUtilities.CreatePropertyFields(m_Property, m_PropertiesContainer);
}
static string UppercaseFirstLetter(string s)
{
return string.IsNullOrEmpty(s) ? string.Empty : char.ToUpper(s[0]) + s.Substring(1);
}
}
}

11
com.unity.perception/Editor/Randomization/VisualElements/Sampler/SamplerInterfaceElement.cs.meta


fileFormatVersion: 2
guid: 134b50014b9f4c0694a087d3529ea4c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

21
com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs


using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
/// <summary>
/// Derive this class to force the Unity Editor to render the default inspector using UIElements for an Object that
/// includes a Parameter field.
/// to allow parameter UIs to render properly
/// </summary>
public abstract class ParameterUIElementsEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var rootElement = new VisualElement();
UIElementsEditorUtilities.CreatePropertyFields(serializedObject, rootElement);
return rootElement;
}
}
}

95
com.unity.perception/Editor/Randomization/Utilities/StaticData.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEditor.Experimental.Perception.Randomization
{
static class StaticData
{
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization";
internal const string uxmlDir = k_RandomizationDir + "/Uxml";
internal static Type[] randomizerTypes;
internal static Type[] samplerTypes;
static StaticData()
{
randomizerTypes = GetConstructableDerivedTypes<Randomizer>();
samplerTypes = GetConstructableDerivedTypes<ISampler>();
}
static Type[] GetConstructableDerivedTypes<T>()
{
var collection = TypeCache.GetTypesDerivedFrom<T>();
var types = new List<Type>();
foreach (var type in collection)
if (!type.IsAbstract && !type.IsInterface)
types.Add(type);
return types.ToArray();
}
public static object GetManagedReferenceValue(SerializedProperty prop, bool parent = false)
{
var path = prop.propertyPath.Replace(".Array.data[", "[");
object obj = prop.serializedObject.targetObject;
var elements = path.Split('.');
if (parent)
elements = elements.Take(elements.Count() - 1).ToArray();
foreach (var element in elements)
if (element.Contains("["))
{
var elementName = element.Substring(0, element.IndexOf("["));
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
obj = GetArrayValue(obj, elementName, index);
}
else
{
obj = GetValue(obj, element);
}
return obj;
}
static object GetValue(object source, string name)
{
if (source == null)
return null;
var type = source.GetType();
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (f == null)
{
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
return p == null ? null : p.GetValue(source, null);
}
return f.GetValue(source);
}
static object GetArrayValue(object source, string name, int index)
{
var value = GetValue(source, name);
if (!(value is IEnumerable enumerable))
return null;
var enumerator = enumerable.GetEnumerator();
while (index-- >= 0)
enumerator.MoveNext();
return enumerator.Current;
}
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) return true;
toCheck = toCheck.BaseType;
}
return false;
}
}
}

76
com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs


using System;
using System.Linq;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Experimental.Perception.Randomization
{
/// <summary>
/// A set of helper functions for simplifying the creation of UI Elements editors
/// from perception randomization classes
/// </summary>
public static class UIElementsEditorUtilities
{
/// <summary>
/// Creates a list of PropertyFields from the class fields of the given SerializedObject
/// and adds them to the specified container element
/// </summary>
/// <param name="serializedObj">The SerializedObject to create property fields for</param>
/// <param name="containerElement">The element to place the created PropertyFields in</param>
public static void CreatePropertyFields(SerializedObject serializedObj, VisualElement containerElement)
{
var fieldType = serializedObj.targetObject.GetType();
var iterator = serializedObj.GetIterator();
iterator.NextVisible(true);
iterator.NextVisible(false);
do
{
var propertyField = CreatePropertyField(iterator, fieldType);
containerElement.Add(propertyField);
} while (iterator.NextVisible(false));
}
/// <summary>
/// Creates a list of PropertyFields from the sub-fields of the given SerializedProperty
/// and adds them to the specified container element
/// </summary>
/// <param name="property">The SerializedProperty to create sub property fields for</param>
/// <param name="containerElement">The element to place the created PropertyFields in</param>
public static void CreatePropertyFields(SerializedProperty property, VisualElement containerElement)
{
var fieldType = StaticData.GetManagedReferenceValue(property).GetType();
var iterator = property.Copy();
var nextSiblingProperty = property.Copy();
nextSiblingProperty.NextVisible(false);
if (iterator.NextVisible(true))
do
{
if (SerializedProperty.EqualContents(iterator, nextSiblingProperty))
break;
var propertyField = CreatePropertyField(iterator, fieldType);
containerElement.Add(propertyField);
} while (iterator.NextVisible(false));
}
/// <summary>
/// Creates a PropertyField from a given SerializedProperty (with tooltips!)
/// </summary>
/// <param name="iterator">The SerializedProperty to create a PropertyField</param>
/// <param name="parentPropertyType">The Type of the class encapsulating the provided SerializedProperty</param>
/// <returns></returns>
public static PropertyField CreatePropertyField(SerializedProperty iterator, Type parentPropertyType)
{
var propertyField = new PropertyField(iterator.Copy());
propertyField.Bind(iterator.serializedObject);
var originalField = parentPropertyType.GetField(iterator.name);
var tooltipAttribute = originalField.GetCustomAttributes(true)
.ToList().Find(att => att.GetType() == typeof(TooltipAttribute));
if (tooltipAttribute != null)
propertyField.tooltip = (tooltipAttribute as TooltipAttribute)?.tooltip;
return propertyField;
}
}
}

3
com.unity.perception/Editor/Randomization/Utilities/UIElementsEditorUtilities.cs.meta


fileFormatVersion: 2
guid: 9ed5513847d3486dbf017c9fb30186b9
timeCreated: 1612048047

101
com.unity.perception/Editor/Randomization/StaticData.cs


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine.Experimental.Perception.Randomization.Parameters;
using UnityEngine.Experimental.Perception.Randomization.Randomizers;
using UnityEngine.Experimental.Perception.Randomization.Samplers;
namespace UnityEngine.Experimental.Perception.Randomization.Editor
{
static class StaticData
{
const string k_RandomizationDir = "Packages/com.unity.perception/Editor/Randomization";
internal const string uxmlDir = k_RandomizationDir + "/Uxml";
internal static readonly string samplerSerializedFieldType;
internal static Type[] randomizerTypes;
internal static Type[] samplerTypes;
static StaticData()
{
randomizerTypes = GetConstructableDerivedTypes<Randomizer>();
samplerTypes = GetConstructableDerivedTypes<ISampler>();
var samplerType = typeof(ISampler);
samplerSerializedFieldType = $"{samplerType.Assembly.GetName().Name} {samplerType.FullName}";
}
static Type[] GetConstructableDerivedTypes<T>()
{
var collection = TypeCache.GetTypesDerivedFrom<T>();
var types = new List<Type>();
foreach (var type in collection)
{
if (!type.IsAbstract && !type.IsInterface)
types.Add(type);
}
return types.ToArray();
}
internal static object GetManagedReferenceValue(SerializedProperty prop, bool parent=false)
{
var path = prop.propertyPath.Replace(".Array.data[", "[");
object obj = prop.serializedObject.targetObject;
var elements = path.Split('.');
if (parent)
elements = elements.Take(elements.Count() - 1).ToArray();
foreach (var element in elements)
{
if (element.Contains("["))
{
var elementName = element.Substring(0, element.IndexOf("["));
var index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[","").Replace("]",""));
obj = GetArrayValue(obj, elementName, index);
}
else
obj = GetValue(obj, element);
}
return obj;
}
static object GetValue(object source, string name)
{
if (source == null)
return null;
var type = source.GetType();
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (f == null)
{
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
return p == null ? null : p.GetValue(source, null);
}
return f.GetValue(source);
}
static object GetArrayValue(object source, string name, int index)
{
var value = GetValue(source, name);
if (!(value is IEnumerable enumerable))
return null;
var enumerator = enumerable.GetEnumerator();
while (index-- >= 0)
enumerator.MoveNext();
return enumerator.Current;
}
public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
while (toCheck != null && toCheck != typeof(object)) {
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur) {
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
}
}

/com.unity.perception/Editor/Randomization/StaticData.cs.meta → /com.unity.perception/Editor/Randomization/Utilities/StaticData.cs.meta

/com.unity.perception/Editor/Utilities.meta → /com.unity.perception/Editor/Randomization/Utilities.meta

/com.unity.perception/Editor/Utilities/ParameterUIElementsEditor.cs.meta → /com.unity.perception/Editor/Randomization/Utilities/ParameterUIElementsEditor.cs.meta

正在加载...
取消
保存