Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Color resource to adjust a specific color through all instances where it is used #1734

Open
Arecher opened this issue Oct 27, 2020 · 27 comments · Fixed by goostengine/goost#30

Comments

@Arecher
Copy link

Arecher commented Oct 27, 2020

Describe the project you are working on:
Making a game that makes a lot of use of Control nodes and a few key colors that are used throughout.

Describe the problem or limitation you are having in your project:
In my current project we're using certain colors extensively throughout all our UI to signal things to the player. Green is a positive stat, red is a negative stat, et cetera. I have been trying to set up my project in such a way to easily allow these important colors to be adjustable for players, to aid any player that might have issues differentiating between certain colours. However I have yet to find a way that makes it easy to create such settings.

The main issue I have been having is that colors can be used in a lot of different places (font, stylebox materials, modulation variables) and the only way to adjust all of them, would be to keep track of them in a singular place and adjust the color in all instances through a script. The other way I can think of is to make a screen-wide shader that changes selected colors into others. However that seems a bit extreme for simply wanting to adjust all instances of a single color throughout your UI, and likely a lot heavier on performance too.

Maybe I have missed something, but I don't think there currently is a good way to adjust a specific color through all instances of the project where this color is used (in the same way that a PNG or material can be adjusted).

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
I would like to see a new resource added: the 'Color' resource. This would be a file that is saved and holds the information of a single color. This resource could then be used in any location where a Color input is required, to make a reference to the saved resource. Think of font_color entries, StyleBox Materials for panels, Modulation/Self_Modulation values.

That way, if during development the color needs to be changed, it can be changed in the set-up resource, rather than in every individual scene, manually. The same way that making changes to a PNG or a Scene would update all instances in which that resource is used. These resources could then also be used for (accessibility) settings, such as to allow players to easily adjust the font colors throughout all UI scenes, or to allow players to adjust colors they might have difficulty seeing due to colorblindness. (Think of the green & red I am currently using to indicate positive & negative stats throughout my project).

Essentially I want a resource akin to saving a Stylebox material, but only for a single color, so it can be used and referenced throughout the editor where Color inputs are required.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
I hope I have made this clear in my examples and explanation. If required I will make a mock-up, but I think the functionality would be in line with all other resources that can currently be made and used throughout the Godot Engine.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
I haven't found a way to properly adjust Color references throughout a project, and I think this will be used a lot by developers that use Control nodes in their projects, as those are the places that Color inputs are most often needed.

Is there a reason why this should be core and not an add-on in the asset library?:
The use of Color inputs throughout the editor makes me feel like this should be a core part of the engine.

Thank you!

@YuriSizov
Copy link
Contributor

If you are speaking strictly Control nodes, you should define color constants on your main theme and adjust them with user preferences. That’s how theming is done for the editor, for example. You’d still need some system-wide signal, probably, to update colors on the fly. You can use a global helper instance for that.

@Calinou
Copy link
Member

Calinou commented Oct 27, 2020

If you need to store a group of related colors to interpolate between, you can use the Gradient resource to achieve this. (Note that you don't have to interpolate between them, but you can. If you don't want to, only use Gradient.interpolate() with an offset where a stop is explicitly defined.)

@Xrayez
Copy link
Contributor

Xrayez commented Oct 27, 2020

Worth mentioning that I've previously implemented VectorResource class, so you can take it as a base to create a similar plugin.

The main advantage of using a resource is that you can connect the changed() signal to virtually any update() method within your project. The plugin originated from #397 proposal.

There was a discussion that core types like Vector2, Rect2, Color, etc. could be made possible to use as resources out of the box, so you could also store any core types on disk, not just Color. At least that's my idea behind it.

@Arecher
Copy link
Author

Arecher commented Oct 28, 2020

If you are speaking strictly Control nodes, you should define color constants on your main theme and adjust them with user preferences.

The issue with Themes, as far as I understand them, is that it affects all children as well. So creating a singular main theme would make all labels look the same, which is not what I need. Having said that, perhaps I could use themes on nodes that do not have children, to create a theme with a specific font colour, so adjusting the theme would update these instances Would limit it to node types and visual appearances that are the same, but better than nothing. Thanks for the suggestion!

If you need to store a group of related colors to interpolate between, you can use the Gradient resource to achieve this. (Note that you don't have to interpolate between them, but you can. If you don't want to, only use Gradient.interpolate() with an offset where a stop is explicitly defined.)

Thank you! I'll definitely investigate. As I thought there must be ways to work around my limitation, but to me saving a Color reference as a resource would still be the preferred/logical way to handle my situation. But that might just be my current level of understanding of the engine, or the way I view the issues I'm trying to solve.

Worth mentioning that I've previously implemented VectorResource class, so you can take it as a base to create a similar plugin.

Very interesting! I'll take a look, who knows, maybe I'll attempt to create such a plugin one day. Thank you for the info!

@YuriSizov
Copy link
Contributor

YuriSizov commented Oct 28, 2020

The issue with Themes, as far as I understand them, is that it affects all children as well. So creating a singular main theme would make all labels look the same, which is not what I need.

This is not what I suggest you use a theme for. You can define color constants with themes. Not assign colors for properties of control nodes, but define a set of colors you can then access at will anywhere where this theme is propagated.

Set them on a theme resource by providing names and optional types.

	theme.set_color("red_color", "FirstType", Color.red)
	theme.set_color("green_color", "FirstType", Color.green)
	theme.set_color("blue_color", "SecondType", Color.blue)

Then on any control node below the one that sets this theme you can get those colors and use as you would like.

@Xrayez
Copy link
Contributor

Xrayez commented Oct 28, 2020

I've tried using Theme with Sprite (not Control):

# character.gd
extends Sprite

export(Theme) var theme setget set_theme


func set_theme(p_theme):
	if theme == p_theme:
		return
	if is_instance_valid(theme):
		theme.disconnect("changed", self, "_on_theme_changed")
	theme = p_theme
	if is_instance_valid(theme):
		theme.connect("changed", self, "_on_theme_changed")


func _on_theme_changed():
	modulate = theme.get_color("team", "Character")
# main.gd
extends Node2D

func _ready():
	$character.theme.set_color("team", "Character", Color.green)

godot_theme_sprite

Saying that it's possible to reuse Theme as a proposed Color resource, even if the documentation suggests that it's used for UI. 👀

Test project:
godot_theme_sprite.zip

@Arecher
Copy link
Author

Arecher commented Oct 28, 2020

This is not what I suggest you use a theme for. You can define color constants with themes. Not assign colors for properties of control nodes, but define a set of colors you can then access at will anywhere where this theme is propagated.

Oh interesting! I had no clue themes could be used this way. I have just set one up, and it's a very convenient way to store and access a whole host of colours! Definitely better than setting up a singleton and saving them in there.

image

The only drawback I see with this method is that (as I understand it) it would require each individual control node that uses one of the saved colours, to also have a script that sets this colour to the correct variable. While this is not the end of the world, it is exactly why I'd hoped a 'Color' resource could be added. Instead of requiring a script to set the Color to the variable, it could be slotted into the Editor UI, where ever a Color Input is required.

image

an example of a small part of the UI I'm currently working on, showing all the different nodes/variables that can use a single colour

As you can see this small part of my project would already require 5 or so scripts, and I expect that throughout the project we will have hundreds of similar instances with other variables/nodes or colours. I fear that will create a lot of overhead, and a messy project, which is part of why I made the initial request.

Having said that, thank you @pycbouh for showing me that Themes can be used this way! I learned something new, and it is probably the best alternative solution I can think of!

@Arecher
Copy link
Author

Arecher commented Oct 28, 2020

That's some cool investigative work @Xrayez ! Thank you for going out of your way to help me out!
With the previous theme explanation, that should get me pretty far in making one central theme with all important colours, so they can easily be changed through settings. 👍

@Xrayez
Copy link
Contributor

Xrayez commented Oct 30, 2020

I've come up with a VariantResource class in goostengine/goost#30 which allows you to take any Variant compatible type and edit it just like a resource:

goost_variant_resource_color

So, this is not limited to just Color. This might not necessarily what this proposal wants to achieve (UI?) but this solves the proposal exactly as it says on the tin.

If core developers find this useful needed, I can write a proposal for this. 🙂

@Arecher
Copy link
Author

Arecher commented Oct 30, 2020

This might not necessarily what this proposal wants to achieve (UI?) but this solves the proposal exactly as it says on the tin.

Yeah, the one part this would be missing is that these resources could be loaded/dragged into any slot of the Editor UI that requests a Color input, such as Modulation variables, Font_Color variables, StyleBox Color variables, etc. Such as seen below:

image

Just wanted to reiterate that for clarity, by no means to disregard your amazing work @Xrayez
Personally I think the VariantResource addition could be very useful!

@YuriSizov
Copy link
Contributor

YuriSizov commented Oct 30, 2020

Yeah, the one part this would be missing is that these resources could be loaded/dragged into any slot of the Editor UI that requests a Color input, such as Modulation variables, Font_Color variables, StyleBox Color variables, etc.

While it's unlikely and even a bad idea to replace every Color property with a ColorResource property of sorts, it would be entirely possible to convert those resources to Colors on drag'n'drop in the editor. But that would only be a one time thing, and won't provide the desired functionality for auto-updating on value change. Now, why would replacing be a bad idea? Well, the overhead from using Resources in place of a simple type can be one reason.

@Arecher
Copy link
Author

Arecher commented Oct 30, 2020

Well, the overhead from using Resources in place of a simple type can be one reason.

I understand. Perhaps I have been unclear about this, but I definitely wouldn't want every Color property to ONLY be adjustable through a ColorResource. Setting a Color locally is perfectly fine in most scenarios, so there is no reason to change that, and as you pointed out, forcing ColorResources everywhere would be annoying to deal with. I would like to see both a (local) Color and a ColorResource option for these properties.

In my mind there are multiple ways of handling such a feature (not limited to the ones listed below):
A) The Color Picker UI has a small button, which can be clicked, and opens a Filesystem browser to load a ColorResource.
B) The way Stylebox Materials are set up: You can create one locally (without saving them), or you can choose to save them.

Now obviously I have no clue how difficult any of this would be. I just wanted to make sure there is no chance of the proposal being misunderstood, as I fear that I haven't always been very clear in my previous posts.

@Jummit
Copy link

Jummit commented Oct 30, 2020

What about adding a palette to the Theme resource, and replacing the hard coded color values with ids for that palette? It would have to be integrated well into the editor to make it work.

@YuriSizov
Copy link
Contributor

Wasn't there a plugin recently that did something like that?

@Xrayez
Copy link
Contributor

Xrayez commented Oct 31, 2020

What about adding a palette to the Theme resource, and replacing the hard coded color values with ids for that palette? It would have to be integrated well into the editor to make it work.

Regarding palette-like behavior, worth mentioning that I've implemented VariantResource previews in goostengine/goost#30:

goost_variant_resource_color_previews

And no, those are not Textures, but actual Variant values stored in a Resource, but those are indeed ImageTextures generated as previews for Variant::TYPE_COLOR.

This currently only works if VariantResource has Color set as type, but could be extended to generate previews for any type.

What would make this feature even more powerful is suggested drag-n-drop, but not sure how difficult it is to actually implement via modules.

@Calinou Calinou changed the title Add 'Color' Resource Add a Color resource to adjust a specific color through all instances where it is used Mar 30, 2021
@me2beats
Copy link

me2beats commented Jun 1, 2023

If you are speaking strictly Control nodes, you should define color constants on your main theme and adjust them with user preferences. That’s how theming is done for the editor, for example. You’d still need some system-wide signal, probably, to update colors on the fly. You can use a global helper instance for that.

not only Controls, but also modulate parameter, materials colors etc.

@me2beats
Copy link

me2beats commented Jun 1, 2023

I like the idea, I was going to create such a proposal too recently.

But the main thing I wasn't sure about was how it would work?
I mean in the inspector, there is for example modulate property, normally it takes Color, but now it also can take ColorResource (which is Resource)?

@me2beats
Copy link

me2beats commented Jun 1, 2023

If so, and a parameter can take one of 2 types, I believe union types should be added #737

Another way is to add another parameter like modulate_cr (where cr is color resource) which takes only ColorResource, but this looks kinda like parameter dupe

@me2beats
Copy link

me2beats commented Jun 1, 2023

Also I imagine when you set the value, it changes the color for all objects that refers to it.
The main problem it solves for me is getting rid of need to write code and store there all objects that refers to this color, set their color parameter in for loop when the value is changed etc
Or even worse, set the new color manually for each object via Inspector (which I actually do alas, when tweaking materials colors for example; ofc I just copy-paste the color, but it still not as handy as it could be with ResourceColor)

@me2beats
Copy link

me2beats commented Jun 1, 2023

Also maybe one resource per Color would be an overkill, so ColorResource could store multiple colors, it would be like a color palette with Colors inside an Array
And when you set ColorResource to say modulate property, you also need to specify the color index

@me2beats
Copy link

me2beats commented Jun 1, 2023

And I believe this could be applied not only to Color, but also for Vectors (VectorResource as XRayez already said), and strings (StringResource), and maybe even ints, floats and bools

@me2beats
Copy link

me2beats commented Jun 1, 2023

Oh in goost they joined all built-in types named it VariantResource
but I think it is bad for typing
Types should be predictable, that's why I'm for separating ColorResource, StringResource, etc

@Zireael07
Copy link

Please edit your comments instead of commenting 5 times in a row...

@Calinou
Copy link
Member

Calinou commented Jun 2, 2023

not only Controls, but also modulate parameter, materials colors etc.

You can query theme items in a script using a Theme resource detached from any Control node 🙂
A similar approach can be used with Gradient resources.

@markusneg
Copy link

Referencing and reusing constants like colors and margins is definitely a good thing to have in GUI development. I just started looking deeper into Godot's theme editor and was even a little bit surprised that it is not possible to define and reuse colors. I ended up manually assigning the same colors for all the Control type items (e.g. for Button: font_color, font_disabled_color, fond_focus_color, ..) and it feels as if loosing the flexibility to quickly prototype and test different color tones and alpha values for the UI elements.
I think this proposal shouldn't be limited to colors but also include more primitive types. Thus, @Xrayez VariantResource seems like a good solution to me, maybe a little bit more statically typed like ThemeResource or even ColorResource/ScalarResource like stated earlier.

@giopiazza
Copy link

giopiazza commented Oct 14, 2023

Loved the proposal. Would really like to see inputs that take in Color in editor also accept a Color reference be that a resource or a token / variable.

Something that would return a Color but allow for semantic color management (say have primary-color, secondary-color, positive-color, brand-color, etc) as well as allow for quickly switching their values anywhere referencing it project wide / all at once.

Kinda like how Figma handles color options with styles and variables or like how CSS variables can work on the web as semantic color references you pass to any property that would take in a color (i.e. for a paragraph text color 'color: var(--primary-text-color)' or 'color: var(--brand-color)', allowing for quickly swapping project wide later on.

Could see that either as ColorResources or as global color variables, or theme color constants, or even something like "Smart Swatches" that could allow for "syncing" globally.

It seems to me that tying this to the Theme makes sense, maybe as presented above by @YuriSizov with the color constants for a theme, but if we could manage a theme color variables visually and assign them as references on Editor to inputs that take in Color where that theme propagates, and have them auto-sync project-wide once changed on the theme, that would be brilliant.

Anyways, thanks for the proposal and replies here, learned a lot from it! 🙏

@DanielSnd
Copy link

Could see that either as ColorResources or as global color variables, or theme color constants, or even something like "Smart Swatches" that could allow for "syncing" globally.

This is exactly what I'm looking for. I'm reusing a theme across different projects, and it's a pain to go through the different styleboxes of the theme changing the "main colors" of the project. Because essentially all the different styleboxes are using the same 3 or 4 colors. It would be great if I could instead of placing the color on each one of those I could place a reference, and then when making a new theme based on it I'd just change the colors on the reference and all of the styleboxes would be automatically updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants