Keymap: update addon register/unregister utilities
Use the same data format and loader that the default key-maps use. This supports nested properties (needed for macros) and fixes modal key-maps which weren't supported. This format still needs to be documented.
This commit is contained in:
@@ -22,71 +22,61 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Add-on helpers to properly (un)register their own keymaps.
|
# Add-on helpers to properly (un)register their own keymaps.
|
||||||
|
|
||||||
# Example of keymaps_description:
|
def addon_keymap_register(keymap_data):
|
||||||
keymaps_description_doc = """
|
|
||||||
keymaps_description is a tuple (((keymap_description), (tuple of keymap_item_descriptions))).
|
|
||||||
keymap_description is a tuple (name, space_type, region_type, is_modal).
|
|
||||||
keymap_item_description is a tuple ({kw_args_for_keymap_new}, (tuple of properties)).
|
|
||||||
kw_args_for_keymap_new is a mapping which keywords match parameters of keymap.new() function.
|
|
||||||
tuple of properties is a tuple of pairs (prop_name, prop_value) (properties being those of called operator).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
KEYMAPS = (
|
|
||||||
# First, keymap identifiers (last bool is True for modal km).
|
|
||||||
(('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', False), (
|
|
||||||
# Then a tuple of keymap items, defined by a dict of kwargs for the km new func, and a tuple of tuples (name, val)
|
|
||||||
# for ops properties, if needing non-default values.
|
|
||||||
({"idname": export_strips.SEQExportStrip.bl_idname, "type": 'P', "value": 'PRESS', "shift": True, "ctrl": True},
|
|
||||||
()),
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def addon_keymap_register(wm, keymaps_description):
|
|
||||||
"""
|
"""
|
||||||
Register a set of keymaps for addons.
|
Register a set of keymaps for addons using a list of keymaps.
|
||||||
|
|
||||||
|
See 'blender_defaults.py' for examples of the format this takes.
|
||||||
|
"""
|
||||||
|
import bpy
|
||||||
|
wm = bpy.context.window_manager
|
||||||
|
|
||||||
|
from bl_keymap_utils.io import keymap_init_from_data
|
||||||
|
|
||||||
""" + keymaps_description_doc
|
|
||||||
kconf = wm.keyconfigs.addon
|
kconf = wm.keyconfigs.addon
|
||||||
if not kconf:
|
if not kconf:
|
||||||
return # happens in background mode...
|
return # happens in background mode...
|
||||||
for km_info, km_items in keymaps_description:
|
for km_name, km_args, km_content in keymap_data:
|
||||||
km_name, km_sptype, km_regtype, km_ismodal = km_info
|
km_space_type = km_args["space_type"]
|
||||||
kmap = [k for k in kconf.keymaps
|
km_region_type = km_args["region_type"]
|
||||||
if k.name == km_name and k.region_type == km_regtype and
|
km_modal = km_args.get("modal", False)
|
||||||
k.space_type == km_sptype and k.is_modal == km_ismodal]
|
kmap = next(iter(
|
||||||
if kmap:
|
k for k in kconf.keymaps
|
||||||
kmap = kmap[0]
|
if k.name == km_name and
|
||||||
else:
|
k.region_type == km_region_type and
|
||||||
kmap = kconf.keymaps.new(km_name, region_type=km_regtype, space_type=km_sptype, modal=km_ismodal)
|
k.space_type == km_space_type and
|
||||||
for kmi_kwargs, props in km_items:
|
k.is_modal == km_modal
|
||||||
kmi = kmap.keymap_items.new(**kmi_kwargs)
|
), None)
|
||||||
kmi.active = True
|
if kmap is None:
|
||||||
for prop, val in props:
|
kmap = kconf.keymaps.new(km_name, **km_args)
|
||||||
setattr(kmi.properties, prop, val)
|
keymap_init_from_data(kmap, km_content["items"], is_modal=km_modal)
|
||||||
|
|
||||||
|
def addon_keymap_unregister(keymap_data):
|
||||||
def addon_keymap_unregister(wm, keymaps_description):
|
|
||||||
"""
|
"""
|
||||||
Unregister a set of keymaps for addons.
|
Unregister a set of keymaps for addons.
|
||||||
|
"""
|
||||||
""" + keymaps_description_doc
|
|
||||||
# NOTE: We must also clean up user keyconfig, else, if user has customized one of add-on's shortcut, this
|
# NOTE: We must also clean up user keyconfig, else, if user has customized one of add-on's shortcut, this
|
||||||
# customization remains in memory, and comes back when re-enabling the addon, causing a segfault... :/
|
# customization remains in memory, and comes back when re-enabling the addon, causing a segfault... :/
|
||||||
|
import bpy
|
||||||
|
wm = bpy.context.window_manager
|
||||||
|
|
||||||
kconfs = wm.keyconfigs
|
kconfs = wm.keyconfigs
|
||||||
for kconf in (kconfs.user, kconfs.addon):
|
for kconf in (kconfs.user, kconfs.addon):
|
||||||
for km_info, km_items in keymaps_description:
|
for km_name, km_args, km_content in keymap_data:
|
||||||
km_name, km_sptype, km_regtype, km_ismodal = km_info
|
km_space_type = km_args["space_type"]
|
||||||
kmaps = (k for k in kconf.keymaps
|
km_region_type = km_args["region_type"]
|
||||||
if k.name == km_name and k.region_type == km_regtype and
|
km_modal = km_args.get("modal", False)
|
||||||
k.space_type == km_sptype and k.is_modal == km_ismodal)
|
kmaps = (
|
||||||
|
k for k in kconf.keymaps
|
||||||
|
if k.name == km_name and
|
||||||
|
k.region_type == km_region_type and
|
||||||
|
k.space_type == km_space_type and
|
||||||
|
k.is_modal == km_modal
|
||||||
|
)
|
||||||
for kmap in kmaps:
|
for kmap in kmaps:
|
||||||
for kmi_kwargs, props in km_items:
|
for kmi_idname, _, _ in km_content["items"]:
|
||||||
idname = kmi_kwargs["idname"]
|
|
||||||
for kmi in kmap.keymap_items:
|
for kmi in kmap.keymap_items:
|
||||||
if kmi.idname == idname:
|
if kmi.idname == kmi_idname:
|
||||||
kmap.keymap_items.remove(kmi)
|
kmap.keymap_items.remove(kmi)
|
||||||
# NOTE: We won't remove addons keymaps themselves, other addons might also use them!
|
# NOTE: We won't remove addons keymaps themselves, other addons might also use them!
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user