2
$\begingroup$

I am using bpy.ops.mesh.extrude_region_move to extrude a selected region along their averaged normal. I don't set the value-component of TRANSFORM_OT_translate, so the operator is modal. The return-value of the operator is not {'CANCELLED'} or {'FINISHED'} it's {'RUNNING_MODAL'}. The user can accept the extrusion with enter or cancel it via esc (normal behaviour of that operator).

My blender-addon needs to know if the user has accepted a extrusion or if it was cancelled (The addon stores the face-ids of a selected region. If the user now extrudes the face ids are recreated. Therefore I need to update the stored face-ids. But I need to know 'when').

Any ideas how I can find out if the extrude_region_move was cancelled/not cancelled?

Thanks!

$\endgroup$
  • 2
    $\begingroup$ If you are calling that operator from within your code you can examine the return value, rv = bpy.ops.extrude_region_move(...), which will be {'CANCELLED'} if it is cancelled, or {'FINISHED'} if completed. $\endgroup$ – batFINGER Sep 3 '15 at 14:21
  • $\begingroup$ The return_value is {'RUNNING_MODAL'} so I can't use it. $\endgroup$ – Hamburml Sep 3 '15 at 14:24
  • $\begingroup$ Don't know if there's a general solution to this, but you can find out with a little hack. Check the dimensions of the object before and after the operation. If there's any difference, the extrusion included a translation (at least if the faces were extruded outwards). You can also use the bmesh calc_volume function to check if there's a difference in volume, which would work even if the faces WERE extruded inwards. $\endgroup$ – TLousky Sep 3 '15 at 14:52
  • $\begingroup$ It is not allways sure: if the user did accept the extrusion, but didn't move the new geometry, the result is the same as if he would have cancelled it. Do you need to differentiate these two cases? $\endgroup$ – Mörkö Sep 3 '15 at 16:04
  • $\begingroup$ @user277143 No, I don't need to differentiate between those two cases. But batFinger's Solution is working great! $\endgroup$ – Hamburml Sep 3 '15 at 17:27
4
$\begingroup$

This looks at the TRANSFORM_OT_translate.value Vector as shown in the 'INFO' reports. If the operator was cancelled it returns (0, 0, 0) else has a length.

import bpy

wm = bpy.context.window_manager

print("TESTing Extrude Op")
for op in wm.operators:
    if op.bl_idname == 'MESH_OT_extrude_region_move':  #name == 'Extrude Region and Move'
        print(op.name, "Found")
        v = op.macros['TRANSFORM_OT_translate'].properties.value
        if v.length:
            print("operator used")
        else:
            print("operator canceled")
|improve this answer|||||
$\endgroup$
  • 1
    $\begingroup$ That is lovely! Thanks! I will post an additional answer of how I did it. $\endgroup$ – Hamburml Sep 3 '15 at 17:28
1
$\begingroup$

@batFinger's Solution was correct. I only want to present my solution because I also used a Timer to check every half second if the Operator is in the wm.operators list.

def execute(self, context):

        bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN',
                     TRANSFORM_OT_translate={
                        "constraint_orientation": 'NORMAL',
                        "constraint_axis": (False, False, True)})

        wm = bpy.context.window_manager
        ob = bpy.context.active_object
        lastLen = len(wm.operators)
        from threading import Timer

        def checkExtrudeOperator():
            #print("Things are being done")
            wm = bpy.context.window_manager
            indexoflastoperator = len(wm.operators)
            if indexoflastoperator > 0 and indexoflastoperator > lastLen:
                lastoperator = wm.operators.items()[indexoflastoperator -1]
                op = lastoperator[1] # get the TRANSFORM_OT_translate
                if op.bl_idname == 'MESH_OT_extrude_region_move':
                    v = op.macros['TRANSFORM_OT_translate'].properties.value
                    if v.length:
                        #we need to get new face ids
                        bm = bmesh.from_edit_mesh(ob.data)
                        region = bpy.context.scene.plator_custom[bpy.context.scene.plator_custom_index]
                        region.face_ids = ""
                        for face in bm.faces:
                            if face.select:
                                region.face_ids = region.face_ids + ";" + str(face.index)
                        print("operator used")
                        return
                    else:

                        print("operator canceled")
                        return
                        # we don't need to get new face ids
            # if operator not found, call checkExtrudeOperator in 0.5 seconds              
            t = Timer(0.5, checkExtrudeOperator)  # every 0.5 seconds, which should be fast enough before the User does something more (and the new face-ids aren't stored) but isn't that fast to make blender slow.
            t.start()

        t = Timer(0.5, checkExtrudeOperator)  # every 0.5 seconds, which should be fast enough before the User does something more (and the new face-ids aren't stored) but isn't that fast to make blender slow.
        t.start()

        return{'FINISHED'}

Unfortunately I found out that blender is not only adding new face-ids but it also recalculates the face-ids of old faces... So the whole way of storing face-ids for 'later' isn't working anymore :-(

|improve this answer|||||
$\endgroup$
  • 2
    $\begingroup$ You can also use context.active_operator.macros['TRANSFORM_OT_translate'].properties.value .. $\endgroup$ – batFINGER Sep 3 '15 at 18:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.