1
$\begingroup$

I am trying to change a the "ratio" within a "decimate" modifier with a modal operator, but cannot get the value to update (my guess is I am not passing the right value?)

import bpy, bmesh

class OBJECT_OT_make_proxy(bpy.types.Operator):
    bl_idname = "object.make_proxy"
    bl_label = "mProxy"

    flt_ratio: bpy.props.FloatProperty(default = 0.25, min = 0, max = 1)

    @classmethod
    def poll(cls, context):    
        return context.active_object is not None

    def execute(self, context):
        #TODO: handle the folder selection, saving and relinking here
        return {'FINISHED'}

    def modal(self, context, event):
        bpy.context.object.modifiers["Decimate"].ratio = self.flt_ratio
        return {'RUNNING_MODAL'}           

    def invoke(self, context, event): 
        #### add modifier ################################
        bpy.ops.object.modifier_add(type='DECIMATE')

        #self.flt_ratio = 0.25 <- commented this out, because it already has a default value        
        bpy.context.window_manager.modal_handler_add(self)
        bpy.context.window_manager.invoke_props_dialog(self)
        return {'RUNNING_MODAL'}

classes = (
    OBJECT_OT_make_proxy,
    )

register, unregister = bpy.utils.register_classes_factory(classes)

if __name__ == "__main__":
    register()

Could somebody please show me what I am doing wrong?

$\endgroup$
  • 1
    $\begingroup$ Also OBJECT_OT_object_make_proxy sounds a bit similar to Display Port port of a display... It's generally a good idea to keep names short and logical. $\endgroup$ – Martynas Žiemys Dec 12 '18 at 11:47
  • $\begingroup$ I was trying to follow your other answer here: blender.stackexchange.com/questions/124095/… Guess I need to revisit it, as I obviously did not get it right. I am sorry, there is so much information to put into my little brain from so many sides, at times its a little overwhelming. $\endgroup$ – morph3us Dec 12 '18 at 12:40
  • $\begingroup$ Sorry, it's not a big deal. I might sound picky. I am just thinking about how it gets out of control with long lines quite fast. I think repeating is not needed. OBJECT_OT_ already means it's an operator in object category. If you think about it, you read the code a lot more than you write it so it should be easy to read and it's easier to read if it's only what is needed, but not more. The way I understand it operator class OBJECT_OT_some_tool with bl_idname object.some_tool still follows the conventions. $\endgroup$ – Martynas Žiemys Dec 12 '18 at 13:08
1
$\begingroup$

You are using FloatProperty, although you only imported StringProperty. You can use it as bpy.props.FloatProperty, or you can import it by adding it to the import from bpy.props import StringProperty, FloatProperty. You will need to define how it is controlled during the modal operation inside invoke as well. See the examples in the Templates menu in the Text Editor's Header.

You could open the example of the modal operator from the Templates menu in the Text Editor's header and then just modify it with what you need carefully checking that you don't break it. I would suggest using some event like mouse move or mouse wheel to control the variables, because you will have a floating panel at the bottom of the 3d view with the value after the operation anyway if you define bl_options = {'REGISTER', 'UNDO'} that is the usual Blender's behavior - adjusting with mouse on the fly and then having that last operator's history panel.

It would be something like this:

import bpy
C = bpy.context

class OBJECT_OT_make_proxy(bpy.types.Operator):
    """Saves the world from war and hunger"""
    bl_idname = "object.make_proxy"
    bl_label = "mProxy"
    bl_options = {'REGISTER', 'UNDO'}

    ratio: bpy.props.FloatProperty( name = "Decimate Ratio",
                                    description = "Does something",
                                    default = 0.25,
                                    min = 0, max = 1    
                                  )
    @classmethod
    def poll(cls, context):    
        return context.object is not None
    def execute(self, context): #This is apparently needed for the history panel to work
        if "mProxyDecimate" not in C.object.modifiers:
            bpy.ops.object.modifier_add(type='DECIMATE')
            C.object.modifiers[len(C.object.modifiers)-1].name = 'mProxyDecimate'
        C.object.modifiers["mProxyDecimate"].ratio = self.ratio
        return {'FINISHED'}

    def modal(self, context, event):

        if event.type == 'WHEELUPMOUSE':
            self.ratio += 0.02
            C.object.modifiers["mProxyDecimate"].ratio = self.ratio
        elif event.type == 'WHEELDOWNMOUSE':
            self.ratio -= 0.02
            C.object.modifiers["mProxyDecimate"].ratio = self.ratio
        elif event.type == 'LEFTMOUSE': #You need to be able to confirm it
            return {'FINISHED'}
        elif event.type in {'RIGHTMOUSE', 'ESC'}: #..and also to get out of it
            bpy.ops.object.modifier_remove(modifier="mProxyDecimate")
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.object:
            if "mProxyDecimate" not in C.object.modifiers:
                bpy.ops.object.modifier_add(type='DECIMATE')
                C.object.modifiers[len(C.object.modifiers)-1].name = 'mProxyDecimate'
            C.object.modifiers["mProxyDecimate"].ratio = self.ratio
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "No active object, could not finish")
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(OBJECT_OT_make_proxy)


def unregister():
    bpy.utils.unregister_class(OBJECT_OT_make_proxy)


if __name__ == "__main__":
    register()
$\endgroup$
  • $\begingroup$ The FloatProperty thing was a copy and paste error, as this is only a smaller part of a bigger script. I edited that out, sorry for the confusion! The invoke part is what I was after, I believe. I did try to decipher the templates and now that you pointed at it, I see that I missed it. Will now try to actually understand that part, thanks! $\endgroup$ – morph3us Dec 12 '18 at 12:43
  • $\begingroup$ I think you will want some event to control your FloatProperty and/or other variables. $\endgroup$ – Martynas Žiemys Dec 12 '18 at 13:17
  • $\begingroup$ I updated the first post with what I came up with, however, it does not behave as expected. The value only gets updated when I double click inside of my popup and exiting from the popup crashes Blender (either through clicking outside of it or "okay" and by using the escape key) $\endgroup$ – morph3us Dec 12 '18 at 15:48
  • $\begingroup$ Okay, edited again, now I can set the modifier, but exiting out of the modal operator still makes Blender crash... $\endgroup$ – morph3us Dec 12 '18 at 21:02
  • $\begingroup$ I think it's better to just modify the example until you make what you need from it while constantly checking if it still works. I added an example to my answer. $\endgroup$ – Martynas Žiemys Dec 12 '18 at 22:16

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.