Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Sharing/reusing color values

Discussion in 'UI Toolkit' started by cecarlsen, Jul 26, 2019.

  1. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    575
    What is the best practice for storing a palette of colors to be used across a UIElements solution?

    I also need access to the colors from C# because I use generateVisualContent where vertices need tints from the palette.

    I read that Unity plans to support USS variables, but I can't find any information on it.
    https://forum.unity.com/threads/sassy-css.591724/#post-3955354
     
  2. jonathanma_unity

    jonathanma_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    101
    Hi cecarlsen,

    I can confirm that USS variables will be available on 2019.3 starting at 2019.3.0a10.

    With this you will be able to define your color palette as variables and reuse them across your USS files.

    They are compliant with CSS variables so you can refer to this link for more information : https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

    To access the variables in C# you need to register to the CustomStyleResolvedEvent which is sent to any elements matching variable definitions. From there you can use the ICustomStyle.TryGetValue interface to retrieve the colors.
     
    Last edited: Jul 26, 2019
  3. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    158
    Also by registering to the
    CustomStyleResolvedEvent
    on your element you can read variables and use them in C#, for example in combination with generateVisualContents.

    Code (CSharp):
    1. class MyElement
    2. {
    3.  
    4.    static CustomStyleProperty<Color> s_MyColor = new CustomStyleProperty("my-color");
    5.  
    6.    Color m_Color;
    7.  
    8.    public MyElement()
    9.    {
    10.       RegisterCallback<CustomStyleResolvedEvent>(evt =>
    11.       {
    12.           if (!evt.customStyle.TryGetValue(s_MyColor, out m_Color))
    13.           {
    14.               // assign default color
    15.                m_Color = Color.red
    16.           }
    17.       });
    18.    }
    19. }
     
    cecarlsen and Stardog like this.
  4. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    575
    Thanks again @antoine-unity It works. I encapsulated USS color palette access in a static class like so because I like to have colors global. I call the method from a callback in EditorWindow.OnEnable after adding the stylesheet to the root element. With the given API I don't see how to avoid a lot of name repetitions. It's not pretty and it will get worse as more colors are added.

    Code (CSharp):
    1. public static class Colors
    2. {
    3.     public static Color connection;
    4.     public static Color connectionHover;
    5.     public static Color connectionSelected;
    6.     public static Color connectionSelectedHover;
    7.  
    8.     static CustomStyleProperty<Color> connectionProp = new CustomStyleProperty<Color>( "--connection-color" );
    9.     static CustomStyleProperty<Color> connectionHoverProp = new CustomStyleProperty<Color>( "--connection-hover-color" );
    10.     static CustomStyleProperty<Color> connectionSelectedProp = new CustomStyleProperty<Color>( "--connection-selected-color" );
    11.     static CustomStyleProperty<Color> connectionSelectedHoverProp = new CustomStyleProperty<Color>( "--connection-selected-hover-color" );
    12.  
    13.     public static void ReadColorsFromUSSProperties( CustomStyleResolvedEvent evt )
    14.     {
    15.         evt.customStyle.TryGetValue( connectionProp, out connection );
    16.         evt.customStyle.TryGetValue( connectionHoverProp, out connectionHover );
    17.         evt.customStyle.TryGetValue( connectionSelectedProp, out connectionSelected );
    18.         evt.customStyle.TryGetValue( connectionSelectedHoverProp, out connectionSelectedHover );
    19.     }
    20. }
    EDIT: In USS, all my color variables are defined in :root. Element type specific colors could be placed in their respective USS selectors, but 1) I like to have the colors centralized and 2) it seems like extra work to grab the same colors again and again every time an element of a specific type is created.
     
    Last edited: Jul 29, 2019
  5. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    158
    This API was mostly designed to be used in the context of a single element. Therefore it shouldn't be required to use multiple variables for each state like "hover" or "selected". Instead, if the element is hover and a selector with ":hover" that changes the "--connection-color" exists, the CustomStyleResolvedEvent event will be invoked when the user interacts with it.

    Another way to limit the number of variables is to stick to a color palette with descriptive names such as "--highlight-color", "--accent-color", "--disabled-color", etc.
     
  6. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    575
    Ah, enlightening. I see that I may be working against your design here.

    However, 1) I am drawing many ConnectionElements and I don't see how it can be performant to pick up colors using callbacks in every element and 2) updating the variables inside selectors spreads out my color palette again, which I find messy. I also cannot use more general global descriptive names, because colors like "--highlight-color", "--accent-color", "--disabled-color" varies for my element types.

    I'll get back if find a cleaner solution.
     
  7. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    208
    any news on uss variables? I can't find any mention of them in the current docs and they'd be super helpful to have
     
  8. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,506
    They work now. For editor windows they can go into a ':root' selector, or into a top-level container.
     
  9. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    208
    UPDATE: got it working!

    like jonathanma_unity mentioned, USS vars are compliant with CSS variables, so they're super easy to use. Here's how it looks:

    Code (JavaScript):
    1.  
    2. /* this selector contains all variables */
    3. :root {
    4.     --accent: rgb(32, 34, 38);
    5.     --bg: rgb(49, 49, 49);
    6.     --bg-light: rgb(46, 46, 46);
    7.     --bg-dark: rgb(51, 51, 51);
    8.     --bg-header: rgb(62, 62, 62);
    9.     --selection: rgb(62, 95, 150);
    10.     --selection-disabled: rgb(65, 65, 65);
    11. }
    12.  
    13. /* variables are then accessed like this */
    14. .class {
    15.     background-color = var(--bg);
    16. }
    17.  
    EDIT
    using the :root selector will work for windows, but not for custom editor/inspectors as some users have mentioned in other threads.

    for inspectors, you'll want to use the top-most available selector and define your USS variables that way, instead of using :root

    (I haven't actually run into this issue yet, just figured I'd pass on this information in case anyone needed it)
     
    Last edited: Feb 16, 2020
    benoitd_unity likes this.
unityunity