1
$\begingroup$

I tried to make this simple operator to add array modifiers while keep in "Edit Mode"

the goal is, add array modifiers to the object while in edit mode and the array count can be adjusted via redo panel, But when i adjust the value on the redo panel is also add new Array modifiers instead only adjusting the "Count" value, however its work as expected while script running in “Object Mode”

from bpy.props import (StringProperty,
                       BoolProperty,
                       IntProperty,
                       FloatProperty,
                       FloatVectorProperty,
                       EnumProperty,
                       PointerProperty,
                       )


class AddModPanel(bpy.types.Panel):
    bl_idname = "PANEL_PT_Addon"
    bl_label = "Panel"
    bl_category = "modifier"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.operator('object.addarray', text="Add Array")


class AddArrayOperator(bpy.types.Operator):
    bl_idname = "object.addarray"
    bl_label = "AddArray"
    bl_options = {'REGISTER', 'UNDO'}

    array_count: IntProperty(name= 'ARRAYCOUNT', default= 1)

    def execute(self, context):
        C= bpy.context
        for o in C.selected_objects:
            mod = o.modifiers.new(type = 'ARRAY', name= 'Array')
            mod.count= self.array_count

        bpy.ops.object.mode_set(mode = 'EDIT') #Keep in edit mode but doesn't work as expected
        #bpy.ops.object.mode_set(mode = 'OBJECT') #Work as expected but is not the goal

        return {'FINISHED'}

def register():
    bpy.utils.register_class(AddArrayOperator)
    bpy.utils.register_class(AddModPanel)


def unregister():
    bpy.utils.unregister_class(AddArrayOperator)
    bpy.utils.unregister_class(AddModPanel)


if __name__ == "__main__":
    register()
#Please try this script from both Edit and Object mode

Below is without any loop version intended for active object only, but the issue still same

from bpy.props import (StringProperty,
                       BoolProperty,
                       IntProperty,
                       FloatProperty,
                       FloatVectorProperty,
                       EnumProperty,
                       PointerProperty,
                       )


class AddModPanel(bpy.types.Panel):
    bl_idname = "PANEL_PT_Addon"
    bl_label = "Panel"
    bl_category = "modifier"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.operator('object.addarray', text="Add Array")

class AddArrayOperator(bpy.types.Operator):
    bl_idname = "object.addarray"
    bl_label = "AddArray"
    bl_options = {'REGISTER', 'UNDO'}

    array_count: IntProperty(name= 'ARRAYCOUNT', default= 1)

    def execute(self, context):
        C= bpy.context
        o= C.active_object
        mod = o.modifiers.new(type = 'ARRAY', name= 'Array')
        mod.count= self.array_count

        bpy.ops.object.mode_set(mode = 'EDIT') #Keep in edit mode but doesn't work as expected
        #bpy.ops.object.mode_set(mode = 'OBJECT') #Work as expected but is not the goal

        return {'FINISHED'}

def register():
    bpy.utils.register_class(AddArrayOperator)
    bpy.utils.register_class(AddModPanel)


def unregister():
    bpy.utils.unregister_class(AddArrayOperator)
    bpy.utils.unregister_class(AddModPanel)


if __name__ == "__main__":
    register()
#Please try this script from both Edit and Object mode

In summary, I just want my script to be able to add array modifiers and adjust dynamically via the redo panel in "Edit Mode", please help. Is there something I am missing? thanks in advance

enter image description here

Note: It's also has same issue in another modifiers such as mirror while changing axis in edit mode via redo panel, the object will keep add new mirror modifier when any redo panel value has updated

PS; i think this is common problem in scripting, but i can't find any question such as this in this forum, hopefully this question is not duplicated

$\endgroup$
3
  • $\begingroup$ Can you please share your whole python file ? I think the issue come from your execute method ... From what I am understanding, it will always create a modifier on the object selected object, each time you click on your operator's button $\endgroup$
    – B.Pader
    Nov 9, 2022 at 7:21
  • $\begingroup$ Hi, i just edited the script. you may just run the script from text editor. at the first execute operator its may work fine but when its used multiple times the issue will occur as mentioned $\endgroup$ Nov 9, 2022 at 9:47
  • 2
    $\begingroup$ Without testing: I would advise to just check if an array modifier has already been added, and only if not add a new one, else: only set the count $\endgroup$ Nov 9, 2022 at 10:33

2 Answers 2

2
$\begingroup$

So it is not something related to the 'Redo' panel.

Working script :

def execute(self, context):
    C= bpy.context
    for o in C.selected_objects:
        for mod in o.modifiers:
            if 'Array' in mod.name:
                continue
        
        mod = o.modifiers.new(type = 'ARRAY', name= 'Array')
        mod.count= self.array_count

    bpy.ops.object.mode_set(mode = 'EDIT') #Keep in edit mode but doesn't work as expected
    #bpy.ops.object.mode_set(mode = 'OBJECT') #Work as expected but is not the goal

    return {'FINISHED'}

In your original python code, you have a loop that is getting all of your object and each time add an array modifier.

C= bpy.context
    for o in C.selected_objects:
        mod = o.modifiers.new(type = 'ARRAY', name= 'Array') #<-right here
        mod.count= self.array_count

So basically, what I've done is to check on each object if there was already a modifier on it. If yes, it will skip the object.

I hope it correspond to the behavior you want

$\endgroup$
3
  • $\begingroup$ Hi thanks for the answer, but i edited the question, there is version without any loop in the script, and the issue still same, its make me confused why in "object mode" work properly but not in "edit mode" :( $\endgroup$ Nov 14, 2022 at 12:27
  • 1
    $\begingroup$ Yes, but without the loop, you are always adding a new modifier nearly each time you use the redo panel. Answer from @S. Magnusson is the best in my opinion. $\endgroup$
    – B.Pader
    Nov 15, 2022 at 6:23
  • 1
    $\begingroup$ The loop of his exemple is only here to check on all the modifiers present on your object and will break once it get the needed modifier, in your case, the array modifier. Then it will use it and set the proper count with the redo panel $\endgroup$
    – B.Pader
    Nov 15, 2022 at 10:05
2
$\begingroup$

One of the other answers skips objects that already have the modifier, but that's not exactly what he's expecting for the redo: it shouldn't add another array modifier, but modify the existing one.

Here's my solution, tested and working in Blender. It has a variable my_mod that can be assigned to an existing array modifier. If there is no existing modifier assigned, it will be assigned to a new array modifier. Then the array count is assigned. I also have the inner loop check the modifier type instead of its name (allowing users to freely rename the modifier):

    def execute(self, context):
        C= bpy.context
        for o in C.selected_objects:
            my_mod = None
            for mod in o.modifiers:
                if mod.type == 'ARRAY': # updates first one it sees, moves on
                    my_mod = mod
                    break
            
            if my_mod is None:
                my_mod = o.modifiers.new(type = 'ARRAY', name= 'Array')
            
            my_mod.count= self.array_count

        bpy.ops.object.mode_set(mode = 'EDIT')

        return {'FINISHED'}
```
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .