Rosalina is a code generation tool for Unity's UI documents make with the new UI Toolkit. It automatically generates C# UI binding scripts based on a UXML document template.
- UI Documents
- Automatic C# bindings generation
- C# document script
EditorWindow
support- Automatic C# bindings generation
- C# document script
Rosalina can either be installed via OpenUPM: https://openupm.com/packages/com.eastylabs.rosalina/
Or by using the following git repository: https://github.com/Eastrall/Rosalina.git
Rosalina is now available via OpenUPM: https://openupm.com/packages/com.eastylabs.rosalina/
OpenUPM provides a detailed explanation of how to add packages to unity.
In Unity, navigate to Window -> Package Manager
:
In the Package Manager
, click on the +
on the top left and select Add package from git URL...
No use the following path to install Rosalina https://github.com/Eastrall/Rosalina.git
You can now start to work with Rosalina.
Rosalina watches your changes related to all *.uxml
files contained in the Assets
folder of your project, parses its content and generates the according C# UI binding code based on the element's names.
Take for instance the following UXML template:
SampleDocument.uxml
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements"
xsi="http://www.w3.org/2001/XMLSchema-instance"
engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
editor-extension-mode="False">
<ui:VisualElement>
<ui:Label text="Label" name="TitleLabel"/>
<ui:Button text="Button" name="Button"/>
</ui:VisualElement>
</ui:UXML>
Rosalina's AssetProcessor
will automatically genearte the following C# UI bindings script:
ℹ️ Note: All generated files are located in the
Assets/Rosalina/AutoGenerated/
folder.
SampleDocument.g.cs
// <autogenerated />
using UnityEngine;
using UnityEngine.UIElements;
public partial class SampleDocument
{
[SerializeField]
private UIDocument _document;
public Label TitleLabel { get; private set; }
public Button Button { get; private set; }
public VisualElement Root
{
get
{
return _document?.rootVisualElement;
}
}
public void InitializeDocument()
{
TitleLabel = (Label)Root?.Q("TitleLabel");
Button = (Button)Root?.Q("Button");
}
}
⚠️ This script behing an auto-generated code based on the UXML template, you should not write code inside this file. It will be overwritten everytime you update your UXML template file.
According to Unity's UI Builder warnings, a VisualElement
names can only contains letters, numbers, underscores and dashes.
Since a name with dashes is not a valid name within a C# context, during the code generation process, Rosalina will automatically convert dashed-names
into PascalCase
.
Meaning that if you have the following UXML:
<ui:VisualElement>
<ui:Button text="Button" name="confirm-button"/>
</ui:VisualElement>
Rosalina will generate the following property:
public Button ConfirmButton { get; private set; }
In case you already have a ConfirmButton
as a VisualElement
name, do not worry, Rosalina will detect it for you during the code generation process and throw an error letting you know there is a duplicate property in your UXML document.
Rosalina supports default UI Document meant to be displayed in-game and UI Documents for Unity's EditorWindow
extensions.
After installing Rosalina, the plugin will automatically create a Bindings-Script when ever yous save a Visual Tree Asset
. The generated file will be located at Assets/Rosalina/AutoGenerated
and share it's name with a .g.cs
extension.
You should NOT edit this file in any way or form, as it will be recreated on each change to the corresponding Visual Tree Asset
document.
If this file is not generated automatically, you can generate it by right-clicking it the Visual Tree Asset
file and select Rosalina -> Generate UI bindings
UI Script
To create the UI-Script, which will contain your code, right-click on the Visual Tree Asset
file.
There, choose Rosalina -> Generate UI script
An UI Document is considered as an "in-game" / "runtime" UI when its editor-extension-mode
XML attribute is set to False
. Thus, the code generator knows that he needs to generate a UI Document component with a MonoBehavior
.
When generating an UI Script, Rosalina will generate the following code:
using UnityEngine;
public partial class SampleDocument : MonoBehaviour
{
private void OnEnable()
{
InitializeDocument();
}
}
The InitializeDocument()
method contains all the UI properties initialization. Every interaction with UI properties such as assigning a text to a label or an clicked event action to a button MUST be defined after the InitializeDocument()
call. Otherwise, you will have a NullReferenceException
.
using UnityEngine;
public partial class SampleDocument : MonoBehaviour
{
private void OnEnable()
{
InitializeDocument();
TitleLabel.text = "Hello world!";
Button.clicked += OnConfirmButtonClicked;
}
private void OnButtonClicked()
{
TitleLabel.text = "Button clicked";
}
}
To use a UI Document as an Unity's Editor Window, you will need to set the editor-extension-mode
XML attribute to True
.
<ui:UXML ... editor-extension-mode="True"> <!-- Set to TRUE -->
<ui:Button text="Sample Button" display-tooltip-when-elided="true" name="SampleButton" />
</ui:UXML>
Or you can check the Editor Extension Authoring
inside the UI Builder
. Select you UI Document root node in the Hierarchy
then check Editor Extension Authoring
inside the Document settings
section.
Thus, the Rosalina's code generator will generate you a class that extends the UnityEditor.EditorWindow
:
// <autogenerated />
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public partial class CustomEditorWindow : EditorWindow
{
public Button SampleButton { get; private set; }
public void CreateGUI()
{
VisualTreeAsset asset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/...");
VisualElement ui = asset.CloneTree();
rootVisualElement.Add(ui);
SampleButton = (Button)rootVisualElement?.Q("SampleButton");
OnCreateGUI();
}
partial void OnCreateGUI();
}
When generating an UI Script, Rosalina will generate the following code:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public partial class CustomEditorWindow : EditorWindow
{
partial void OnCreateGUI()
{
}
}
Every interaction with UI properties such as assigning a text to a label or an clicked event action to a button MUST be defined inside the OnCreateGUI()
method:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public partial class CustomEditorWindow : EditorWindow
{
partial void OnCreateGUI()
{
SampleButton.clicked += OnSampleButtonClicked;
}
private void OnSampleButtonClicked()
{
Debug.Log("Hello world!");
}
}
If you want, you can also control the behavior of the window and tell Unity how to open it; for instance, with from a Menu Item
:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public partial class CustomEditorWindow : EditorWindow
{
[MenuItem("Window/My Custom Editor Window")]
public static void ShowWindow()
{
EditorWindow.CreateWindow<CustomEditorWindow>("My Custom Editor Window!");
}
partial void OnCreateGUI()
{
SampleButton.clicked += OnSampleButtonClicked;
}
private void OnSampleButtonClicked()
{
Debug.Log("Hello world!");
}
}
This will add a new entry named My Custom Editor Window
to the Window
menu item:
And when clicking on that menu item, the custom editor window will appear and you can now interact with the elements:
As pointed out by JuliaP_Unity on Unity Forums the document initialization process (element queries) should be done on the OnEnable()
hook, since the UIDocument
visual tree asset is instancied at this moment.
Thank you for the tip!
- The generated files share the name of the
Visual Tree Asset
. Currently, it's not possible to change the script names. - Rosalina currently does not support namespaces.
- It's currently not possible to deactivate the generation of UI-Bindings on
Visual Tree Asset
save.
For now, Rosalina only generates the UI Document bindings and code behind scripts based on the UI element names. You still need to create on your own the GameObject
with a UIDocument
component and then add the UI script (not the UI binding scripts).
ℹ️ In next versions, we could think of an extension that automatically creates a GameObject with the UI script attached to it. 😄
If you like the project, don't hesitate to contribute! All contributions are welcome!