1
$\begingroup$

I have a bit of a tricky request. I am trying to create a dynamic script that changes Blender's user preferences based on the current selection. Basically, I want to change the user preference option, "rotate around selection" when I don't have anything selected. This means I can dynamically change between selections as I work in the viewport. I have gotten the basic functionality down, but I ran into two problems.

The first issue is that it doesn't automatically run on start up. I have tried putting it into the registered function but to no avail so I have to activate it with a keypress.

The second issue is what I am really curious about. I have looked all around but it seems the only way to continually look for input is to use a modal operation. I don't want it to affect the speed of the viewport, but i would really like to take advantage of the events in the modal operations. I don't know if there is another way to handle this, but one of the issues i have found it that it stops the script refreshing command (F8). I can turn the script off with F8 and then press the F8 shortcut again but i would really not like to do that. I was wondering if after the process is killed with F8 it can automatically call the refresh script function. I am not entirely sure how to approach this and any help would be greatly appreciated!

import bpy

    class NewPreferenceOperator(bpy.types.Operator):
        bl_idname = "object.modal_timer_operator"
        bl_label = "Modal Timer Operator"

        _timer = None

        def modal(self, context, event):
            if event.type == 'F8':
                return {'CANCELLED'}

            if event.type == 'MIDDLEMOUSE':
                selected = bpy.context.selected_objects
                if not selected:
                    bpy.context.user_preferences.view.use_rotate_around_active = False
                else:
                    bpy.context.user_preferences.view.use_rotate_around_active = True
            return {'PASS_THROUGH'}

        def execute(self, context):
            self._timer = context.window_manager.event_timer_add(0.1, context.window)
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}

        def cancel(self, context):
            context.window_manager.event_timer_remove(self._timer)

    def register():
        bpy.utils.register_module(__name__)
        wm = bpy.context.window_manager
        km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
        kmi = km.keymap_items.new(NewPreferenceOperator.bl_idname, 'Y', 'PRESS', ctrl=False, shift=False)
        pass

    def unregister():
        bpy.utils.unregister_module(__name__)
        pass

    if __name__ == '__main__':
        register()
$\endgroup$
1
$\begingroup$

When registered to run on startup, it has the name of the module, in the case below ui_panel.py is a registered text.

if __name__ in ["__main__", "ui_panel"]:
    print("Running ", __name__)  # see the diff between reg or run script
    register()

The refresh (aka reload) script operator is, which IIRC is the operator called by hitting F8

bpy.ops.script.reload()

Instead of cancelling with

return {'CANCELLED'}

use

return self.cancel(context)

then append the operator call to your cancel method, (ie after removing the timer),.

My preferred way of turning on and off modals is using the update method of a boolproperty

def start(self, context):
    if self.bgl_draw_speaker:
        bpy.ops.wm.draw_speaker_vis()

bpy.types.Scene.bgl_draw_speaker = BoolProperty(update=start,
                                                name="Draw Details",                                                    
                                                description="Show BGL Visualiser")

and have if not scene.bge_draw_speaker as a way to terminate the modal op.

|improve this answer|||||
$\endgroup$
  • $\begingroup$ Thanks a lot! The script reload command is just what I needed. I am sorry to be a pain, but I can’t get the cancel method to run in the modal operator. I put a print statement into the function and found it wasn't even running before. Do you know where I could be going wrong? Also I can’t get the ”if name” statement to run either. It just won’t execute the print the statement in the function which is leading me to believe it is not running. The strange thing is that the entire script is working fine though. I’ll continue to see if I can find the problem. $\endgroup$ – Ryan Grzesiak Sep 16 '15 at 23:07
  • $\begingroup$ oh sorry, didn't notice, rather than return {'CANCELLED'} use return self.cancel(context). Change ui_panel to match the name of your file in the text editor, must have a .py extension, you can also just have register() without the if, if you are going to use it exclusively as a registered text script. $\endgroup$ – batFINGER Sep 17 '15 at 9:22
  • $\begingroup$ You have been a wonderful help in my journey to understand how to use the modal operation. I tried to use the self.cancel as you suggested and it worked running after the modal finished. The issue however, was that I could not run the Script Reload because it said the modal was still running. I have probably been a bit of a pain and your knowledge of the area has been awesome. As I was trying some different methods, I found a way to bypass the Middle Mouse click and just active the "view3d.rotate" at the end of my function. Thanks for all the help and all the best! $\endgroup$ – Ryan Grzesiak Sep 17 '15 at 23: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.