2

My goal is to print out a message when you click on the UI to change the active modifier.

enter image description here

I tried different methods but failed

import bpy

def message_callback(k, *kw): print("You changed the active modifier by clicking through the UI!")

method 1

bpy.msgbus.subscribe_rna( key=(bpy.types.ObjectModifiers, "active"), owner="method_1", args=(), notify=message_callback)

method 2

bpy.msgbus.subscribe_rna( key=bpy.context.object.modifiers.active, owner="method_2", args=(), notify=message_callback)

method 3

bpy.app.handlers.depsgraph_update_post.append(message_callback)

Finally I thought of a way

I provided a draw level solution below, but the performance was poor since the draw function will run a lot on some operations, so I'm looking for another answer.

X Y
  • 5,234
  • 1
  • 6
  • 20

1 Answers1

2

Check all objects on draw level with poor performance

import bpy
DATA = {}

def message_callback(k, *kw): print("You changed the active modifier by clicking through the UI!")

def check_all_objects(): for ob in bpy.data.objects: if hasattr(ob, "modifiers"): if hasattr(ob.modifiers, "active"): # need check, In old version blend file, It is possible that only a few objects have this property and others do not if ob in DATA and DATA[ob] == ob.modifiers.active: continue

            store_data()
            return True
return False

def store_data(): DATA.clear() DATA.update({ob: ob.modifiers.active for ob in bpy.data.objects if hasattr(ob, "modifiers") and hasattr(ob.modifiers, "active") })

def draw(): print('draw')

if check_all_objects():
    message_callback()

doesn't work if no viewport

bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

Finally found a good solution that works for me

ACT_MD = [None]
def draw_callback(self, context):
    ob = context.object
    if hasattr(ob, "modifiers") and hasattr(ob.modifiers, "active"):
        if ob.modifiers.active != ACT_MD[0]:
            print('active object changed or active modifier changed!!')
            ACT_MD[0] = ob.modifiers.active

bpy.types.TOPBAR_HT_upper_bar.append(draw_callback)

X Y
  • 5,234
  • 1
  • 6
  • 20
  • Iterating over all objects is harsh on every redraw. Maybe it would be enough to only check the active object? After all when you check the active modifier, you do in on the active object, right? – Markus von Broady Jan 01 '24 at 12:41
  • You are right, i forgot this. Can't seem to change the active modifier without changing the active object in UI. – X Y Jan 01 '24 at 13:34
  • 1
    Well you can change the modifiers on an inactive object, if you pin the panel using the button in the top right, but it's a rather extreme usecase and I don't think many people even know it exists. Depends on your workflow. – Gorgious Jan 03 '24 at 09:31