Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/bpy_extras/__init__.py1
-rw-r--r--release/scripts/modules/bpy_extras/asset_utils.py63
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/assets.py74
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py196
5 files changed, 313 insertions, 22 deletions
diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py
index 1caef074d43..cb990b014a1 100644
--- a/release/scripts/modules/bpy_extras/__init__.py
+++ b/release/scripts/modules/bpy_extras/__init__.py
@@ -24,6 +24,7 @@ Utility modules associated with the bpy module.
__all__ = (
"anim_utils",
+ "asset_utils",
"object_utils",
"io_utils",
"image_utils",
diff --git a/release/scripts/modules/bpy_extras/asset_utils.py b/release/scripts/modules/bpy_extras/asset_utils.py
new file mode 100644
index 00000000000..db982e119d4
--- /dev/null
+++ b/release/scripts/modules/bpy_extras/asset_utils.py
@@ -0,0 +1,63 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+Helpers for asset management tasks.
+"""
+
+import bpy
+from bpy.types import (
+ Context,
+)
+
+__all__ = (
+ "SpaceAssetInfo",
+)
+
+class SpaceAssetInfo:
+ @classmethod
+ def is_asset_browser(cls, space_data: bpy.types.Space):
+ return space_data.type == 'FILE_BROWSER' and space_data.browse_mode == 'ASSETS'
+
+ @classmethod
+ def is_asset_browser_poll(cls, context: Context):
+ return cls.is_asset_browser(context.space_data)
+
+ @classmethod
+ def get_active_asset(cls, context: Context):
+ if hasattr(context, "active_file"):
+ active_file = context.active_file
+ return active_file.asset_data if active_file else None
+
+class AssetBrowserPanel:
+ bl_space_type = 'FILE_BROWSER'
+
+ @classmethod
+ def poll(cls, context):
+ return SpaceAssetInfo.is_asset_browser_poll(context)
+
+class AssetMetaDataPanel:
+ bl_space_type = 'FILE_BROWSER'
+ bl_region_type = 'TOOL_PROPS'
+
+ @classmethod
+ def poll(cls, context):
+ active_file = context.active_file
+ return SpaceAssetInfo.is_asset_browser_poll(context) and active_file and active_file.asset_data
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 71b2de41d9e..e91d3b3ce60 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -27,6 +27,7 @@ if "bpy" in locals():
_modules = [
"add_mesh_torus",
"anim",
+ "assets",
"clip",
"console",
"constraint",
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
new file mode 100644
index 00000000000..c317df78aa5
--- /dev/null
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -0,0 +1,74 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+from bpy_extras.asset_utils import (
+ SpaceAssetInfo,
+)
+
+class ASSET_OT_tag_add(bpy.types.Operator):
+ """Add a new keyword tag to the active asset"""
+
+ bl_idname = "asset.tag_add"
+ bl_label = "Add Asset Tag"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return SpaceAssetInfo.is_asset_browser_poll(context) and SpaceAssetInfo.get_active_asset(context)
+
+ def execute(self, context):
+ active_asset = SpaceAssetInfo.get_active_asset(context)
+ active_asset.tags.new("Unnamed Tag")
+
+ return {'FINISHED'}
+
+
+class ASSET_OT_tag_remove(bpy.types.Operator):
+ """Remove an existing keyword tag from the active asset"""
+
+ bl_idname = "asset.tag_remove"
+ bl_label = "Remove Asset Tag"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ if not SpaceAssetInfo.is_asset_browser_poll(context):
+ return False
+
+ active_asset = SpaceAssetInfo.get_active_asset(context)
+ if not active_asset:
+ return False
+
+ return active_asset.active_tag in range(len(active_asset.tags))
+
+ def execute(self, context):
+ active_asset = SpaceAssetInfo.get_active_asset(context)
+ tag = active_asset.tags[active_asset.active_tag]
+
+ active_asset.tags.remove(tag)
+ active_asset.active_tag -= 1
+
+ return {'FINISHED'}
+
+
+classes = (
+ ASSET_OT_tag_add,
+ ASSET_OT_tag_remove,
+)
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index a9bb2e79762..527a5bc623e 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -17,27 +17,79 @@
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
+
+import bpy
+
from bpy.types import Header, Panel, Menu, UIList
+from bpy_extras import (
+ asset_utils,
+)
+
class FILEBROWSER_HT_header(Header):
bl_space_type = 'FILE_BROWSER'
+ def draw_asset_browser_buttons(self, context):
+ layout = self.layout
+
+ space_data = context.space_data
+ params = space_data.params
+
+ row = layout.row(align=True)
+ row.prop(params, "asset_library", text="")
+ # External libraries don't auto-refresh, add refresh button.
+ if params.asset_library != 'LOCAL':
+ row.operator("file.refresh", text="", icon="FILE_REFRESH")
+
+ layout.separator_spacer()
+
+ # Uses prop_with_popover() as popover() only adds the triangle icon in headers.
+ layout.prop_with_popover(
+ params,
+ "display_type",
+ panel="FILEBROWSER_PT_display",
+ text="",
+ icon_only=True,
+ )
+ layout.prop_with_popover(
+ params,
+ "display_type",
+ panel="FILEBROWSER_PT_filter",
+ text="",
+ icon='FILTER',
+ icon_only=True,
+ )
+
+ layout.prop(params, "filter_search", text="", icon='VIEWZOOM')
+
+ layout.operator(
+ "screen.region_toggle",
+ text="",
+ icon='PREFERENCES',
+ depress=is_option_region_visible(context, space_data)
+ ).region_type = 'TOOL_PROPS'
+
def draw(self, context):
+ from bpy_extras.asset_utils import SpaceAssetInfo
+
layout = self.layout
- st = context.space_data
+ space_data = context.space_data
- if st.active_operator is None:
+ if space_data.active_operator is None:
layout.template_header()
FILEBROWSER_MT_editor_menus.draw_collapsible(context, layout)
- # can be None when save/reload with a file selector open
-
- layout.separator_spacer()
+ if SpaceAssetInfo.is_asset_browser(space_data):
+ layout.separator()
+ self.draw_asset_browser_buttons(context)
+ else:
+ layout.separator_spacer()
- layout.template_running_jobs()
+ if not context.screen.show_statusbar:
+ layout.template_running_jobs()
class FILEBROWSER_PT_display(Panel):
@@ -144,6 +196,9 @@ class FILEBROWSER_PT_filter(Panel):
row.label(icon='BLANK1') # Indentation
sub = row.column(align=True)
+
+ sub.prop(params, "use_filter_asset_only")
+
filter_id = params.filter_id
for identifier in dir(filter_id):
if identifier.startswith("category_"):
@@ -160,6 +215,11 @@ def panel_poll_is_upper_region(region):
return region.alignment in {'LEFT', 'RIGHT'}
+def panel_poll_is_asset_browsing(context):
+ from bpy_extras.asset_utils import SpaceAssetInfo
+ return SpaceAssetInfo.is_asset_browser_poll(context)
+
+
class FILEBROWSER_UL_dir(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
direntry = item
@@ -187,7 +247,7 @@ class FILEBROWSER_PT_bookmarks_volumes(Panel):
@classmethod
def poll(cls, context):
- return panel_poll_is_upper_region(context.region)
+ return panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
def draw(self, context):
layout = self.layout
@@ -207,7 +267,7 @@ class FILEBROWSER_PT_bookmarks_system(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region)
+ return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
def draw(self, context):
layout = self.layout
@@ -241,7 +301,7 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel):
@classmethod
def poll(cls, context):
- return panel_poll_is_upper_region(context.region)
+ return panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
def draw(self, context):
layout = self.layout
@@ -278,7 +338,7 @@ class FILEBROWSER_PT_bookmarks_recents(Panel):
@classmethod
def poll(cls, context):
- return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region)
+ return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
def draw(self, context):
layout = self.layout
@@ -302,7 +362,7 @@ class FILEBROWSER_PT_advanced_filter(Panel):
@classmethod
def poll(cls, context):
# only useful in append/link (library) context currently...
- return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region)
+ return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context)
def draw(self, context):
layout = self.layout
@@ -314,12 +374,26 @@ class FILEBROWSER_PT_advanced_filter(Panel):
if params.use_filter_blendid:
layout.separator()
col = layout.column(align=True)
+
+ col.prop(params, "use_filter_asset_only")
+
filter_id = params.filter_id
for identifier in dir(filter_id):
if identifier.startswith("filter_"):
col.prop(filter_id, identifier, toggle=True)
+def is_option_region_visible(context, space):
+ if 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
+
+
class FILEBROWSER_PT_directory_path(Panel):
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'UI'
@@ -334,16 +408,6 @@ class FILEBROWSER_PT_directory_path(Panel):
return True
- def is_option_region_visible(self, context, space):
- if 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(self, context):
layout = self.layout
space = context.space_data
@@ -388,7 +452,7 @@ class FILEBROWSER_PT_directory_path(Panel):
"screen.region_toggle",
text="",
icon='PREFERENCES',
- depress=self.is_option_region_visible(context, space)
+ depress=is_option_region_visible(context, space)
).region_type = 'TOOL_PROPS'
@@ -482,6 +546,89 @@ class FILEBROWSER_MT_context_menu(Menu):
layout.prop_menu_enum(params, "sort_method")
+class ASSETBROWSER_PT_navigation_bar(asset_utils.AssetBrowserPanel, Panel):
+ bl_label = "Asset Navigation"
+ bl_region_type = 'TOOLS'
+ bl_options = {'HIDE_HEADER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ space_file = context.space_data
+
+ col = layout.column()
+
+ col.scale_x = 1.3
+ col.scale_y = 1.3
+ col.prop(space_file.params, "asset_category", expand=True)
+
+
+class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
+ bl_region_type = 'TOOL_PROPS'
+ bl_label = "Asset Metadata"
+ bl_options = {'HIDE_HEADER'}
+
+ def draw(self, context):
+ layout = self.layout
+ active_file = context.active_file
+ active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context)
+
+ layout.use_property_split = True
+
+ if not active_file or not active_asset:
+ layout.label(text="No asset selected.")
+ return
+
+ box = layout.box()
+ box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0)
+ if bpy.ops.ed.lib_id_load_custom_preview.poll():
+ box.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="Load Custom")
+ layout.prop(active_file, "name")
+
+
+class ASSETBROWSER_PT_metadata_details(asset_utils.AssetBrowserPanel, Panel):
+ bl_region_type = 'TOOL_PROPS'
+ bl_label = "Details"
+ bl_parent_id = "ASSETBROWSER_PT_metadata"
+
+ def draw(self, context):
+ layout = self.layout
+ active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context)
+
+ layout.use_property_split = True
+
+ if active_asset:
+ layout.prop(active_asset, "description")
+
+
+class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
+ bl_label = "Tags"
+
+ def draw(self, context):
+ layout = self.layout
+ asset_data = asset_utils.SpaceAssetInfo.get_active_asset(context)
+
+ row = layout.row()
+ row.template_list("ASSETBROWSER_UL_metadata_tags", "asset_tags", asset_data, "tags",
+ asset_data, "active_tag", rows=4)
+
+ col = row.column(align=True)
+ col.operator("asset.tag_add", icon='ADD', text="")
+ col.operator("asset.tag_remove", icon='REMOVE', text="")
+
+
+class ASSETBROWSER_UL_metadata_tags(UIList):
+ def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
+ tag = item
+
+ row = layout.row(align=True)
+ # Non-editable entries would show grayed-out, which is bad in this specific case, so switch to mere label.
+ if tag.is_property_readonly("name"):
+ row.label(text=tag.name, icon_value=icon)
+ else:
+ row.prop(tag, "name", text="", emboss=False, icon_value=icon)
+
+
classes = (
FILEBROWSER_HT_header,
FILEBROWSER_PT_display,
@@ -498,6 +645,11 @@ classes = (
FILEBROWSER_MT_view,
FILEBROWSER_MT_select,
FILEBROWSER_MT_context_menu,
+ ASSETBROWSER_PT_navigation_bar,
+ ASSETBROWSER_PT_metadata,
+ ASSETBROWSER_PT_metadata_details,
+ ASSETBROWSER_PT_metadata_tags,
+ ASSETBROWSER_UL_metadata_tags,
)
if __name__ == "__main__": # only for live edit.