2
$\begingroup$

I'm now trying to change Navigation into walk Navigation in the 3D viewport. So I write the code below.

import bpy

for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for region in area.regions:
            if region.type == 'WINDOW':
                bpy.ops.view3D.walk()      

this returns error

  File "D:\3Dmodels\python_demos.blend\operator_modal_view3d.py", line 11, in <module>
  File "D:\programs\Blender\stable\blender-2.92.0-windows64\2.92\scripts\modules\bpy\ops.py", line 132, in __call__
    ret = _op_call(self.idname_py(), None, kw)
RuntimeError: Operator bpy.ops.view3D.walk.poll() expected a view3d region

So I added a line override = {'area': area, 'region': region} and change walk() into walk(override).

import bpy

for area in bpy.context.screen.areas:
    if area.type == 'VIEW_3D':
        for region in area.regions:
            if region.type == 'WINDOW':
                override = {'area': area, 'region': region}
                bpy.ops.view3D.walk(override)   

However, Blender returns another error

ERROR (wm.operator): C:\b\buildbot-worker-windows\windows_292\blender.git\source\blender\windowmanager\intern\wm_event_system.c:1321 wm_operator_invoke: invalid operator call 'VIEW3D_OT_walk'

So if anyone knows how to run bpy.ops.view3D.walk(), please teach me and I would be very happy!

$\endgroup$

1 Answer 1

2
$\begingroup$

Putting 3D viewport in walk mode from py console.

Think you were 99% there.

IMO always a good idea to try things out in the python console

>>> C.area.type
'CONSOLE'

Override the context by finding a view3d area in the screen. Make sure an area aside from console is a view3d.

>>> for a in C.screen.areas:
...     if a.type == 'VIEW_3D':
...         break
...         
>>> a.type
'VIEW_3D'

Make a dictionary and fill with usual suspects area, space_data, and region It is AFAIK always the case that the 'WINDOW' region is the last in the area regions. If not of this opinion can iterate them as shown in question.

>>> c = {}
>>> c["area"] = a
>>> c["space_data"] = a.spaces.active
>>> c["region"] = a.regions[-1]

Ok now give the override a go... oh and remember all letters in an operator are expected to be lower case eg 3d not 3D.... (However it does appear to accept view3D, but autocompletes on view3d)

Attempt 1... passed through.. equivalent of doing NADA.. but no errors.

>>> bpy.ops.view3d.walk(c)
{'PASS_THROUGH'}

Ok will try good old 'INVOKE_DEFAULT' execution context, this is as if we were there in the 3D view and pressed a button or chose it in a menu...

Attempt 2... BINGO.. 3D view is in walk mode.

>>> bpy.ops.view3d.walk(c, 'INVOKE_DEFAULT')
{'RUNNING_MODAL'}

Ok all that done and shown, if you are going to write an operator that is invoked from within the 3d viewport, all the override stuff is not required. (Similarly if you change the area to a 3d viewport as shown by @Chris, but in reality we rarely want to do that way... hard to type into console if it becomes the 3d viewport (for example)) The default execution context of a button or menu pressed is 'INVOKE_DEFAULT'.

$\endgroup$
2
  • $\begingroup$ Thank you for your amazing answer! This worked perfectly and helped me to understand it deeply! $\endgroup$
    – tatmius
    Mar 8, 2021 at 21:06
  • $\begingroup$ I found out that we only need to override area and region, blender.stackexchange.com/a/230836/31447 $\endgroup$
    – brockmann
    Jul 19, 2021 at 7:53

You must log in to answer this question.

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