0
$\begingroup$

I have created an addon where I made an icon gallery which appends simple objects and shows the object's properties such as location, rotation mode, rotation, scale.

After appending objects to the scene through the addon and saving the file if we again start that blend file the file crashes without opening.

Here is the addon: https://mega.nz/file/0w8QlZwR#nm_geLuv8YvHuO_w14it1U2LNsKu3jpO_eJc2DwIizk

Here is the code:

bl_info = {
    "name": "Icon Gallery Manual",
    "author": "Muzammil",
    "version": (1, 0),
    "blender": (3, 0, 0),
    "location": "View3D > Add > Icon Gallery",
    "description": "Adds a new Mesh Object",
    "warning": "",
    "doc_url": "",
    "category": "View 3D",
}
import bpy, os, bpy.utils.previews
addon_path = os.path.dirname(os.path.realpath(__file__))
files_path = os.path.join(addon_path, 'Blend files')
icons_path = os.path.join(addon_path, 'Images')

wm = bpy.context.window_manager

def dynamic_enum(self,context):
    enum_items = []

    if context is None:
        return enum_items

    pcoll = previews['main']

    icon_images = []
    for fn in os.listdir(icons_path):
        icon_images.append(fn)

    for i, name in enumerate(icon_images):
        filepath = os.path.join(icons_path, name)
        icon = pcoll.get(name)
        if not icon:
            thumb = pcoll.load(name,filepath, 'IMAGE')
        else:
            thumb = pcoll[name]
        enum_items.append((name,name,'',thumb.icon_id,i))
        
    pcoll.icon_gallery = enum_items
    return pcoll.icon_gallery
    
class CUSTOM_PT_PANEL(bpy.types.Panel):
    bl_label = 'Icon Gallery'
    bl_idname = 'CUSTOM_PT_PANEL'
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Icon Gallery'
    
    def draw(self,context):
        l = self.layout
        l.template_icon_view(wm, 'icon_gallery')
        r = l.row()
        r.scale_y = 2
        r.operator('custom.add_objects', icon = 'HEART')
        c = l.column(align=True)
        if context.object:
            b = c.box()
            b.label(text='Acitve Object: '+context.object.name)
            c.prop(context.object,'location')
            if not bpy.context.object.rotation_mode == 'QUATERNION':
                c.prop(context.object,'rotation_euler', text='Rotation')
            else:
                c.prop(context.object,'rotation_quaternion', text='Rotation')
            c.prop(context.object,'rotation_mode')
            c.prop(context.object,'scale')
        
class CUSTOM_OT_OPERATOR(bpy.types.Operator):
    bl_label = 'Add'
    bl_idname = 'custom.add_objects'
    
    def execute(self,context):
        name = wm.icon_gallery.replace(os.path.splitext(wm.icon_gallery)[1], '')
        before_data = list(bpy.data.objects)
        bpy.ops.wm.append(directory=os.path.join(files_path, 'File.blend','Object'), filename=name)
        new_data = list(filter(lambda d: not d in before_data, list(bpy.data.objects)))
        appended = new_data[0]
        bpy.context.view_layer.objects.active = appended
        appended.location.xyz = (0,0,0)
        appended.rotation_euler.x = 0
        appended.rotation_euler.y = 0
        appended.rotation_euler.z = 0
        appended.scale.xyz = (1,1,1)
        return {'FINISHED'}
classes = [CUSTOM_PT_PANEL,CUSTOM_OT_OPERATOR]
previews = {}

def register():
    bpy.types.WindowManager.icon_gallery = bpy.props.EnumProperty(items=dynamic_enum)
    pcoll = bpy.utils.previews.new()
    pcoll.icon_gallery = ()
    previews['main'] = pcoll
    
    for cls in classes:
        bpy.utils.register_class(cls)
    
def unregister():
    del bpy.types.WindowManager.icon_gallery
    
    for pcoll in previews.values():
        bpy.utils.previews.remove(pcoll)
    previews.clear()

    for cls in classes:
        bpy.utils.unregister_class(cls)

if __name__ == '__main__':
    register()
```
$\endgroup$
0

1 Answer 1

2
$\begingroup$

You are defining your wm variable as global, I'm not 100% sure why but I can only assume this is using the wrong context when reloaded.

Placing the wm definition inside the function that is using it solves this as it will use the context passed to it.

bl_info = {
    "name": "Icon Gallery Manual",
    "author": "Muzammil",
    "version": (1, 0),
    "blender": (3, 0, 0),
    "location": "View3D > Add > Icon Gallery",
    "description": "Adds a new Mesh Object",
    "warning": "",
    "doc_url": "",
    "category": "View 3D",
}
import bpy, os, bpy.utils.previews

addon_path = os.path.dirname(os.path.realpath(__file__))
files_path = os.path.join(addon_path, "Blend files")
icons_path = os.path.join(addon_path, "Images")



def dynamic_enum(self, context):
    enum_items = []

    if context is None:
        return enum_items

    pcoll = previews["main"]

    icon_images = []
    for fn in os.listdir(icons_path):
        icon_images.append(fn)

    for i, name in enumerate(icon_images):
        filepath = os.path.join(icons_path, name)
        icon = pcoll.get(name)
        if not icon:
            thumb = pcoll.load(name, filepath, "IMAGE")
        else:
            thumb = pcoll[name]
        enum_items.append((name, name, "", thumb.icon_id, i))

    pcoll.icon_gallery = enum_items
    return pcoll.icon_gallery


class CUSTOM_PT_PANEL(bpy.types.Panel):
    bl_label = "Icon Gallery"
    bl_idname = "CUSTOM_PT_PANEL"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Icon Gallery"

    def draw(self, context):
        wm = context.window_manager # moved to here
        l = self.layout
        l.template_icon_view(wm, "icon_gallery")
        r = l.row()
        r.scale_y = 2
        r.operator("custom.add_objects", icon="HEART")
        c = l.column(align=True)
        if context.object:
            b = c.box()
            b.label(text="Acitve Object: " + context.object.name)
            c.prop(context.object, "location")
            if not bpy.context.object.rotation_mode == "QUATERNION":
                c.prop(context.object, "rotation_euler", text="Rotation")
            else:
                c.prop(context.object, "rotation_quaternion", text="Rotation")
            c.prop(context.object, "rotation_mode")
            c.prop(context.object, "scale")


class CUSTOM_OT_OPERATOR(bpy.types.Operator):
    bl_label = "Add"
    bl_idname = "custom.add_objects"

    def execute(self, context):
        wm = context.window_manager # moved to here
        name = wm.icon_gallery.replace(os.path.splitext(wm.icon_gallery)[1], "")
        before_data = list(bpy.data.objects)
        bpy.ops.wm.append(directory=os.path.join(files_path, "File.blend", "Object"), filename=name)
        new_data = list(filter(lambda d: not d in before_data, list(bpy.data.objects)))
        appended = new_data[0]
        bpy.context.view_layer.objects.active = appended
        appended.location.xyz = (0, 0, 0)
        appended.rotation_euler.x = 0
        appended.rotation_euler.y = 0
        appended.rotation_euler.z = 0
        appended.scale.xyz = (1, 1, 1)
        return {"FINISHED"}


classes = [CUSTOM_PT_PANEL, CUSTOM_OT_OPERATOR]
previews = {}


def register():
    bpy.types.WindowManager.icon_gallery = bpy.props.EnumProperty(items=dynamic_enum)
    pcoll = bpy.utils.previews.new()
    pcoll.icon_gallery = ()
    previews["main"] = pcoll

    for cls in classes:
        bpy.utils.register_class(cls)


def unregister():
    del bpy.types.WindowManager.icon_gallery

    for pcoll in previews.values():
        bpy.utils.previews.remove(pcoll)
    previews.clear()

    for cls in classes:
        bpy.utils.unregister_class(cls)


# if __name__ == '__main__':
#     register()
$\endgroup$
1
  • 1
    $\begingroup$ Thank you. It really helped. $\endgroup$
    – Muzammil
    Commented Dec 24, 2022 at 5:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .