ui_previews_dynamic_enum.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. import os
  21. import bpy
  22. def enum_previews_from_directory_items(self, context):
  23. """EnumProperty callback"""
  24. enum_items = []
  25. if context is None:
  26. return enum_items
  27. wm = context.window_manager
  28. directory = wm.my_previews_dir
  29. # Get the preview collection (defined in register func).
  30. pcoll = preview_collections["main"]
  31. if directory == pcoll.my_previews_dir:
  32. return pcoll.my_previews
  33. print("Scanning directory: %s" % directory)
  34. if directory and os.path.exists(directory):
  35. # Scan the directory for png files
  36. image_paths = []
  37. for fn in os.listdir(directory):
  38. if fn.lower().endswith(".png"):
  39. image_paths.append(fn)
  40. for i, name in enumerate(image_paths):
  41. # generates a thumbnail preview for a file.
  42. filepath = os.path.join(directory, name)
  43. icon = pcoll.get(name)
  44. if not icon:
  45. thumb = pcoll.load(name, filepath, 'IMAGE')
  46. else:
  47. thumb = pcoll[name]
  48. enum_items.append((name, name, "", thumb.icon_id, i))
  49. pcoll.my_previews = enum_items
  50. pcoll.my_previews_dir = directory
  51. return pcoll.my_previews
  52. class PreviewsExamplePanel(bpy.types.Panel):
  53. """Creates a Panel in the Object properties window"""
  54. bl_label = "Previews Example Panel"
  55. bl_idname = "OBJECT_PT_previews"
  56. bl_space_type = 'PROPERTIES'
  57. bl_region_type = 'WINDOW'
  58. bl_context = "object"
  59. def draw(self, context):
  60. layout = self.layout
  61. wm = context.window_manager
  62. row = layout.row()
  63. row.prop(wm, "my_previews_dir")
  64. row = layout.row()
  65. row.template_icon_view(wm, "my_previews")
  66. row = layout.row()
  67. row.prop(wm, "my_previews")
  68. # We can store multiple preview collections here,
  69. # however in this example we only store "main"
  70. preview_collections = {}
  71. def register():
  72. from bpy.types import WindowManager
  73. from bpy.props import (
  74. StringProperty,
  75. EnumProperty,
  76. )
  77. WindowManager.my_previews_dir = StringProperty(
  78. name="Folder Path",
  79. subtype='DIR_PATH',
  80. default=""
  81. )
  82. WindowManager.my_previews = EnumProperty(
  83. items=enum_previews_from_directory_items,
  84. )
  85. # Note that preview collections returned by bpy.utils.previews
  86. # are regular Python objects - you can use them to store custom data.
  87. #
  88. # This is especially useful here, since:
  89. # - It avoids us regenerating the whole enum over and over.
  90. # - It can store enum_items' strings
  91. # (remember you have to keep those strings somewhere in py,
  92. # else they get freed and Blender references invalid memory!).
  93. import bpy.utils.previews
  94. pcoll = bpy.utils.previews.new()
  95. pcoll.my_previews_dir = ""
  96. pcoll.my_previews = ()
  97. preview_collections["main"] = pcoll
  98. bpy.utils.register_class(PreviewsExamplePanel)
  99. def unregister():
  100. from bpy.types import WindowManager
  101. del WindowManager.my_previews
  102. for pcoll in preview_collections.values():
  103. bpy.utils.previews.remove(pcoll)
  104. preview_collections.clear()
  105. bpy.utils.unregister_class(PreviewsExamplePanel)
  106. if __name__ == "__main__":
  107. register()