godot: Control methods has_theme_font*() always returns true

Godot version

4.1.2 stable

System information

Arch Linux

Issue description

When making a call in a control script to the methods… has_theme_font(&"asid", &"fasdf") or has_theme_font_size(&"dasfd", &"asda") methods always return true even with absolutely no custom theme in use at all in project. (NOTE: Variable name and theme_type values, in examples above, are arbitrary)

The above is not the case for the methods has_theme_color, has_theme_constant, has_theme_stylebox

Steps to reproduce

  1. Create new project
  2. Add a Control node
  3. Add script to Control node

Add the following code to the script…

func _ready() -> void:
	print("Color Type Exists: ", has_theme_color(&"aisujghfd", &"asdlkujfb"))
	print("Constant Type Exists: ", has_theme_constant(&"aisujghfd", &"asdlkujfb"))
	print("Font Size Type Exists: ", has_theme_font_size(&"aisujghfd", &"asdlkujfb"))
	print("Font Type Exists: ", has_theme_font(&"aisujghfd", &"asdlkujfb"))
	print("Stylebox Size Type Exists: ", has_theme_stylebox(&"aisujghfd", &"asdlkujfb"))

Run the scene. Output should look like…

Color Type Exists: false
Constant Type Exists: false
Font Size Type Exists: true
Font Type Exists: true
Stylebox Size Type Exists: false

Minimal reproduction project

Follow “Steps to Reproduce”

About this issue

  • Original URL
  • State: open
  • Created 7 months ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

To be clear, this Control is being created in an Addon for users to be able to use it in their projects

So my answer from before applies. We currently don’t have a system that allows you to create sharable GUI widgets with default theme definitions. We are working on it, but nothing exists that would make your life easier if that’s your goal.

this is explicitly untrue

Let’s roll back for a second. I’m describing how the system is designed to work and what considerations we had when we designed it. I’m saying that the current behavior is a conscious one and not a bug or an oversight. I’m saying that as far as Godot’s theming system is concerned there is no use differentiating between “there is no explicit definition (ignoring fallback)” and “there is no definition of any kind (including fallback)”.

You can’t say that it’s untrue, because it is what it is, and it does what it does. There are no analogs for such fallback values for other theme items, otherwise the behavior would’ve been the same. This is an explicit piece of functionality that any theme can define a global font definition that all controls must respect even if they don’t have explicit definitions for their properties.

Now, you may disagree that this is what it should do, and we can discuss it. But I think at this point what’s important is that your use case is creating sharable and themable GUI widgets, and we are aware of the limitations that exist around that and a solution for this should hopefully arrive in Godot 4.3.

The check is for checking a font is available with the configuration, not to check if a specific one exists, I’d say

This is fine, in theory, but that’s not explicitly stated (at least under the definition of the has_theme_font*() methods. The issue is, then, how do I test if a specific theme name / type actually exists?

For my custom Control that I’m working on, I need to know if someone has applied a theme (somewhere in the tree, if not directly on an instance of my custom Control) which defined a value within the custom theme type I’m looking for, or if I should just pull that value from some default location (in my case, a secondary Theme object I pull the information from, but is not, itself, put into the tree).

How is one supposed to identify if a font or font_size theme value of name/type exists if the default font/size makes the has_theme_font*() methods return true?

For instance, in my project (where I found this issue), I’m trying to create a custom control that can be themed with a custom theme type. I’m placing all of what I want as default theme values in a “default.theme” file and my custom control is using a function such as…

const DEFAULT_THEME : Theme = preload("res://path/to/default.theme")
func _GetThemeFont(font_name : StringName, type : StringName) -> Font:
  if has_theme_font(font_name, type):
    return get_theme_font(font_name, type)
  return DEFAULT_THEME.get_font(font_name, type)

The above pattern works beautifully with Color, Constant, and Stylebox theme components, but, if as stated, having a default font/font size in the project (which is a projects default state) causes the has_theme_font*() methods to always return true, then I’m not entirely sure these methods really do what they say on the tin.

What would I use in replacement of has_theme_font*() to truely test if a font or font size of the given name and type are actually defined somewhere in the tree?

Because I wanted to use my own font and/or font size if one wasn’t defined for my custom theme type.

That goes against the theming system and the theme propagation logic. For any given control or window it is expected to respect its own local overrides plus every other theme resource from this and any themable parent node, plus two global themes: the default one and the project one.

So I’d like to understand why do you need to break the theming logic to achieve your goals, and what your goals are. If you want to have a sharable GUI widget and need to define some defaults, akin to the default theme for built-in controls and widgets, then this is not yet supported in a useful way, so there is no good solution for this.

The core problem is there is no way for me to know if a custom theme name/type combination is actually defined or not for front and font size values and there seems to be no workaround for this.

I agree that there is no way to check if a specific definition exists. That is because there is no use for this in the theming system where we don’t care if a specific definition exists. We only care if there is a usable value for any given pair of keys. A fallback value counts.

So no, your needs and approaches are not moot. I need to understand them to either find a workaround for you or to conclude that we are missing a useful feature.

For my custom Control that I’m working on, I need to know if someone has applied a theme (somewhere in the tree, if not directly on an instance of my custom Control) which defined a value within the custom theme type I’m looking for, or if I should just pull that value from some default location (in my case, a secondary Theme object I pull the information from, but is not, itself, put into the tree).

Themes are not designed to be used like that. Why would your secondary theme resource not be in the tree?

It is documented in the theme documentation, but indeed a mention in the control and window documentation would be nice. This applies to font sizes as well.