blender/release/scripts/modules/bpy/utils/previews.py
Bastien Montagne d30f664c04 Expose PreviewImage & custom icons to py API.
This commit mainly:

* Exposes PreviewImage struct in RNA, including ways for user to set images data.
* Adds a new kind of PreviewImage, using a file path and IMB_thumb to get image.
* Adds a new kind of custom icon using PreviewImage, unrelated to ID previews system.
* Adds a python API (utils.previews) to allow python scripts to access those custom previews/icons.

Note that loading image from files' thumbnails is done when needed (deferred loading), not
when defining the custom preview/icon.

WARNING: for release addons who would want to use this, please keep it to a strict minimum, really needed level.
We do not want our UI to explode under hundreds of different flashy icons!

For more info, see also the release notes of Blender 2.75 (http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.75/Addons)
and the example/templates featured with Blender.

Patch by Campbell (ideasman42), Inês (brita) and Bastien (mont29).

Differential Revision: https://developer.blender.org/D1255
2015-05-11 16:37:15 +02:00

138 lines
3.6 KiB
Python

# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
"""
This module contains utility functions to handle custom previews.
It behaves as a high-level 'cached' previews manager.
This allows addons to generate their own previews, and use them as icons in UI widgets
('icon_value' of UILayout functions).
"""
__all__ = (
"new",
"remove",
)
import _bpy
_utils_previews = _bpy._utils_previews
del _bpy
_uuid_open = set()
# High-level previews manager.
# not accessed directly
class _BPyImagePreviewCollection(dict):
"""
Dict-like class of previews.
"""
# Internal notes:
# - keys in the dict are stored by name
# - values are instances of bpy.types.ImagePreview
# - Blender's internal 'PreviewImage' struct uses 'self._uuid' prefix.
def __init__(self):
super().__init__()
self._uuid = hex(id(self))
_uuid_open.add(self._uuid)
def __del__(self):
if self._uuid not in _uuid_open:
return
raise ResourceWarning(
"<%s id=%s[%d]>: left open, remove with "
"'bpy.utils.previews.remove()'" %
(self.__class__.__name__, self._uuid, len(self)))
self.close()
def _gen_key(self, name):
return ":".join((self._uuid, name))
def new(self, name):
if name in self:
raise KeyException("key %r already exists")
p = self[name] = _utils_previews.new(
self._gen_key(name))
return p
new.__doc__ = _utils_previews.new.__doc__
def load(self, name, path, path_type, force_reload=False):
if name in self:
raise KeyException("key %r already exists")
p = self[name] = _utils_previews.load(
self._gen_key(name), path, path_type, force_reload)
return p
load.__doc__ = _utils_previews.load.__doc__
def release(self, name):
p = self.pop(name, None)
if p is not None:
_utils_previews.release(self._gen_key(name))
release.__doc__ = _utils_previews.release.__doc__
def clear(self):
for name in self.keys():
_utils_previews.release(self._gen_key(name))
super().clear()
def close(self):
self.clear()
_uuid_open.remove(self._uuid)
def __delitem__(self, key):
return self.release(key)
def __repr__(self):
return "<%s id=%s[%d], %s>" % (
self.__class__.__name__,
self._uuid,
len(self),
super().__repr__())
def new():
"""
Return a new preview collection.
"""
return _BPyImagePreviewCollection()
def remove(p):
"""
Remove the specified previews collection.
"""
p.close()
# don't complain about resources on exit (only unregister)
import atexit
def exit_clear_warning():
del _BPyImagePreviewCollection.__del__
atexit.register(exit_clear_warning)
del atexit, exit_clear_warning