# SPDX-License-Identifier: GPL-2.0-or-later """ Action Library - GUI definition. """ import bpy from pathlib import Path from bpy.types import ( AssetHandle, Context, Header, Menu, Panel, UIList, WindowManager, WorkSpace, ) from bpy_extras import asset_utils from asset_library.common.bl_utils import ( get_addon_prefs, get_object_libraries, ) from asset_library.common.functions import ( get_active_library ) def pose_library_panel_poll(): return bpy.context.object and bpy.context.object.mode == 'POSE' class PoseLibraryPanel: @classmethod def pose_library_panel_poll(cls, context: Context) -> bool: return bool( context.object and context.object.mode == 'POSE' ) @classmethod def poll(cls, context: Context) -> bool: return cls.pose_library_panel_poll(context); class AssetLibraryMenu: @classmethod def poll(cls, context): from bpy_extras.asset_utils import SpaceAssetInfo return SpaceAssetInfo.is_asset_browser_poll(context) class ASSETLIB_PT_libraries(Panel): bl_label = "Libraries" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Item' @classmethod def poll(cls, context: Context) -> bool: return context.object and get_object_libraries(context.object) def draw(self, context: Context) -> None: layout = self.layout for f in get_object_libraries(context.object): row = layout.row(align=True) row.label(text=f) row.operator("assetlib.open_blend", icon='FILE_BLEND', text='').filepath = f ''' class ASSETLIB_PT_pose_library_usage(Panel): bl_space_type = 'FILE_BROWSER' bl_region_type = "TOOLS" bl_label = "Action Library" # asset_categories = {'ANIMATIONS'} @classmethod def poll(cls, context: Context) -> bool: sp = context.space_data if not context.object or not context.object.mode == 'POSE': return False if not (sp and sp.type == 'FILE_BROWSER' and sp.browse_mode == 'ASSETS'): return False return True def draw(self, context: Context) -> None: layout = self.layout wm = context.window_manager sp = context.space_data sp.params.asset_library_ref if sp.params.asset_library_ref == 'LOCAL': col = layout.column(align=True) row = col.row(align=True) row.operator("poselib.create_pose_asset", text="Create Pose", icon='POSE_HLT').activate_new_action = False row.operator("actionlib.replace_pose", text='Replace Pose', icon='FILE_REFRESH') col.operator("actionlib.create_anim_asset", text="Create Anim", icon='ANIM') col.separator() row = col.row(align=True) row.operator("actionlib.edit_action", text='Edit Action', icon='ACTION') row.operator("actionlib.clear_action", text='Finish Edit', icon='CHECKBOX_HLT') col.separator() col.operator("actionlib.generate_preview", icon='RESTRICT_RENDER_OFF', text="Generate Thumbnail") col.operator("actionlib.update_action_data", icon='FILE_TEXT', text="Update Action Data") else: col = layout.column(align=True) row = col.row(align=True) row.operator("actionlib.store_anim_pose", text='Store Anim/Pose', icon='ACTION') ''' class ASSETLIB_PT_pose_library_editing(PoseLibraryPanel, asset_utils.AssetBrowserPanel, Panel): bl_space_type = 'FILE_BROWSER' bl_region_type = "TOOL_PROPS" bl_label = "Metadata" #bl_options = {'HIDE_HEADER'} # asset_categories = {'ANIMATIONS'} @classmethod def poll(cls, context: Context) -> bool: sp = context.space_data if not (sp and sp.type == 'FILE_BROWSER' and sp.browse_mode == 'ASSETS'): return False if not (context.active_file and context.active_file.asset_data): return False return True def draw(self, context: Context) -> None: layout = self.layout layout.use_property_split = True asset_data = context.active_file.asset_data metadata = ['camera', 'is_single_frame', 'rest_pose'] if 'camera' in asset_data.keys(): layout.prop(asset_data, f'["camera"]', text='Camera', icon='CAMERA_DATA') if 'is_single_frame' in asset_data.keys(): layout.prop(asset_data, f'["is_single_frame"]', text='Is Single Frame') if 'rest_pose' in asset_data.keys(): layout.prop(asset_data, f'["rest_pose"]', text='Rest Pose', icon='ACTION') if 'filepath' in asset_data.keys(): layout.prop(asset_data, f'["filepath"]', text='Filepath') class ASSETLIB_MT_context_menu(AssetLibraryMenu, Menu): bl_label = "Asset Library Menu" @classmethod def poll(cls, context): if not asset_utils.SpaceAssetInfo.is_asset_browser(context.space_data): cls.poll_message_set("Current editor is not an asset browser") return False prefs = get_addon_prefs() asset_lib_ref = context.space_data.params.asset_library_ref lib = get_active_library() if not lib: return False return True def draw(self, context): lib = get_active_library() lib.library_type.draw_context_menu(self.layout) def is_option_region_visible(context, space): from bpy_extras.asset_utils import SpaceAssetInfo if SpaceAssetInfo.is_asset_browser(space): pass # For the File Browser, there must be an operator for there to be options # (irrelevant for the Asset Browser). elif not space.active_operator: return False for region in context.area.regions: if region.type == 'TOOL_PROPS' and region.width <= 1: return False return True def draw_assetbrowser_header(self, context): lib = get_active_library() if not lib: bpy.types.FILEBROWSER_HT_header._draw_asset_browser_buttons(self, context) return space_data = context.space_data params = context.space_data.params row = self.layout.row(align=True) row.separator() row.operator("assetlib.bundle", icon='UV_SYNC_SELECT', text='').name = lib.name #op #op.clean = False #op.only_recent = True lib.library_type.draw_header(row) if context.selected_files and context.active_file: row.separator() row.label(text=context.active_file.name) row.separator_spacer() sub = row.row() sub.ui_units_x = 10 sub.prop(params, "filter_search", text="", icon='VIEWZOOM') row.separator_spacer() row.prop_with_popover( params, "display_type", panel="ASSETBROWSER_PT_display", text="", icon_only=True, ) row.operator( "screen.region_toggle", text="", icon='PREFERENCES', depress=is_option_region_visible(context, space_data) ).region_type = 'TOOL_PROPS' ### Messagebus subscription to monitor asset library changes. _msgbus_owner = object() def _on_asset_library_changed() -> None: """Update areas when a different asset library is selected.""" refresh_area_types = {'DOPESHEET_EDITOR', 'VIEW_3D'} for win in bpy.context.window_manager.windows: for area in win.screen.areas: if area.type not in refresh_area_types: continue area.tag_redraw() def register_message_bus() -> None: bpy.msgbus.subscribe_rna( key=(bpy.types.FileAssetSelectParams, "asset_library_ref"), owner=_msgbus_owner, args=(), notify=_on_asset_library_changed, options={'PERSISTENT'}, ) def unregister_message_bus() -> None: bpy.msgbus.clear_by_owner(_msgbus_owner) @bpy.app.handlers.persistent def _on_blendfile_load_pre(none, other_none) -> None: # The parameters are required, but both are None. unregister_message_bus() @bpy.app.handlers.persistent def _on_blendfile_load_post(none, other_none) -> None: # The parameters are required, but both are None. register_message_bus() classes = ( ASSETLIB_PT_pose_library_editing, #ASSETLIB_PT_pose_library_usage, ASSETLIB_MT_context_menu, ASSETLIB_PT_libraries ) def register() -> None: for cls in classes: bpy.utils.register_class(cls) bpy.types.FILEBROWSER_HT_header._draw_asset_browser_buttons = bpy.types.FILEBROWSER_HT_header.draw_asset_browser_buttons bpy.types.FILEBROWSER_HT_header.draw_asset_browser_buttons = draw_assetbrowser_header #WorkSpace.active_pose_asset_index = bpy.props.IntProperty( # name="Active Pose Asset", # # TODO explain which list the index belongs to, or how it can be used to get the pose. # description="Per workspace index of the active pose asset" #) # Register for window-manager. This is a global property that shouldn't be # written to files. #WindowManager.pose_assets = bpy.props.CollectionProperty(type=AssetHandle) # bpy.types.UI_MT_list_item_context_menu.prepend(pose_library_list_item_context_menu) # bpy.types.ASSETLIB_MT_context_menu.prepend(pose_library_list_item_context_menu) # bpy.types.ACTIONLIB_MT_context_menu.prepend(pose_library_list_item_context_menu) #bpy.types.ASSETBROWSER_MT_editor_menus.append(draw_assetbrowser_header) register_message_bus() bpy.app.handlers.load_pre.append(_on_blendfile_load_pre) bpy.app.handlers.load_post.append(_on_blendfile_load_post) def unregister() -> None: for cls in reversed(classes): bpy.utils.unregister_class(cls) bpy.types.FILEBROWSER_HT_header.draw_asset_browser_buttons = bpy.types.FILEBROWSER_HT_header._draw_asset_browser_buttons del bpy.types.FILEBROWSER_HT_header._draw_asset_browser_buttons unregister_message_bus() #del WorkSpace.active_pose_asset_index #del WindowManager.pose_assets # bpy.types.UI_MT_list_item_context_menu.remove(pose_library_list_item_context_menu) # bpy.types.ASSETLIB_MT_context_menu.remove(pose_library_list_item_context_menu) # bpy.types.ACTIONLIB_MT_context_menu.remove(pose_library_list_item_context_menu) #bpy.types.ASSETBROWSER_MT_editor_menus.remove(draw_assetbrowser_header)