diff options
Diffstat (limited to 'release/scripts/modules/bpy_types.py')
-rw-r--r-- | release/scripts/modules/bpy_types.py | 192 |
1 files changed, 172 insertions, 20 deletions
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 15d92cd6b61..6cca60bd49e 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -60,7 +60,7 @@ class Library(bpy_types.ID): # See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE, # we could make this an attribute in rna. attr_links = ("actions", "armatures", "brushes", "cameras", - "curves", "grease_pencil", "groups", "images", + "curves", "grease_pencil", "collections", "images", "lamps", "lattices", "materials", "metaballs", "meshes", "node_groups", "objects", "scenes", "sounds", "speakers", "textures", "texts", @@ -96,12 +96,12 @@ class Texture(bpy_types.ID): ) -class Group(bpy_types.ID): +class Collection(bpy_types.ID): __slots__ = () @property def users_dupli_group(self): - """The dupli group this group is used in""" + """The collection instance objects this collection is used in""" import bpy return tuple(obj for obj in bpy.data.objects if self == obj.dupli_group) @@ -118,11 +118,11 @@ class Object(bpy_types.ID): if child.parent == self) @property - def users_group(self): - """The groups this object is in""" + def users_collection(self): + """The collections this object is in""" import bpy - return tuple(group for group in bpy.data.groups - if self in group.objects[:]) + return tuple(collection for collection in bpy.data.collections + if self in collection.objects[:]) @property def users_scene(self): @@ -144,6 +144,15 @@ class WindowManager(bpy_types.ID): finally: self.popmenu_end__internal(popup) + def popover(self, draw_func, keymap=None): + import bpy + popup = self.popover_begin__internal() + + try: + draw_func(popup, bpy.context) + finally: + self.popover_end__internal(popup, keymap) + def popup_menu_pie(self, event, draw_func, title="", icon='NONE'): import bpy pie = self.piemenu_begin__internal(title, icon, event) @@ -517,15 +526,6 @@ class Text(bpy_types.ID): self.clear() self.write(string) - @property - def users_logic(self): - """Logic bricks that use this text""" - import bpy - return tuple(obj for obj in bpy.data.objects - if self in [cont.text for cont in obj.game.controllers - if cont.type == 'PYTHON'] - ) - # values are module: [(cls, path, line), ...] TypeMap = {} @@ -592,6 +592,106 @@ class OrderedMeta(RNAMeta): return OrderedDictMini() # collections.OrderedDict() +# Same as 'Operator' +# only without 'as_keywords' +class Manipulator(StructRNA, metaclass=OrderedMeta): + __slots__ = () + + def __getattribute__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return getattr(properties, attr) + return super().__getattribute__(attr) + + def __setattr__(self, attr, value): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return setattr(properties, attr, value) + return super().__setattr__(attr, value) + + def __delattr__(self, attr): + properties = StructRNA.path_resolve(self, "properties") + bl_rna = getattr(properties, "bl_rna", None) + if (bl_rna is not None) and (attr in bl_rna.properties): + return delattr(properties, attr) + return super().__delattr__(attr) + + from _bpy import ( + _rna_manipulator_target_set_handler as target_set_handler, + _rna_manipulator_target_get_value as target_get_value, + _rna_manipulator_target_set_value as target_set_value, + _rna_manipulator_target_get_range as target_get_range, + ) + + # Convenience wrappers around private `_gawain` module. + def draw_custom_shape(self, shape, *, matrix=None, select_id=None): + """ + Draw a shape created form :class:`bpy.types.Manipulator.draw_custom_shape`. + + :arg shape: The cached shape to draw. + :type shape: Undefined. + :arg matrix: 4x4 matrix, when not given + :class:`bpy.types.Manipulator.matrix_world` is used. + :type matrix: :class:`mathutils.Matrix` + :arg select_id: The selection id. + Only use when drawing within :class:`bpy.types.Manipulator.draw_select`. + :type select_it: int + """ + import gpu + + if matrix is None: + matrix = self.matrix_world + + batch, dims = shape + + # XXX, can we avoid setting the shader every time? + batch.program_set_builtin('3D_UNIFORM_COLOR' if dims == 3 else '2D_UNIFORM_COLOR') + + if select_id is not None: + gpu.select.load_id(select_id) + else: + if self.is_highlight: + color = (*self.color_highlight, self.alpha_highlight) + else: + color = (*self.color, self.alpha) + batch.uniform_f32("color", *color) + + with gpu.matrix.push_pop(): + gpu.matrix.multiply_matrix(matrix) + batch.draw() + + @staticmethod + def new_custom_shape(type, verts): + """ + Create a new shape that can be passed to :class:`bpy.types.Manipulator.draw_custom_shape`. + + :arg type: The type of shape to create in (POINTS, LINES, TRIS, LINE_STRIP). + :type type: string + :arg verts: Coordinates. + :type verts: sequence of of 2D or 3D coordinates. + :arg display_name: Optional callback that takes the full path, returns the name to display. + :type display_name: Callable that takes a string and returns a string. + :return: The newly created shape. + :rtype: Undefined (it may change). + """ + from _gawain.types import ( + Gwn_Batch, + Gwn_VertBuf, + Gwn_VertFormat, + ) + dims = len(verts[0]) + if dims not in {2, 3}: + raise ValueError("Expected 2D or 3D vertex") + fmt = Gwn_VertFormat() + pos_id = fmt.attr_add(id="pos", comp_type='F32', len=dims, fetch_mode='FLOAT') + vbo = Gwn_VertBuf(len=len(verts), format=fmt) + vbo.fill(id=pos_id, data=verts) + batch = Gwn_Batch(type=type, buf=vbo) + return (batch, dims) + + # Only defined so operators members can be used by accessing self.order # with doc generation 'self.properties.bl_rna.properties' can fail class Operator(StructRNA, metaclass=OrderedMeta): @@ -666,7 +766,23 @@ class _GenericUI: # ensure menus always get default context operator_context_default = self.layout.operator_context + # Support filtering out by owner + workspace = context.workspace + if workspace.use_filter_by_owner: + owner_names = {owner_id.name for owner_id in workspace.owner_ids} + else: + owner_names = None + for func in draw_ls._draw_funcs: + + # Begin 'owner_id' filter. + if owner_names is not None: + owner_id = getattr(func, "_owner", None) + if owner_id is not None: + if func._owner not in owner_names: + continue + # End 'owner_id' filter. + # so bad menu functions don't stop # the entire menu from drawing try: @@ -682,6 +798,13 @@ class _GenericUI: return draw_funcs + @staticmethod + def _dyn_owner_apply(draw_func): + from _bpy import _bl_owner_id_get + owner_id = _bl_owner_id_get() + if owner_id is not None: + draw_func._owner = owner_id + @classmethod def is_extended(cls): return bool(getattr(cls.draw, "_draw_funcs", None)) @@ -693,6 +816,7 @@ class _GenericUI: takes the same arguments as the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.append(draw_func) @classmethod @@ -702,6 +826,7 @@ class _GenericUI: the menus draw function """ draw_funcs = cls._dyn_ui_initialize() + cls._dyn_owner_apply(draw_func) draw_funcs.insert(0, draw_func) @classmethod @@ -731,7 +856,8 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): def path_menu(self, searchpaths, operator, *, props_default=None, prop_filepath="filepath", - filter_ext=None, filter_path=None, display_name=None): + filter_ext=None, filter_path=None, display_name=None, + add_operator=None): """ Populate a menu from a list of paths. @@ -777,12 +903,16 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): files.sort() + col = layout.column(align=True) + for f, filepath in files: # Intentionally pass the full path to 'display_name' callback, # since the callback may want to use part a directory in the name. - props = layout.operator( + row = col.row(align=True) + name = display_name(filepath) if display_name else bpy.path.display_name(f) + props = row.operator( operator, - text=display_name(filepath) if display_name else bpy.path.display_name(f), + text=name, translate=False, ) @@ -794,6 +924,25 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): if operator == "script.execute_preset": props.menu_idname = self.bl_idname + if add_operator: + props = row.operator(add_operator, text="", icon='ZOOMOUT') + props.name = name + props.remove_name = True + + if add_operator: + wm = bpy.data.window_managers[0] + + layout.separator() + row = layout.row() + + sub = row.row() + sub.emboss = 'NORMAL' + sub.prop(wm, "preset_name", text="") + + props = row.operator(add_operator, text="", icon='ZOOMIN') + props.name = wm.preset_name + + def draw_preset(self, context): """ Define these on the subclass: @@ -801,16 +950,19 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): - preset_subdir (string) Optionally: + - preset_add_operator (string) - preset_extensions (set of strings) - preset_operator_defaults (dict of keyword args) """ import bpy ext_valid = getattr(self, "preset_extensions", {".py", ".xml"}) props_default = getattr(self, "preset_operator_defaults", None) + add_operator = getattr(self, "preset_add_operator", None) self.path_menu(bpy.utils.preset_paths(self.preset_subdir), self.preset_operator, props_default=props_default, - filter_ext=lambda ext: ext.lower() in ext_valid) + filter_ext=lambda ext: ext.lower() in ext_valid, + add_operator=add_operator) @classmethod def draw_collapsible(cls, context, layout): |