2
$\begingroup$

I tried imitating Blender's TAB press (Edit Mode Toggle) by using object.mode_set(mode='EDIT'), but this doesn't work for grease pencil objects which require object.mode_set(mode='EDIT_GPENCIL') instead.

I checked the keymap editor but the Enum property there doesn't even match the documentation:

enter image description here Am I being silly or what is going on here?

TLDR

What API command can I use to match the default behavior of TAB press (not have to worry about object types like mesh vs grease_pencil)?

EDIT: Thanks batfinger and Marcus for helping out!

$\endgroup$
2
  • $\begingroup$ I tried using TAB on all objects you can add from SHIFT+A menu. I only got a different mode for grease pencil, for which TAB executes bpy.ops.gpencil.editmode_toggle() However, if you go into POSE MODE and press TAB there, you will get both editmode toggle and posemode toggle. The same happens when you press TAB again, Blender remembers that you were in POSE MODE. $\endgroup$ – Markus von Broady Feb 3 at 22:43
  • $\begingroup$ Yeah, I'm hoping to figure out how that 1 keymap for TAB manages to work for every case, and also why the documentation doesn't match the keymap editor. $\endgroup$ – Armored Wolf Feb 4 at 1:13
3
$\begingroup$

Keymap sets a toggle.

The operator has two properties, mode and toggle

>>> bpy.ops.object.mode_set(
mode_set()
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
Sets the object interaction mode

enter image description here Mesh object active

The TAB Shortcut The toggle property is set to True.

which correlates to

bpy.ops.object.mode_set(mode='EDIT', toggle=True)

enter image description here GPencil object active

Why is it blank when GP is active, the keymap uses 'EDIT' as the setting, which is not available as an enum item. (See below) Appears to be some dodgy fix in place behind the scenes, replacing 'EDIT' with a startswith 'EDIT' option.

The shortcut can be emulated by emulating this.

import bpy
ob = bpy.context.object

bpy.ops.object.mode_set(
        mode = 'EDIT_GPENCIL' if ob.type == 'GPENCIL' else 'EDIT',
        toggle=True,
        )

use this in your scripts to emulate tab.

Dynamic Enum

On the "Non Matching". An enum property can be dynamic, ie items added / removed based on context. If a grease pencil object is active the options are different for if a mesh object is active, etc.

The documentation shows all possible items, of which only a subset will be valid, based on context.

EDIT

On further investigation, the shortcut is using

bpy.ops.gpencil.editmode_toggle()

this can be confirmed by pressing TAB with GP object active and in python console

>>> C.active_operator
<bpy_struct, Operator("GPENCIL_OT_editmode_toggle") at 0x7f3221be1988>

>>> C.window_manager.operator_properties_last('gpencil.editmode_toggle').back
False

when the context object is a gpencil, so without any knowledge of context, could use a try catch clause

import bpy

try:
    bpy.ops.object.mode_set(
            mode = 'EDIT',
            toggle=True,
            )
except TypeError:
    bpy.ops.gpencil.editmode_toggle()

which will still throw a runtime error if the context object is None for example.

$\endgroup$
4
  • $\begingroup$ Sadly this doesn't work. Create an armature, press CTRL+TAB to go to POSE mode. Now pressing TAB will alternate between EDIT mode and POSE mode. But executing bpy.ops.object.mode_set(toggle=True) will alternate between POSE mode and OBJECT mode. It does work for grease pencil, though. However, it doesn't always work. Create a new file, go to scripting tab and execute the code - nothing changes (at least for me, I'm on 2.91.0 at the moment). $\endgroup$ – Markus von Broady Feb 4 at 9:24
  • $\begingroup$ @MarkusvonBroady, jumped to wrong conclusion on blank setting as in screenshot. With any other editable object type set it is 'EDIT'. Which was "dumb" on my part since leaving it out makes it default to 'OBJECT'. Changing for the odd man out GPENCIL object fixes it and produces AFAICT standard behaviour. Thanks for the heads up. $\endgroup$ – batFINGER Feb 4 at 9:52
  • $\begingroup$ Now it works great! When debugging with bpy.app.debug_wm = True both methods (manually pressing TAB and running the script) produce the exact same log output (except for bpy.ops.text.run_script()) $\endgroup$ – Markus von Broady Feb 4 at 10:09
  • 1
    $\begingroup$ Thanks batfinger and Marcus for going so deep into this! $\endgroup$ – Armored Wolf Feb 4 at 19:58

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.