diff --git a/blender/arm/exporter.py b/blender/arm/exporter.py index bd73697535..bf5822e6a3 100644 --- a/blender/arm/exporter.py +++ b/blender/arm/exporter.py @@ -784,11 +784,24 @@ def export_object(self, bobject: bpy.types.Object, out_parent: Dict = None) -> N if len(bobject.arm_propertylist) > 0: out_object['properties'] = [] for proplist_item in bobject.arm_propertylist: + # Check if the property is a collection (array type). + if proplist_item.type_prop == 'array': + # Convert the collection to a list. + array_type = proplist_item.array_item_type + collection_value = getattr(proplist_item, 'array_prop') + property_name = array_type + '_prop' + value = [str(getattr(item, property_name)) for item in collection_value] + else: + # Handle other types of properties. + value = getattr(proplist_item, proplist_item.type_prop + '_prop') + out_property = { 'name': proplist_item.name_prop, - 'value': getattr(proplist_item, proplist_item.type_prop + '_prop')} + 'value': value + } out_object['properties'].append(out_property) + # Export the object reference and material references objref = bobject.data if objref is not None: diff --git a/blender/arm/props_properties.py b/blender/arm/props_properties.py index b7fb24ed20..935c946941 100644 --- a/blender/arm/props_properties.py +++ b/blender/arm/props_properties.py @@ -2,12 +2,31 @@ from bpy.types import Menu, Panel, UIList from bpy.props import * + +class ArmArrayItem(bpy.types.PropertyGroup): + # Name property for each array item + name_prop: StringProperty(name="Name", default="Item") + index_prop = bpy.props.IntProperty( + name="Index", + description="Index of the item", + default=0, + options={'HIDDEN', 'SKIP_SAVE'} + ) + + # Properties for each type + string_prop: StringProperty(name="String", default="") + integer_prop: IntProperty(name="Integer", default=0) + float_prop: FloatProperty(name="Float", default=0.0) + boolean_prop: BoolProperty(name="Boolean", default=False) + + class ArmPropertyListItem(bpy.types.PropertyGroup): type_prop: EnumProperty( items = [('string', 'String', 'String'), ('integer', 'Integer', 'Integer'), ('float', 'Float', 'Float'), ('boolean', 'Boolean', 'Boolean'), + ('array', 'Array', 'Array'), ], name = "Type") name_prop: StringProperty(name="Name", description="A name for this item", default="my_prop") @@ -15,6 +34,89 @@ class ArmPropertyListItem(bpy.types.PropertyGroup): integer_prop: IntProperty(name="Integer", description="A name for this item", default=0) float_prop: FloatProperty(name="Float", description="A name for this item", default=0.0) boolean_prop: BoolProperty(name="Boolean", description="A name for this item", default=False) + array_prop: CollectionProperty(type=ArmArrayItem) + array_item_type: EnumProperty( + items = [ + ('string', 'String', 'String'), + ('integer', 'Integer', 'Integer'), + ('float', 'Float', 'Float'), + ('boolean', 'Boolean', 'Boolean'), + # Add more types here as needed + ], + name = "New Item Type", + default = 'string' + ) + +class ARM_UL_ArrayItemList(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # Use the item's index within the array as its uneditable name + array_type = data.array_item_type + + if self.layout_type in {'DEFAULT', 'COMPACT'}: + # Display the index of the item as its name in a non-editable label + layout.label(text=str(index)) + + # Display the appropriate property based on the array type + if array_type == 'string': + layout.prop(item, "string_prop", text="") + elif array_type == 'integer': + layout.prop(item, "integer_prop", text="") + elif array_type == 'float': + layout.prop(item, "float_prop", text="") + elif array_type == 'boolean': + layout.prop(item, "boolean_prop", text="") + # Add other types as needed + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon="OBJECT_DATAMODE") + + +class ArmArrayAddItem(bpy.types.Operator): + bl_idname = "arm_array.add_item" + bl_label = "Add Array Item" + + def execute(self, context): + obj = bpy.context.object + if obj.arm_propertylist and obj.arm_propertylist_index < len(obj.arm_propertylist): + selected_item = obj.arm_propertylist[obj.arm_propertylist_index] + + # Create a new item in the array + new_item = selected_item.array_prop.add() + + # Set the type of the new item based on the selected type + new_item_type = selected_item.array_item_type + if new_item_type == 'string': + new_item.string_prop = "" # Default value for string + elif new_item_type == 'integer': + new_item.integer_prop = 0 # Default value for integer + elif new_item_type == 'float': + new_item.float_prop = 0.0 # Default value for float + elif new_item_type == 'boolean': + new_item.boolean_prop = False # Default value for boolean + + # Set the index of the new item + new_item_index = len(selected_item.array_prop) - 1 + new_item.index_prop = new_item_index + + # Update the array index + selected_item.array_index = new_item_index + + return {'FINISHED'} + +# Operator to remove an item from the array +class ArmArrayRemoveItem(bpy.types.Operator): + bl_idname = "arm_array.remove_item" + bl_label = "Remove Array Item" + + def execute(self, context): + obj = bpy.context.object + if obj.arm_propertylist and obj.arm_propertylist_index < len(obj.arm_propertylist): + selected_item = obj.arm_propertylist[obj.arm_propertylist_index] + if selected_item.array_prop: + selected_item.array_prop.remove(selected_item.array_index) + if selected_item.array_index > 0: + selected_item.array_index -= 1 + return {'FINISHED'} class ARM_UL_PropertyList(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): @@ -37,6 +139,8 @@ class ArmPropertyListNewItem(bpy.types.Operator): ('integer', 'Integer', 'Integer'), ('float', 'Float', 'Float'), ('boolean', 'Boolean', 'Boolean'), + ('array', 'Array', 'Array'), + ], name = "Type") @@ -126,28 +230,54 @@ def execute(self, context): def draw_properties(layout, obj): layout.label(text="Properties") - rows = 2 - if len(obj.arm_traitlist) > 1: - rows = 4 + + # Draw the ARM_UL_PropertyList + rows = 4 if len(obj.arm_propertylist) > 1 else 2 row = layout.row() row.template_list("ARM_UL_PropertyList", "The_List", obj, "arm_propertylist", obj, "arm_propertylist_index", rows=rows) + + # Column for buttons next to ARM_UL_PropertyList col = row.column(align=True) - op = col.operator("arm_propertylist.new_item", icon='ADD', text="") - op = col.operator("arm_propertylist.delete_item", icon='REMOVE', text="") + col.operator("arm_propertylist.new_item", icon='ADD', text="") + col.operator("arm_propertylist.delete_item", icon='REMOVE', text="") if len(obj.arm_propertylist) > 1: col.separator() - op = col.operator("arm_propertylist.move_item", icon='TRIA_UP', text="") - op.direction = 'UP' - op = col.operator("arm_propertylist.move_item", icon='TRIA_DOWN', text="") - op.direction = 'DOWN' + col.operator("arm_propertylist.move_item", icon='TRIA_UP', text="").direction = 'UP' + col.operator("arm_propertylist.move_item", icon='TRIA_DOWN', text="").direction = 'DOWN' + + # Draw UI List for array items if the selected property is an array + if obj.arm_propertylist and obj.arm_propertylist_index < len(obj.arm_propertylist): + selected_item = obj.arm_propertylist[obj.arm_propertylist_index] + if selected_item.type_prop == 'array': + layout.label(text="Array Items") + + # Dropdown to select the type of new array items + layout.prop(selected_item, "array_item_type", text="Array Type") + + # Template list for array items + row = layout.row() + row.template_list("ARM_UL_ArrayItemList", "", selected_item, "array_prop", selected_item, "array_index", rows=rows) + + # Column for buttons next to the array items list + col = row.column(align=True) + col.operator("arm_array.add_item", icon='ADD', text="") + col.operator("arm_array.remove_item", icon='REMOVE', text="") + + + + __REG_CLASSES = ( + ArmArrayItem, ArmPropertyListItem, ARM_UL_PropertyList, + ARM_UL_ArrayItemList, ArmPropertyListNewItem, ArmPropertyListDeleteItem, ArmPropertyListMoveItem, + ArmArrayAddItem, + ArmArrayRemoveItem, ) __reg_classes, unregister = bpy.utils.register_classes_factory(__REG_CLASSES) @@ -156,3 +286,5 @@ def register(): __reg_classes() bpy.types.Object.arm_propertylist = CollectionProperty(type=ArmPropertyListItem) bpy.types.Object.arm_propertylist_index = IntProperty(name="Index for arm_propertylist", default=0) + # New property for tracking the active index in array items + bpy.types.PropertyGroup.array_index = IntProperty(name="Array Index", default=0)