godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

Use a cascading style system for Control theming #9743

Open hunterloftis opened 6 months ago

hunterloftis commented 6 months ago

Describe the project you are working on

A 2D game with a typical number of menus & buttons, that needs to be styled in a way that works for both controller players and keyboard+mouse players.

Describe the problem or limitation you are having in your project

Godot's styling system, especially for controls with multiple state combinations like Buttons, is both overwrought and under-powered. This has been discussed elsewhere, including:

The limitation of focus as only an overlay is especially problematic, as it makes many common patterns impossible to implement with native buttons. This is especially the case for games with both mouse and controller input, where you often want similar behavior between focus (controlled by controller d-pad) and hover (controlled by mouse). The main menus of many commercial games would not be implementable in Godot without a custom button system.

Additionally, due to the combinatoric way that Godot currently implements themes (hover_pressed_mirrored), the floor of work for theming a Godot game is quite high. Many styles get repeatedly copy, pasted, tweaked, then copy, pasted again.

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

Instead, Godot should consider cascading control styles, in user-definable order, with a state mask. This has several advantages:

  1. The floor for customization becomes very low. If only a single style is specified, that would become the default for all states in a control (vs the current situation where Godot's default theme "bleeds in" to state combinations that are not specified).
  2. The ceiling for customization becomes very high. If desired, a user could split out and specify a different look for every possible state combination, with their own preferred priority. This includes fixing the current issue of focus - how it cannot change margins, obscures text, etc.
  3. The gradient between low and high is intuitive. A user can start with a simple single button theme, then gradually add more states as necessary.

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

Here's a rough example of how a cascade of styles with state masks would work:

image image

When Godot renders this button, it selects the first style in the array whose mask matches its current state. The mask is a bitwise AND. So with this button, for instance:

  1. If the button is disabled, the first style is used (gray)
  2. Else, if the button is pressed, the second style is used (black)
  3. Else, if the button is focused or hovered, the third/fourth style is used (pink)
  4. By default, the last style is used (white)

These states are intuitive and easy to understand by running through the list top-to-bottom. This example ordering is reasonable for my use-case, but another game might prefer for hovered and focused buttons to have different styles, or for just-hovered and just-focused to be different from hovered-and-focused, and all of that would be straightforward to add.

If Godot were willing/able to completely rethink theming from the ground up, there is likely a better approach. However, with the goal of pragmatism, this change maintains the existing primitives & states while providing a simpler & more powerful way for users to apply them.

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

No

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

Doing this as an add-on would require completely replacing Godot's built-in controls & themes with custom versions, and would remove the Godot-made-with-Godot dogfooding of Godot's own UI.

dalexeev commented 6 months ago

See also:

Shadowblitz16 commented 5 months ago

LabelSettings could be moved to Font and then Font Color could just be Font. That would include font, font size, outline size, shadow offset, font color, outline color, and shadow color.

Also I would suggest having Button Style be a Control Style since we may want normal, hovered, focused, pressed, and disabled states for other controls