Workspace: Move engines to workspace and Properties Editor cleanup
[blender.git] / release / scripts / templates_py / ui_previews_dynamic_enum.py
1 # This sample script demonstrates a dynamic EnumProperty with custom icons.
2 # The EnumProperty is populated dynamically with thumbnails of the contents of
3 # a chosen directory in 'enum_previews_from_directory_items'.
4 # Then, the same enum is displayed with different interfaces. Note that the
5 # generated icon previews do not have Blender IDs, which means that they can
6 # not be used with UILayout templates that require IDs,
7 # such as template_list and template_ID_preview.
8 #
9 # Other use cases:
10 # - make a fixed list of enum_items instead of calculating them in a function
11 # - generate isolated thumbnails to use as custom icons in buttons
12 #   and menu items
13 #
14 # For custom icons, see the template "ui_previews_custom_icon.py".
15 #
16 # For distributable scripts, it is recommended to place the icons inside the
17 # script directory and access it relative to the py script file for portability:
18 #
19 #    os.path.join(os.path.dirname(__file__), "images")
20
21
22 import os
23 import bpy
24
25
26 def enum_previews_from_directory_items(self, context):
27     """EnumProperty callback"""
28     enum_items = []
29
30     if context is None:
31         return enum_items
32
33     wm = context.window_manager
34     directory = wm.my_previews_dir
35
36     # Get the preview collection (defined in register func).
37     pcoll = preview_collections["main"]
38
39     if directory == pcoll.my_previews_dir:
40         return pcoll.my_previews
41
42     print("Scanning directory: %s" % directory)
43
44     if directory and os.path.exists(directory):
45         # Scan the directory for png files
46         image_paths = []
47         for fn in os.listdir(directory):
48             if fn.lower().endswith(".png"):
49                 image_paths.append(fn)
50
51         for i, name in enumerate(image_paths):
52             # generates a thumbnail preview for a file.
53             filepath = os.path.join(directory, name)
54             thumb = pcoll.load(filepath, filepath, 'IMAGE')
55             enum_items.append((name, name, "", thumb.icon_id, i))
56
57     pcoll.my_previews = enum_items
58     pcoll.my_previews_dir = directory
59     return pcoll.my_previews
60
61
62 class PreviewsExamplePanel(bpy.types.Panel):
63     """Creates a Panel in the Object properties window"""
64     bl_label = "Previews Example Panel"
65     bl_idname = "OBJECT_PT_previews"
66     bl_space_type = 'PROPERTIES'
67     bl_region_type = 'WINDOW'
68     bl_context = "object"
69
70     def draw(self, context):
71         layout = self.layout
72         wm = context.window_manager
73
74         row = layout.row()
75         row.prop(wm, "my_previews_dir")
76
77         row = layout.row()
78         row.template_icon_view(wm, "my_previews")
79
80         row = layout.row()
81         row.prop(wm, "my_previews")
82
83
84 # We can store multiple preview collections here,
85 # however in this example we only store "main"
86 preview_collections = {}
87
88
89 def register():
90     from bpy.types import WindowManager
91     from bpy.props import (
92             StringProperty,
93             EnumProperty,
94             )
95
96     WindowManager.my_previews_dir = StringProperty(
97             name="Folder Path",
98             subtype='DIR_PATH',
99             default=""
100             )
101
102     WindowManager.my_previews = EnumProperty(
103             items=enum_previews_from_directory_items,
104             )
105
106     # Note that preview collections returned by bpy.utils.previews
107     # are regular Python objects - you can use them to store custom data.
108     #
109     # This is especially useful here, since:
110     # - It avoids us regenerating the whole enum over and over.
111     # - It can store enum_items' strings
112     #   (remember you have to keep those strings somewhere in py,
113     #   else they get freed and Blender references invalid memory!).
114     import bpy.utils.previews
115     pcoll = bpy.utils.previews.new()
116     pcoll.my_previews_dir = ""
117     pcoll.my_previews = ()
118
119     preview_collections["main"] = pcoll
120
121     bpy.utils.register_class(PreviewsExamplePanel)
122
123
124 def unregister():
125     from bpy.types import WindowManager
126
127     del WindowManager.my_previews
128
129     for pcoll in preview_collections.values():
130         bpy.utils.previews.remove(pcoll)
131     preview_collections.clear()
132
133     bpy.utils.unregister_class(PreviewsExamplePanel)
134
135
136 if __name__ == "__main__":
137     register()