Sun Position: fix error in HDRI mode when no env tex is selected
[blender-addons.git] / pose_library / gui.py
bloba7be26adbe667c9b6ea0f618181499780b211142
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 """
4 Pose Library - GUI definition.
5 """
7 import bpy
8 from bpy.types import (
9 AssetHandle,
10 Context,
11 Menu,
12 Panel,
13 UIList,
14 WindowManager,
15 WorkSpace,
19 class PoseLibraryPanel:
20 @classmethod
21 def pose_library_panel_poll(cls, context: Context) -> bool:
22 return bool(context.object and context.object.mode == 'POSE')
24 @classmethod
25 def poll(cls, context: Context) -> bool:
26 return cls.pose_library_panel_poll(context)
29 class VIEW3D_PT_pose_library(PoseLibraryPanel, Panel):
30 bl_space_type = "VIEW_3D"
31 bl_region_type = "UI"
32 bl_category = "Animation"
33 bl_label = "Pose Library"
35 def draw(self, context: Context) -> None:
36 layout = self.layout
38 if hasattr(layout, "template_asset_view"):
39 workspace = context.workspace
40 wm = context.window_manager
41 activate_op_props, drag_op_props = layout.template_asset_view(
42 "pose_assets",
43 workspace,
44 "asset_library_ref",
45 wm,
46 "pose_assets",
47 workspace,
48 "active_pose_asset_index",
49 filter_id_types={"filter_action"},
50 activate_operator="poselib.apply_pose_asset",
51 drag_operator="poselib.blend_pose_asset",
54 # Make sure operators properties match those used in
55 # `pose_library_list_item_context_menu` so shortcuts show in menus (see T103267).
56 activate_op_props.flipped = False
59 def pose_library_list_item_context_menu(self: UIList, context: Context) -> None:
60 def is_pose_asset_view() -> bool:
61 # Important: Must check context first, or the menu is added for every kind of list.
62 list = getattr(context, "ui_list", None)
63 if not list or list.bl_idname != "UI_UL_asset_view" or list.list_id != "pose_assets":
64 return False
65 if not context.active_file:
66 return False
67 return True
69 def is_pose_library_asset_browser() -> bool:
70 asset_library_ref = getattr(context, "asset_library_ref", None)
71 if not asset_library_ref:
72 return False
73 asset = getattr(context, "asset_file_handle", None)
74 if not asset:
75 return False
76 return bool(asset.id_type == 'ACTION')
78 if not is_pose_asset_view() and not is_pose_library_asset_browser():
79 return
81 layout = self.layout
83 layout.separator()
85 # Make sure these operator properties match those used in `VIEW3D_PT_pose_library`.
86 layout.operator("poselib.apply_pose_asset", text="Apply Pose").flipped = False
87 layout.operator("poselib.apply_pose_asset", text="Apply Pose Flipped").flipped = True
89 old_op_ctx = layout.operator_context
90 layout.operator_context = 'INVOKE_DEFAULT'
91 props = layout.operator("poselib.blend_pose_asset", text="Blend Pose")
92 layout.operator_context = old_op_ctx
94 layout.separator()
95 props = layout.operator("poselib.pose_asset_select_bones", text="Select Pose Bones")
96 props.select = True
97 props = layout.operator("poselib.pose_asset_select_bones", text="Deselect Pose Bones")
98 props.select = False
100 if not is_pose_asset_view():
101 layout.separator()
102 layout.operator("asset.assign_action")
104 layout.separator()
105 if is_pose_asset_view():
106 layout.operator("asset.open_containing_blend_file")
108 props.select = False
111 class DOPESHEET_PT_asset_panel(PoseLibraryPanel, Panel):
112 bl_space_type = "DOPESHEET_EDITOR"
113 bl_region_type = "UI"
114 bl_label = "Create Pose Asset"
115 bl_category = "Action"
117 def draw(self, context: Context) -> None:
118 layout = self.layout
119 col = layout.column(align=True)
120 row = col.row(align=True)
121 row.operator("poselib.create_pose_asset").activate_new_action = True
122 if bpy.types.POSELIB_OT_restore_previous_action.poll(context):
123 row.operator("poselib.restore_previous_action", text="", icon='LOOP_BACK')
124 col.operator("poselib.copy_as_asset", icon="COPYDOWN")
126 layout.operator("poselib.convert_old_poselib")
129 def pose_library_list_item_asset_menu(self: UIList, context: Context) -> None:
130 layout = self.layout
131 layout.menu("ASSETBROWSER_MT_asset")
134 class ASSETBROWSER_MT_asset(Menu):
135 bl_label = "Asset"
137 @classmethod
138 def poll(cls, context):
139 from bpy_extras.asset_utils import SpaceAssetInfo
141 return SpaceAssetInfo.is_asset_browser_poll(context)
143 def draw(self, context: Context) -> None:
144 layout = self.layout
146 layout.operator("poselib.paste_asset", icon='PASTEDOWN')
147 layout.separator()
148 layout.operator("poselib.create_pose_asset").activate_new_action = False
151 ### Messagebus subscription to monitor asset library changes.
152 _msgbus_owner = object()
155 def _on_asset_library_changed() -> None:
156 """Update areas when a different asset library is selected."""
157 refresh_area_types = {'DOPESHEET_EDITOR', 'VIEW_3D'}
158 for win in bpy.context.window_manager.windows:
159 for area in win.screen.areas:
160 if area.type not in refresh_area_types:
161 continue
163 area.tag_redraw()
166 def register_message_bus() -> None:
167 bpy.msgbus.subscribe_rna(
168 key=(bpy.types.FileAssetSelectParams, "asset_library_ref"),
169 owner=_msgbus_owner,
170 args=(),
171 notify=_on_asset_library_changed,
172 options={'PERSISTENT'},
176 def unregister_message_bus() -> None:
177 bpy.msgbus.clear_by_owner(_msgbus_owner)
180 @bpy.app.handlers.persistent
181 def _on_blendfile_load_pre(none, other_none) -> None:
182 # The parameters are required, but both are None.
183 unregister_message_bus()
186 @bpy.app.handlers.persistent
187 def _on_blendfile_load_post(none, other_none) -> None:
188 # The parameters are required, but both are None.
189 register_message_bus()
192 classes = (
193 DOPESHEET_PT_asset_panel,
194 VIEW3D_PT_pose_library,
195 ASSETBROWSER_MT_asset,
198 _register, _unregister = bpy.utils.register_classes_factory(classes)
201 def register() -> None:
202 _register()
204 WorkSpace.active_pose_asset_index = bpy.props.IntProperty(
205 name="Active Pose Asset",
206 # TODO explain which list the index belongs to, or how it can be used to get the pose.
207 description="Per workspace index of the active pose asset",
209 # Register for window-manager. This is a global property that shouldn't be
210 # written to files.
211 WindowManager.pose_assets = bpy.props.CollectionProperty(type=AssetHandle)
213 bpy.types.UI_MT_list_item_context_menu.prepend(pose_library_list_item_context_menu)
214 bpy.types.ASSETBROWSER_MT_context_menu.prepend(pose_library_list_item_context_menu)
215 bpy.types.ASSETBROWSER_MT_editor_menus.append(pose_library_list_item_asset_menu)
217 register_message_bus()
218 bpy.app.handlers.load_pre.append(_on_blendfile_load_pre)
219 bpy.app.handlers.load_post.append(_on_blendfile_load_post)
222 def unregister() -> None:
223 _unregister()
225 unregister_message_bus()
227 del WorkSpace.active_pose_asset_index
228 del WindowManager.pose_assets
230 bpy.types.UI_MT_list_item_context_menu.remove(pose_library_list_item_context_menu)
231 bpy.types.ASSETBROWSER_MT_context_menu.remove(pose_library_list_item_context_menu)