override UI

I want to override blender layout, and have read same example codes in the cookbook “Code snippets”. In the chapter “interface”, I found I don’t understand the “Override layout & functions” part. For example, in the defintion of Class “UILayout_FAKE”, I don’t understand the statement “real_func = UILayout.getattribute(self, attr)” and “return UILayout_FAKE(ret)”. I thought the “ret” is a UILayout object, and shouldn’t put into the brackets. Can someone help?

import bpy

classes = [“Panel”, “Menu”, “Header”]
UILayout = bpy.types.UILayout

op_blacklist = [
“render.render”,
“object.modifier_add”,
“object.forcefield_toggle”,
]

prop_blacklist = [
“Object.location”,
“Object.scale”,
“Object.rotation_euler”,
“RenderSettings.display_mode”,
]

def filter_operator(op_id):
if op_id in op_blacklist:
return False
return True

def filter_prop(data, prop):
prop_id = “%s.%s” % (data.class.name, prop)
if prop_id in prop_blacklist:
return False
return True

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"):
        real_func = UILayout.__getattribute__(self, attr)

        def dummy_func(*args, **kw):
            print("    wrapped", attr)
            if filter_operator(args[0]):
                ret = real_func(*args, **kw)
            else:
                # UILayout.__getattribute__(self, "label")()
                # may need to be set
                ret = OperatorProperties_FAKE()
            return ret
        return dummy_func
    elif attr in ("prop", "prop_enum"):
        real_func = UILayout.__getattribute__(self, attr)

        def dummy_func(*args, **kw):
            print("    wrapped", attr)
            if filter_prop(args[0], args[1]):
                ret = real_func(*args, **kw)
            else:
                ret = None
            return ret
        return dummy_func
    else:
        return UILayout.__getattribute__(self, attr)

    print(self, attr)

def operator(*args, **kw):
    print("OP")
    return super().operator(*args, **kw)

def draw_override(func_orig, self_real, context):
print(“ass”)
if 1:
class Wrapper(self_real.class):
def getattribute(self, attr):
if attr == “layout”:
ret = self_real.layout
return UILayout_FAKE(ret)
else:
return super().getattr(self, attr)

        @property
        def layout(self):
            ret = self_real.layout
            print("wrapped")
            return ret
    print(1)
    self_wrap = Wrapper(self_real)
    ret = func_orig(self_wrap, context)
else:
    # simple, no wrapping
    ret = func_orig(self_wrap, context)

return ret

def poll_override(func_orig, context):

ret = func_orig(context)

return ret

for cls_name in classes:
cls = getattr(bpy.types, cls_name)

for subcls in cls.__subclasses__():
    if "draw" in subcls.__dict__:  # dont want to get parents draw()

        def replace_draw():
            # function also serves to hold draw_old in a local namespace
            draw_orig = subcls.draw

            def draw(self, context):
                return draw_override(draw_orig, self, context)
            subcls.draw = draw

        replace_draw()

    if "poll" in subcls.__dict__:  # dont want to get parents poll()
        def replace_poll():
            # function also serves to hold draw_old in a local namespace
            poll_orig = subcls.poll

            def poll(context):
                return poll_override(poll_orig, context)
            subcls.poll = poll

        replace_poll()

Here is a simple way to do it.

Code From Batfinger


import bpy
def goofer(self,context):
    self.layout.label("NA")
    
bpy.types.OBJECT_PT_context_object.draw = goofer

This will override the area where you type in an Object name with a label that displays “NA”.

You can override the Panel Type with your own draw routine and either generate an alternate, or simply issue a pass to blank that panel. So the key is locating the panel types you want to override then create your own draw routines for them. The only way I know of locating those panel types is to examine the existing python GUI code in the Blender folder.