Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/eastrall/rosalina

Rosalina is a code generation tool for Unity's UI documents. It generates C# code-behind script based on a UXML template.
https://github.com/eastrall/rosalina

binding-generator code-behind code-generation csharp dotnet roslyn ui-builder ui-elements ui-toolkit uielements unity unity-editor unity-plugin unity-tool unity-tools unity-ui unity-uielement unity3d unity3d-plugin

Last synced: 7 days ago
JSON representation

Rosalina is a code generation tool for Unity's UI documents. It generates C# code-behind script based on a UXML template.

Awesome Lists containing this project

README

        

# Rosalina

[![openupm](https://img.shields.io/npm/v/com.eastylabs.rosalina?label=openupm&registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.eastylabs.rosalina/)

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.

## Key features

* [UI Documents](https://docs.unity3d.com/Manual/UIE-simple-ui-toolkit-workflow.html)
* Automatic C# bindings generation
* C# document script
* [`EditorWindow`](https://docs.unity3d.com/ScriptReference/EditorWindow.html) support
* Automatic C# bindings generation
* C# document script
* Custom Components
* Automatic C# bindings generation
* C# document script

## How to install

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``

### Installing via OpenUPM

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.

### Installing via git repository

In Unity, navigate to ``Window -> Package Manager``:

![image](https://user-images.githubusercontent.com/4021025/204278700-989b139c-cbf3-4c56-8ebe-91309258aac2.png)

In the ``Package Manager``, click on the ``+`` on the top left and select ``Add package from git URL...``

![image](https://user-images.githubusercontent.com/4021025/204278730-38f06044-b298-484e-b6ad-43cb1684134e.png)

No use the following path to install Rosalina ``https://github.com/Eastrall/Rosalina.git``

![image](https://user-images.githubusercontent.com/4021025/204278754-8bfa4b2d-dd57-4a59-af45-ff05470272fc.png)

You can now start to work with Rosalina.

## How it works

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`**

```xml




```

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`**

```csharp
//
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("TitleLabel");
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:

```xml

```
Rosalina will generate the following property:
```csharp
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.

## How to use

After installing Rosalina, the code generation process is disabled by default, and should be enabled.
Go to `Edit > Project Settings > Rosalina` and enable it:

![image](https://github.com/Eastrall/Rosalina/assets/4021025/124c946f-1a66-404e-8b91-1a3ed02d7c56)

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...`:

![image](https://github.com/Eastrall/Rosalina/assets/4021025/047b3b35-c913-4a38-9fc9-99127b68d887)

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.

![image](https://github.com/Eastrall/Rosalina/assets/4021025/d4bf640a-a653-48b3-badc-602b5ebb4a09)

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.

### UI Document

Generator Type: `Document`

When generating an UI Script, Rosalina will generate the following code:
```csharp
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`.

```csharp
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.

### Custom components

To use a UI Document as an Unity's Editor Window, set the Generator type in Rosalina's properties window, to `Component`.

![image](https://github.com/Eastrall/Rosalina/assets/4021025/db621190-4a49-43cb-8c28-89592dccf23a)

Take this UXML file for example:
```xml


```

Rosalina's code generator will generate the following class:
```csharp
//
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("TitleLabel");
SampleButton = Root?.Q("SampleButton");
}
}
```

Then when using this component in another UI Document, Editor or component, Rosalina will automatically initialize it using it's constructor:
```xml



```
```csharp
//
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("MyCustomComponent"));
}
}
```
In your `SampleDocument` script, you can access the `CustomLabel` just like any other UI element or object instance:
```csharp
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!";
}
}
```

### Editor Window

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:
```xml

```

Rosalina's code generator will generate you a class that extends the `UnityEditor.EditorWindow`:

```csharp
//
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("Assets/...");
VisualElement ui = asset.CloneTree();
rootVisualElement.Add(ui);
SampleButton = rootVisualElement?.Q("SampleButton");
OnCreateGUI();
}

partial void OnCreateGUI();
}
```

When generating an UI Script, Rosalina will generate the following code:
```csharp
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:

```csharp
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`:

```csharp
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public partial class CustomEditorWindow : EditorWindow
{
[MenuItem("Window/My Custom Editor Window")]
public static void ShowWindow()
{
EditorWindow.CreateWindow("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:

![image](https://user-images.githubusercontent.com/4021025/204351292-d34f54e3-b3bb-4efb-a79b-b2768fb257fa.png)

And when clicking on that menu item, the custom editor window will appear and you can now interact with the elements:

![image](https://user-images.githubusercontent.com/4021025/204351418-008a1521-c796-4ec6-852c-43a2a5064e4d.png)

## Notes

As pointed out by [JuliaP_Unity](https://forum.unity.com/members/juliap_unity.4707193/) on [Unity Forums](https://forum.unity.com/threads/share-your-ui-toolkit-projects.980061/#post-7799040) 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!*

## Known limitations

* 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.

## Final words

If you like the project, don't hesitate to contribute! All contributions are welcome!