Skip to content

Refactor ColorPicker #4353

Open
godotengine/godot
#99515
@KoBeWi

Description

Describe the project you are working on

Godot

Describe the problem or limitation you are having in your project

ColorPicker's source code is full of fun stuff like this:

if (hsv_mode_enabled) {
	set_raw_mode(false);
	btn_raw->set_disabled(true);
} else if (raw_mode_enabled) {
	set_hsv_mode(false);
	btn_hsv->set_disabled(true);
} else {
	btn_raw->set_disabled(false);
	btn_hsv->set_disabled(false);
}

It has RGB, HSV and Raw move, but they never were properly separated, resulting in lots of spaghetti code, with OKHSL mode going to be added soon that adds even more messy code.

What's more, we have this:
image
Color modes are just two exclusive CheckButtons. So if we wanted to add more... well, there's just no space. The OKHSL workarounds this by coupling the color mode with a special picker shape (lol).

Speaking of shapes, there's no easy way to change them at runtime. Picker shape is a property; in editor there is a setting for default shape, but you can change it only via the setting. And in case of OKHSL mode, you are tied to a specific shape to be able to use it.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

ColorPicker code should be refactored and cleaned up, to make multiple color modes more maintainable and easier to add.

First, get rid of the CheckButtons. It was ok when Raw was the only option, but now it needs to be changed. Since all modes are exclusive, they could just be put under an OptionButton:
image
This way we can add infinite color modes and don't need to worry about space.

With the space saved by removing a button, we could probably add another button, for changing shapes. This would however require icons for each shape, as their names are too long. Also switching to OKHSL color mode should automatically change shape if it's different.

Bonus things to consider:

  • being able to select what color modes are supported per picker (e.g. array of string etc.)
  • being able to add custom color modes via scripting (see implementation)

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

The easiest way to properly decouple color modes, that I can think of, is adding a struct called ColorMode. Each color mode differs in color rules and slider setup.
image
For each slider we have:

  • labels (RGB, HSV etc)
  • gradients
  • value range (0-255, 0-100 etc)

And each color mode has a set of rules how to construct color from slider values and vice versa.

So the struct ColorMode would this set of methods (non-exhaustive):

  • get_slider_count() - returns number of sliders (useful if we ever add CMYK or something); default impl returns 3
  • get_slider_label(idx) - returns the label for slider idx
  • get_slider_min(idx) - returns min value for the slider idx; default is 0
  • get_slider_max(idx)
  • get_slider_gradient(idx) - returns the gradient for slider idx
  • set_color(color) - used to set slider values from color
  • get_color() - the opposite
  • get_shape_override() - returns shape name associated with this mode (for OKHSL); returns "" by default, which doesn't change mode

Alpha would be available independently from other sliders, but you'd be able to specify its range by using SLIDER_ALPHA_IDX constant as slider idx in the relevant methods.

Color modes RGB, HSV, WHATEVER would be defined using structs inheriting ColorMode that implement these methods. ColorPicker would have a method to add a color mode struct under given name. ColorPicker would then operate on the selected mode struct instead of navigating code with milion ifs.

As for the scripting option I mentioned, ColorMode struct could possibly be exposed as abstract class which you can implement and add to ColorPicker.

If this enhancement will not be used often, can it be worked around with a few lines of script?

🤔

Is there a reason why this should be core and not an add-on in the asset library?

It's about core class code health.

Activity

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

Metadata

Assignees

No one assigned

    Labels

    breaks compatProposal will inevitably break compatibilitytopic:gui

    Type

    No type

    Projects

    • Status

      In Discussion

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions