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
- Custom Components
- 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 => _document?.rootVisualElement;
public void InitializeDocument()
{
TitleLabel = Root?.Q<Label>("TitleLabel");
Button = Root?.Q<Button>("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.
After installing Rosalina, the code generation process is disabled by default, and should be enabled.
Go to Edit > Project Settings > Rosalina
and enable it:
Once Rosalina is enabled, you will need to manually add a UXML file to the Rosalina's code generation processor.
To do so, right-click on a UXML file, go to Rosalina > Properties...
:
The Rosalina's properties window opens next to the inspector tab, and you can enable it to add the current file to the Rosalina's code generation processor.
Rosalina provides three generator types:
- Document
- Component
- Editor
Choose the generator type according to your needs.
When generating a UXML file binding-script, it will be automatically created and 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.
Generator Type: Document
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";
}
}
Note, even if this file has been generated, you still can edit it because it will not be overwritten each time you change a UXML file.
To use a UI Document as an Unity's Editor Window, set the Generator type in Rosalina's properties window, to Component
.
Take this UXML file for example:
<ui:UXML ...>
<ui:Label text="My custom label" name="TitleLabel" />
<ui:Button text="Sample Button" display-tooltip-when-elided="true" name="SampleButton" />
</ui:UXML>
Rosalina's code generator will generate the following class:
// <auto-generated>
using UnityEngine.UIElements;
public partial class CustomComponent
{
public Label TitleLabel { get; private set; }
public Button SampleButton { get; private set; }
public VisualElement Root { get; }
public CustomComponent(VisualElement root)
{
Root = root;
TitleLabel = Root?.Q<Label>("TitleLabel");
SampleButton = Root?.Q<Button>("SampleButton");
}
}
Then when using this component in another UI Document, Editor or component, Rosalina will automatically initialize it using it's constructor:
<ui:UXML ...>
<ui:Template name="CustomComponent" src="project://..." />
<!-- Other UI elements... -->
<ui:Instance template="CustomComponent" name="MyCustomComponent" />
</ui:UXML>
// <auto-generated>
using UnityEngine;
using UnityEngine.UIElements;
public partial class SampleDocument
{
[SerializeField]
private UIDocument _document;
// Other UI element properties...
public CustomComponent MyCustomComponent { get; private set; }
public VisualElement Root => _document?.rootVisualElement;
public void InitializeDocument()
{
// Other initializations...
CustomLabel = new CustomComponent(Root?.Q<VisualElement>("MyCustomComponent"));
}
}
In your SampleDocument
script, you can access the CustomLabel
just like any other UI element or object instance:
using UnityEngine;
public partial class SampleDocument : MonoBehaviour
{
private void OnEnable()
{
InitializeDocument();
// Setting the TitleLabel's text within the CustomLabel component.
CustomLabel.TitleLabel.text = "Hello world!";
}
}
To use a UI Document as an Unity's Editor Window, set the Generator type in Rosalina's properties window, to Editor
.
Take this UXML file for example:
<ui:UXML ...>
<ui:Button text="Sample Button" display-tooltip-when-elided="true" name="SampleButton" />
</ui:UXML>
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 = rootVisualElement?.Q<Button>("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.
If you like the project, don't hesitate to contribute! All contributions are welcome!