0

I'm trying to create a dynamic GUI menu in Godot 4.1.1, where when an object is selected it's properties can be seen in the GUI. So far, I have this working for un-editable fields - however there are also properties that will need to be edited.

_on_grouped is called whenever a node is added to a group and if it's "selected" then it's internal properties are generated for GUI controls and added.

@onready var properties_grid_container = $Properties/MarginContainer/VBoxContainer/ScrollContainer/GridContainer

func _add_property(name: String, value: String):
    var label = Label.new()
    label.text = name
    label.size_flags_horizontal = Control.SIZE_EXPAND_FILL

    var value_label = Label.new()
    value_label.text = value

    properties_grid_container.add_child(label)
    properties_grid_container.add_child(value_label)

func _on_grouped(group: String, node: Node):
    if group == "selected":
        properties_open = true

        # Remove all children from properties_grid_container
        for child in properties_grid_container.get_children():
            properties_grid_container.remove_child(child)
            child.queue_free()

        if node.parent_object is TypeOne:
            var my_object = node.parent_object

            # Add agent_id to properties
            _add_property("ID", str(my_object.custom_id))

        if node.parent_object is TypeTwo:

            var my_object = node.parent_object

            # Add agent_id to properties
            _add_property("Property Two", str(my_object.custom_property_two))

This all works fine (note this is a minimal example, each type has it's own method to extract the properties). However I'm now stuck on how I could extend this to editable properties.

I've got a start of a method like this:

func _add_editable_property(name: String, initial_value: String):
    var label = Label.new()
    label.text = name
    label.size_flags_horizontal = Control.SIZE_EXPAND_FILL

    var value_label = LineEdit.new()
    value_label.text = initial_value

    properties_grid_container.add_child(label)
    properties_grid_container.add_child(value_label)

    # Add a signal to the LineEdit to update the property
    #value_label.connect("text_changed", self._on_property_changed, [name, value_label])

However, I cannot think of a way to connect when the text is changed (or submitted) back to the original object. I would prefer to have this done automatically per field, rather than have a separate "save changes" button.

Does anyone have any ideas as to any approaches that could make this work? Thanks in advance.

AdmiralJonB
  • 2,038
  • 3
  • 23
  • 27

1 Answers1

1

You can change the function _add_editable_property to receive a callback function.

func _add_editable_property(name: String, initial_value: String, callback: Callable):
    var label = Label.new()
    label.text = name
    label.size_flags_horizontal = Control.SIZE_EXPAND_FILL

    var value_label = LineEdit.new()
    value_label.text = initial_value

    properties_grid_container.add_child(label)
    properties_grid_container.add_child(value_label)

    # You can use Godot 4 syntax here for connecting signals
    value_label.text_changed.connect(callback)

Then, in the _on_grouped function, you call _add_editable_property like this:

        if node.parent_object is TypeThree:
            var my_object = node.parent_object
            _add_property(
                 "Property Three", 
                 str(my_object.custom_property_three), 
                 func(new_value):
                      my_object.custom_property_three = new_value
            )

(I don't have the Godot editor on this machine right now, so I'm not confident about the formatting, but the syntax should be like this)

Cassiano
  • 71
  • 1
  • 3
  • Ooh, using a lambda function as the callback. That's certainly something that didn't come to mind. I'll give it a test and mark as an answer if all ok! – AdmiralJonB Aug 18 '23 at 10:00