Confusion using Checkable property on exported variables

Godot Version

4.4.1

Question

I’m very new to Godot and am having trouble understanding how the ‘Checkable’ property_usage_flag works.

I’ve been in the docs and also found these two forum posts:

I’ve been able to create a Checkable property with that information..

I’ve tried:
property.usage = PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_EDITOR
property.usage = PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_STORAGE
property.usage = 20

All three variations will add the checkbox to the property, but the checkbox seems to always default to ‘checked’. I can’t get it to add an unchecked checkbox.

Once the checkbox is added I can’t figure out how to access it, manipulate it or query it with code.

Checking the property with _validate_property() doesn’t reflect any changes made to the checkbox.

I want to be able to ask the property whether the box is checked or not, and I want to be able to control the default state of the checkbox.

Can anyone point me in the right direction? Thanks.

As I explained in one of the post you linked before, the @export variable can’t have a Variant type like Vector2 or int or Dictionary because those types can’t be null and the checkbox only works if the variable can be null.

The way to know if the checkbox is checked or not is to compare the variable to null. If the variable is null then the checkbox will be unchecked. The default state of the checkbox is the default value you give to the variable. If you give the variable the value null then the checkbox won’t be checked. If you give the variable any other value then the checkbox will be checked.

Example:

@tool
extends Node


@export var test = Vector2.ZERO


func _validate_property(property: Dictionary) -> void:
	if property.name == "test":
		property.type = TYPE_VECTOR2
		property.usage |= PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_EDITOR
		if test != null:
				property.usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED
1 Like

Oh! Ok, I was thinking about this all wrong.

I’m used to scripting UI and having the checkbox be a property of the variable, like val.enabled, that you can set or query to find out if you can interact with the value in the UI.

But here GDScript is showing whether or not the value itself is null. That just wasn’t clicking for me. Thank you.

The whole concept of property usage flags, combining them, hints and hint strings is going to take some getting used to.

Thanks again for helping me understand it finally.

For that you may want to use 2 variables instead. For example:

@tool
extends Node


@export var has_border:bool = true:
	set(value):
		has_border = value
		notify_property_list_changed()
@export var border = Vector2.ZERO


func _validate_property(property: Dictionary) -> void:
	if property.name == "border":
		if has_border:
            # Show in editor
			property.usage = PROPERTY_USAGE_DEFAULT
		else:
            # Hide in editor
			property.usage = PROPERTY_USAGE_STORAGE
1 Like

Hi again!

So, I’m having some trouble understanding the checkable behavior applied to a Node export variable.

When the variable is unchecked, the value returns null like you’d expect.

image

But when I check the variable’s box, even though no Node is assigned, the variable’s value returns nothing in the output log, but is also NOT null.

image

So, node_var == null returns false, but print(node_var) returns nothing.

Usually for error checking I’d ask something like:

if node_var != null:
     get_node(node_var).get_property_list()

But in this case the error check won’t work because the value isn’t technically null, but it’s functionally null, and so it throws errors.

How do you handle a situation like this?

EDIT:
This seems to work.

	set(value):
		node_var = value
		if value != null: 
			if get_node_or_null(value) != null:
		#tween_settings_delay_node = value
				print(get_node(value).get_property_list())

Is this a decent way to do this or is this dangerous for any reason?

It prints nothing because the exported Node is a NodePath Variant and when you enable the checkbox the default unassigned value is NodePath() which prints nothing. You can use NodePath.is_empty() instead if you want:

set(value):
		node_var = value
		if value != null and not value.is_empty(): 
			print(get_node(value).get_property_list())
1 Like

I like that. .is_empty() seems cleaner and more readable. Thanks for your help!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.