feat: Added handler bubble-up logic.
parent
12362b3cbd
commit
55235c7032
|
@ -16,7 +16,10 @@
|
|||
|
||||
"""A visual DSL for electromagnetic simulation design and analysis implemented as a Blender node editor."""
|
||||
|
||||
# from . import assets, node_trees, operators, preferences, registration
|
||||
from functools import reduce
|
||||
|
||||
# from . import node_trees, operators, preferences, registration
|
||||
from . import assets, preferences, registration
|
||||
from . import contracts as ct
|
||||
from .utils import logger
|
||||
|
||||
|
@ -32,6 +35,17 @@ BL_REGISTER: list[ct.BLClass] = [
|
|||
# *node_trees.BL_REGISTER,
|
||||
]
|
||||
|
||||
BL_HANDLERS: ct.BLHandlers = reduce(
|
||||
lambda a, b: a + b,
|
||||
[
|
||||
assets.BL_HANDLERS,
|
||||
# *operators.BL_HANDLERS,
|
||||
# *assets.BL_HANDLERS,
|
||||
# *node_trees.BL_HANDLERS,
|
||||
],
|
||||
ct.BLHandlers(),
|
||||
)
|
||||
|
||||
BL_HOTKEYS: list[ct.KeymapItemDef] = [
|
||||
# *operators.BL_HOTKEYS,
|
||||
# *assets.BL_HOTKEYS,
|
||||
|
@ -64,6 +78,7 @@ def register() -> None:
|
|||
log.info('Registering Addon: %s', ct.addon.NAME)
|
||||
|
||||
registration.register_classes(BL_REGISTER)
|
||||
registration.register_handlers(BL_HANDLERS)
|
||||
registration.register_hotkeys(BL_HOTKEYS)
|
||||
|
||||
log.info('Finished Registration of Addon: %s', ct.addon.NAME)
|
||||
|
@ -83,7 +98,8 @@ def unregister() -> None:
|
|||
"""
|
||||
log.info('Starting %s Unregister', ct.addon.NAME)
|
||||
|
||||
registration.unregister_classes()
|
||||
registration.unregister_hotkeys()
|
||||
registration.unregister_handlers()
|
||||
registration.unregister_classes()
|
||||
|
||||
log.info('Finished %s Unregister', ct.addon.NAME)
|
||||
|
|
|
@ -14,17 +14,30 @@
|
|||
# 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/>.
|
||||
|
||||
from functools import reduce
|
||||
|
||||
import oscillode.contracts as ct
|
||||
|
||||
from . import geonodes
|
||||
|
||||
BL_REGISTER = [
|
||||
BL_REGISTER: list[ct.BLClass] = [
|
||||
*geonodes.BL_REGISTER,
|
||||
]
|
||||
|
||||
BL_HOTKEYS = [
|
||||
BL_HANDLERS: ct.BLHandlers = reduce(
|
||||
lambda a, b: a + b,
|
||||
[
|
||||
geonodes.BL_HANDLERS,
|
||||
],
|
||||
ct.BLHandlers(),
|
||||
)
|
||||
|
||||
BL_HOTKEYS: list[ct.KeymapItemDef] = [
|
||||
*geonodes.BL_HOTKEYS,
|
||||
]
|
||||
|
||||
__all__ = [
|
||||
'BL_REGISTER',
|
||||
'BL_HANDLERS',
|
||||
'BL_HOTKEYS',
|
||||
]
|
||||
|
|
|
@ -579,11 +579,11 @@ def initialize_asset_libraries(_: bpy.types.Scene):
|
|||
)
|
||||
|
||||
|
||||
bpy.app.handlers.load_pre.append(initialize_asset_libraries)
|
||||
|
||||
BL_REGISTER = [
|
||||
NodeAssetPanel,
|
||||
GeoNodesToStructureNode,
|
||||
]
|
||||
|
||||
BL_HOTKEYS = []
|
||||
BL_HANDLERS: ct.BLHandlers = ct.BLHandlers(load_pre=(initialize_asset_libraries,))
|
||||
|
||||
BL_HOTKEYS: list[ct.KeymapItemDef] = []
|
||||
|
|
|
@ -39,6 +39,7 @@ from .bl import (
|
|||
PropName,
|
||||
SocketName,
|
||||
)
|
||||
from .bl_handlers import BLHandlers
|
||||
from .icons import Icon
|
||||
from .mobj_types import ManagedObjType
|
||||
from .node_tree_types import (
|
||||
|
@ -74,6 +75,7 @@ __all__ = [
|
|||
'PresetName',
|
||||
'PropName',
|
||||
'SocketName',
|
||||
'BLHandlers',
|
||||
'Icon',
|
||||
'BLInstance',
|
||||
'InstanceID',
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
# 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.app.handlers` callbacks."""
|
||||
|
||||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from oscillode.utils.staticproperty import staticproperty
|
||||
|
||||
BLHandler = typ.Callable[[], None]
|
||||
BLHandlerWithFile = typ.Callable[[str], None]
|
||||
BLHandlerWithRenderStats = typ.Callable[[typ.Any], None]
|
||||
|
||||
|
||||
class BLHandlers(pyd.BaseModel):
|
||||
"""Contains lists of handlers associated with this addon."""
|
||||
|
||||
animation_playback_post: tuple[BLHandler, ...] = ()
|
||||
animation_playback_pre: tuple[BLHandler, ...] = ()
|
||||
annotation_post: tuple[BLHandler, ...] = ()
|
||||
annotation_pre: tuple[BLHandler, ...] = ()
|
||||
composite_cancel: tuple[BLHandler, ...] = ()
|
||||
composite_post: tuple[BLHandler, ...] = ()
|
||||
composite_pre: tuple[BLHandler, ...] = ()
|
||||
depsgraph_update_post: tuple[BLHandler, ...] = ()
|
||||
depsgraph_update_pre: tuple[BLHandler, ...] = ()
|
||||
frame_change_post: tuple[BLHandler, ...] = ()
|
||||
frame_change_pre: tuple[BLHandler, ...] = ()
|
||||
load_factory_preferences_post: tuple[BLHandler, ...] = ()
|
||||
load_factory_startup_post: tuple[BLHandler, ...] = ()
|
||||
load_post: tuple[BLHandlerWithFile, ...] = ()
|
||||
load_post_fail: tuple[BLHandlerWithFile, ...] = ()
|
||||
load_pre: tuple[BLHandlerWithFile, ...] = ()
|
||||
object_bake_cancel: tuple[BLHandler, ...] = ()
|
||||
object_bake_complete: tuple[BLHandler, ...] = ()
|
||||
object_bake_pre: tuple[BLHandler, ...] = ()
|
||||
redo_post: tuple[BLHandler, ...] = ()
|
||||
redo_pre: tuple[BLHandler, ...] = ()
|
||||
render_cancel: tuple[BLHandler, ...] = ()
|
||||
render_complete: tuple[BLHandler, ...] = ()
|
||||
render_init: tuple[BLHandler, ...] = ()
|
||||
render_post: tuple[BLHandler, ...] = ()
|
||||
render_pre: tuple[BLHandler, ...] = ()
|
||||
render_stats: tuple[BLHandler, ...] = ()
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
@staticproperty # type: ignore[arg-type]
|
||||
def hander_categories() -> tuple[str, ...]: # type: ignore[misc]
|
||||
"""Returns an immutable string sequence of handler categories."""
|
||||
return (
|
||||
'animation_playback_post',
|
||||
'animation_playback_pre',
|
||||
'annotation_post',
|
||||
'annotation_pre',
|
||||
'composite_cancel',
|
||||
'composite_post',
|
||||
'composite_pre',
|
||||
'depsgraph_update_post',
|
||||
'depsgraph_update_pre',
|
||||
'frame_change_post',
|
||||
'frame_change_pre',
|
||||
'load_factory_preferences_post',
|
||||
'load_factory_startup_post',
|
||||
'load_post',
|
||||
'load_post_fail',
|
||||
'load_pre',
|
||||
'object_bake_cancel',
|
||||
'object_bake_complete',
|
||||
'object_bake_pre',
|
||||
'redo_post',
|
||||
'redo_pre',
|
||||
'render_cancel',
|
||||
'render_complete',
|
||||
'render_init',
|
||||
'render_post',
|
||||
'render_pre',
|
||||
'render_stats',
|
||||
)
|
||||
|
||||
####################
|
||||
# - Merging
|
||||
####################
|
||||
def __add__(self, other: typ.Self) -> typ.Self:
|
||||
"""Concatenate the handlers of two `BLHandlers` objects."""
|
||||
return BLHandlers(
|
||||
**{
|
||||
hndl_cat: getattr(self, hndl_cat) + getattr(self, hndl_cat)
|
||||
for hndl_cat in self.handler_categories
|
||||
}
|
||||
)
|
||||
|
||||
def register(self) -> None:
|
||||
"""Registers all handlers declared by-category."""
|
||||
for handler_category in BLHandlers.handler_categories:
|
||||
for handler in getattr(self, handler_category):
|
||||
getattr(bpy.app.handlers, handler_category).append(handler)
|
||||
|
||||
def unregister(self) -> None:
|
||||
"""Unregisters only this addon's handlers from bpy.app.handlers."""
|
||||
for handler_category in BLHandlers.handler_categories:
|
||||
for handler in getattr(self, handler_category):
|
||||
bpy_handlers = getattr(bpy.app.handlers, handler_category)
|
||||
if handler in bpy_handlers:
|
||||
bpy_handlers.remove(handler)
|
|
@ -33,9 +33,12 @@ log = logger.get(__name__)
|
|||
# - Globals
|
||||
####################
|
||||
_REGISTERED_CLASSES: list[ct.BLClass] = []
|
||||
|
||||
_ADDON_KEYMAP: bpy.types.KeyMap | None = None
|
||||
_REGISTERED_HOTKEYS: list[ct.BLKeymapItem] = []
|
||||
|
||||
_REGISTERED_HANDLERS: ct.BLHandlers | None = None
|
||||
|
||||
|
||||
####################
|
||||
# - Class Registration
|
||||
|
@ -74,6 +77,35 @@ def unregister_classes() -> None:
|
|||
_REGISTERED_CLASSES.clear()
|
||||
|
||||
|
||||
####################
|
||||
# - Handler Registration
|
||||
####################
|
||||
def register_handlers(bl_handlers: ct.BLHandlers) -> None:
|
||||
"""Register the given Blender handlers."""
|
||||
global _REGISTERED_HANDLERS # noqa: PLW0603
|
||||
|
||||
log.info('Registering BLHandlers') ## TODO: More information
|
||||
if _REGISTERED_HANDLERS is None:
|
||||
bl_handlers.register()
|
||||
_REGISTERED_HANDLERS = bl_handlers
|
||||
|
||||
msg = 'There are already BLHandlers registered; they must be unregistered before a new set can be registered.'
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
def unregister_handlers() -> None:
|
||||
"""Unregister this addon's registered Blender handlers."""
|
||||
global _REGISTERED_HANDLERS # noqa: PLW0603
|
||||
|
||||
log.info('Unregistering BLHandlers') ## TODO: More information
|
||||
if _REGISTERED_HANDLERS is not None:
|
||||
_REGISTERED_HANDLERS.register()
|
||||
_REGISTERED_HANDLERS = None
|
||||
|
||||
msg = 'There are no BLHandlers registered; therefore, there is nothing to register.'
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
####################
|
||||
# - Keymap Registration
|
||||
####################
|
||||
|
|
|
@ -193,6 +193,12 @@ ignore = [
|
|||
"E501", # Let Formatter Worry about Line Length
|
||||
]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*" = [
|
||||
"D100", # It's okay to not have module-level docstrings in test modules.
|
||||
"D104", # Same for packages.
|
||||
]
|
||||
|
||||
####################
|
||||
# - Tooling: Ruff Sublinters
|
||||
####################
|
||||
|
|
Loading…
Reference in New Issue