Search Unity

GUI Rosalina - Code generation for UI Toolkit documents (UI Elements)

Discussion in 'Tools In Progress' started by Eastrall, Jan 10, 2022.

  1. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello everyone!

    I would like to introduce my Unity extension for UI Toolkit! I recently started using the new Unity UI Toolkit and UI Builder and love the new way of building user interfaces! And I kinda faced some issues about binding the actual UXML template and a C# script, but where the are issues, there is always a solution! :)

    The issue I faced

    If you already tested it, you might have noticed that linking UIDocument elements (like buttons, labels, etc..) is kinda cumbersome, since you have to reference your UI document to your script and then use the following method:

    Code (CSharp):
    1. private void OnEnable()
    2. {
    3.     var element = document.rootVisualElement.Q("ElementName");
    4.     // Other elements...
    5. }
    Now imagine, you are changing an element name, and forgot to update your script, it will simply not work anymore and you will spend some time figuring out what's wrong.

    This is where Rosalina comes in!

    What is Rosalina ?

    Rosalina is a code generator tool that generates a C# script with all UI properties based on a UXML file. Of course, you can extend the original script and focus on your logic instead of assigning your properties manually, Rosalina does it for you. ;)

    Think about it like the code-behind a WinForm or WPF UI.

    Take for instance the following UXML template:

    SampleDocument.uxml
    Code (uxml):
    1. <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance"
    2.          engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
    3.          noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    4.     <ui:VisualElement>
    5.         <ui:Label text="Label" name="TitleLabel" />
    6.         <ui:Button text="Button" name="Button" />
    7.     </ui:VisualElement>
    8. </ui:UXML>
    Rosalina's AssetProcessor will automatically genearte the following C# UI bindings script:

    SampleDocument.g.cs

    Code (CSharp):
    1. // <autogenearted />
    2. using UnityEngine;
    3. using UnityEngine.UIElements;
    4.  
    5. public partial class SampleDocument
    6. {
    7.     [SerializeField]
    8.     private UIDocument _document;
    9.     public Label TitleLabel { get; private set; }
    10.  
    11.     public Button Button { get; private set; }
    12.  
    13.     public VisualElement Root
    14.     {
    15.         get
    16.         {
    17.             return _document?.rootVisualElement;
    18.         }
    19.     }
    20.  
    21.     public void InitializeDocument()
    22.     {
    23.         TitleLabel = (Label)Root?.Q("TitleLabel");
    24.         Button = (Button)Root?.Q("Button");
    25.     }
    26. }
    Warning: This script behing an auto-genearted 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.

    Rosalina provides a context-menu option to generate a C# UI script where you can place your UI related code without the risk of behing overwritten by Rosalina's asset processor. Just right click on the UXML and access Rosalina menu-item, then select Genearte UI script.



    This option will generate the following code:

    SampleDocument.cs

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public partial class SampleDocument : MonoBehaviour
    4. {
    5.     private void OnEnable()
    6.     {
    7.         InitializeDocument();
    8.     }
    9. }
    You can now update this code to interact with UI components such as:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public partial class SampleDocument : MonoBehaviour
    4. {
    5.     private void OnEnable()
    6.     {
    7.         InitializeDocument();
    8.         Button1.clicked += OnButtonClick;
    9.     }
    10.  
    11.     private void OnButtonClick()
    12.     {
    13.         TitleLabel.text = "Clicked!";
    14.     }
    15. }
    And the result in action :


    Change Log

    4.0.0 - 2023-09-23
    Enhancement
    • Bindings/Script generators code cleaning
    • Added manual generation (#26) (PR #27)
    • Added UXML custom properties window for configuring how Rosalina should behave. (#26) (PR #27)
    • Change bindings initialization method to generic methods. (#26) (PR #27)
    • Add custom component support (#25) (PR #27)
    • Rosalina settings improvement

    3.0.1 - 2023-07-16
    Bug fixes
    • Fixed a bug preventing Rosalina's settings file creation.
    3.0.0 - 2023-04-09
    Enhancement
    • Change editor extensions bindings to its own Editor folder
    • Add clear and generate all bindings menu items
    • Replace Roslyn Library with Rosyn dlls instead
    • Add Rosalina settings to enable/disable the generator

    2.0.0 - 2022-11-28
    Enhancement
    • Change generated binding files location to Assets/Rosalina/AutoGenerated
    • Add EditorWindow support.
    Bug fixes
    • Fixed a bug related to Generate UI Script menu item where UI script wasn't generated.

    1.2.1 - 2022-09-14
    Bug fixes
    • Fix visual tree asset property query generation in bindings (e0b6005)

    1.2.0 - 2022-08-25
    Enhancement

    1.1.0 - 2022-06-19
    Enhancement
    • Add support for kebab-case properties in UXML. (c2ef56c)
    Bug fixes
    • Apply filter to Assets/ folder to prevent generating bindings for internal unity Uxml files. (PR #17)

    1.0.3 - 2022-06-05
    Bug fixes

    1.0.2 - 2022/05/28
    Misc
    • Remove all Roslyn related dll files and build a single dll with all necessary components for code generation.
    • Add netstandard2.0 project with the Rosalina.Roslyn assembly project generating the single dll for code generation.

    1.0.1 - 2022/03/05
    Bug fixes
    Misc
    • Review Rosalina generation main entry point.
    • Clean menu item code.

    1.0.0 - 2022/02/01
    Features
    • Watcher on UXML templates
    • Code generation for UI bindings based on UXML templates
    • Menu-item to re-generate UI bindings
    • Menu-item to generate a UI script

    Known limitations

    For now, Rosalina only generates the UI Document bindings and code behding 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).

    --------------

    This is still in early development, but I'd like to ear (read) your feedback about this kind of tool. Could it be useful for you or for future developers building UIs ? Would love to read your thoughts!

    This tool is open-source and available at : https://github.com/Eastrall/Rosalina Contributions are welcome!
    You can follow the progress on the GitHub project's roadmap: https://github.com/Eastrall/Rosalina/projects/1

    The roadmap will be updateed when new features are added, so stay tuned to GitHub! :)

    Thanks for reading!


    PS: this post will be updated frequently with more informations, roadmap updates and changelog.
     
    Last edited: Sep 23, 2023
    KMUX, saskenergy, Ryiah and 5 others like this.
  2. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Small update on the roadmap, I have completed so far :
    • the code-cleaning
    • changed the private fields to public readonly properties to avoid development errors
    • Add a menu-item when you right click on a UXML template to generate the code-behind


    Roadmap on github has been updated! :)
     
  3. Xan_9

    Xan_9

    Joined:
    Oct 7, 2020
    Posts:
    31
    Very interesting!
    What is the difference between 'Generate UI Script' and 'Generate Code-Behind'?
     
  4. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    The "Generate Code-Behind" will generate the bindings based on the UXML template (elements with names), and the "Generate UI script" will generate the actual MonoBehavior script where you'll add your UI logic.

    Perhaps I'll rename the "Generate Code-Behind" in "Generate UI Bindings" instead. :)
     
  5. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Main post has been updated. The initial roadmap has been completed and Rosalina is ready to be used. (I guess so :) )
    Since it respects the Unity Package layout, you can add the package using the git URL: https://github.com/Eastrall/Rosalina.git

    If you have any suggestions that could improve the project, feel free to open an issue on github or write an answer here! :)
     
  6. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    I just made a new 2021.2 project and imported the package but when I click on the uxml there is not Roslina option.

    When I press play I get this error.
    Unloading broken assembly Packages/com.eastylabs.rosalina/Editor/Roslyn/Microsoft.CodeAnalysis.Features.dll, this assembly can cause crashes in the runtime
     
    Last edited: Feb 24, 2022
  7. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello, thanks for your feedback!
    Can you provide more specific details about your Unity version?
     
  8. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    2021.2.13f1 and I tried it in an existing 2021.28f1 and it did not work. Since it is no longer a pre-release and is part of the standard Unity install, the release notes say that it is backported to earlier versions so they are all running the release version with a new project is created in any version and I bet that if you upgrade to the new release of whatever project you are using that it will get the release version and break the project like it did my 2021 project.
     
  9. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Thank you for specifying your Unity version. I will look into that issue and provide a fix for Unity 2021.2.13f1.
     
  10. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello, I haven't been able to reproduce the error on Unity latest version (2021.2.13f1). Could you provide a reproduction project on a public Github repo, it would be great.
    Maybe you are using extra packages that are conflicting with Rosalina?
     
  11. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello everyone,

    Just released version 1.0.1 of Rosalina : https://github.com/Eastrall/Rosalina/releases/tag/v1.0.1

    It fixes a null reference exception when the user selects any Rosalina's menu-items when no game object is selected. Also, I have cleaned a little bit the code of both menu-items.
     
  12. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
  13. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    This is what I get with a new 2121.2.14f project. I installed Roslina from disk.
     
  14. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    I just tried it without using the dashes in the names and it works.
     
    Eastrall likes this.
  15. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Yes, you shouldn't use the dashes in your element names, since the name is used as a C# property. Always use PascalCase or camelCase.
    I personally use PascalCase for element names. :)
     
  16. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    It does not recognize all of the elements and controls. Will it do that in the future?
     
  17. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Sure! I'll be glad to add more controls support!
    For now, the supported controls are the following:
    • VisualElement
    • ScrollView
    • ListView
    • IMGUIContainer
    • GroupBox
    • Label
    • Button
    • Toggle
    • Scroller
    • TextField
    • Foldout
    • Slider
    • SliderInt
    • MinMaxSlider
    • ProgressBar
    • DropdownField
    • RadioButton
    • RadioButtonGroup
    If you need an extra control, please open a issue on GitHub :)
     
  18. Randolphjand

    Randolphjand

    Joined:
    Sep 23, 2017
    Posts:
    28
    I figured out what I was not doing. For Roslina to include it, you Must change the default name.
    Thank you so much for this tool. It saves all of the boring grunt work.
     
  19. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
  20. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
  21. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello,

    A new version of Rosalina is now online : https://github.com/Eastrall/Rosalina/releases/tag/v1.1.0
    This adds the support of "kebab-case" element names. These names will be converted into "PascalCase" properties during code generation. In case of duplicate properties, Rosalina will throw an error and cancel the code generation process.
     
  22. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
  23. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
  24. mark-007

    mark-007

    Joined:
    Mar 4, 2015
    Posts:
    27
    Just wanted to say... this is awesome and thank you :)

    Honestly.. Unity should include this as standard!
     
    Eastrall likes this.
  25. teremy

    teremy

    Joined:
    May 2, 2015
    Posts:
    88
    I'm justing starting out with UIToolkit and have experience with many other GUI framework, so I was looking for something like this. Have not tested it yet, but great effort and I also think there should be an official solution. Unity should just hire you for this :).
     
    Eastrall likes this.
  26. mark-007

    mark-007

    Joined:
    Mar 4, 2015
    Posts:
    27
    It's worth checking out the issues page as there are a few things that need to be born in mind.. it currently doesn't support namespaces, so I forked it and added namespace support but not sure if the developer wants that as a PR or not. It's also worth checking if it's compatible with other packages you use as there does seem to be an issue as detailed in issue #23 https://github.com/Eastrall/Rosalina/issues/23 - we hit that with the popular NetCorder package.
     
    Eastrall likes this.
  27. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    To be honest, I completly forgot to reply to your suggestion, sorry about that: https://github.com/Eastrall/Rosalina/issues/13#issuecomment-1484150349
    Feel free to contribute to the project by opening a PR and submit it for review. :)

    The tool isn't perfect, and I am aware that there can be some incompatiblities due to the libraries the package uses (Roslyn). Since I am not a Unity expert, I look forward and seek reviews from other developers in order to improve my knowledge with the Unity Engine and also, contribute to the community.
     
  28. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    mark-007 likes this.
  29. mark-007

    mark-007

    Joined:
    Mar 4, 2015
    Posts:
    27
    Thats awesome - nice one :)
     
    rstecca_inovus and Eastrall like this.
  30. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Hello everyone, just released version 4.0.0 that adds many features to Rosalina! Check it out here: https://github.com/Eastrall/Rosalina/releases/tag/v4.0.0

    Thanks to suggestions, we have added "Custom components" support, improved our bindings generators, added a properties window for each UXML files that allows you to enable (or not) Rosalina for the given file, and also select the kind of generator you want to use!
     
    bb8_1 likes this.
  31. Braneloc

    Braneloc

    Joined:
    Nov 28, 2012
    Posts:
    8
    If it didn't exist, someone would have to invent it :):):)
    Luckily I found this before starting :D
    Any chance of it generating namespaces ?
     
  32. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    There is actually a PR related to this: https://github.com/Eastrall/Rosalina/pull/28
    The subject can be a little tricky since, because the namespace should the same on both generated and user-script. I believe there is some additionnal digging to do before having something stable and ready to use.
     
  33. Braneloc

    Braneloc

    Joined:
    Nov 28, 2012
    Posts:
    8
    Had a quick look at that, looks like it adds it to prefs, but not to the autogeneration. Looks like a good start though. If the namespace is an issue, maybe add it directly to the class name ?
     
  34. Eastrall

    Eastrall

    Joined:
    Dec 14, 2020
    Posts:
    31
    Maybe a way to go would be to track the user-script unique id and use the namespace defined in that script. During generation, we could load the C# syntax tree and get the namespace out of it. I'll look into it when I have a moment.
     
  35. mark-007

    mark-007

    Joined:
    Mar 4, 2015
    Posts:
    27
    Would love to see that merged in.. We're still using an old custom version where I hacked in namespace support but would love to see it in your official one :)
     
    Eastrall likes this.
  36. CashewTheCat

    CashewTheCat

    Joined:
    Nov 29, 2017
    Posts:
    20
    Man I was so stoked to find this, and I excitedly read through the documentation. Right to the second to last line.
    • Rosalina currently does not support namespaces.
    What a bummer. It's kind of a deal-breaker for me, but I think I will still wind up using it, but in a less automated fashion. Still, it will save me loads of work.
     
  37. CashewTheCat

    CashewTheCat

    Joined:
    Nov 29, 2017
    Posts:
    20
    Did you do something semi-hard-coded to fit your specific use-case, or was it generic? I'm about to open this thing up and do the same thing...
     
  38. CashewTheCat

    CashewTheCat

    Joined:
    Nov 29, 2017
    Posts:
    20
    Another concern. I am using Rosalina in a section of the project which is compiled to its own assembly. Seems like I need to create a dedicated Rosalina assembly and then reference it from my assembly. It works, but its not great. Is the generation target directory configurable? I couldn't find it.

    Update: actually partials all need to be defined in the same assembly per C# standard, so this will not work at all for me. Bummer.