0
$\begingroup$

I want to create a dialog to get user input during a load_pre handler for handling version control.

As .blend could be opened for edits by another user, I might want to notify users attempting to edit it that it is already being worked on.

I could also want to ask users if when they open a blend file if they would like to open it for edit.

@persistent
def on_load_pre(*args):
    """ Before opening Blend files this is called """
    filepath, _ = args

    if not filepath:
        return

    print('this gets printed to console')
    bpy.ops.wm.call_menu(name = YesNoMenu.bl_idname)  # however any operator called here will do nothing
    print('this also prints to console')

I have tried implementing operator that will call invoke_popup, invoke_dialog, invoke_props in it's invoke method. And calling the operator with INVOKE_DEFAULT but I never get any prompt for users to handle input.

In the code above I try opening a custom menu with two operators but again this doesn't show anything. The print before gets printed to console as will the print that follows.

A similar question seemed like it could be what I am looking for but following the code there will only cause Blender to crash.

In other DCC we usually handle this with a Qt/PySide dialog warning if the file is already opened by another user and will open a yes/no dialog asking if users want to check out the file or not.


Updating with another - full non working example.

import bpy

from bpy.types import Operator
from bpy.app.handlers import (
    load_pre,
    persistent
)
from bpy.app import timers


class Checkout(Operator):
    bl_idname = "p4.edit"
    bl_label = "Checkout"

    def invoke(self, context, event):
        print('Invoke')
        import random

        # fake chance of file being checked out by another user
        checked_out_by_other_user = random.randint(0, 1)

        if checked_out_by_other_user:
            print(f"{context.blend_data.filepath} is already checked out by another user")
            self.report({'WARNING'}, f"{context.blend_data.filepath} is already checked out by another user")
            return {'PASS_THROUGH'}

        return context.window_manager.invoke_confirm(self, event)

    def execute(self, context):
        self.report({'INFO'}, f"Checking out {context.blend_data.filepath}")
        print(f"Checking out {context.blend_data.filepath}")
        return {'FINISHED'}


def checkout():
    bpy.ops.p4.edit('INVOKE_DEFAULT')


@persistent
def on_load_pre(*args):
    filepath, _ = args
    
    if not filepath:
        return  # do nothing for untitled blend files

    timers.register(checkout, first_interval=0.0)


def register():
    load_pre.append(on_load_pre)


def unregister():
    load_pre.remove(on_load_pre)

Calling the operator works close to what I expect, but again does nothing when called from the app handler

$\endgroup$
6
  • $\begingroup$ Hello ! I'm not sure interface elements nor application timers nor operators are supposed to be available when load_pre is fired, so I'm not surprised calling an operator fails. Have you tried on load_post ? $\endgroup$
    – Gorgious
    Feb 15 at 13:22
  • $\begingroup$ Have not tried that no. Want to run it before users load to be able and get the latest version from Perforce before users open it however. $\endgroup$ Feb 15 at 13:39
  • $\begingroup$ So if I can update already opened files outside of Blender and have these updates show in the opened .blend then it could work $\endgroup$ Feb 15 at 13:41
  • $\begingroup$ Calling operator is allowed in the load_post so could maybe use both to solve my issue. $\endgroup$ Feb 15 at 13:59
  • $\begingroup$ At this point maybe you want your users to use an external launcher for Blender and manage everything outside of it ? $\endgroup$
    – Gorgious
    Feb 15 at 14:05

0

You must log in to answer this question.

Browse other questions tagged .