[CustomEditor(typeof(Labeling)), CanEditMultipleObjects]
class LabelingEditor : Editor
{
private VisualElement m_Root ;
private VisualElement m_ManualLabelingContainer ;
private VisualElement m_AutoLabelingContainer ;
private VisualElement m_FromLabelConfigsContainer ;
private VisualElement m_SuggestedLabelsContainer ;
private VisualElement m_SuggestedOnNamePanel ;
private VisualElement m_SuggestedOnPathPanel ;
private ListView m_CurrentLabelsListView ;
private ListView m_SuggestLabelsListView_ FromName ;
private ListView m_SuggestLabelsListView_ FromPath ;
private ScrollView m_LabelConfigsScrollView ;
private PopupField < string > m_LabelingSchemesPopup ;
private Button m_AddButton ;
private Button m_AddAutoLabelToConfButton ;
private Toggle m_AutoLabelingToggle ;
private Label m_CurrentAutoLabel ;
private Label m_CurrentAutoLabelTitle ;
private Label m_AddManualLabelsTitle ;
VisualElement m_Root ;
VisualElement m_ManualLabelingContainer ;
VisualElement m_AutoLabelingContainer ;
VisualElement m_FromLabelConfigsContainer ;
VisualElement m_SuggestedLabelsContainer ;
VisualElement m_SuggestedOnNamePanel ;
VisualElement m_SuggestedOnPathPanel ;
ListView m_CurrentLabelsListView ;
ListView m_Suggested LabelsListViewFromName ;
ListView m_Suggested LabelsListViewFromPath ;
ScrollView m_LabelConfigsScrollView ;
PopupField < string > m_LabelingSchemesPopup ;
Button m_AddButton ;
Button m_AddAutoLabelToConfButton ;
Toggle m_AutoLabelingToggle ;
Label m_CurrentAutoLabel ;
Label m_CurrentAutoLabelTitle ;
Label m_AddManualLabelsTitle ;
private Labeling m_Labeling ;
Labeling m_Labeling ;
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
private string m_UxmlPath ;
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
string m_UxmlPath ;
private List < string > m_SuggestedLabelsBasedOnName = new List < string > ( ) ;
private List < string > m_SuggestedLabelsBasedOnPath = new List < string > ( ) ;
List < string > m_SuggestedLabelsBasedOnName = new List < string > ( ) ;
List < string > m_SuggestedLabelsBasedOnPath = new List < string > ( ) ;
private List < Type > m_LabelConfigTypes ;
private readonly List < ScriptableObject > m_AllLabelConfigsInProject = new List < ScriptableObject > ( ) ;
List < Type > m_LabelConfigTypes ;
readonly List < ScriptableObject > m_AllLabelConfigsInProject = new List < ScriptableObject > ( ) ;
private readonly List < AssetLabelingScheme > m_LabelingSchemes = new List < AssetLabelingScheme > ( ) ;
readonly List < AssetLabelingScheme > m_LabelingSchemes = new List < AssetLabelingScheme > ( ) ;
/// <summary>
/// List of separator characters used for parsing asset names for auto labeling or label suggestion purposes
/// </summary>
public static readonly string [ ] PathSeparators = { "/" } ;
private void OnEnable ( )
void OnEnable ( )
{
m_LabelConfigTypes = AddToConfigWindow . FindAllSubTypes ( typeof ( LabelConfig < > ) ) ;
m_Root = AssetDatabase . LoadAssetAtPath < VisualTreeAsset > ( m_UxmlPath ) . CloneTree ( ) ;
m_CurrentLabelsListView = m_Root . Q < ListView > ( "current-labels-listview" ) ;
m_SuggestLabelsListView_ FromName = m_Root . Q < ListView > ( "suggested-labels-name-listview" ) ;
m_SuggestLabelsListView_ FromPath = m_Root . Q < ListView > ( "suggested-labels-path-listview" ) ;
m_Suggested LabelsListViewFromName = m_Root . Q < ListView > ( "suggested-labels-name-listview" ) ;
m_Suggested LabelsListViewFromPath = m_Root . Q < ListView > ( "suggested-labels-path-listview" ) ;
m_LabelConfigsScrollView = m_Root . Q < ScrollView > ( "label-configs-scrollview" ) ;
m_SuggestedOnNamePanel = m_Root . Q < VisualElement > ( "suggested-labels-from-name" ) ;
m_SuggestedOnPathPanel = m_Root . Q < VisualElement > ( "suggested-labels-from-path" ) ;
m_Root . schedule . Execute ( CheckForModelChanges ) . Every ( 3 0 ) ;
}
private int m_PreviousLabelsArraySize = - 1 ;
int m_PreviousLabelsArraySize = - 1 ;
/// <summary>
/// This boolean is used to signify when changes in the model are triggered directly from the inspector UI by the user.
/// In these cases, the scheduled model checker does not need to update the UI again.
private SerializedProperty m_FirstItemLabelsArray ;
private void CheckForModelChanges ( )
SerializedProperty m_FirstItemLabelsArray ;
void CheckForModelChanges ( )
{
if ( ChangesHappeningInForeground )
{
}
}
private bool SerializedObjectHasValidLabelingScheme ( SerializedObject serObj )
bool SerializedObjectHasValidLabelingScheme ( SerializedObject serObj )
private bool IsValidLabelingSchemeName ( string schemeName )
bool IsValidLabelingSchemeName ( string schemeName )
private bool m_ItIsPossibleToAddMultipleAutoLabelsToConfig ;
private void UpdateUiAspects ( )
bool m_ItIsPossibleToAddMultipleAutoLabelsToConfig ;
void UpdateUiAspects ( )
{
m_ManualLabelingContainer . SetEnabled ( ! m_AutoLabelingToggle . value ) ;
m_AutoLabelingContainer . SetEnabled ( m_AutoLabelingToggle . value ) ;
}
}
private void UpdateCurrentAutoLabelValue ( SerializedObject serObj )
void UpdateCurrentAutoLabelValue ( SerializedObject serObj )
{
var array = serObj . FindProperty ( nameof ( Labeling . labels ) ) ;
if ( array . arraySize > 0 )
}
private bool AreSelectedAssetsCompatibleWithAutoLabelScheme ( AssetLabelingScheme scheme )
bool AreSelectedAssetsCompatibleWithAutoLabelScheme ( AssetLabelingScheme scheme )
{
foreach ( var asset in serializedObject . targetObjects )
{
return true ;
}
private void InitializeLabelingSchemes ( VisualElement parent )
void InitializeLabelingSchemes ( VisualElement parent )
{
//this function should be called only once during the lifecycle of the editor element
AssetLabelingScheme labelingScheme = new AssetNameLabelingScheme ( ) ;
m_LabelingSchemesPopup . RegisterValueChangedCallback ( evt = > AssignAutomaticLabelToSelectedAssets ( ) ) ;
}
private void AutoLabelToggleChanged ( )
void AutoLabelToggleChanged ( )
{
UpdateUiAspects ( ) ;
RefreshManualLabelingData ( ) ;
}
private void AssignAutomaticLabelToSelectedAssets ( )
void AssignAutomaticLabelToSelectedAssets ( )
{
//the 0th index of this popup is "<Select Scheme>" and should not do anything
if ( m_LabelingSchemesPopup . index = = 0 )
RefreshManualLabelingData ( ) ;
}
private void AssesAutoLabelingStatus ( )
void AssesAutoLabelingStatus ( )
{
var enabledOrNot = true ;
if ( serializedObject . targetObjects . Length = = 1 )
UpdateUiAspects ( ) ;
}
private HashSet < string > CreateUnionOfAllLabels ( )
HashSet < string > CreateUnionOfAllLabels ( )
{
HashSet < String > result = new HashSet < string > ( ) ;
foreach ( var obj in targets )
}
return result ;
}
private string FindNewLabelValue ( HashSet < string > labels )
string FindNewLabelValue ( HashSet < string > labels )
{
string baseLabel = "New Label" ;
string label = baseLabel ;
}
}
public void RemoveAddedLabelsFromSuggestedLists ( )
void RemoveAddedLabelsFromSuggestedLists ( )
public void RefreshSuggestedLabelLists ( )
void RefreshSuggestedLabelLists ( )
{
m_SuggestedLabelsBasedOnName . Clear ( ) ;
m_SuggestedLabelsBasedOnPath . Clear ( ) ;
{
if ( e is AddedLabelEditor addedLabel )
{
addedLabel . m_I ndexInList = i ;
addedLabel . m_L abelTextField. value = CommonLabels [ i ] ;
addedLabel . i ndexInList = i ;
addedLabel . l abelTextField. value = CommonLabels [ i ] ;
}
}
void SetupSuggestedLabelsListViews ( )
{
SetupSuggestedLabelsBasedOnFlatList ( m_SuggestLabelsListView_ FromName , m_SuggestedLabelsBasedOnName ) ;
SetupSuggestedLabelsBasedOnFlatList ( m_SuggestLabelsListView_ FromPath , m_SuggestedLabelsBasedOnPath ) ;
SetupSuggestedLabelsBasedOnFlatList ( m_Suggested LabelsListViewFromName , m_SuggestedLabelsBasedOnName ) ;
SetupSuggestedLabelsBasedOnFlatList ( m_Suggested LabelsListViewFromPath , m_SuggestedLabelsBasedOnPath ) ;
}
void SetupSuggestedLabelsBasedOnFlatList ( ListView labelsListView , List < string > stringList )
{
if ( e is SuggestedLabelElement suggestedLabel )
{
suggestedLabel . m_L abel. text = stringList [ i ] ;
suggestedLabel . l abel. text = stringList [ i ] ;
}
}
}
}
internal class AddedLabelEditor : VisualElement
class AddedLabelEditor : VisualElement
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
public TextField m_LabelTextField ;
public int m_IndexInList ;
public TextField labelTextField ;
public int indexInList ;
m_LabelTextField = this . Q < TextField > ( "label-value" ) ;
labelTextField = this . Q < TextField > ( "label-value" ) ;
m_LabelTextField . isDelayed = true ;
labelTextField . isDelayed = true ;
m_LabelTextField . RegisterValueChangedCallback ( ( cEvent ) = >
labelTextField . RegisterValueChangedCallback ( ( cEvent ) = >
if ( editor . CommonLabels . Contains ( cEvent . newValue ) & & editor . CommonLabels . IndexOf ( cEvent . newValue ) ! = m_IndexInList )
if ( editor . CommonLabels . Contains ( cEvent . newValue ) & & editor . CommonLabels . IndexOf ( cEvent . newValue ) ! = indexInList )
{
//The listview recycles child visual elements and that causes the RegisterValueChangedCallback event to be called when scrolling.
//Therefore, we need to make sure we are not in this code block just because of scrolling, but because the user is actively changing one of the labels.
if ( targetObject is Labeling labeling )
{
var indexToModifyInTargetLabelList =
labeling . labels . IndexOf ( editor . CommonLabels [ m_I ndexInList] ) ;
labeling . labels . IndexOf ( editor . CommonLabels [ i ndexInList] ) ;
var serializedLabelingObject2 = new SerializedObject ( labeling ) ;
addToConfigButton . clicked + = ( ) = >
{
AddToConfigWindow . ShowWindow ( m_L abelTextField. value ) ;
AddToConfigWindow . ShowWindow ( l abelTextField. value ) ;
} ;
removeButton . clicked + = ( ) = >
var serializedLabelingObject2 = new SerializedObject ( labeling ) ;
var serializedLabelArray2 = serializedLabelingObject2 . FindProperty ( "labels" ) ;
serializedLabelArray2 . DeleteArrayElementAtIndex ( commonsIndexToLabelsIndex [ m_I ndexInList] ) ;
serializedLabelArray2 . DeleteArrayElementAtIndex ( commonsIndexToLabelsIndex [ i ndexInList] ) ;
internal class SuggestedLabelElement : VisualElement
class SuggestedLabelElement : VisualElement
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
public Label m_L abel;
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
public Label l abel;
m_L abel = this . Q < Label > ( "label-value" ) ;
l abel = this . Q < Label > ( "label-value" ) ;
var addButton = this . Q < Button > ( "add-button" ) ;
addButton . clicked + = ( ) = >
if ( targetObject is Labeling labeling )
{
if ( labeling . labels . Contains ( m_L abel. text ) )
if ( labeling . labels . Contains ( l abel. text ) )
serializedLabelArray2 . GetArrayElementAtIndex ( serializedLabelArray2 . arraySize - 1 ) . stringValue = m_L abel. text ;
serializedLabelArray2 . GetArrayElementAtIndex ( serializedLabelArray2 . arraySize - 1 ) . stringValue = l abel. text ;
serializedLabelingObject2 . ApplyModifiedProperties ( ) ;
serializedLabelingObject2 . SetIsDifferentCacheDirty ( ) ;
editor . serializedObject . SetIsDifferentCacheDirty ( ) ;
}
}
internal class LabelConfigElement : VisualElement
class LabelConfigElement : VisualElement
private string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
private bool m_Collapsed = true ;
string m_UxmlDir = "Packages/com.unity.perception/Editor/GroundTruth/Uxml/" ;
bool m_Collapsed = true ;
private ListView m_LabelsListView ;
private VisualElement m_CollapseToggle ;
ListView m_LabelsListView ;
VisualElement m_CollapseToggle ;
public LabelConfigElement ( LabelingEditor editor , ScriptableObject config )
{
{
if ( e is SuggestedLabelElement suggestedLabel )
{
suggestedLabel . m_L abel. text = labelList [ i ] ;
suggestedLabel . l abel. text = labelList [ i ] ;
}
}
/// <summary>
/// A labeling scheme based on which an automatic label can be produced for a given asset. E.g. based on asset name, asset path, etc.
/// </summary>
internal abstract class AssetLabelingScheme
abstract class AssetLabelingScheme
{
/// <summary>
/// The description of how this scheme generates labels. Used in the dropdown menu in the UI.
/// <summary>
/// Asset labeling scheme that outputs the given asset's name as its automatic label
/// </summary>
internal class AssetNameLabelingScheme : AssetLabelingScheme
class AssetNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description = > "Use asset name" ;
/// <summary>
/// Asset labeling scheme that outputs the given asset's file name, including extension, as its automatic label
/// </summary>
internal class AssetFileNameLabelingScheme : AssetLabelingScheme
class AssetFileNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description = > "Use file name with extension" ;
/// <summary>
/// Asset labeling scheme that outputs the given asset's folder name as its automatic label
/// </summary>
internal class CurrentOrParentsFolderNameLabelingScheme : AssetLabelingScheme
class CurrentOrParentsFolderNameLabelingScheme : AssetLabelingScheme
{
///<inheritdoc/>
public override string Description = > "Use the asset's folder name" ;