Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions ObjectTranslator/Scripts/Editor/ObjectTranslatorEditorWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class ObjectTranslatorEditorWindow : EditorWindow
{
private List<GameObject> _objectsWithComponent;
private ObjectTranslator _objectTranslator;

private void OnGUI()
{
// _objectsWithComponent = FindObjectsWithComponent();
_objectsWithComponent = GetSortedObjectsWithComponent<ObjectTranslator>();

GUILayout.Label("Translate Objects", EditorStyles.boldLabel);

GUILayout.Space(10);
GUILayout.Label("All Objects", EditorStyles.boldLabel);

if(GUILayout.Button("Run on All"))
{
if(_objectsWithComponent != null)
TranslateAllObjects();
else
Debug.Log("There are no objects with the component");
}

GUILayout.Space(10);
GUILayout.Label("Run Per Object", EditorStyles.boldLabel);

if(_objectsWithComponent != null)
foreach(var obj in _objectsWithComponent)
if(GUILayout.Button(obj.name))
{
TranslateSelectedObject(obj);
Debug.Log("Run on Selected Object was pressed");
}
}

[MenuItem("Tools/Object Translator UGUI")]
public static void ShowWindow()
{
GetWindow(typeof(ObjectTranslatorEditorWindow));
}

private List<GameObject> GetSortedObjectsWithComponent<T>() where T : Component
{
// cr question: is FindObjectsByType the best option here?
var allObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
var objectsWithComponent = new List<GameObject>();

foreach(var obj in allObjects)
{
if(obj.GetComponent<T>() != null)
objectsWithComponent.Add(obj);
}

Debug.Log($"Found {objectsWithComponent.Count} objects with {typeof(T).Name}");

//Sort objects so "xx11" is after "xx2"
objectsWithComponent.Sort((a, b) => EditorUtility.NaturalCompare(a.name, b.name));

return objectsWithComponent;
}

// Original function
/*private List<GameObject> FindObjectsWithComponent()
{
var allObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.InstanceID);
var objectsWithComponent = new List<GameObject>();

foreach(var obj in allObjects)
if(obj.GetComponent<ObjectTranslator>() != null)
objectsWithComponent.Add(obj);

Debug.Log($"Found {objectsWithComponent.Count} objects with ObjectTranslator");

return objectsWithComponent;
}*/

private void TranslateAllObjects()
{
foreach(var obj in _objectsWithComponent)
{
var translator = obj.GetComponent<ObjectTranslator>();

if(translator != null)
translator.TranslateObject();
}
}

private void TranslateSelectedObject(GameObject obj)
{
var translator = obj.GetComponent<ObjectTranslator>();

if(translator != null)
translator.TranslateObject();
}

}
170 changes: 170 additions & 0 deletions ObjectTranslator/Scripts/Editor/ObjectTranslatorEditorWindowUITK.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using UITKUtils;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UIElements;

public class ObjectTranslatorEditorWindowUITK : EditorWindow
{
private const string TranslateAllButtonName = "TranslateAll";
private const string TranslateSelectionButtonName = "TranslateSelection";
private const string TranslatableObjectsListViewName = "TranslatableObjectsListView";

private const string ErrorVisualTreeAssetMissing = "No VisualTreeAsset assigned in the Inspector";
private const string ErrorCheckUXMLComponentNames =
"Null Reference Exception thrown. Make sure your UXML component labels are correct.";

[SerializeField] private VisualTreeAsset m_treeVisualAsset;

private List<GameObject> m_objectsWithComponent;
private ObjectTranslator m_objectTranslator;

private VisualElement m_Root;
private ListView m_TranslatableObjectListView;
private Button m_TranslateAllButton;
private Button m_TranslateSelectionButton;

private void OnEnable()
{
EditorApplication.hierarchyChanged += OnHierarchyChanged;
}

private void OnDisable()
{
EditorApplication.hierarchyChanged -= OnHierarchyChanged;
}

// chonky method. clean this up
public void CreateGUI()
{
m_Root = rootVisualElement;

if(m_treeVisualAsset == null)
{
Debug.Log(ErrorVisualTreeAssetMissing);
return;
}

m_treeVisualAsset.CloneTree(m_Root);
InitializeFields();
InitializeObjectsWithComponent();
MakeListView();
BindButtonCallbacks();
}

[MenuItem("Tools/Object Translator UITK")]
public static void ShowWindow()
{
var window = GetWindow<ObjectTranslatorEditorWindowUITK>();
window.titleContent = new GUIContent("Object Translator UITK");
}

private void InitializeFields()
{
m_TranslateAllButton = m_Root.Q<Button>(TranslateAllButtonName);
Validation.CheckQuery(m_TranslateAllButton, TranslateAllButtonName);

m_TranslateSelectionButton = m_Root.Q<Button>(TranslateSelectionButtonName);
Validation.CheckQuery(m_TranslateSelectionButton, TranslateSelectionButtonName);

m_TranslatableObjectListView = m_Root.Q<ListView>(TranslatableObjectsListViewName);
Validation.CheckQuery(m_TranslatableObjectListView, TranslatableObjectsListViewName);
}

private void OnHierarchyChanged()
{
RefreshObjectList();
Repaint();
}

private void RefreshObjectList()
{
m_objectsWithComponent = GetSortedObjectsWithComponent<ObjectTranslator>();
m_TranslatableObjectListView.Rebuild();
m_TranslatableObjectListView.ClearSelection();
}

private List<GameObject> GetSortedObjectsWithComponent<T>() where T : Component
{
// cr question: is FindObjectsByType the best option here?
var allObjects = FindObjectsByType<GameObject>(FindObjectsSortMode.None);
var objectsWithComponent = new List<GameObject>();

foreach(var obj in allObjects)
{
if(obj.GetComponent<T>() != null)
objectsWithComponent.Add(obj);
}


Debug.Log($"Found {objectsWithComponent.Count} objects with {typeof(T).Name}");

//Sort objects so "xx11" is after "xx2"
objectsWithComponent.Sort((a, b) => EditorUtility.NaturalCompare(a.name, b.name));

return objectsWithComponent;
}

private void InitializeObjectsWithComponent()
{
m_objectsWithComponent = GetSortedObjectsWithComponent<ObjectTranslator>();
}

private void BindButtonCallbacks()
{
m_TranslateAllButton.clicked += () =>
{
if(m_objectsWithComponent == null) return;
foreach(var obj in m_objectsWithComponent)
{
var translator = obj.GetComponent<ObjectTranslator>();

Undo.RecordObject(obj.transform, "Translate Object");
translator.TranslateObject();
}
};

m_TranslateSelectionButton.clicked += () =>
{
var selectedObjects = m_TranslatableObjectListView.selectedItems;

if(selectedObjects == null) return;
foreach(var item in selectedObjects)
if(item is GameObject obj)
{
Undo.RecordObject(obj.transform, "Translate Object");
obj.GetComponent<ObjectTranslator>()?.TranslateObject();
}
};
}

private void MakeListView()
{
Func<VisualElement> makeItem = () => new Label();
Action<VisualElement, int> bindItem = (element, i) =>
{
if(i < 0 || i >= m_objectsWithComponent.Count)
{
Debug.LogWarning("Index out of bounds in bindItem.");
return;
}

var label = element as Label;
label.text = m_objectsWithComponent[i].name;
};

if(m_TranslatableObjectListView != null)
{
m_TranslatableObjectListView.makeItem = makeItem;
m_TranslatableObjectListView.bindItem = bindItem;
m_TranslatableObjectListView.itemsSource = m_objectsWithComponent;
m_TranslatableObjectListView.selectionType = SelectionType.Multiple;
}
else
{
Debug.Log(ErrorCheckUXMLComponentNames);
}
}
}
15 changes: 15 additions & 0 deletions ObjectTranslator/Scripts/Editor/ObjectTranslatorInspector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ObjectTranslator))]
public class ObjectTranslatorInspector : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();

var objectTranslator = (ObjectTranslator)target;

if(GUILayout.Button("Translate Object")) objectTranslator.TranslateObject();
}
}
25 changes: 25 additions & 0 deletions ObjectTranslator/Scripts/ObjectTranslator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using UnityEngine;

public class ObjectTranslator : MonoBehaviour
{
[Header("Translate")] [SerializeField] [ContextMenuItem("Translate", nameof(TranslateObject))]
private Vector3 translation = Vector3.up;

private void Awake()
{
Debug.Log("Awake");
TranslateObject();
}

[ContextMenu("Translate Object")]
public void TranslateObject()
{
transform.Translate(translation);
}

[ContextMenu("Reset Translation")]
public void ResetTranslation()
{
transform.position = Vector3.zero;
}
}
6 changes: 6 additions & 0 deletions ObjectTranslator/UIToolkit/ObjectTranslatorStylesheet.uss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.section {
padding-top: 10px;
padding-right: 10px;
padding-bottom: 10px;
padding-left: 10px;
}
11 changes: 11 additions & 0 deletions ObjectTranslator/UIToolkit/ObjectTranslatorStylesheet.uss.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions ObjectTranslator/UIToolkit/ObjectTranslatorVisualTree.uxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="project://database/Assets/UI%20Toolkit/ObjectTranslator/ObjectTranslatorStylesheet.uss?fileID=7433441132597879392&amp;guid=21ffbed9b9868ed418b9fbf8a0c5db51&amp;type=3#ObjectTranslatorStylesheet" />
<engine:VisualElement name="Container" style="flex-grow: 1;">
<engine:ListView name="TranslatableObjectsListView" header-title="Translatable Objects" show-border="false" class="section" style="height: 384px;" />
</engine:VisualElement>
<engine:Button text="Translate Selection" name="TranslateSelection" style="justify-content: flex-end;" />
<engine:Button text="Translate All" name="TranslateAll" tooltip="This tooltip was set in the UI Builder." style="justify-content: flex-end;" />
</engine:UXML>
10 changes: 10 additions & 0 deletions ObjectTranslator/UIToolkit/ObjectTranslatorVisualTree.uxml.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.