godot icon indicating copy to clipboard operation
godot copied to clipboard

Allow exporting variables of type Variant

Open KoBeWi opened this issue 1 year ago • 3 comments

Inspired by https://github.com/godotengine/godot-proposals/issues/9269 Closes https://github.com/godotengine/godot-proposals/issues/9368

This PR allows for exporting variables of type Variant. They show a property editor similar to what Array and Dictionary are using:

https://github.com/godotengine/godot/assets/2223172/b5aa8fdc-f107-44fd-b79a-bc46658857de

This allows for nice flexibility, where you can change not only the variable, but also its value and allows for better customization.

example plugin for "tri-state bool"
@tool
extends EditorPlugin

var state3 := TriStateBoolInspectorPlugin.new()

func _enter_tree() -> void:
	add_inspector_plugin(state3)


func _exit_tree() -> void:
	remove_inspector_plugin(state3)

class TriStateBoolInspectorPlugin extends EditorInspectorPlugin:
	func _can_handle(object: Object) -> bool:
		return true
	
	func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
		if type == TYPE_NIL and hint_string == "3bool":
			add_property_editor(name, TriStateBoolEditor.new())
			return true
		return false

class TriStateBoolEditor extends EditorProperty:
	var button: TriStateCheckbox
	
	func _init() -> void:
		button = TriStateCheckbox.new()
		add_child(button)
		button.pressed.connect(func(): get_edited_object().set(get_edited_property(), button.state))
	
	func _update_property() -> void:
		button.state = get_edited_object().get(get_edited_property())

class TriStateCheckbox extends Button:
	const STATES = [null, false, true]
	
	var textures: Array[Texture2D]
	var state: Variant:
		set(s):
			state = s
			icon = textures[STATES.find(state)]
	
	func _init() -> void:
		size_flags_horizontal = SIZE_SHRINK_BEGIN
		
		for color in [Color.RED, Color.GREEN, Color.BLUE]:
			var gradient := Gradient.new()
			gradient.remove_point(1)
			gradient.colors = [color]
			
			var texture := GradientTexture2D.new()
			texture.gradient = gradient
			texture.width = 16
			texture.height = 16
			textures.append(texture)
	
	func _pressed() -> void:
		for i in STATES.size():
			if STATES[i] == state:
				state = STATES[(i + 1) % STATES.size()]
				break

Example usage:

@export_custom(0, "3bool") var boolean_hat_trick

https://github.com/godotengine/godot/assets/2223172/1aab2534-ff73-4f29-aa85-0b7792b6319f

(the text is updated with _process().

KoBeWi avatar Mar 09 '24 19:03 KoBeWi

  • See also #33080.

I wanted to salvage/re-implement it. I think this should work like Dictionary key/value editor, the user could select the type first, then the value.

dalexeev avatar Mar 09 '24 20:03 dalexeev

I thought about that too, but opted for a simpler solution (as the goal was customizability itself). I can rework this into the type dropdown widget if that's better.

KoBeWi avatar Mar 09 '24 20:03 KoBeWi

Ok reworked

https://github.com/godotengine/godot/assets/2223172/b5aa8fdc-f107-44fd-b79a-bc46658857de

KoBeWi avatar Mar 24 '24 20:03 KoBeWi