Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

206 lines
7.0 KiB
Python

# SPDX-FileCopyrightText: 2017-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later
"""
Module to manage overriding various parts of Blender.
Intended for use with 'app_templates', though it can be used from anywhere.
"""
# TODO, how to check these aren't from add-ons.
# templates might need to un-register while filtering.
def class_filter(cls_parent, **kw):
whitelist = kw.pop("whitelist", None)
blacklist = kw.pop("blacklist", None)
kw_items = tuple(kw.items())
for cls in cls_parent.__subclasses__():
# same as is_registered()
if "bl_rna" in cls.__dict__:
if blacklist is not None and cls.__name__ in blacklist:
continue
if ((whitelist is not None and cls.__name__ is whitelist) or
all((getattr(cls, attr) in expect) for attr, expect in kw_items)):
yield cls
def ui_draw_filter_register(
*,
ui_ignore_classes=None,
ui_ignore_operator=None,
ui_ignore_property=None,
ui_ignore_menu=None,
ui_ignore_label=None
):
import bpy
UILayout = bpy.types.UILayout
if ui_ignore_classes is None:
ui_ignore_classes = (
bpy.types.Panel,
bpy.types.Menu,
bpy.types.Header,
)
class OperatorProperties_Fake:
pass
class UILayout_Fake(bpy.types.UILayout):
__slots__ = ()
def __getattribute__(self, attr):
# ensure we always pass down UILayout_Fake instances
if attr in {"row", "split", "column", "box", "column_flow"}:
real_func = UILayout.__getattribute__(self, attr)
def dummy_func(*args, **kw):
# print("wrapped", attr)
ret = real_func(*args, **kw)
return UILayout_Fake(ret)
return dummy_func
elif attr in {"operator", "operator_menu_enum", "operator_enum", "operator_menu_hold"}:
if ui_ignore_operator is None:
return UILayout.__getattribute__(self, attr)
real_func = UILayout.__getattribute__(self, attr)
def dummy_func(*args, **kw):
# print("wrapped", attr)
ui_test = ui_ignore_operator(args[0])
if ui_test is False:
ret = real_func(*args, **kw)
else:
if ui_test is None:
UILayout.__getattribute__(self, "label")(text="")
else:
assert ui_test is True
# may need to be set
ret = OperatorProperties_Fake()
return ret
return dummy_func
elif attr in {"prop", "prop_enum"}:
if ui_ignore_property is None:
return UILayout.__getattribute__(self, attr)
real_func = UILayout.__getattribute__(self, attr)
def dummy_func(*args, **kw):
# print("wrapped", attr)
ui_test = ui_ignore_property(args[0].__class__.__name__, args[1])
if ui_test is False:
ret = real_func(*args, **kw)
else:
if ui_test is None:
UILayout.__getattribute__(self, "label")(text="")
else:
assert ui_test is True
ret = None
return ret
return dummy_func
elif attr == "menu":
if ui_ignore_menu is None:
return UILayout.__getattribute__(self, attr)
real_func = UILayout.__getattribute__(self, attr)
def dummy_func(*args, **kw):
# print("wrapped", attr)
ui_test = ui_ignore_menu(args[0])
if ui_test is False:
ret = real_func(*args, **kw)
else:
if ui_test is None:
UILayout.__getattribute__(self, "label")(text="")
else:
assert ui_test is True
ret = None
return ret
return dummy_func
elif attr == "label":
if ui_ignore_label is None:
return UILayout.__getattribute__(self, attr)
real_func = UILayout.__getattribute__(self, attr)
def dummy_func(*args, **kw):
# print("wrapped", attr)
ui_test = ui_ignore_label(args[0] if args else kw.get("text", ""))
if ui_test is False:
ret = real_func(*args, **kw)
else:
if ui_test is None:
real_func(text="")
else:
assert ui_test is True
ret = None
return ret
return dummy_func
else:
return UILayout.__getattribute__(self, attr)
# print(self, attr)
def operator(*args, **kw):
return super().operator(*args, **kw)
def draw_override(func_orig, self_real, context):
cls_real = self_real.__class__
if cls_real is super:
# simple, no wrapping
return func_orig(self_real, context)
class Wrapper(cls_real):
__slots__ = ()
def __getattribute__(self, attr):
if attr == "layout":
return UILayout_Fake(self_real.layout)
else:
cls = super()
try:
return cls.__getattr__(self, attr)
except AttributeError:
# class variable
try:
return getattr(cls, attr)
except AttributeError:
# for preset bl_idname access
return getattr(UILayout(self), attr)
@property
def layout(self):
# print("wrapped")
return self_real.layout
return func_orig(Wrapper(self_real), context)
ui_ignore_store = []
for cls in ui_ignore_classes:
for subcls in list(cls.__subclasses__()):
if "draw" in subcls.__dict__: # don't want to get parents draw()
def replace_draw():
# function also serves to hold draw_old in a local name-space
draw_orig = subcls.draw
def draw(self, context):
return draw_override(draw_orig, self, context)
subcls.draw = draw
ui_ignore_store.append((subcls, "draw", subcls.draw))
replace_draw()
return ui_ignore_store
def ui_draw_filter_unregister(ui_ignore_store):
for (obj, attr, value) in ui_ignore_store:
setattr(obj, attr, value)