fix: Registration of keymaps and associated errors.

uv-refactor
Sofus Albert Høgsbro Rose 2024-10-02 12:55:38 +02:00
parent 55235c7032
commit 383f7d9bfd
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
12 changed files with 329 additions and 122 deletions

View File

@ -18,8 +18,8 @@
from functools import reduce from functools import reduce
# from . import node_trees, operators, preferences, registration # from . import node_trees
from . import assets, preferences, registration from . import assets, operators, preferences, registration
from . import contracts as ct from . import contracts as ct
from .utils import logger from .utils import logger
@ -30,8 +30,8 @@ log = logger.get(__name__)
# - Load and Register Addon # - Load and Register Addon
#################### ####################
BL_REGISTER: list[ct.BLClass] = [ BL_REGISTER: list[ct.BLClass] = [
# *operators.BL_REGISTER, *operators.BL_REGISTER,
# *assets.BL_REGISTER, *assets.BL_REGISTER,
# *node_trees.BL_REGISTER, # *node_trees.BL_REGISTER,
] ]
@ -39,20 +39,18 @@ BL_HANDLERS: ct.BLHandlers = reduce(
lambda a, b: a + b, lambda a, b: a + b,
[ [
assets.BL_HANDLERS, assets.BL_HANDLERS,
# *operators.BL_HANDLERS, operators.BL_HANDLERS,
# *assets.BL_HANDLERS, assets.BL_HANDLERS,
# *node_trees.BL_HANDLERS, # node_trees.BL_HANDLERS,
], ],
ct.BLHandlers(), ct.BLHandlers(),
) )
BL_HOTKEYS: list[ct.KeymapItemDef] = [ BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
# *operators.BL_HOTKEYS, *assets.BL_KEYMAP_ITEMS,
# *assets.BL_HOTKEYS, *operators.BL_KEYMAP_ITEMS,
] ]
## TODO: BL_HANDLERS and BL_SOCKET_DEFS
#################### ####################
# - Registration # - Registration
@ -79,7 +77,7 @@ def register() -> None:
registration.register_classes(BL_REGISTER) registration.register_classes(BL_REGISTER)
registration.register_handlers(BL_HANDLERS) registration.register_handlers(BL_HANDLERS)
registration.register_hotkeys(BL_HOTKEYS) registration.register_keymaps(BL_KEYMAP_ITEMS)
log.info('Finished Registration of Addon: %s', ct.addon.NAME) log.info('Finished Registration of Addon: %s', ct.addon.NAME)
else: else:
@ -98,7 +96,7 @@ def unregister() -> None:
""" """
log.info('Starting %s Unregister', ct.addon.NAME) log.info('Starting %s Unregister', ct.addon.NAME)
registration.unregister_hotkeys() registration.unregister_keymaps()
registration.unregister_handlers() registration.unregister_handlers()
registration.unregister_classes() registration.unregister_classes()

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Internal assets for use via the Python API and/or directly by the user as an asset library."""
from functools import reduce from functools import reduce
import oscillode.contracts as ct import oscillode.contracts as ct
@ -32,8 +34,8 @@ BL_HANDLERS: ct.BLHandlers = reduce(
ct.BLHandlers(), ct.BLHandlers(),
) )
BL_HOTKEYS: list[ct.KeymapItemDef] = [ BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
*geonodes.BL_HOTKEYS, *geonodes.BL_KEYMAP_ITEMS,
] ]
__all__ = [ __all__ = [

View File

@ -31,17 +31,17 @@ log = logger.get(__name__)
#################### ####################
# GeoNodes Paths # GeoNodes Paths
## Internal ## Internal
GN_INTERNAL_PATH = ct.addon.PATH_ASSETS / 'internal' GN_INTERNAL_PATH: Path = ct.addon.PATH_ASSETS / 'internal'
GN_INTERNAL_INPUTS_PATH = GN_INTERNAL_PATH / 'input' GN_INTERNAL_INPUTS_PATH: Path = GN_INTERNAL_PATH / 'input'
GN_INTERNAL_SOURCES_PATH = GN_INTERNAL_PATH / 'source' GN_INTERNAL_SOURCES_PATH: Path = GN_INTERNAL_PATH / 'source'
GN_INTERNAL_STRUCTURES_PATH = GN_INTERNAL_PATH / 'structure' GN_INTERNAL_STRUCTURES_PATH: Path = GN_INTERNAL_PATH / 'structure'
GN_INTERNAL_MONITORS_PATH = GN_INTERNAL_PATH / 'monitor' GN_INTERNAL_MONITORS_PATH: Path = GN_INTERNAL_PATH / 'monitor'
GN_INTERNAL_SIMULATIONS_PATH = GN_INTERNAL_PATH / 'simulation' GN_INTERNAL_SIMULATIONS_PATH: Path = GN_INTERNAL_PATH / 'simulation'
## Structures ## Structures
GN_STRUCTURES_PATH = ct.addon.PATH_ASSETS / 'structures' GN_STRUCTURES_PATH: Path = ct.addon.PATH_ASSETS / 'structures'
GN_STRUCTURES_PRIMITIVES_PATH = GN_STRUCTURES_PATH / 'primitives' GN_STRUCTURES_PRIMITIVES_PATH: Path = GN_STRUCTURES_PATH / 'primitives'
GN_STRUCTURES_ARRAYS_PATH = GN_STRUCTURES_PATH / 'arrays' GN_STRUCTURES_ARRAYS_PATH: Path = GN_STRUCTURES_PATH / 'arrays'
class GeoNodes(enum.StrEnum): class GeoNodes(enum.StrEnum):
@ -473,10 +473,10 @@ class GeoNodesToStructureNode(bpy.types.Operator):
## 3. We compute it manually, to avoid the jank. ## 3. We compute it manually, to avoid the jank.
node_location = get_view_location( node_location = get_view_location(
editor_region, editor_region,
[ (
event.mouse_x - editor_region.x, event.mouse_x - editor_region.x,
event.mouse_y - editor_region.y, event.mouse_y - editor_region.y,
], ),
context.preferences.system.ui_scale, context.preferences.system.ui_scale,
) )
@ -525,8 +525,8 @@ ASSET_LIB_SPECS: dict[str, Path] = {
} }
@bpy.app.handlers.persistent @bpy.app.handlers.persistent # type: ignore[misc]
def initialize_asset_libraries(_: bpy.types.Scene): def initialize_asset_libraries(_: bpy.types.Scene) -> None:
"""Before loading a `.blend` file, ensure that the WindowManager properties relied on by NodeAssetPanel are available. """Before loading a `.blend` file, ensure that the WindowManager properties relied on by NodeAssetPanel are available.
- Several asset libraries, defined under the global `ASSET_LIB_SPECS`, are added/replaced such that the name:path map is respected. - Several asset libraries, defined under the global `ASSET_LIB_SPECS`, are added/replaced such that the name:path map is respected.
@ -586,4 +586,4 @@ BL_REGISTER = [
BL_HANDLERS: ct.BLHandlers = ct.BLHandlers(load_pre=(initialize_asset_libraries,)) BL_HANDLERS: ct.BLHandlers = ct.BLHandlers(load_pre=(initialize_asset_libraries,))
BL_HOTKEYS: list[ct.KeymapItemDef] = [] BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = []

View File

@ -22,24 +22,25 @@ from .bl import (
BLColorRGBA, BLColorRGBA,
BLEnumElement, BLEnumElement,
BLEnumID, BLEnumID,
BLEventType,
BLEventValue,
BLIcon, BLIcon,
BLIconSet, BLIconSet,
BLIDStruct, BLIDStruct,
BLImportMethod, BLImportMethod,
BLKeymapItem,
BLModifierType, BLModifierType,
BLNodeTreeInterfaceID, BLNodeTreeInterfaceID,
BLOperatorStatus, BLOperatorStatus,
BLPropFlag, BLPropFlag,
BLRegionType, BLRegionType,
BLSpaceType, BLSpaceType,
KeymapItemDef,
ManagedObjName, ManagedObjName,
PresetName, PresetName,
PropName, PropName,
SocketName, SocketName,
) )
from .bl_handlers import BLHandlers from .bl_handlers import BLHandlers
from .bl_keymap import BLKeymapItem
from .icons import Icon from .icons import Icon
from .mobj_types import ManagedObjType from .mobj_types import ManagedObjType
from .node_tree_types import ( from .node_tree_types import (
@ -58,6 +59,8 @@ __all__ = [
'BLColorRGBA', 'BLColorRGBA',
'BLEnumElement', 'BLEnumElement',
'BLEnumID', 'BLEnumID',
'BLEventType',
'BLEventValue',
'BLIcon', 'BLIcon',
'BLIconSet', 'BLIconSet',
'BLIDStruct', 'BLIDStruct',

View File

@ -45,7 +45,7 @@ if 'RUNNING_BLEXT_TESTS' in os.environ:
PATH_ADDON_ROOT.parent / 'dev' / 'local' PATH_ADDON_ROOT.parent / 'dev' / 'local'
) ## TODO: Consult init_settings ) ## TODO: Consult init_settings
else: else:
PATH_CACHE: Path = Path(bpy.utils.extension_path_user(__package__, create=True)) PATH_CACHE: Path = Path(bpy.utils.extension_path_user(__package__, create=True)) # type: ignore[no-redef]
#################### ####################

View File

@ -95,7 +95,6 @@ BLIDStruct: typ.TypeAlias = (
| bpy.types.WorkSpace | bpy.types.WorkSpace
| bpy.types.World | bpy.types.World
) )
BLKeymapItem: typ.TypeAlias = typ.Any ## TODO: Better Type
BLPropFlag: typ.TypeAlias = typ.Literal[ BLPropFlag: typ.TypeAlias = typ.Literal[
'HIDDEN', 'HIDDEN',
'SKIP_SAVE', 'SKIP_SAVE',
@ -112,6 +111,24 @@ BLColorRGBA = tuple[float, float, float, float]
#################### ####################
# - Operators # - Operators
#################### ####################
BLRegionType: typ.TypeAlias = typ.Literal[
'WINDOW',
'HEADER',
'CHANNELS',
'TEMPORARY',
'UI',
'TOOLS',
'TOOL_PROPS',
'ASSET_SHELF',
'ASSET_SHELF_HEADER',
'PREVIEW',
'HUD',
'NAVIGATION_BAR',
'EXECUTE',
'FOOTER',
'TOOL_HEADER',
'XR',
]
BLSpaceType: typ.TypeAlias = typ.Literal[ BLSpaceType: typ.TypeAlias = typ.Literal[
'EMPTY', 'EMPTY',
'VIEW_3D', 'VIEW_3D',
@ -133,32 +150,151 @@ BLSpaceType: typ.TypeAlias = typ.Literal[
'SPREADSHEET', 'SPREADSHEET',
'PREFERENCES', 'PREFERENCES',
] ]
BLRegionType: typ.TypeAlias = typ.Literal[
'WINDOW',
'HEADER',
'CHANNELS',
'TEMPORARY',
'UI',
'TOOLS',
'TOOL_PROPS',
'ASSET_SHELF',
'ASSET_SHELF_HEADER',
'PREVIEW',
'HUD',
'NAVIGATION_BAR',
'EXECUTE',
'FOOTER',
'TOOL_HEADER',
'XR',
]
BLOperatorStatus: typ.TypeAlias = set[ BLOperatorStatus: typ.TypeAlias = set[
typ.Literal['RUNNING_MODAL', 'CANCELLED', 'FINISHED', 'PASS_THROUGH', 'INTERFACE'] typ.Literal['RUNNING_MODAL', 'CANCELLED', 'FINISHED', 'PASS_THROUGH', 'INTERFACE']
] ]
####################
# - Operators
####################
## TODO: Write the rest in.
BLEventType: typ.TypeAlias = typ.Literal[
'NONE',
'LEFTMOUSE',
'MIDDLEMOUSE',
'RIGHTMOUSE',
'BUTTON4MOUSE',
'BUTTON5MOUSE',
'BUTTON6MOUSE',
'BUTTON7MOUSE',
'PEN',
'ERASOR',
'MOUSEMOVE',
'INBETWEEN_MOUSEMOVE',
'TRACKPADPAN',
'TRACKPADZOOM',
'MOUSEROTATE',
'MOUSESMARTZOOM',
'WHEELUPMOUSE',
'WHEELDOWNMOUSE',
'WHEELINMOUSE',
'WHEELOUTMOUSE',
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'ZERO',
'ONE',
'TWO',
'THREE',
'FOUR',
'FIVE',
'SIX',
'SEVEN',
'EIGHT',
'NINE',
'LEFT_CTRL',
'LEFT_ALT',
'LEFT_SHIFT',
'RIGHT_ALT',
'RIGHT_CTRL',
'RIGHT_SHIFT',
'ESC',
'TAB',
'RET', ## Enter
'SPACE',
'LINE_FEED',
'BACK_SPACE',
'DEL',
'SEMI_COLON',
'PERIOD',
'COMMA',
'QUOTE',
'ACCENT_GRAVE',
'MINUS',
'PLUS',
'SLASH',
'BACK_SLASH',
'EQUAL',
'LEFT_BRACKET',
'RIGHT_BRACKET',
'LEFT_ARROW',
'DOWN_ARROW',
'RIGHT_ARROW',
'UP_ARROW',
'NUMPAD_0',
'NUMPAD_1',
'NUMPAD_2',
'NUMPAD_3',
'NUMPAD_4',
'NUMPAD_5',
'NUMPAD_6',
'NUMPAD_7',
'NUMPAD_8',
'NUMPAD_9',
'NUMPAD_PERIOD',
'NUMPAD_SLASH',
'NUMPAD_ASTERIX',
'NUMPAD_MINUS',
'NUMPAD_PLUS',
'NUMPAD_ENTER',
'F1',
'F2',
'F3',
'F4',
'F5',
'F6',
'F7',
'F8',
'F9',
'F10',
'F11',
'F12',
'PAUSE',
'INSERT',
'HOME',
'PAGE_UP',
'PAGE_DOWN',
'END',
'MEDIA_PLAY',
'MEDIA_STOP',
'MEDIA_FIRST',
'MEDIA_LAST',
]
BLEventValue: typ.TypeAlias = typ.Literal[
'ANY',
'PRESS',
'RELEASE',
'CLICK',
'DOUBLE_CLICK',
'CLICK_DRAG',
'NOTHING',
]
#################### ####################
# - Addon Types # - Addon Types
#################### ####################
KeymapItemDef: typ.TypeAlias = typ.Any
ManagedObjName = str ManagedObjName = str
#################### ####################

View File

@ -58,6 +58,9 @@ class BLHandlers(pyd.BaseModel):
render_post: tuple[BLHandler, ...] = () render_post: tuple[BLHandler, ...] = ()
render_pre: tuple[BLHandler, ...] = () render_pre: tuple[BLHandler, ...] = ()
render_stats: tuple[BLHandler, ...] = () render_stats: tuple[BLHandler, ...] = ()
## TODO: Verify these type signatures.
## TODO: A validator to check that all handlers are decorated with bpy.app.handlers.persistent
#################### ####################
# - Properties # - Properties

View File

@ -0,0 +1,60 @@
# oscillode
# Copyright (C) 2024 oscillode Project Contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Declares types for working with `bpy.types.KeyMap`s."""
import bpy
import pydantic as pyd
from .bl import BLEventType, BLEventValue, BLSpaceType
from .operator_types import OperatorType
class BLKeymapItem(pyd.BaseModel):
"""Contains lists of handlers associated with this addon."""
operator: OperatorType
event_type: BLEventType
event_value: BLEventValue
shift: bool = False
ctrl: bool = False
alt: bool = False
key_modifier: BLEventType = 'NONE'
space_type: BLSpaceType = 'EMPTY'
def register(self, addon_keymap: bpy.types.KeyMap) -> bpy.types.KeymapItem:
"""Registers this hotkey with an addon keymap.
Raises:
ValueError: If the `space_type` constraint of the addon keymap does not match the `space_type` constraint of this `BLKeymapItem`.
"""
if self.space_type == addon_keymap.space_type:
addon_keymap.keymap_items.new(
self.operator,
self.event_type,
self.event_value,
shift=self.shift,
ctrl=self.ctrl,
alt=self.alt,
key_modifier=self.key_modifier,
)
msg = f'Addon keymap space type {addon_keymap.space_type} does not match space_type of BLKeymapItem to register: {self}'
raise ValueError(msg)
## TODO: Check if space_type matches?

View File

@ -312,6 +312,8 @@ class MaxwellSimTree(bpy.types.NodeTree):
default=True, default=True,
) )
viewer_node_type: ct.NodeType = ct.NodeType.Viewer
#################### ####################
# - Init Methods # - Init Methods
#################### ####################

View File

@ -16,11 +16,22 @@
"""Blender operators that ship with Oscillode.""" """Blender operators that ship with Oscillode."""
from functools import reduce
from oscillode import contracts as ct
from . import connect_viewer from . import connect_viewer
BL_REGISTER = [ BL_REGISTER: list[ct.BLClass] = [
*connect_viewer.BL_REGISTER, *connect_viewer.BL_REGISTER,
] ]
BL_HOTKEYS = [ BL_HANDLERS: ct.BLHandlers = reduce(
*connect_viewer.BL_HOTKEYS, lambda a, b: a + b,
[
*connect_viewer.BL_HANDLERS,
],
ct.BLHandlers(),
)
BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
*connect_viewer.BL_KEYMAP_ITEMS,
] ]

View File

@ -19,7 +19,6 @@
import bpy import bpy
from oscillode import contracts as ct from oscillode import contracts as ct
from oscillode.node_trees.maxwell_sim_nodes.contracts import node_types
from oscillode.utils import logger from oscillode.utils import logger
log = logger.get(__name__) log = logger.get(__name__)
@ -79,16 +78,17 @@ class ConnectViewerNode(bpy.types.Operator):
selected_node = context.selected_nodes[0] selected_node = context.selected_nodes[0]
# Find Viewer Node... # Find Viewer Node...
viewer_node_type = node_tree.viewer_node_type
for node in node_tree.nodes: for node in node_tree.nodes:
# TODO: Support multiple viewer nodes. # TODO: Support multiple viewer nodes.
if hasattr(node, 'node_type') and node.node_type is node_types.Viewer: if hasattr(node, 'node_type') and node.node_type is viewer_node_type:
viewer_node = node viewer_node = node
break break
# ...OR: Create Viewer Node # ...OR: Create Viewer Node
else: else:
# TODO: Place viewer where it doesn't overlap other nodes. # TODO: Place viewer where it doesn't overlap other nodes.
viewer_node = node_tree.nodes.new(node_types.Viewer.value) viewer_node = node_tree.nodes.new(viewer_node_type)
viewer_node.location.x = selected_node.location.x + 250 viewer_node.location.x = selected_node.location.x + 250
viewer_node.location.y = selected_node.location.y viewer_node.location.y = selected_node.location.y
selected_node.select = False selected_node.select = False
@ -112,19 +112,19 @@ class ConnectViewerNode(bpy.types.Operator):
#################### ####################
# - Blender Registration # - Blender Registration
#################### ####################
BL_REGISTER = [ BL_REGISTER: list[ct.BLClass] = [
ConnectViewerNode, ConnectViewerNode,
] ]
BL_HOTKEYS = [ BL_HANDLERS: ct.BLHandlers = ct.BLHandlers()
{
'_': ( BL_KEYMAP_ITEMS: list[ct.BLKeymapItem] = [
ct.BLKeymapItem(
ct.OperatorType.ConnectViewerNode, ct.OperatorType.ConnectViewerNode,
'LEFTMOUSE', event_type='LEFTMOUSE',
'PRESS', event_value='PRESS',
), ctrl=True,
'ctrl': True, shift=True,
'shift': True, space_type='NODE_EDITOR',
'alt': False, )
},
] ]

View File

@ -17,9 +17,13 @@
"""Manages the registration of Blender classes, including delayed registrations that require access to Python dependencies. """Manages the registration of Blender classes, including delayed registrations that require access to Python dependencies.
Attributes: Attributes:
_ADDON_KEYMAP: Addon-specific keymap used to register operator hotkeys. _REGISTERED_CLASSES: Blender classes currently registered by this addon.
REG__CLASSES: Currently registered Blender classes. _REGISTERED_KEYMAPS: Addon keymaps currently registered by this addon.
_REGISTERED_HOTKEYS: Currently registered Blender keymap items. Each addon keymap is constrained to a single `space_type`, which is the key.
_REGISTERED_KEYMAP_ITEMS: Addon keymap items currently registered by this addon.
Each keymap item is paired to the keymap within which it is registered.
_Each keymap is guaranteed to also be found in `_REGISTERED_KEYMAPS`._
_REGISTERED_HANDLERS: Addon handlers currently registered by this addon.
""" """
import bpy import bpy
@ -34,8 +38,8 @@ log = logger.get(__name__)
#################### ####################
_REGISTERED_CLASSES: list[ct.BLClass] = [] _REGISTERED_CLASSES: list[ct.BLClass] = []
_ADDON_KEYMAP: bpy.types.KeyMap | None = None _REGISTERED_KEYMAPS: dict[ct.BLSpaceType, bpy.types.KeyMap] = {}
_REGISTERED_HOTKEYS: list[ct.BLKeymapItem] = [] _REGISTERED_KEYMAP_ITEMS: list[tuple[bpy.types.KeyMap, bpy.types.KeymapItem]] = []
_REGISTERED_HANDLERS: ct.BLHandlers | None = None _REGISTERED_HANDLERS: ct.BLHandlers | None = None
@ -109,59 +113,47 @@ def unregister_handlers() -> None:
#################### ####################
# - Keymap Registration # - Keymap Registration
#################### ####################
def register_hotkeys(hotkey_defs: list[dict]) -> None: def register_keymaps(keymap_items: list[ct.BLKeymapItem]) -> None:
"""Registers a list of Blender hotkey definitions. """Registers a list of Blender hotkey definitions.
Parameters: Parameters:
hotkey_defs: List of Blender hotkey definitions to register. bl_keymap_items: List of Blender hotkey definitions to register.
""" """
# Lazy-Load BL_NODE_KEYMAP # Aggregate Requested Spaces of All Keymap Items
global _ADDON_KEYMAP # noqa: PLW0603 keymap_space_types: set[ct.BLSpaceType] = {
if _ADDON_KEYMAP is None: keymap_item.space_type for keymap_item in keymap_items
_ADDON_KEYMAP = bpy.context.window_manager.keyconfigs.addon.keymaps.new( }
name='Node Editor',
space_type='NODE_EDITOR',
)
log.info(
'Registered Addon Keymap (Base for Keymap Items): %s',
str(_ADDON_KEYMAP),
)
# Register Keymaps # Create Addon Keymap per Requested Space
log.info('Registering %s Keymap Items', len(hotkey_defs)) for keymap_space_type in keymap_space_types:
for keymap_item_def in hotkey_defs: log.info('Registering %s Keymap', keymap_space_type)
keymap_item = _ADDON_KEYMAP.keymap_items.new( bl_keymap = bpy.context.window_manager.keyconfigs.addon.keymaps.new(
*keymap_item_def['_'], name=f'{ct.addon.NAME} - {keymap_space_type}',
ctrl=keymap_item_def['ctrl'], space_type=keymap_space_type,
shift=keymap_item_def['shift'],
alt=keymap_item_def['alt'],
) )
log.debug( _REGISTERED_KEYMAPS[keymap_space_type] = bl_keymap
'Registered Keymap Item %s with spec %s',
repr(keymap_item), # Register Keymap Items in Correct Addon Keymap
keymap_item_def, for keymap_item in keymap_items:
) log.info('Registering %s Keymap Item', keymap_item)
_REGISTERED_HOTKEYS.append(keymap_item) bl_keymap = _REGISTERED_KEYMAPS[keymap_item.space_type]
bl_keymap_item = keymap_item.register(bl_keymap)
_REGISTERED_KEYMAP_ITEMS.append((bl_keymap, bl_keymap_item))
def unregister_hotkeys() -> None: def unregister_keymaps() -> None:
"""Unregisters all Blender hotkeys associated with the addon.""" """Unregisters all Blender keymaps associated with the addon."""
global _ADDON_KEYMAP # noqa: PLW0603 # Unregister Keymap Items from Correct Addon Keymap
for bl_keymap, bl_keymap_item in reversed(_REGISTERED_KEYMAP_ITEMS):
log.info('Unregistering %s BL Keymap Item', bl_keymap_item)
bl_keymap.keymap_items.remove(bl_keymap_item)
# Unregister Keymaps _REGISTERED_KEYMAP_ITEMS.clear()
log.info('Unregistering %s Keymap Items', len(_REGISTERED_HOTKEYS))
for keymap_item in reversed(_REGISTERED_HOTKEYS):
log.debug(
'Unregistered Keymap Item %s',
repr(keymap_item),
)
_ADDON_KEYMAP.keymap_items.remove(keymap_item)
# Lazy-Unload BL_NODE_KEYMAP # Delete Addon Keymaps
if _ADDON_KEYMAP is not None: for bl_keymap in reversed(_REGISTERED_KEYMAPS.values()):
log.info( log.info('Unregistering %s Keymap', bl_keymap)
'Unregistered Keymap %s', bpy.context.window_manager.keyconfigs.addon.keymaps.remove(bl_keymap)
repr(_ADDON_KEYMAP),
) _REGISTERED_KEYMAPS.clear()
_REGISTERED_HOTKEYS.clear()
_ADDON_KEYMAP = None