Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional UI elements for create menu #11281

Merged
merged 4 commits into from
Dec 9, 2022
Merged
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
185 changes: 157 additions & 28 deletions com.microsoft.mrtk.uxcomponents/Editor/CreateElementMenus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using UnityEngine.UI;
using UnityEditor.UI;
using UnityEngine.EventSystems;
using UnityEngine.XR.Interaction.Toolkit.UI;
using Microsoft.MixedReality.GraphicsTools;
using TMPro;
using System.Reflection;
using System.Linq;
Expand All @@ -27,14 +29,15 @@ static internal class CreateElementMenus
// The basic building block button; contains an icon, text, and label.
private static readonly string ActionButtonPath = AssetDatabase.GUIDToAssetPath("c6b351a67ceb69140b199996bbbea156");

// CanvasBackplate.mat
// Backplate material for menu plates.
private static readonly string PlateMaterialPath = AssetDatabase.GUIDToAssetPath("65972ebbfd5c529479f9c30fd3ec3f6a");

// Reflection into internal UGUI editor utilities.
private static System.Reflection.MethodInfo PlaceUIElementRoot = null;

private static GameObject CreateElement(string path, MenuCommand menuCommand)
private static GameObject SetupElement(GameObject gameObject, MenuCommand menuCommand)
{
Object prefab = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
GameObject gameObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
Undo.RegisterCreatedObjectUndo(gameObject, "Create " + gameObject.name);

// This is evil :)
// UGUI contains plenty of helper utilities for spawning and managing new Canvas objects
Expand Down Expand Up @@ -63,66 +66,192 @@ private static GameObject CreateElement(string path, MenuCommand menuCommand)
Canvas canvas = gameObject.GetComponentInParent<Canvas>();
RectTransform rt = canvas.GetComponent<RectTransform>();

// If the canvas's only child is us; let's resize the canvas to be a decent starting size.
// If the canvas's only child is us; let's make sure the Canvas has reasonable starting defaults.
// Otherwise, it was probably an existing canvas we were added to, so we shouldn't mess with it.
if (rt.childCount == 1 && rt.GetChild(0) == gameObject.transform)
{
// 1mm : 1 unit measurement ratio.
if (rt.lossyScale != Vector3.one * 0.001f)
{
rt.localScale = Vector3.one * 0.001f;
}
SetReasonableCanvasDefaults(canvas);

// Reset our own object to zero-position relative to the parent canvas.
gameObject.GetComponent<RectTransform>().anchoredPosition3D = Vector3.zero;
}

// 150mm x 150mm.
rt.sizeDelta = Vector2.one * 150.0f;
return gameObject;
}

// All our canvases will be worldspace (by default.)
canvas.renderMode = RenderMode.WorldSpace;
private static GameObject CreateElementFromPath(string path, MenuCommand menuCommand)
{
Object prefab = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
GameObject gameObject = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
Undo.RegisterCreatedObjectUndo(gameObject, "Create " + gameObject.name);

// 30cm in front of the camera.
rt.position = Camera.main.transform.position + Camera.main.transform.forward * 0.3f;
gameObject.GetComponent<RectTransform>().anchoredPosition3D = Vector3.zero;
return SetupElement(gameObject, menuCommand);
}

// PlaceUIElementRoot will have created a GraphicRaycaster for us.
// We don't want that (at least by default)
GraphicRaycaster raycaster = canvas.GetComponent<GraphicRaycaster>();
if (raycaster == null)
{
UnityEngine.Object.Destroy(raycaster);
}
private static void SetReasonableCanvasDefaults(Canvas canvas)
{
RectTransform rt = canvas.GetComponent<RectTransform>();

// 1mm : 1 unit measurement ratio.
if (rt.lossyScale != Vector3.one * 0.001f)
{
rt.localScale = Vector3.one * 0.001f;
}
// 150mm x 150mm.
rt.sizeDelta = Vector2.one * 150.0f;

// All our canvases will be worldspace (by default.)
canvas.renderMode = RenderMode.WorldSpace;
Undo.RecordObject(canvas, "Set Canvas RenderMode to WorldSpace");

// 30cm in front of the camera.
rt.position = Camera.main.transform.position + Camera.main.transform.forward * 0.3f;
Undo.RecordObject(rt, "Set Canvas Position");

// No GraphicRaycaster by default. Users can add one, if they like.
GraphicRaycaster raycaster = canvas.GetComponent<GraphicRaycaster>();
if (raycaster != null)
{
Undo.DestroyObjectImmediate(raycaster);
}

// CanvasScaler should be there by default.
CanvasScaler scaler = canvas.GetComponent<CanvasScaler>();
if (scaler == null)
{
scaler = Undo.AddComponent<CanvasScaler>(canvas.gameObject);
}
}

[MenuItem("GameObject/UI/MRTK/Canvas", false, 0)]
private static void CreateEmptyCanvas(MenuCommand menuCommand)
{
Undo.SetCurrentGroupName("Create Canvas");
int group = Undo.GetCurrentGroup();

GameObject gameObject = new GameObject("Canvas");
Undo.RegisterCreatedObjectUndo(gameObject, "Create blank MRTK Canvas");

Canvas canvas = Undo.AddComponent<Canvas>(gameObject);
SetReasonableCanvasDefaults(canvas);

Undo.CollapseUndoOperations(group);
}

[MenuItem("GameObject/UI/MRTK/Canvas + Graphic Raycasting", false, 0)]
private static void CreateGraphicRaycastingCanvas(MenuCommand menuCommand)
{
Undo.SetCurrentGroupName("Create Canvas (Raycasting-enabled)");
int group = Undo.GetCurrentGroup();

GameObject gameObject = new GameObject("Canvas");
Undo.RegisterCreatedObjectUndo(gameObject, "Create MRTK Canvas with Graphic Raycasting");

Canvas canvas = Undo.AddComponent<Canvas>(gameObject);
SetReasonableCanvasDefaults(canvas);

Undo.AddComponent<GraphicRaycaster>(gameObject);
Undo.AddComponent<TrackedDeviceGraphicRaycaster>(gameObject);

Undo.CollapseUndoOperations(group);
}

// TODO: This may end up being prefabified at some point. Also TODO,
// ensure this gets theming scripts when that system is ready.
[MenuItem("GameObject/UI/MRTK/Plate", false, 0)]
private static GameObject CreatePlate(MenuCommand menuCommand)
{
Undo.SetCurrentGroupName("Create Plate");
int group = Undo.GetCurrentGroup();

GameObject gameObject = new GameObject("Plate", typeof(CanvasElementRoundedRect));


Undo.RegisterCreatedObjectUndo(gameObject, "Create " + gameObject.name);

// gameObject.transform.SetParent((menuCommand.context as GameObject).transform, false);

SetupElement(gameObject, menuCommand);

CanvasElementRoundedRect roundedRect = gameObject.GetComponent<CanvasElementRoundedRect>();

roundedRect.raycastTarget = false;
roundedRect.material = AssetDatabase.LoadAssetAtPath(PlateMaterialPath, typeof(Material)) as Material;
roundedRect.Radius = 13.0f;
roundedRect.Thickness = 2.0f;
roundedRect.Wedges = 8;
roundedRect.SmoothEdges = true;
Undo.RecordObject(roundedRect, "Set Plate RoundedRect properties");


Undo.CollapseUndoOperations(group);

return gameObject;
}

[MenuItem("GameObject/UI/MRTK/Action Button", false, 0)]
private static void CreateActionButton(MenuCommand menuCommand)
{
CreateElement(ActionButtonPath, menuCommand);
CreateElementFromPath(ActionButtonPath, menuCommand);
}

[MenuItem("GameObject/UI/MRTK/Action Button (Wide)", false, 1)]
private static void CreateActionButtonWide(MenuCommand menuCommand)
private static GameObject CreateActionButtonWide(MenuCommand menuCommand)
{
GameObject gameObject = CreateElement(ActionButtonPath, menuCommand);
Undo.SetCurrentGroupName("Create Action Button (wide)");
int group = Undo.GetCurrentGroup();

GameObject gameObject = CreateElementFromPath(ActionButtonPath, menuCommand);

RectTransform rt = gameObject.GetComponent<RectTransform>();
rt.sizeDelta = new Vector2(128.0f, 32.0f);
Undo.RecordObject(rt, "Set Action Button (Wide) size");
LayoutElement le = gameObject.GetComponent<LayoutElement>();
le.minWidth = 128.0f;
Undo.RecordObject(le, "Set Action Button (Wide) min width");

var text = gameObject.GetComponentsInChildren<TMP_Text>(true).Where(t => t.name == "Text").First();
text.gameObject.SetActive(true);
text.alignment = TextAlignmentOptions.Left;
text.text = "<size=8>Header</size><size=6>\n<alpha=#88>Meta text goes here</size>";
Undo.RecordObject(text, "Set Action Button (Wide) text");

PrefabUtility.RecordPrefabInstancePropertyModifications(gameObject);

return gameObject;
}

[MenuItem("GameObject/UI/MRTK/Empty Button", false, 2)]
private static void CreateEmptyButton(MenuCommand menuCommand)
{
CreateElement(EmptyButtonPath, menuCommand);
CreateElementFromPath(EmptyButtonPath, menuCommand);
}

[MenuItem("GameObject/UI/MRTK/List Menu", false, 0)]
private static void CreateListMenu(MenuCommand menuCommand)
{
Undo.SetCurrentGroupName("Create ListMenu");
int group = Undo.GetCurrentGroup();

var plate = CreatePlate(menuCommand);

var layout = Undo.AddComponent<VerticalLayoutGroup>(plate);
layout.padding = new RectOffset(4, 4, 4, 4);
Undo.RecordObject(layout, "Set ListMenu VerticalLayoutGroup properties");

var fitter = Undo.AddComponent<ContentSizeFitter>(plate);
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
Undo.RecordObject(fitter, "Set ListMenu ContentSizeFitter properties");

for (int i = 0; i < 4; i++)
{
var button = CreateActionButtonWide(menuCommand);
Undo.SetTransformParent(button.transform, plate.transform, "Reparent button to plate");

}

Undo.CollapseUndoOperations(group);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"name": "Microsoft.MixedReality.Toolkit.UXComponents.Editor",
"rootNamespace": "Microsoft.MixedReality.Toolkit.Editor",
"references": [
"Unity.TextMeshPro"
"Unity.TextMeshPro",
"Unity.XR.Interaction.Toolkit",
"Microsoft.MixedReality.GraphicsTools"
keveleigh marked this conversation as resolved.
Show resolved Hide resolved
],
"includePlatforms": [
"Editor"
Expand Down
4 changes: 3 additions & 1 deletion com.microsoft.mrtk.uxcomponents/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
},
"unity": "2020.3",
"dependencies": {
"com.microsoft.mrtk.graphicstools.unity": "0.4.0",
"com.microsoft.mrtk.uxcore": "3.0.0-development",
"com.microsoft.mrtk.spatialmanipulation": "3.0.0-development",
"com.microsoft.mrtk.standardassets": "3.0.0-development"
"com.microsoft.mrtk.standardassets": "3.0.0-development",
"com.unity.xr.interaction.toolkit": "2.2.0"
},
"msftTestDependencies": {
"com.microsoft.mrtk.input": "3.0.0-development"
Expand Down