import bpy class vPainterSetting(bpy.types.PropertyGroup): is_vPainter_enabled: bpy.props.BoolProperty( name="Addon Enabled", description="Enable / disable the virtual Painter", default=False, update=lambda self, context: toggle_operator(context) ) texture_panel_state: bpy.props.BoolProperty( name="Textures", default=False, description="Textures used for painting" ) def toggle_operator(context): """Start or stop the modal operator based on the checkbox.""" if context.scene.vPainter_settings.is_vPainter_enabled: # Start the operator bpy.ops.paint.virtual_painter('INVOKE_DEFAULT') class textureSelection(bpy.types.PropertyGroup): texture: bpy.props.PointerProperty( name="Texture", type=bpy.types.Image, description="Select a texture", ) color: bpy.props.FloatVectorProperty( name="Color", subtype='COLOR', size=4, min=0.0, max=1.0, default=(1.0, 1.0, 1.0, 1.0), description="Select a color (RGBA)", ) class VIEW3D_PT_ToolActiveToolPanel(bpy.types.Panel): bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = "Tool" bl_label = "Virtual Painter" bl_idname = "VIEW3D_PT_virtual_Painter" def draw(self, context): layout = self.layout tool_settings = context.scene.vPainter_settings normal_texture = context.scene.normal_texture_settings texture_collection = context.scene.texture_collection_settings # Add the checkbox to toggle the operator layout.prop( tool_settings, "is_vPainter_enabled", text="DISABLE" if tool_settings.is_vPainter_enabled else "ENABLE", toggle=True, invert_checkbox=True ) # Collapsible section of used textures layout.prop( tool_settings, "texture_panel_state", emboss=False, icon="DOWNARROW_HLT" if tool_settings.texture_panel_state else "RIGHTARROW", toggle=True ) if tool_settings.texture_panel_state: section = layout.box() section.label(text="Normal Texture") # Normal texture selection section.prop(normal_texture, "texture", text="", icon="TEXTURE") section.separator(type='LINE') # Custom texture selection section.label(text="Custom Texture") # Display all items in the collection for index, item in enumerate(texture_collection): box = section.box() box.prop(item, "texture", text="", icon="TEXTURE") box.prop(item, "color", text="", icon="COLOR") box.operator("custom_texture.remove_item", text="", icon="X").index = index section.operator("custom_texture.add_item", icon="ADD") # Operator to add new items to the collection class IMAGE_OT_AddItem(bpy.types.Operator): bl_idname = "custom_texture.add_item" bl_label = "Add New" bl_description = "Add a new texture" def execute(self, context): texture_collection = context.scene.texture_collection_settings texture_collection.add() return {'FINISHED'} # Operator to remove items from the collection class IMAGE_OT_RemoveItem(bpy.types.Operator): bl_idname = "custom_texture.remove_item" bl_label = "" bl_description = "Remove this texture" index: bpy.props.IntProperty() def execute(self, context): texture_collection = context.scene.texture_collection_settings if 0 <= self.index < len(texture_collection): texture_collection.remove(self.index) return {'FINISHED'} def register(): bpy.utils.register_class(vPainterSetting) bpy.utils.register_class(textureSelection) bpy.utils.register_class(VIEW3D_PT_ToolActiveToolPanel) bpy.utils.register_class(IMAGE_OT_AddItem) bpy.utils.register_class(IMAGE_OT_RemoveItem) bpy.types.Scene.vPainter_settings = bpy.props.PointerProperty(type=vPainterSetting) bpy.types.Scene.normal_texture_settings = bpy.props.PointerProperty(type=textureSelection) bpy.types.Scene.texture_collection_settings = bpy.props.CollectionProperty(type=textureSelection) def unregister(): bpy.utils.unregister_class(vPainterSetting) bpy.utils.unregister_class(textureSelection) bpy.utils.unregister_class(VIEW3D_PT_ToolActiveToolPanel) bpy.utils.unregister_class(IMAGE_OT_AddItem) bpy.utils.unregister_class(IMAGE_OT_RemoveItem) del bpy.types.Scene.vPainter_settings del bpy.types.Scene.normal_texture_settings del bpy.types.Scene.texture_collection_settings