asset_library/gui.py

334 lines
10 KiB
Python

# 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)