diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c
index a3eacf8fe4d..f650df09f0c 100644
--- a/release/datafiles/userdef/userdef_default_theme.c
+++ b/release/datafiles/userdef/userdef_default_theme.c
@@ -1085,6 +1085,35 @@ const bTheme U_theme_default = {
.edited_object = RGBA(0x00806266),
.row_alternate = RGBA(0xffffff04),
},
+ .space_assets = {
+ .back = RGBA(0x28282800),
+ .title = RGBA(0xffffffff),
+ .text = RGBA(0xe6e6e6ff),
+ .text_hi = RGBA(0xffffffff),
+ .header = RGBA(0x303030b3),
+ .header_text = RGBA(0xeeeeeeff),
+ .header_text_hi = RGBA(0xffffffff),
+ .tab_active = RGBA(0x303030ff),
+ .tab_inactive = RGBA(0x1d1d1dff),
+ .tab_back = RGBA(0x181818ff),
+ .tab_outline = RGBA(0x3d3d3dff),
+ .button = RGBA(0x30303000),
+ .button_title = RGBA(0xffffffff),
+ .button_text = RGBA(0xccccccff),
+ .button_text_hi = RGBA(0xffffffff),
+ .navigation_bar = RGBA(0x303030ff),
+ .execution_buts = RGBA(0x303030ff),
+ .panelcolors = {
+ .header = RGBA(0x3d3d3dff),
+ .back = RGBA(0x3d3d3dff),
+ .sub_back = RGBA(0x0000001f),
+ },
+ .hilite = RGBA(0x4772b3ff),
+ .vertex_size = 3,
+ .outline_width = 1,
+ .facedot_size = 4,
+ .row_alternate = RGBA(0xffffff04),
+ },
.tarm = {
{
.solid = RGBA(0x9a0000ff),
diff --git a/scripts/presets/interface_theme/Blender_Light.xml b/scripts/presets/interface_theme/Blender_Light.xml
index 68245c53525..b45f85d2ef3 100644
--- a/scripts/presets/interface_theme/Blender_Light.xml
+++ b/scripts/presets/interface_theme/Blender_Light.xml
@@ -1388,6 +1388,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+import bpy
+from bpy.types import Header, Menu, Panel, UIList
+
+
+class ASSETBROWSER_HT_header(Header):
+ bl_space_type = 'ASSET_BROWSER'
+
+ def draw(self, context):
+ layout = self.layout
+ space = context.space_data
+
+ layout.template_header()
+
+ ASSETBROWSER_MT_editor_menus.draw_collapsible(context, layout)
+
+ layout.separator_spacer()
+
+ layout.operator(
+ "screen.region_toggle",
+ text="",
+ icon='PREFERENCES',
+ depress=is_option_region_visible(context, space)
+ ).region_type = 'UI'
+
+
+def is_option_region_visible(context, space):
+ for region in context.area.regions:
+ if region.type == 'UI' and region.width <= 1:
+ return False
+
+ return True
+
+
+class ASSETBROWSER_MT_editor_menus(Menu):
+ bl_idname = "ASSETBROWSER_MT_editor_menus"
+ bl_label = ""
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.menu("ASSETBROWSER_MT_view")
+ layout.menu("ASSETBROWSER_MT_select")
+ layout.menu("ASSETBROWSER_MT_edit")
+
+
+class ASSETBROWSER_MT_view(Menu):
+ bl_label = "View"
+
+ def draw(self, context):
+ layout = self.layout
+ st = context.space_data
+
+ layout.prop(st, "show_region_nav_bar", text="Navigation")
+
+ layout.separator()
+
+ layout.menu("INFO_MT_area")
+
+
+class ASSETBROWSER_MT_select(Menu):
+ bl_label = "Select"
+
+ def draw(self, _context):
+ layout = self.layout
+
+
+class ASSETBROWSER_MT_edit(Menu):
+ bl_label = "Edit"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("asset.catalog_undo", text="Undo")
+ layout.operator("asset.catalog_redo", text="Redo")
+
+
+class ASSETBROWSER_PT_metadata(Panel):
+ bl_space_type = 'ASSET_BROWSER'
+ bl_region_type = 'UI'
+ bl_label = "Asset Metadata"
+ bl_options = {'HIDE_HEADER'}
+ bl_category = 'Metadata'
+
+ def draw(self, context):
+ layout = self.layout
+ wm = context.window_manager
+ asset_handle = context.asset_handle
+ asset_file = asset_handle.file_data
+
+ if asset_handle is None:
+ layout.label(text="No active asset", icon='INFO')
+ return
+
+ asset_library_ref = context.asset_library_ref
+ asset_lib_path = bpy.types.AssetHandle.get_full_library_path(asset_file, asset_library_ref)
+
+ prefs = context.preferences
+ show_asset_debug_info = prefs.view.show_developer_ui and prefs.experimental.show_asset_debug_info
+
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ if asset_handle.local_id:
+ # If the active file is an ID, use its name directly so renaming is possible from right here.
+ layout.prop(asset_handle.local_id, "name")
+
+ if show_asset_debug_info:
+ col = layout.column(align=True)
+ col.label(text="Asset Catalog:")
+ col.prop(asset_handle.local_id.asset_data, "catalog_id", text="UUID")
+ col.prop(asset_handle.local_id.asset_data, "catalog_simple_name", text="Simple Name")
+ else:
+ layout.prop(asset_file, "name")
+
+ if show_asset_debug_info:
+ col = layout.column(align=True)
+ col.enabled = False
+ col.label(text="Asset Catalog:")
+ col.prop(asset_file.asset_data, "catalog_id", text="UUID")
+ col.prop(asset_file.asset_data, "catalog_simple_name", text="Simple Name")
+
+ row = layout.row(align=True)
+ row.prop(wm, "asset_path_dummy", text="Source")
+ row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS')
+
+ layout.prop(asset_file.asset_data, "description")
+ layout.prop(asset_file.asset_data, "author")
+
+
+class ASSETBROWSER_PT_metadata_preview(Panel):
+ bl_space_type = 'ASSET_BROWSER'
+ bl_region_type = 'UI'
+ bl_label = "Preview"
+ bl_category = 'Metadata'
+
+ def draw(self, context):
+ layout = self.layout
+ asset_handle = context.asset_handle
+ asset_file = asset_handle.file_data
+
+ row = layout.row()
+ box = row.box()
+ box.template_icon(icon_value=asset_file.preview_icon_id, scale=5.0)
+
+ col = row.column(align=True)
+ col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="")
+ col.separator()
+ col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="")
+ col.menu("ASSETBROWSER_MT_metadata_preview_menu", icon='DOWNARROW_HLT', text="")
+
+
+class ASSETBROWSER_MT_metadata_preview_menu(Menu):
+ bl_label = "Preview"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("ed.lib_id_generate_preview_from_object", text="Render Active Object")
+
+
+class ASSETBROWSER_PT_metadata_tags(Panel):
+ bl_space_type = 'ASSET_BROWSER'
+ bl_region_type = 'UI'
+ bl_label = "Tags"
+ bl_category = 'Metadata'
+
+ def draw(self, context):
+ layout = self.layout
+ asset = context.asset_handle
+ asset_data = asset.file_data.asset_data
+
+ row = layout.row()
+ row.template_list("ASSETBROWSEROLD_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 = (
+ ASSETBROWSER_HT_header,
+ ASSETBROWSER_MT_editor_menus,
+ ASSETBROWSER_MT_view,
+ ASSETBROWSER_MT_select,
+ ASSETBROWSER_MT_edit,
+ ASSETBROWSER_PT_metadata,
+ ASSETBROWSER_PT_metadata_preview,
+ ASSETBROWSER_MT_metadata_preview_menu,
+ ASSETBROWSER_PT_metadata_tags,
+ ASSETBROWSER_UL_metadata_tags,
+)
+
+if __name__ == "__main__": # only for live edit.
+ from bpy.utils import register_class
+ for cls in classes:
+ register_class(cls)
diff --git a/scripts/startup/bl_ui/space_filebrowser.py b/scripts/startup/bl_ui/space_filebrowser.py
index 1a8063da420..1592f197382 100644
--- a/scripts/startup/bl_ui/space_filebrowser.py
+++ b/scripts/startup/bl_ui/space_filebrowser.py
@@ -64,7 +64,7 @@ class FILEBROWSER_HT_header(Header):
layout.template_header()
if SpaceAssetInfo.is_asset_browser(space_data):
- ASSETBROWSER_MT_editor_menus.draw_collapsible(context, layout)
+ ASSETBROWSEROLD_MT_editor_menus.draw_collapsible(context, layout)
layout.separator()
self.draw_asset_browser_buttons(context)
else:
@@ -638,19 +638,19 @@ class AssetBrowserMenu:
return SpaceAssetInfo.is_asset_browser_poll(context)
-class ASSETBROWSER_MT_editor_menus(AssetBrowserMenu, Menu):
- bl_idname = "ASSETBROWSER_MT_editor_menus"
+class ASSETBROWSEROLD_MT_editor_menus(AssetBrowserMenu, Menu):
+ bl_idname = "ASSETBROWSEROLD_MT_editor_menus"
bl_label = ""
def draw(self, _context):
layout = self.layout
- layout.menu("ASSETBROWSER_MT_view")
- layout.menu("ASSETBROWSER_MT_select")
+ layout.menu("ASSETBROWSEROLD_MT_view")
+ layout.menu("ASSETBROWSEROLD_MT_select")
layout.menu("ASSETBROWSER_MT_catalog")
-class ASSETBROWSER_MT_view(AssetBrowserMenu, Menu):
+class ASSETBROWSEROLD_MT_view(AssetBrowserMenu, Menu):
bl_label = "View"
def draw(self, context):
@@ -671,7 +671,7 @@ class ASSETBROWSER_MT_view(AssetBrowserMenu, Menu):
layout.menu("INFO_MT_area")
-class ASSETBROWSER_MT_select(AssetBrowserMenu, Menu):
+class ASSETBROWSEROLD_MT_select(AssetBrowserMenu, Menu):
bl_label = "Select"
def draw(self, _context):
@@ -700,7 +700,7 @@ class ASSETBROWSER_MT_catalog(AssetBrowserMenu, Menu):
layout.operator("asset.catalog_new").parent_path = ""
-class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
+class ASSETBROWSEROLD_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
bl_region_type = 'TOOL_PROPS'
bl_label = "Asset Metadata"
bl_options = {'HIDE_HEADER'}
@@ -750,7 +750,7 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel):
layout.prop(asset_file_handle.asset_data, "author")
-class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
+class ASSETBROWSEROLD_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
bl_label = "Preview"
def draw(self, context):
@@ -765,10 +765,10 @@ class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="")
col.separator()
col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="")
- col.menu("ASSETBROWSER_MT_metadata_preview_menu", icon='DOWNARROW_HLT', text="")
+ col.menu("ASSETBROWSEROLD_MT_metadata_preview_menu", icon='DOWNARROW_HLT', text="")
-class ASSETBROWSER_MT_metadata_preview_menu(bpy.types.Menu):
+class ASSETBROWSEROLD_MT_metadata_preview_menu(bpy.types.Menu):
bl_label = "Preview"
def draw(self, _context):
@@ -776,7 +776,7 @@ class ASSETBROWSER_MT_metadata_preview_menu(bpy.types.Menu):
layout.operator("ed.lib_id_generate_preview_from_object", text="Render Active Object")
-class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
+class ASSETBROWSEROLD_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
bl_label = "Tags"
def draw(self, context):
@@ -784,7 +784,7 @@ class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
asset_data = asset_utils.SpaceAssetInfo.get_active_asset(context)
row = layout.row()
- row.template_list("ASSETBROWSER_UL_metadata_tags", "asset_tags", asset_data, "tags",
+ row.template_list("ASSETBROWSEROLD_UL_metadata_tags", "asset_tags", asset_data, "tags",
asset_data, "active_tag", rows=4)
col = row.column(align=True)
@@ -792,7 +792,7 @@ class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
col.operator("asset.tag_remove", icon='REMOVE', text="")
-class ASSETBROWSER_UL_metadata_tags(UIList):
+class ASSETBROWSEROLD_UL_metadata_tags(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
tag = item
@@ -850,15 +850,15 @@ classes = (
FILEBROWSER_MT_view_pie,
ASSETBROWSER_PT_display,
ASSETBROWSER_PT_filter,
- ASSETBROWSER_MT_editor_menus,
- ASSETBROWSER_MT_view,
- ASSETBROWSER_MT_select,
+ ASSETBROWSEROLD_MT_editor_menus,
+ ASSETBROWSEROLD_MT_view,
+ ASSETBROWSEROLD_MT_select,
ASSETBROWSER_MT_catalog,
- ASSETBROWSER_MT_metadata_preview_menu,
- ASSETBROWSER_PT_metadata,
- ASSETBROWSER_PT_metadata_preview,
- ASSETBROWSER_PT_metadata_tags,
- ASSETBROWSER_UL_metadata_tags,
+ ASSETBROWSEROLD_MT_metadata_preview_menu,
+ ASSETBROWSEROLD_PT_metadata,
+ ASSETBROWSEROLD_PT_metadata_preview,
+ ASSETBROWSEROLD_PT_metadata_tags,
+ ASSETBROWSEROLD_UL_metadata_tags,
ASSETBROWSER_MT_context_menu,
)
diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py
index 8d1fa237754..64aa3a86fde 100644
--- a/scripts/startup/bl_ui/space_userpref.py
+++ b/scripts/startup/bl_ui/space_userpref.py
@@ -1228,8 +1228,7 @@ class ThemeGenericClassGenerator:
("Scroll Bar", "wcol_scroll"),
("Progress Bar", "wcol_progress"),
("List Item", "wcol_list_item"),
- # Not used yet, so hide this from the UI.
- # ("Data-View Item", "wcol_view_item"),
+ ("Data-View Item", "wcol_view_item"),
("Tab", "wcol_tab"),
]
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 0b58adf7ca7..c00a296e379 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -205,6 +205,7 @@ struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C);
struct SpaceClip *CTX_wm_space_clip(const bContext *C);
struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C);
struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C);
+struct SpaceAssets *CTX_wm_space_assets(const bContext *C);
void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm);
void CTX_wm_window_set(bContext *C, struct wmWindow *win);
@@ -380,6 +381,7 @@ bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);
const struct AssetLibraryReference *CTX_wm_asset_library_ref(const bContext *C);
struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid);
+struct AssetHandle *CTX_wm_asset_handle_ptr(const bContext *C);
struct AssetRepresentation *CTX_wm_asset(const bContext *C);
diff --git a/source/blender/blenkernel/intern/context.cc b/source/blender/blenkernel/intern/context.cc
index 36eec388622..16a3114b8c3 100644
--- a/source/blender/blenkernel/intern/context.cc
+++ b/source/blender/blenkernel/intern/context.cc
@@ -929,6 +929,15 @@ SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C)
return nullptr;
}
+struct SpaceAssets *CTX_wm_space_assets(const bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_ASSETS) {
+ return static_cast(area->spacedata.first);
+ }
+ return nullptr;
+}
+
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -1493,6 +1502,17 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid)
return AssetHandle{nullptr};
}
+/**
+ * \note Only works in the new Asset Browser and the asset view template (not in the old File
+ * Browser based Asset Browser).
+ * TODO Replace #CTX_wm_asset_handle() with this.
+ */
+AssetHandle *CTX_wm_asset_handle_ptr(const bContext *C)
+{
+ return static_cast(
+ CTX_data_pointer_get_type(C, "asset_handle", &RNA_AssetHandle).data);
+}
+
AssetRepresentation *CTX_wm_asset(const bContext *C)
{
return static_cast(ctx_data_pointer_get(C, "asset"));
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index c62443303f1..e444ed2f282 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -1159,6 +1159,10 @@ static void write_area(BlendWriter *writer, ScrArea *area)
if (space_type && space_type->blend_write) {
space_type->blend_write(writer, sl);
}
+ else if (sl->spacetype == SPACE_ASSETS) {
+ BLO_write_struct(writer, SpaceAssets, sl);
+ // SpaceAssets *space_assets = (SpaceAssets *)sl;
+ }
}
}
diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc
index f114084199e..1cb124a43f2 100644
--- a/source/blender/blenloader/intern/readfile.cc
+++ b/source/blender/blenloader/intern/readfile.cc
@@ -2603,6 +2603,7 @@ static void lib_link_workspace_layout_restore(IDNameLib_Map *id_map,
lib_link_restore_viewer_path(id_map, &sspreadsheet->viewer_path);
break;
}
+ case SPACE_ASSETS:
case SPACE_INFO:
case SPACE_IMASEL:
case SPACE_SOUND:
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index a6e55f7b12d..94618af515c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -104,6 +104,9 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
*/
{
/* Keep this block, even when empty. */
+ /* TODO version bump. */
+ btheme->space_assets = btheme->space_file;
+ btheme->tui.wcol_view_item = U_theme_default.tui.wcol_view_item;
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt
index 9fff8bf861c..840759dddc5 100644
--- a/source/blender/editors/CMakeLists.txt
+++ b/source/blender/editors/CMakeLists.txt
@@ -27,6 +27,7 @@ if(WITH_BLENDER)
add_subdirectory(sound)
add_subdirectory(space_action)
add_subdirectory(space_api)
+ add_subdirectory(space_assets)
add_subdirectory(space_buttons)
add_subdirectory(space_clip)
add_subdirectory(space_console)
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index 9d5f10eddd2..7394d3a3ad4 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -33,6 +33,7 @@ set(SRC
intern/asset_ops.cc
intern/asset_temp_id_consumer.cc
intern/asset_type.cc
+ intern/asset_view_catalog_filter.cc
ED_asset_catalog.h
ED_asset_catalog.hh
@@ -46,6 +47,7 @@ set(SRC
ED_asset_mark_clear.h
ED_asset_temp_id_consumer.h
ED_asset_type.h
+ ED_asset_view_catalog_filter.h
intern/asset_library_reference.hh
)
diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h
index 8bfd4f7150e..428db0e1d78 100644
--- a/source/blender/editors/asset/ED_asset_handle.h
+++ b/source/blender/editors/asset/ED_asset_handle.h
@@ -23,6 +23,7 @@ struct AssetHandle;
struct AssetRepresentation *ED_asset_handle_get_representation(const struct AssetHandle *asset);
const char *ED_asset_handle_get_name(const struct AssetHandle *asset);
+const char *ED_asset_handle_get_identifier(const struct AssetHandle *asset);
struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset);
struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset);
ID_Type ED_asset_handle_get_id_type(const struct AssetHandle *asset);
diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h
index 19528c5dde6..2d4cadf1ea4 100644
--- a/source/blender/editors/asset/ED_asset_list.h
+++ b/source/blender/editors/asset/ED_asset_list.h
@@ -12,6 +12,7 @@
extern "C" {
#endif
+struct AssetCatalogFilterSettings;
struct AssetLibraryReference;
struct ID;
struct bContext;
@@ -26,11 +27,12 @@ struct wmNotifier;
*/
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
+void ED_assetlist_catalog_filter_set(const struct AssetLibraryReference *,
+ const struct AssetCatalogFilterSettings *catalog_filter);
bool ED_assetlist_is_loaded(const struct AssetLibraryReference *library_reference);
-void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
- const struct bContext *C);
void ED_assetlist_clear(const struct AssetLibraryReference *library_reference, struct bContext *C);
bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *library_reference);
+
/**
* Tag all asset lists in the storage that show main data as needing an update (re-fetch).
*
@@ -50,11 +52,18 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
*/
void ED_assetlist_storage_exit(void);
-AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
- int asset_index);
+AssetHandle *ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
+ int asset_index);
+struct PreviewImage *ED_assetlist_asset_preview_request(
+ const struct AssetLibraryReference *library_reference, AssetHandle *asset_handle);
+int ED_assetlist_asset_preview_icon_id_request(const AssetLibraryReference *library_reference,
+ AssetHandle *asset_handle);
struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle);
+struct AssetLibrary *ED_assetlist_library_get(
+ const struct AssetLibraryReference *library_reference);
+
/**
* \return True if the region needs a UI redraw.
*/
diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh
index eeca6390bca..1f50eb211ba 100644
--- a/source/blender/editors/asset/ED_asset_list.hh
+++ b/source/blender/editors/asset/ED_asset_list.hh
@@ -6,6 +6,7 @@
#pragma once
+#include
#include
#include "BLI_function_ref.hh"
@@ -29,8 +30,12 @@ blender::asset_system::AssetLibrary *ED_assetlist_library_get_once_available(
const AssetLibraryReference &library_reference);
/* Can return false to stop iterating. */
-using AssetListIterFn = blender::FunctionRef;
+using AssetListIterFn = blender::FunctionRef;
/**
+ * Iterate the currently loaded assets for the referenced asset library, calling \a fn for each
+ * asset. This may be executed while the asset list is loading asynchronously. Assets will then be
+ * included as they get done loading.
+ *
* \warning Never keep the asset handle passed to \a fn outside of \a fn's scope. While iterating,
* the file data wrapped by the asset handle can be freed, since the file cache has a maximum size.
*/
diff --git a/source/blender/editors/asset/ED_asset_view_catalog_filter.h b/source/blender/editors/asset/ED_asset_view_catalog_filter.h
new file mode 100644
index 00000000000..e0325e8c6d0
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_view_catalog_filter.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#pragma once
+
+#include "DNA_space_types.h"
+
+struct AssetLibrary;
+struct AssetMetaData;
+struct bUUID;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AssetViewCatalogFilterSettingsHandle AssetViewCatalogFilterSettingsHandle;
+
+AssetViewCatalogFilterSettingsHandle *asset_view_create_catalog_filter_settings(void);
+void asset_view_delete_catalog_filter_settings(
+ AssetViewCatalogFilterSettingsHandle **filter_settings_handle);
+bool asset_view_set_catalog_filter_settings(
+ AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ AssetCatalogFilterMode catalog_visibility,
+ bUUID catalog_id);
+void asset_view_ensure_updated_catalog_filter_data(
+ AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ const AssetLibrary *asset_library);
+bool asset_view_is_asset_visible_in_catalog_filter_settings(
+ const AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ const AssetMetaData *asset_data);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc
index 824d5d0ed08..8338a2d6ec8 100644
--- a/source/blender/editors/asset/intern/asset_handle.cc
+++ b/source/blender/editors/asset/intern/asset_handle.cc
@@ -29,6 +29,11 @@ const char *ED_asset_handle_get_name(const AssetHandle *asset)
return AS_asset_representation_name_get(asset->file_data->asset);
}
+const char *ED_asset_handle_get_identifier(const AssetHandle *asset)
+{
+ return asset->file_data->relpath;
+}
+
AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset_handle)
{
return AS_asset_representation_metadata_get(asset_handle->file_data->asset);
diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc
index c7df300ed24..e3db8ea0d4f 100644
--- a/source/blender/editors/asset/intern/asset_list.cc
+++ b/source/blender/editors/asset/intern/asset_list.cc
@@ -13,6 +13,7 @@
#include
#include "AS_asset_library.hh"
+#include "AS_asset_representation.hh"
#include "BKE_context.h"
@@ -21,6 +22,7 @@
#include "DNA_space_types.h"
+#include "BKE_icons.h"
#include "BKE_preferences.h"
#include "WM_api.h"
@@ -74,32 +76,13 @@ class FileListWrapper {
}
};
-class PreviewTimer {
- /* Non-owning! The Window-Manager registers and owns this. */
- wmTimer *timer_ = nullptr;
-
- public:
- void ensureRunning(const bContext *C)
- {
- if (!timer_) {
- timer_ = WM_event_add_timer_notifier(
- CTX_wm_manager(C), CTX_wm_window(C), NC_ASSET | ND_ASSET_LIST_PREVIEW, 0.01);
- }
- }
-
- void stop(const bContext *C)
- {
- if (timer_) {
- WM_event_remove_timer_notifier(CTX_wm_manager(C), CTX_wm_window(C), timer_);
- timer_ = nullptr;
- }
- }
-};
-
class AssetList : NonCopyable {
FileListWrapper filelist_;
+ /** Storage for asset handles, items are lazy-created on request.
+ * Asset handles are stored as a pointer here, to ensure a consistent memory address (address
+ * inside the map changes as the map changes). */
+ mutable Map> asset_handle_map_;
AssetLibraryReference library_ref_;
- PreviewTimer previews_timer_;
public:
AssetList() = delete;
@@ -109,14 +92,15 @@ class AssetList : NonCopyable {
void setup();
void fetch(const bContext &C);
- void ensurePreviewsJob(const bContext *C);
+ void setCatalogFilterSettings(const AssetCatalogFilterSettings &settings);
void clear(bContext *C);
- AssetHandle asset_get_by_index(int index) const;
+ AssetHandle *asset_get_by_index(int index) const;
bool needsRefetch() const;
bool isLoaded() const;
asset_system::AssetLibrary *asset_library() const;
+ AssetHandle &asset_handle_from_file(const FileDirEntry &) const;
void iterate(AssetListIterFn fn) const;
bool listen(const wmNotifier ¬ifier) const;
int size() const;
@@ -167,6 +151,7 @@ void AssetList::fetch(const bContext &C)
if (filelist_needs_force_reset(files)) {
filelist_readjob_stop(files, CTX_wm_manager(&C));
filelist_clear_from_reset_tag(files);
+ asset_handle_map_.clear();
}
if (filelist_needs_reading(files)) {
@@ -178,6 +163,12 @@ void AssetList::fetch(const bContext &C)
filelist_filter(files);
}
+void AssetList::setCatalogFilterSettings(const AssetCatalogFilterSettings &settings)
+{
+ filelist_set_asset_catalog_filter_options(
+ filelist_, (AssetCatalogFilterMode)settings.filter_mode, &settings.active_catalog_id);
+}
+
bool AssetList::needsRefetch() const
{
return filelist_needs_force_reset(filelist_) || filelist_needs_reading(filelist_);
@@ -193,6 +184,15 @@ asset_system::AssetLibrary *AssetList::asset_library() const
return reinterpret_cast(filelist_asset_library(filelist_));
}
+AssetHandle &AssetList::asset_handle_from_file(const FileDirEntry &file) const
+{
+ AssetHandle &asset = *asset_handle_map_.lookup_or_add(
+ file.uid, std::make_unique(AssetHandle{&file}));
+ /* The file is recreated while loading, update the pointer here. */
+ asset.file_data = &file;
+ return asset;
+}
+
void AssetList::iterate(AssetListIterFn fn) const
{
FileList *files = filelist_;
@@ -204,7 +204,7 @@ void AssetList::iterate(AssetListIterFn fn) const
continue;
}
- AssetHandle asset_handle = {file};
+ AssetHandle &asset_handle = asset_handle_from_file(*file);
if (!fn(asset_handle)) {
/* If the callback returns false, we stop iterating. */
break;
@@ -212,30 +212,6 @@ void AssetList::iterate(AssetListIterFn fn) const
}
}
-void AssetList::ensurePreviewsJob(const bContext *C)
-{
- FileList *files = filelist_;
- int numfiles = filelist_files_ensure(files);
-
- filelist_cache_previews_set(files, true);
- filelist_file_cache_slidingwindow_set(files, 256);
- /* TODO fetch all previews for now. */
- filelist_file_cache_block(files, numfiles / 2);
- filelist_cache_previews_update(files);
-
- {
- const bool previews_running = filelist_cache_previews_running(files) &&
- !filelist_cache_previews_done(files);
- if (previews_running) {
- previews_timer_.ensureRunning(C);
- }
- else {
- /* Preview is not running, no need to keep generating update events! */
- previews_timer_.stop(C);
- }
- }
-}
-
void AssetList::clear(bContext *C)
{
/* Based on #ED_fileselect_clear() */
@@ -244,13 +220,18 @@ void AssetList::clear(bContext *C)
filelist_readjob_stop(files, CTX_wm_manager(C));
filelist_freelib(files);
filelist_clear(files);
+ asset_handle_map_.clear();
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST, nullptr);
}
-AssetHandle AssetList::asset_get_by_index(int index) const
+AssetHandle *AssetList::asset_get_by_index(int index) const
{
- return {filelist_file(filelist_, index)};
+ FileDirEntry *file = filelist_file(filelist_, index);
+ if (!file) {
+ return nullptr;
+ }
+ return &asset_handle_from_file(*file);
}
/**
@@ -266,7 +247,11 @@ bool AssetList::listen(const wmNotifier ¬ifier) const
break;
}
case NC_ASSET:
- if (ELEM(notifier.data, ND_ASSET_LIST, ND_ASSET_LIST_READING, ND_ASSET_LIST_PREVIEW)) {
+ if (ELEM(notifier.data, ND_ASSET_LIST)) {
+ filelist_tag_needs_filtering(filelist_);
+ return true;
+ }
+ if (ELEM(notifier.data, ND_ASSET_LIST_READING)) {
return true;
}
if (ELEM(notifier.action, NA_ADDED, NA_REMOVED, NA_EDITED)) {
@@ -438,13 +423,12 @@ bool ED_assetlist_is_loaded(const AssetLibraryReference *library_reference)
return list->isLoaded();
}
-void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference,
- const bContext *C)
+void ED_assetlist_catalog_filter_set(const struct AssetLibraryReference *library_reference,
+ const struct AssetCatalogFilterSettings *settings)
{
-
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
- list->ensurePreviewsJob(C);
+ list->setCatalogFilterSettings(*settings);
}
}
@@ -479,13 +463,44 @@ asset_system::AssetLibrary *ED_assetlist_library_get_once_available(
return list->asset_library();
}
-AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
- int asset_index)
+AssetHandle *ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference,
+ int asset_index)
{
const AssetList *list = AssetListStorage::lookup_list(*library_reference);
return list->asset_get_by_index(asset_index);
}
+PreviewImage *ED_assetlist_asset_preview_request(const AssetLibraryReference *library_reference,
+ AssetHandle *asset_handle)
+{
+ if (asset_handle->preview) {
+ return asset_handle->preview;
+ }
+
+ if (ID *local_id = ED_asset_handle_get_local_id(asset_handle)) {
+ asset_handle->preview = BKE_previewimg_id_get(local_id);
+ }
+ else {
+ const char *asset_identifier = ED_asset_handle_get_identifier(asset_handle);
+ const int source = filelist_preview_source_get(asset_handle->file_data->typeflag);
+ const std::string asset_path = AS_asset_representation_full_path_get(
+ asset_handle->file_data->asset);
+
+ asset_handle->preview = BKE_previewimg_cached_thumbnail_read(
+ asset_identifier, asset_path.c_str(), source, false);
+ }
+
+ return asset_handle->preview;
+}
+
+int ED_assetlist_asset_preview_icon_id_request(const AssetLibraryReference *library_reference,
+ AssetHandle *asset_handle)
+{
+ PreviewImage *preview = ED_assetlist_asset_preview_request(library_reference, asset_handle);
+ ID *local_id = ED_asset_handle_get_local_id(asset_handle);
+ return BKE_icon_preview_ensure(local_id, preview);
+}
+
ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
{
ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data);
@@ -496,6 +511,15 @@ ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
return filelist_geticon_image_ex(asset_handle->file_data);
}
+AssetLibrary *ED_assetlist_library_get(const AssetLibraryReference *library_reference)
+{
+ AssetList *list = AssetListStorage::lookup_list(*library_reference);
+ if (list) {
+ return reinterpret_cast(list->asset_library());
+ }
+ return nullptr;
+}
+
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index 6f2aedcbad5..9248817760f 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -430,13 +430,24 @@ static void ASSET_OT_library_refresh(struct wmOperatorType *ot)
/* -------------------------------------------------------------------- */
+static AssetLibrary *get_asset_library(const bContext *C)
+{
+ if (const SpaceFile *sfile = CTX_wm_space_file(C)) {
+ return ED_fileselect_active_asset_library_get(sfile);
+ }
+ if (const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C)) {
+ return ED_assetlist_library_get(library_ref);
+ }
+ return nullptr;
+}
+
static bool asset_catalog_operator_poll(bContext *C)
{
const SpaceFile *sfile = CTX_wm_space_file(C);
if (!sfile) {
return false;
}
- const AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ const AssetLibrary *asset_library = get_asset_library(C);
if (!asset_library) {
return false;
}
@@ -449,16 +460,20 @@ static bool asset_catalog_operator_poll(bContext *C)
static int asset_catalog_new_exec(bContext *C, wmOperator *op)
{
- SpaceFile *sfile = CTX_wm_space_file(C);
- struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ AssetLibrary *asset_library = get_asset_library(C);
char *parent_path = RNA_string_get_alloc(op->ptr, "parent_path", nullptr, 0, nullptr);
blender::asset_system::AssetCatalog *new_catalog = ED_asset_catalog_add(
asset_library, "Catalog", parent_path);
- if (sfile) {
+ if (SpaceFile *sfile = CTX_wm_space_file(C)) {
ED_fileselect_activate_asset_catalog(sfile, new_catalog->catalog_id);
}
+ else if (SpaceAssets *sassets = CTX_wm_space_assets(C)) {
+ /* TODO how can we select the catalog here in a nice way, without being space dependent? Idea:
+ * use an operator macro instead? */
+ UNUSED_VARS(sassets);
+ }
MEM_freeN(parent_path);
@@ -489,8 +504,7 @@ static void ASSET_OT_catalog_new(struct wmOperatorType *ot)
static int asset_catalog_delete_exec(bContext *C, wmOperator *op)
{
- SpaceFile *sfile = CTX_wm_space_file(C);
- struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ AssetLibrary *asset_library = get_asset_library(C);
char *catalog_id_str = RNA_string_get_alloc(op->ptr, "catalog_id", nullptr, 0, nullptr);
asset_system::CatalogID catalog_id;
if (!BLI_uuid_parse_string(&catalog_id, catalog_id_str)) {
@@ -525,13 +539,16 @@ static void ASSET_OT_catalog_delete(struct wmOperatorType *ot)
static asset_system::AssetCatalogService *get_catalog_service(bContext *C)
{
- const SpaceFile *sfile = CTX_wm_space_file(C);
- if (!sfile) {
- return nullptr;
+ if (const SpaceFile *sfile = CTX_wm_space_file(C)) {
+ AssetLibrary *asset_lib = ED_fileselect_active_asset_library_get(sfile);
+ return AS_asset_library_get_catalog_service(asset_lib);
+ }
+ if (const AssetLibraryReference *library_ref = CTX_wm_asset_library_ref(C)) {
+ AssetLibrary *asset_lib = ED_assetlist_library_get(library_ref);
+ return AS_asset_library_get_catalog_service(asset_lib);
}
- AssetLibrary *asset_lib = ED_fileselect_active_asset_library_get(sfile);
- return AS_asset_library_get_catalog_service(asset_lib);
+ return nullptr;
}
static int asset_catalog_undo_exec(bContext *C, wmOperator * /*op*/)
@@ -542,7 +559,7 @@ static int asset_catalog_undo_exec(bContext *C, wmOperator * /*op*/)
}
catalog_service->undo();
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | ND_ASSET_CATALOGS, nullptr);
return OPERATOR_FINISHED;
}
@@ -572,7 +589,7 @@ static int asset_catalog_redo_exec(bContext *C, wmOperator * /*op*/)
}
catalog_service->redo();
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ WM_event_add_notifier(C, NC_ASSET | ND_ASSET_CATALOGS, nullptr);
return OPERATOR_FINISHED;
}
@@ -649,8 +666,7 @@ static bool asset_catalogs_save_poll(bContext *C)
static int asset_catalogs_save_exec(bContext *C, wmOperator * /*op*/)
{
- const SpaceFile *sfile = CTX_wm_space_file(C);
- ::AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ ::AssetLibrary *asset_library = get_asset_library(C);
ED_asset_catalogs_save_from_main_path(asset_library, CTX_data_main(C));
@@ -685,11 +701,12 @@ static bool has_external_files(Main *bmain, struct ReportList *reports);
static bool asset_bundle_install_poll(bContext *C)
{
/* This operator only works when the asset browser is set to Current File. */
- const SpaceFile *sfile = CTX_wm_space_file(C);
- if (sfile == nullptr) {
+ const AssetLibraryReference *asset_library_ref = CTX_wm_asset_library_ref(C);
+ if (asset_library_ref == nullptr) {
return false;
}
- if (!ED_fileselect_is_local_asset_library(sfile)) {
+
+ if (asset_library_ref->type == ASSET_LIBRARY_LOCAL) {
return false;
}
diff --git a/source/blender/editors/asset/intern/asset_view_catalog_filter.cc b/source/blender/editors/asset/intern/asset_view_catalog_filter.cc
new file mode 100644
index 00000000000..4f383018c19
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_view_catalog_filter.cc
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edasset
+ */
+
+#include
+
+#include "AS_asset_catalog.hh"
+#include "AS_asset_library.hh"
+
+#include "DNA_space_types.h"
+
+#include "ED_asset_view_catalog_filter.h"
+
+namespace asset_system = blender::asset_system;
+
+struct AssetViewCatalogFilter {
+ AssetCatalogFilterSettings filter_settings;
+ std::unique_ptr catalog_filter;
+};
+
+AssetViewCatalogFilterSettingsHandle *asset_view_create_catalog_filter_settings()
+{
+ AssetViewCatalogFilter *filter_settings = MEM_new(__func__);
+ return reinterpret_cast(filter_settings);
+}
+
+void asset_view_delete_catalog_filter_settings(
+ AssetViewCatalogFilterSettingsHandle **filter_settings_handle)
+{
+ AssetViewCatalogFilter **filter_settings = reinterpret_cast(
+ filter_settings_handle);
+ MEM_delete(*filter_settings);
+ *filter_settings = nullptr;
+}
+
+bool asset_view_set_catalog_filter_settings(
+ AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ AssetCatalogFilterMode catalog_visibility,
+ ::bUUID catalog_id)
+{
+ AssetViewCatalogFilter *filter_settings = reinterpret_cast(
+ filter_settings_handle);
+ bool needs_update = false;
+
+ if (filter_settings->filter_settings.filter_mode != catalog_visibility) {
+ filter_settings->filter_settings.filter_mode = catalog_visibility;
+ needs_update = true;
+ }
+
+ if (filter_settings->filter_settings.filter_mode == ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG &&
+ !BLI_uuid_equal(filter_settings->filter_settings.active_catalog_id, catalog_id)) {
+ filter_settings->filter_settings.active_catalog_id = catalog_id;
+ needs_update = true;
+ }
+
+ return needs_update;
+}
+
+void asset_view_ensure_updated_catalog_filter_data(
+ AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ const ::AssetLibrary *asset_library)
+{
+ AssetViewCatalogFilter *filter_settings = reinterpret_cast(
+ filter_settings_handle);
+ const asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
+ asset_library);
+
+ if (filter_settings->filter_settings.filter_mode != ASSET_CATALOG_SHOW_ALL_ASSETS) {
+ filter_settings->catalog_filter = std::make_unique(
+ catalog_service->create_catalog_filter(
+ filter_settings->filter_settings.active_catalog_id));
+ }
+}
+
+bool asset_view_is_asset_visible_in_catalog_filter_settings(
+ const AssetViewCatalogFilterSettingsHandle *filter_settings_handle,
+ const AssetMetaData *asset_data)
+{
+ const AssetViewCatalogFilter *filter_settings = reinterpret_cast(
+ filter_settings_handle);
+
+ switch (filter_settings->filter_settings.filter_mode) {
+ case ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG:
+ return !filter_settings->catalog_filter->is_known(asset_data->catalog_id);
+ case ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG:
+ return filter_settings->catalog_filter->contains(asset_data->catalog_id);
+ case ASSET_CATALOG_SHOW_ALL_ASSETS:
+ /* All asset files should be visible. */
+ return true;
+ }
+
+ BLI_assert_unreachable();
+ return false;
+}
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index e2e5a8b97af..75ac1f578f3 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -26,6 +26,7 @@ void ED_spacemacros_init(void);
* Calls for registering default spaces, only called once, from #ED_spacetypes_init
* \{ */
+void ED_spacetype_assets(void);
void ED_spacetype_outliner(void);
void ED_spacetype_view3d(void);
void ED_spacetype_ipo(void);
diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc
index 1b5330acc19..0f03279e204 100644
--- a/source/blender/editors/interface/interface_layout.cc
+++ b/source/blender/editors/interface/interface_layout.cc
@@ -4549,8 +4549,8 @@ static void ui_litem_layout_grid_flow(uiLayout *litem)
BLI_assert(gflow->tot_columns > 0);
BLI_assert(gflow->tot_rows > 0);
- const int space_x = style->columnspace;
- const int space_y = style->buttonspacey;
+ const int space_x = litem->align ? 0 : style->columnspace;
+ const int space_y = litem->align ? 0 : style->buttonspacey;
blender::Array widths(gflow->tot_columns);
blender::Array heights(gflow->tot_rows);
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 71bd66ff651..34b2c6db3d6 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -38,7 +38,9 @@ struct AssetViewListData {
bool show_names;
};
-static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle)
+static void asset_view_item_but_drag_set(uiBut *but,
+ AssetViewListData *list_data,
+ AssetHandle *asset_handle)
{
ID *id = ED_asset_handle_get_local_id(asset_handle);
if (id != nullptr) {
@@ -54,13 +56,14 @@ static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle)
if (blend_path[0]) {
ImBuf *imbuf = ED_assetlist_asset_image_get(asset_handle);
- UI_but_drag_set_asset(but,
- asset_handle,
- BLI_strdup(blend_path),
- import_method,
- ED_asset_handle_get_preview_icon_id(asset_handle),
- imbuf,
- 1.0f);
+ UI_but_drag_set_asset(
+ but,
+ asset_handle,
+ BLI_strdup(blend_path),
+ import_method,
+ ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, asset_handle),
+ imbuf,
+ 1.0f);
}
}
@@ -77,7 +80,8 @@ static void asset_view_draw_item(uiList *ui_list,
{
AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata;
- AssetHandle asset_handle = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
+ AssetHandle asset_handle = *ED_assetlist_asset_get_by_index(&list_data->asset_library_ref,
+ index);
PointerRNA file_ptr;
RNA_pointer_create(&list_data->screen->id,
@@ -88,30 +92,31 @@ static void asset_view_draw_item(uiList *ui_list,
uiBlock *block = uiLayoutGetBlock(layout);
const bool show_names = list_data->show_names;
- /* TODO ED_fileselect_init_layout(). Share somehow? */
- const float size_x = (96.0f / 20.0f) * UI_UNIT_X;
- const float size_y = (96.0f / 20.0f) * UI_UNIT_Y - (show_names ? 0 : UI_UNIT_Y);
- uiBut *but = uiDefIconTextBut(block,
- UI_BTYPE_PREVIEW_TILE,
- 0,
- ED_asset_handle_get_preview_icon_id(&asset_handle),
- show_names ? ED_asset_handle_get_name(&asset_handle) : "",
- 0,
- 0,
- size_x,
- size_y,
- nullptr,
- 0,
- 0,
- 0,
- 0,
- "");
- ui_def_but_icon(but,
- ED_asset_handle_get_preview_icon_id(&asset_handle),
- /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
- UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
+ const int size_x = UI_preview_tile_size_x();
+ const int size_y = show_names ? UI_preview_tile_size_y() : UI_preview_tile_size_y_no_label();
+ uiBut *but = uiDefIconTextBut(
+ block,
+ UI_BTYPE_PREVIEW_TILE,
+ 0,
+ ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, &asset_handle),
+ show_names ? ED_asset_handle_get_name(&asset_handle) : "",
+ 0,
+ 0,
+ size_x,
+ size_y,
+ nullptr,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+ ui_def_but_icon(
+ but,
+ ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, &asset_handle),
+ /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
+ UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (!ui_list->dyn_data->custom_drag_optype) {
- asset_view_item_but_drag_set(but, &asset_handle);
+ asset_view_item_but_drag_set(but, list_data, &asset_handle);
}
}
@@ -130,8 +135,8 @@ static void asset_view_filter_items(uiList *ui_list,
C,
[&name_filter, list_data, &filter_settings](
const PointerRNA &itemptr, blender::StringRefNull name, int index) {
- AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
- if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
+ AssetHandle *asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
+ if (!ED_asset_filter_matches_asset(&filter_settings, asset)) {
return UI_LIST_ITEM_NEVER_SHOW;
}
return name_filter(itemptr, name, index);
@@ -139,8 +144,8 @@ static void asset_view_filter_items(uiList *ui_list,
dataptr,
propname,
[list_data](const PointerRNA & /*itemptr*/, int index) -> std::string {
- AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
- return ED_asset_handle_get_name(&asset);
+ AssetHandle *asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index);
+ return ED_asset_handle_get_name(asset);
});
}
@@ -248,7 +253,6 @@ void uiTemplateAssetView(uiLayout *layout,
}
ED_assetlist_storage_fetch(&asset_library_ref, C);
- ED_assetlist_ensure_previews_job(&asset_library_ref, C);
const int tot_items = ED_assetlist_size(&asset_library_ref);
populate_asset_collection(asset_library_ref, *assets_dataptr, assets_propname);
diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc
index 547811ef1f8..9c6486b0666 100644
--- a/source/blender/editors/interface/interface_template_search_menu.cc
+++ b/source/blender/editors/interface/interface_template_search_menu.cc
@@ -643,6 +643,8 @@ static MenuSearch_Data *menu_items_from_ui_create(
SPACE_MENU_NOP(SPACE_STATUSBAR);
SPACE_MENU_NOP(SPACE_TOPBAR);
SPACE_MENU_NOP(SPACE_SPREADSHEET);
+ /* TODO */
+ SPACE_MENU_NOP(SPACE_ASSETS);
}
}
for (int i = 0; i < idname_array_len; i++) {
diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc
index ca2834be58b..b0fc7bdd2b8 100644
--- a/source/blender/editors/interface/interface_widgets.cc
+++ b/source/blender/editors/interface/interface_widgets.cc
@@ -5464,13 +5464,17 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
eFontStyle_Align text_align)
{
rcti trect = *rect;
- const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
const bool has_text = name && name[0];
+ const float padding = PREVIEW_PAD;
if (has_text) {
+ UI_fontstyle_set(fstyle);
+ BLF_width_and_height(
+ fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
+
/* draw icon in rect above the space reserved for the label */
- rect->ymin += text_size;
+ rect->ymin += round_fl_to_int(font_dims[1] + 2 * padding);
}
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(BIFIconID(iconid), 1.0f, rect);
@@ -5480,15 +5484,9 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
return;
}
- BLF_width_and_height(
- fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
-
/* text rect */
- trect.ymin += U.widget_unit / 2;
- trect.ymax = trect.ymin + font_dims[1];
- if (trect.xmax > rect->xmax - PREVIEW_PAD) {
- trect.xmax = rect->xmax - PREVIEW_PAD;
- }
+ BLI_rcti_pad(&trect, -padding * 2, -padding * 2);
+ trect.ymax = round_fl_to_int(trect.ymin + font_dims[1]);
{
char drawstr[UI_MAX_DRAW_STR];
diff --git a/source/blender/editors/interface/resources.cc b/source/blender/editors/interface/resources.cc
index 6a2e2ff9073..6f7440ac353 100644
--- a/source/blender/editors/interface/resources.cc
+++ b/source/blender/editors/interface/resources.cc
@@ -140,6 +140,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case SPACE_SPREADSHEET:
ts = &btheme->space_spreadsheet;
break;
+ case SPACE_ASSETS:
+ ts = &btheme->space_assets;
+ break;
default:
ts = &btheme->space_view3d;
break;
diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt
index 0024e7935d8..109cdaefa18 100644
--- a/source/blender/editors/space_api/CMakeLists.txt
+++ b/source/blender/editors/space_api/CMakeLists.txt
@@ -23,6 +23,7 @@ set(SRC
set(LIB
bf_editor_geometry
bf_editor_space_action
+ bf_editor_space_assets
bf_editor_space_buttons
bf_editor_space_clip
bf_editor_space_console
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 0ed48924bbe..8e7cf596fb8 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -63,6 +63,7 @@ void ED_spacetypes_init(void)
U.widget_unit = 20;
/* Create space types. */
+ ED_spacetype_assets();
ED_spacetype_outliner();
ED_spacetype_view3d();
ED_spacetype_ipo();
diff --git a/source/blender/editors/space_assets/CMakeLists.txt b/source/blender/editors/space_assets/CMakeLists.txt
new file mode 100644
index 00000000000..2ab817b8cb1
--- /dev/null
+++ b/source/blender/editors/space_assets/CMakeLists.txt
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(INC
+ ../include
+ ../../asset_system
+ ../../blenfont
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../gpu
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/glew-mx
+ ../../../../intern/guardedalloc
+ # RNA_prototypes.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesrna
+)
+
+set(SRC
+ asset_browser_draw.cc
+ asset_browser_ops.cc
+ asset_browser_panels.cc
+ asset_catalog_tree_view.cc
+ asset_view.cc
+ space_assets.cc
+
+ asset_browser_intern.hh
+ asset_view.hh
+)
+
+set(LIB
+)
+
+blender_add_lib(bf_editor_space_assets "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+# RNA_prototypes.h
+add_dependencies(bf_editor_space_assets bf_rna)
diff --git a/source/blender/editors/space_assets/asset_browser_draw.cc b/source/blender/editors/space_assets/asset_browser_draw.cc
new file mode 100644
index 00000000000..187e7ac2ffc
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_browser_draw.cc
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "asset_browser_intern.hh"
+#include "asset_view.hh"
+
+namespace blender::ed::asset_browser {
+
+} // namespace blender::ed::asset_browser
+
+using namespace blender::ed::asset_browser;
+
+void asset_browser_main_region_draw(const bContext *C, ARegion *region)
+{
+ SpaceAssets *asset_space = CTX_wm_space_assets(C);
+ bScreen *screen = CTX_wm_screen(C);
+ View2D *v2d = ®ion->v2d;
+
+ UI_ThemeClearColor(TH_BACK);
+
+ UI_view2d_view_ortho(v2d);
+
+ const uiStyle *style = UI_style_get_dpi();
+ const float padding = style->panelouter;
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiLayout *layout = UI_block_layout(
+ block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ padding,
+ -padding,
+ /* 3x (instead of 2x) padding to add extra space for the scrollbar on the right. */
+ region->winx - 3 * padding,
+ 1,
+ 0,
+ style);
+
+ PointerRNA asset_space_ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceAssetBrowser, asset_space, &asset_space_ptr);
+ PropertyRNA *active_asset_idx_prop = RNA_struct_find_property(&asset_space_ptr,
+ "active_asset_idx");
+
+ asset_view_create_in_layout(*C,
+ asset_space->asset_library_ref,
+ asset_space->catalog_filter,
+ asset_space_ptr,
+ active_asset_idx_prop,
+ *v2d,
+ *layout);
+
+ /* Update main region View2d dimensions. */
+ int layout_width, layout_height;
+ UI_block_layout_resolve(block, &layout_width, &layout_height);
+ UI_view2d_totRect_set(v2d, layout_width, layout_height);
+
+ UI_block_end(C, block);
+ UI_block_draw(C, block);
+
+ /* reset view matrix */
+ UI_view2d_view_restore(C);
+ UI_view2d_scrollers_draw(v2d, nullptr);
+}
diff --git a/source/blender/editors/space_assets/asset_browser_intern.hh b/source/blender/editors/space_assets/asset_browser_intern.hh
new file mode 100644
index 00000000000..67402d51852
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_browser_intern.hh
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#pragma once
+
+void asset_browser_operatortypes();
+
+struct ARegion;
+struct ARegionType;
+struct AssetLibrary;
+struct bContext;
+struct PointerRNA;
+struct PropertyRNA;
+struct uiLayout;
+struct wmMsgBus;
+
+void asset_browser_main_region_draw(const bContext *C, ARegion *region);
+
+void asset_browser_navigation_region_panels_register(ARegionType *art);
+
+void asset_view_create_catalog_tree_view_in_layout(::AssetLibrary *asset_library,
+ uiLayout *layout,
+ PointerRNA *catalog_filter_owner_ptr,
+ PropertyRNA *catalog_filter_prop,
+ wmMsgBus *msg_bus);
diff --git a/source/blender/editors/space_assets/asset_browser_ops.cc b/source/blender/editors/space_assets/asset_browser_ops.cc
new file mode 100644
index 00000000000..0e4be9b6ccc
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_browser_ops.cc
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#include "asset_browser_intern.hh"
+
+void asset_browser_operatortypes() {}
diff --git a/source/blender/editors/space_assets/asset_browser_panels.cc b/source/blender/editors/space_assets/asset_browser_panels.cc
new file mode 100644
index 00000000000..4bf9851096b
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_browser_panels.cc
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#include
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_screen.h"
+
+#include "BLI_listbase.h"
+
+#include "BLT_translation.h"
+
+#include "ED_asset.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+
+#include "asset_browser_intern.hh"
+
+static void assets_panel_asset_catalog_buttons_draw(const bContext *C, Panel *panel)
+{
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceAssets *assets_space = CTX_wm_space_assets(C);
+
+ uiLayout *col = uiLayoutColumn(panel->layout, false);
+ uiLayout *row = uiLayoutRow(col, true);
+
+ PointerRNA assets_space_ptr;
+ RNA_pointer_create(&screen->id, &RNA_SpaceAssetBrowser, assets_space, &assets_space_ptr);
+
+ uiItemR(row, &assets_space_ptr, "asset_library_ref", 0, "", ICON_NONE);
+ if (assets_space->asset_library_ref.type == ASSET_LIBRARY_LOCAL) {
+ bContext *mutable_ctx = CTX_copy(C);
+ if (WM_operator_name_poll(mutable_ctx, "asset.bundle_install")) {
+ uiItemS(col);
+ uiItemMenuEnumO(col,
+ mutable_ctx,
+ "asset.bundle_install",
+ "asset_library_ref",
+ "Copy Bundle to Asset Library...",
+ ICON_IMPORT);
+ }
+ CTX_free(mutable_ctx);
+ }
+ else {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_library_refresh");
+ }
+
+ uiItemS(col);
+
+ AssetLibrary *library = ED_assetlist_library_get(&assets_space->asset_library_ref);
+ PropertyRNA *catalog_filter_prop = RNA_struct_find_property(&assets_space_ptr, "catalog_filter");
+
+ asset_view_create_catalog_tree_view_in_layout(
+ library, col, &assets_space_ptr, catalog_filter_prop, CTX_wm_message_bus(C));
+}
+
+void asset_browser_navigation_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_cnew("asset browser catalog buttons");
+ strcpy(pt->idname, "FILE_PT_asset_catalog_buttons");
+ strcpy(pt->label, N_("Asset Catalogs"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PANEL_TYPE_NO_HEADER;
+ pt->draw = assets_panel_asset_catalog_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_assets/asset_catalog_tree_view.cc b/source/blender/editors/space_assets/asset_catalog_tree_view.cc
new file mode 100644
index 00000000000..32a0611e967
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_catalog_tree_view.cc
@@ -0,0 +1,747 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#include "AS_asset_catalog.hh"
+#include "AS_asset_catalog_tree.hh"
+#include "AS_asset_library.hh"
+
+#include "DNA_space_types.h"
+
+#include "BKE_asset.h"
+
+#include "BLI_string_ref.hh"
+
+#include "BLT_translation.h"
+
+#include "ED_asset.h"
+#include "ED_undo.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+#include "UI_tree_view.hh"
+
+#include "RNA_prototypes.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_types.h"
+
+#include "asset_browser_intern.hh"
+
+using namespace blender;
+using namespace blender::asset_system;
+
+namespace blender::ed::asset_browser {
+
+class AssetCatalogTreeViewAllItem;
+
+class AssetCatalogTreeView : public ui::AbstractTreeView {
+ /** The asset library this catalog tree comes from. May be null when drawing the catalog tree
+ * before the library was read. */
+ ::AssetLibrary *asset_library_;
+ /** The asset catalog tree this tree-view represents. */
+ AssetCatalogTree *catalog_tree_;
+
+ PointerRNA catalog_filter_owner_;
+ PropertyRNA &catalog_filter_prop_;
+ /** Used to notify the parts of the UI that display the filtered assets. */
+ wmMsgBus *msg_bus_;
+
+ friend class AssetCatalogTreeViewItem;
+ friend class AssetCatalogDropTarget;
+ friend class AssetCatalogTreeViewAllItem;
+
+ public:
+ AssetCatalogTreeView(::AssetLibrary *library,
+ const PointerRNA &catalog_filter_owner,
+ PropertyRNA &catalog_filter_prop,
+ wmMsgBus *msg_bus);
+
+ void build_tree() override;
+ bool listen(const wmNotifier ¬ifier) const override;
+
+ void activate_catalog_by_id(asset_system::CatalogID catalog_id);
+
+ private:
+ ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewOrItem &view_parent_item,
+ AssetCatalogTreeItem &catalog);
+
+ AssetCatalogTreeViewAllItem &add_all_item();
+ void add_unassigned_item();
+ bool is_active_catalog(CatalogID catalog_id) const;
+
+ AssetCatalogFilterSettings &catalog_filter_settings() const;
+ void notify_catalog_filter_change();
+ void notify_catalog_tree_change();
+ void notify_catalog_assignments_change();
+};
+
+/* ---------------------------------------------------------------------- */
+
+class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
+ /** The catalog tree item this tree view item represents. */
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item);
+
+ void on_activate() override;
+
+ void build_row(uiLayout &row) override;
+ void build_context_menu(bContext &C, uiLayout &column) const override;
+
+ bool supports_renaming() const override;
+ bool rename(StringRefNull new_name) override;
+
+ /** Add drag support for catalog items. */
+ std::unique_ptr create_drag_controller() const override;
+ /** Add dropping support for catalog items. */
+ std::unique_ptr create_drop_target() override;
+};
+
+class AssetCatalogDragController : public ui::AbstractViewItemDragController {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item);
+
+ int get_drag_type() const override;
+ void *create_drag_data() const override;
+ void on_drag_start() override;
+};
+
+class AssetCatalogDropTarget : public ui::AbstractViewItemDropTarget {
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogDropTarget(AssetCatalogTreeView &tree_view, AssetCatalogTreeItem &catalog_item);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) const override;
+
+ ::AssetLibrary &get_asset_library() const;
+
+ static AssetCatalog *get_drag_catalog(const wmDrag &drag, const ::AssetLibrary &asset_library);
+ static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
+ static bool can_modify_catalogs(const ::AssetLibrary &asset_library,
+ const char **r_disabled_hint);
+ static bool drop_assets_into_catalog(struct bContext *C,
+ AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name = "");
+ /**
+ * \param drop_catalog_id: Can be unset to drop into the root level of the tree.
+ */
+ static bool drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional drop_catalog_id = std::nullopt);
+
+ private:
+ std::string drop_tooltip_asset_list(const wmDrag &drag) const;
+ std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
+};
+
+/** Only reason this isn't just `BasicTreeViewItem` is to add a '+' icon for adding a root level
+ * catalog. */
+class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
+ using BasicTreeViewItem::BasicTreeViewItem;
+
+ void build_row(uiLayout &row) override;
+
+ struct DropTarget : public ui::AbstractViewItemDropTarget {
+ DropTarget(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) const override;
+ };
+
+ std::unique_ptr create_drop_target() override;
+};
+
+class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
+ using BasicTreeViewItem::BasicTreeViewItem;
+
+ struct DropTarget : public ui::AbstractViewItemDropTarget {
+ DropTarget(AssetCatalogTreeView &tree_view);
+
+ bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
+ std::string drop_tooltip(const wmDrag &drag) const override;
+ bool on_drop(struct bContext *C, const wmDrag &drag) const override;
+ };
+
+ std::unique_ptr create_drop_target() override;
+};
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library,
+ const PointerRNA &catalog_filter_owner,
+ PropertyRNA &catalog_filter_prop,
+ wmMsgBus *msg_bus)
+ : asset_library_(library),
+ catalog_tree_(AS_asset_library_get_catalog_tree(library)),
+ catalog_filter_owner_(catalog_filter_owner),
+ catalog_filter_prop_(catalog_filter_prop),
+ msg_bus_(msg_bus)
+{
+}
+
+void AssetCatalogTreeView::build_tree()
+{
+ AssetCatalogTreeViewAllItem &all_item = add_all_item();
+ all_item.set_collapsed(false);
+
+ if (catalog_tree_) {
+ /* Pass the "All" item on as parent of the actual catalog items. */
+ catalog_tree_->foreach_root_item([this, &all_item](AssetCatalogTreeItem &item) {
+ build_catalog_items_recursive(all_item, item);
+ });
+ }
+
+ add_unassigned_item();
+}
+
+ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
+ ui::TreeViewOrItem &view_parent_item, AssetCatalogTreeItem &catalog)
+{
+ ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item(
+ &catalog);
+ view_item.set_is_active_fn(
+ [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
+
+ catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
+ build_catalog_items_recursive(view_item, child);
+ });
+ return view_item;
+}
+
+AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
+{
+ AssetCatalogTreeViewAllItem &item = add_tree_item(IFACE_("All"));
+ item.set_on_activate_fn([this](ui::BasicTreeViewItem & /*item*/) {
+ catalog_filter_settings().filter_mode = ASSET_CATALOG_SHOW_ALL_ASSETS;
+ notify_catalog_filter_change();
+ });
+ item.set_is_active_fn(
+ [this]() { return catalog_filter_settings().filter_mode == ASSET_CATALOG_SHOW_ALL_ASSETS; });
+ return item;
+}
+
+void AssetCatalogTreeView::add_unassigned_item()
+{
+ AssetCatalogTreeViewUnassignedItem &item = add_tree_item(
+ IFACE_("Unassigned"), ICON_FILE_HIDDEN);
+
+ item.set_on_activate_fn([this](ui::BasicTreeViewItem & /*item*/) {
+ catalog_filter_settings().filter_mode = ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG;
+ notify_catalog_filter_change();
+ });
+ item.set_is_active_fn([this]() {
+ return catalog_filter_settings().filter_mode == ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG;
+ });
+}
+
+void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
+{
+ AssetCatalogFilterSettings &catalog_filter = catalog_filter_settings();
+ catalog_filter.filter_mode = ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG;
+ catalog_filter.active_catalog_id = catalog_id;
+ notify_catalog_filter_change();
+}
+
+bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
+{
+ const AssetCatalogFilterSettings &catalog_filter = catalog_filter_settings();
+ return (catalog_filter.filter_mode == ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG) &&
+ (catalog_filter.active_catalog_id == catalog_id);
+}
+
+AssetCatalogFilterSettings &AssetCatalogTreeView::catalog_filter_settings() const
+{
+ /* Copy so we can pass a non-const pointer to this to RNA functions. */
+ PointerRNA catalog_filter_owner = catalog_filter_owner_;
+ PointerRNA catalog_filter_ptr = RNA_property_pointer_get(&catalog_filter_owner,
+ &catalog_filter_prop_);
+ BLI_assert(catalog_filter_ptr.type == &RNA_AssetCatalogFilterSettings);
+
+ return *reinterpret_cast(catalog_filter_ptr.data);
+}
+
+bool AssetCatalogTreeView::listen(const wmNotifier ¬ifier) const
+{
+ switch (notifier.category) {
+ case NC_ASSET:
+ if (ELEM(notifier.data, ND_ASSET_CATALOGS, ND_ASSET_LIST_READING)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AssetCatalogTreeView::notify_catalog_filter_change()
+{
+ WM_msg_publish_rna(msg_bus_, &catalog_filter_owner_, &catalog_filter_prop_);
+}
+
+void AssetCatalogTreeView::notify_catalog_tree_change()
+{
+ WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
+}
+
+void AssetCatalogTreeView::notify_catalog_assignments_change()
+{
+ WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST, nullptr);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item)
+ : BasicTreeViewItem(catalog_item->get_name()), catalog_item_(*catalog_item)
+{
+}
+
+void AssetCatalogTreeViewItem::on_activate()
+{
+ AssetCatalogTreeView &tree_view = static_cast(get_tree_view());
+ tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
+void AssetCatalogTreeViewItem::build_row(uiLayout &row)
+{
+ const std::string label_override = catalog_item_.has_unsaved_changes() ? (label_ + "*") : label_;
+ add_label(row, label_override);
+
+ if (!is_hovered()) {
+ return;
+ }
+
+ uiButViewItem *item_but = view_item_button();
+ PointerRNA *props;
+
+ props = UI_but_extra_operator_icon_add(
+ (uiBut *)item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
+}
+
+void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column) const
+{
+ PointerRNA props;
+
+ uiItemFullO(&column,
+ "ASSET_OT_catalog_new",
+ "New Catalog",
+ ICON_NONE,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "parent_path", catalog_item_.catalog_path().c_str());
+
+ char catalog_id_str_buffer[UUID_STRING_LEN] = "";
+ BLI_uuid_format(catalog_id_str_buffer, catalog_item_.get_catalog_id());
+ uiItemFullO(&column,
+ "ASSET_OT_catalog_delete",
+ "Delete Catalog",
+ ICON_NONE,
+ nullptr,
+ WM_OP_INVOKE_DEFAULT,
+ 0,
+ &props);
+ RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
+ uiItemO(&column, "Rename", ICON_NONE, "UI_OT_view_item_rename");
+
+ /* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
+ * in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
+ * catalog to the menu draw callback (via context probably). */
+ MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true);
+ if (!mt) {
+ return;
+ }
+ UI_menutype_draw(&C, mt, &column);
+}
+
+bool AssetCatalogTreeViewItem::supports_renaming() const
+{
+ const AssetCatalogTreeView &tree_view = static_cast(
+ get_tree_view());
+ return !ED_asset_catalogs_read_only(*tree_view.asset_library_);
+}
+
+bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
+{
+ /* Important to keep state. */
+ BasicTreeViewItem::rename(new_name);
+
+ const AssetCatalogTreeView &tree_view = static_cast(
+ get_tree_view());
+ ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
+ return true;
+}
+
+std::unique_ptr AssetCatalogTreeViewItem::create_drop_target()
+{
+ return std::make_unique(
+ static_cast(get_tree_view()), catalog_item_);
+}
+
+std::unique_ptr AssetCatalogTreeViewItem::
+ create_drag_controller() const
+{
+ return std::make_unique(
+ static_cast(get_tree_view()), catalog_item_);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDropTarget::AssetCatalogDropTarget(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractViewItemDropTarget(tree_view), catalog_item_(catalog_item)
+{
+}
+
+bool AssetCatalogDropTarget::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ const ::AssetLibrary &library = get_asset_library();
+ if (!can_modify_catalogs(library, r_disabled_hint)) {
+ return false;
+ }
+
+ const AssetCatalog *drag_catalog = get_drag_catalog(drag, library);
+ /* NOTE: Technically it's not an issue to allow this (the catalog will just receive a new
+ * path and the catalog system will generate missing parents from the path). But it does
+ * appear broken to users, so disabling entirely. */
+ if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) {
+ *r_disabled_hint = "Catalog cannot be dropped into itself";
+ return false;
+ }
+ if (catalog_item_.catalog_path() == drag_catalog->path.parent()) {
+ *r_disabled_hint = "Catalog is already placed inside this catalog";
+ return false;
+ }
+ return true;
+ }
+ if (drag.type == WM_DRAG_ASSET_LIST) {
+ return has_droppable_asset(drag, r_disabled_hint);
+ }
+ return false;
+}
+
+std::string AssetCatalogDropTarget::drop_tooltip(const wmDrag &drag) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_tooltip_asset_catalog(drag);
+ }
+ return drop_tooltip_asset_list(drag);
+}
+
+std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
+
+ return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " +
+ TIP_("into") + " '" + catalog_item_.get_name() + "'";
+}
+
+std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
+
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
+
+ /* Don't try to be smart by dynamically adding the 's' for the plural. Just makes translation
+ * harder, so use full literals. */
+ std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") :
+ TIP_("Move asset to catalog");
+
+ basic_tip += ": " + catalog_item_.get_name();
+
+ /* Display the full catalog path, but only if it's not exactly the same as the already shown name
+ * (i.e. not a root level catalog with no parent). */
+ if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
+ basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
+ }
+
+ return basic_tip;
+}
+
+bool AssetCatalogDropTarget::on_drop(struct bContext *C, const wmDrag &drag) const
+{
+ if (drag.type == WM_DRAG_ASSET_CATALOG) {
+ return drop_asset_catalog_into_catalog(
+ drag, get_view(), catalog_item_.get_catalog_id());
+ }
+ return drop_assets_into_catalog(C,
+ get_view(),
+ drag,
+ catalog_item_.get_catalog_id(),
+ catalog_item_.get_simple_name());
+}
+
+bool AssetCatalogDropTarget::drop_asset_catalog_into_catalog(
+ const wmDrag &drag,
+ AssetCatalogTreeView &tree_view,
+ const std::optional drop_catalog_id)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+ ED_asset_catalog_move(tree_view.asset_library_, catalog_drag->drag_catalog_id, drop_catalog_id);
+ tree_view.activate_catalog_by_id(catalog_drag->drag_catalog_id);
+
+ tree_view.notify_catalog_tree_change();
+
+ return true;
+}
+
+bool AssetCatalogDropTarget::drop_assets_into_catalog(struct bContext *C,
+ AssetCatalogTreeView &tree_view,
+ const wmDrag &drag,
+ CatalogID catalog_id,
+ StringRefNull simple_name)
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ if (!asset_drags) {
+ return false;
+ }
+
+ bool did_update = false;
+ LISTBASE_FOREACH (wmDragAssetListItem *, asset_item, asset_drags) {
+ if (asset_item->is_external) {
+ /* Only internal assets can be modified! */
+ continue;
+ }
+
+ did_update = true;
+ BKE_asset_metadata_catalog_id_set(
+ asset_item->asset_data.local_id->asset_data, catalog_id, simple_name.c_str());
+
+ /* TODO */
+ /* Trigger re-run of filtering to update visible assets. */
+ // filelist_tag_needs_filtering(tree_view.space_file_.files);
+ // file_select_deselect_all(&tree_view.space_file_, FILE_SEL_SELECTED |
+ // FILE_SEL_HIGHLIGHTED);
+ }
+
+ if (did_update) {
+ tree_view.notify_catalog_assignments_change();
+ ED_undo_push(C, "Assign Asset Catalog");
+ }
+ return true;
+}
+
+AssetCatalog *AssetCatalogDropTarget::get_drag_catalog(const wmDrag &drag,
+ const ::AssetLibrary &asset_library)
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return nullptr;
+ }
+ const asset_system::AssetCatalogService *catalog_service = AS_asset_library_get_catalog_service(
+ &asset_library);
+ const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
+
+ return catalog_service->find_catalog(catalog_drag->drag_catalog_id);
+}
+
+bool AssetCatalogDropTarget::has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint)
+{
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+
+ *r_disabled_hint = nullptr;
+ /* There needs to be at least one asset from the current file. */
+ LISTBASE_FOREACH (const wmDragAssetListItem *, asset_item, asset_drags) {
+ if (!asset_item->is_external) {
+ return true;
+ }
+ }
+
+ *r_disabled_hint = TIP_("Only assets from this current file can be moved between catalogs");
+ return false;
+}
+
+bool AssetCatalogDropTarget::can_modify_catalogs(const ::AssetLibrary &library,
+ const char **r_disabled_hint)
+{
+ if (ED_asset_catalogs_read_only(library)) {
+ *r_disabled_hint = "Catalogs cannot be edited in this asset library";
+ return false;
+ }
+ return true;
+}
+
+::AssetLibrary &AssetCatalogDropTarget::get_asset_library() const
+{
+ return *get_view().asset_library_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
+ AssetCatalogTreeItem &catalog_item)
+ : ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
+{
+}
+
+int AssetCatalogDragController::get_drag_type() const
+{
+ return WM_DRAG_ASSET_CATALOG;
+}
+
+void *AssetCatalogDragController::create_drag_data() const
+{
+ wmDragAssetCatalog *drag_catalog = (wmDragAssetCatalog *)MEM_callocN(sizeof(*drag_catalog),
+ __func__);
+ drag_catalog->drag_catalog_id = catalog_item_.get_catalog_id();
+ return drag_catalog;
+}
+
+void AssetCatalogDragController::on_drag_start()
+{
+ AssetCatalogTreeView &tree_view_ = get_view();
+ tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
+}
+
+/* ---------------------------------------------------------------------- */
+
+void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
+{
+ ui::BasicTreeViewItem::build_row(row);
+
+ PointerRNA *props;
+
+ UI_but_extra_operator_icon_add(
+ (uiBut *)view_item_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
+
+ props = UI_but_extra_operator_icon_add(
+ (uiBut *)view_item_button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ /* No parent path to use the root level. */
+ RNA_string_set(props, "parent_path", nullptr);
+}
+
+std::unique_ptr AssetCatalogTreeViewAllItem::create_drop_target()
+{
+ return std::make_unique(
+ static_cast(get_tree_view()));
+}
+
+AssetCatalogTreeViewAllItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view)
+ : ui::AbstractViewItemDropTarget(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewAllItem::DropTarget::can_drop(const wmDrag &drag,
+ const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_CATALOG) {
+ return false;
+ }
+ ::AssetLibrary &library = *get_view().asset_library_;
+ if (!AssetCatalogDropTarget::can_modify_catalogs(library, r_disabled_hint)) {
+ return false;
+ }
+
+ const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(drag, library);
+ if (drag_catalog->path.parent() == "") {
+ *r_disabled_hint = "Catalog is already placed at the highest level";
+ return false;
+ }
+
+ return true;
+}
+
+std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(
+ drag, *get_view().asset_library_);
+
+ return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
+ TIP_("to the top level of the tree");
+}
+
+bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(struct bContext * /*C*/,
+ const wmDrag &drag) const
+{
+ BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
+ return AssetCatalogDropTarget::drop_asset_catalog_into_catalog(
+ drag,
+ get_view(),
+ /* No value to drop into the root level. */
+ std::nullopt);
+}
+
+/* ---------------------------------------------------------------------- */
+
+std::unique_ptr AssetCatalogTreeViewUnassignedItem::
+ create_drop_target()
+{
+ return std::make_unique(
+ static_cast(get_tree_view()));
+}
+
+AssetCatalogTreeViewUnassignedItem::DropTarget::DropTarget(AssetCatalogTreeView &tree_view)
+ : ui::AbstractViewItemDropTarget(tree_view)
+{
+}
+
+bool AssetCatalogTreeViewUnassignedItem::DropTarget::can_drop(const wmDrag &drag,
+ const char **r_disabled_hint) const
+{
+ if (drag.type != WM_DRAG_ASSET_LIST) {
+ return false;
+ }
+ return AssetCatalogDropTarget::has_droppable_asset(drag, r_disabled_hint);
+}
+
+std::string AssetCatalogTreeViewUnassignedItem::DropTarget::drop_tooltip(const wmDrag &drag) const
+{
+ const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
+ const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
+
+ return is_multiple_assets ? TIP_("Move assets out of any catalog") :
+ TIP_("Move asset out of any catalog");
+}
+
+bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(struct bContext *C,
+ const wmDrag &drag) const
+{
+ /* Assign to nil catalog ID. */
+ return AssetCatalogDropTarget::drop_assets_into_catalog(
+ C, get_view(), drag, CatalogID{});
+}
+
+} // namespace blender::ed::asset_browser
+
+/* ---------------------------------------------------------------------- */
+
+void asset_view_create_catalog_tree_view_in_layout(::AssetLibrary *asset_library,
+ uiLayout *layout,
+ PointerRNA *catalog_filter_owner_ptr,
+ PropertyRNA *catalog_filter_prop,
+ wmMsgBus *msg_bus)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+
+ UI_block_layout_set_current(block, layout);
+
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "asset catalog tree view",
+ std::make_unique(
+ asset_library, *catalog_filter_owner_ptr, *catalog_filter_prop, msg_bus));
+
+ ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
+}
diff --git a/source/blender/editors/space_assets/asset_view.cc b/source/blender/editors/space_assets/asset_view.cc
new file mode 100644
index 00000000000..e69af532a08
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_view.cc
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+#include "BKE_context.h"
+
+#include "DNA_asset_types.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+
+#include "ED_asset.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+
+#include "WM_message.h"
+
+#include "asset_view.hh"
+
+namespace blender::ed::asset_browser {
+
+AssetGridView::AssetGridView(const AssetLibraryReference &asset_library_ref,
+ const PointerRNA &active_asset_idx_owner_ptr,
+ PropertyRNA *active_asset_idx_prop,
+ wmMsgBus *msg_bus)
+ : asset_library_ref_(asset_library_ref),
+ active_asset_idx_owner_(active_asset_idx_owner_ptr),
+ active_asset_idx_prop_(*active_asset_idx_prop),
+ msg_bus_(*msg_bus)
+{
+}
+
+void AssetGridView::build_items()
+{
+ int idx = 0;
+ ED_assetlist_iterate(asset_library_ref_, [this, &idx](AssetHandle &asset) {
+ AssetGridViewItem &item = add_item(asset_library_ref_, asset);
+
+ item.set_is_active_fn([this, idx]() -> bool {
+ return idx == RNA_property_int_get(&active_asset_idx_owner_, &active_asset_idx_prop_);
+ });
+ item.set_on_activate_fn([this, idx](ui::PreviewGridItem & /*item*/) {
+ RNA_property_int_set(&active_asset_idx_owner_, &active_asset_idx_prop_, idx);
+ WM_msg_publish_rna(&msg_bus_, &active_asset_idx_owner_, &active_asset_idx_prop_);
+ });
+
+ idx++;
+ return true;
+ });
+}
+
+bool AssetGridView::listen(const wmNotifier ¬ifier) const
+{
+ return ED_assetlist_listen(&asset_library_ref_, ¬ifier);
+}
+
+/* ---------------------------------------------------------------------- */
+
+AssetGridViewItem::AssetGridViewItem(const AssetLibraryReference &asset_library_ref,
+ AssetHandle &asset)
+ : ui::PreviewGridItem(ED_asset_handle_get_identifier(&asset),
+ ED_asset_handle_get_name(&asset),
+ ED_assetlist_asset_preview_icon_id_request(&asset_library_ref, &asset)),
+ /* Get a copy so the identifier is always available (the file data wrapped by the handle may
+ * be freed). */
+ asset_identifier_(identifier_)
+{
+ /* Update reference so we don't point into the possibly freed file data. */
+ identifier_ = asset_identifier_;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void asset_view_create_in_layout(const bContext &C,
+ const AssetLibraryReference &asset_library_ref,
+ const AssetCatalogFilterSettings &catalog_filter_settings,
+ const PointerRNA &active_asset_idx_owner_ptr,
+ PropertyRNA *active_asset_idx_prop,
+ const View2D &v2d,
+ uiLayout &layout)
+{
+ uiBlock *block = uiLayoutGetBlock(&layout);
+ UI_block_layout_set_current(block, &layout);
+
+ ED_assetlist_storage_fetch(&asset_library_ref, &C);
+ ED_assetlist_catalog_filter_set(&asset_library_ref, &catalog_filter_settings);
+
+ ui::AbstractGridView *grid_view = UI_block_add_view(
+ *block,
+ "asset grid view",
+ std::make_unique(asset_library_ref,
+ active_asset_idx_owner_ptr,
+ active_asset_idx_prop,
+ CTX_wm_message_bus(&C)));
+
+ ui::GridViewBuilder builder(*block);
+ builder.build_grid_view(*grid_view, v2d, layout);
+}
+
+} // namespace blender::ed::asset_browser
diff --git a/source/blender/editors/space_assets/asset_view.hh b/source/blender/editors/space_assets/asset_view.hh
new file mode 100644
index 00000000000..20b405c350f
--- /dev/null
+++ b/source/blender/editors/space_assets/asset_view.hh
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#pragma once
+
+#include "DNA_asset_types.h"
+
+#include "UI_grid_view.hh"
+
+struct AssetCatalogFilterSettings;
+struct bContext;
+struct PointerRNA;
+struct PropertyRNA;
+struct uiLayout;
+struct View2D;
+struct wmMsgBus;
+
+namespace blender::ed::asset_browser {
+
+class AssetGridView : public blender::ui::AbstractGridView {
+ AssetLibraryReference asset_library_ref_;
+
+ /** Reference to bind the active asset of the editor to the view. */
+ PointerRNA active_asset_idx_owner_;
+ PropertyRNA &active_asset_idx_prop_;
+ wmMsgBus &msg_bus_;
+
+ public:
+ AssetGridView(const AssetLibraryReference &,
+ const PointerRNA &active_asset_idx_owner_ptr,
+ PropertyRNA *active_asset_idx_prop,
+ wmMsgBus *msg_bus);
+
+ void build_items() override;
+ bool listen(const wmNotifier &) const override;
+};
+
+class AssetGridViewItem : public ui::PreviewGridItem {
+ /* Can't store this here, since the wrapped FileDirEntry will be freed while progressively
+ * loading items. */
+ // AssetHandle &asset_;
+ std::string asset_identifier_;
+
+ public:
+ AssetGridViewItem(const AssetLibraryReference &asset_library_ref, AssetHandle &);
+};
+
+void asset_view_create_in_layout(const bContext &C,
+ const AssetLibraryReference &asset_library_ref,
+ const AssetCatalogFilterSettings &catalog_filter_settings,
+ const PointerRNA &active_asset_idx_owner_ptr,
+ PropertyRNA *active_asset_idx_prop,
+ const View2D &v2d,
+ uiLayout &layout);
+
+} // namespace blender::ed::asset_browser
diff --git a/source/blender/editors/space_assets/space_assets.cc b/source/blender/editors/space_assets/space_assets.cc
new file mode 100644
index 00000000000..67590d181de
--- /dev/null
+++ b/source/blender/editors/space_assets/space_assets.cc
@@ -0,0 +1,312 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup spassets
+ */
+
+#include
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_asset.h"
+#include "BKE_screen.h"
+
+#include "BLI_listbase.h"
+
+#include "ED_asset.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+
+#include "asset_browser_intern.hh"
+#include "asset_view.hh"
+
+/* ---------------------------------------------------------------------- */
+/* Asset Browser Space */
+
+static SpaceLink *asset_browser_create(const ScrArea * /*area*/, const Scene * /*scene*/)
+{
+ SpaceAssets *assets_space = MEM_cnew("asset browser space");
+ assets_space->spacetype = SPACE_ASSETS;
+
+ BKE_asset_library_reference_init_default(&assets_space->asset_library_ref);
+
+ {
+ /* Header. */
+ ARegion *region = MEM_cnew("asset browser header");
+ BLI_addtail(&assets_space->regionbase, region);
+ region->regiontype = RGN_TYPE_HEADER;
+ region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+ }
+
+ {
+ /* Navigation region */
+ ARegion *region = MEM_cnew("asset browser navigation region");
+
+ BLI_addtail(&assets_space->regionbase, region);
+ region->regiontype = RGN_TYPE_NAV_BAR;
+ region->alignment = RGN_ALIGN_LEFT;
+ }
+
+ {
+ /* Sidebar region */
+ ARegion *region = MEM_cnew("asset browser sidebar region");
+
+ BLI_addtail(&assets_space->regionbase, region);
+ region->regiontype = RGN_TYPE_UI;
+ region->alignment = RGN_ALIGN_RIGHT;
+ region->flag = RGN_FLAG_HIDDEN;
+ }
+
+ {
+ /* Main region. */
+ ARegion *region = MEM_cnew("asset browser main region");
+ BLI_addtail(&assets_space->regionbase, region);
+ region->regiontype = RGN_TYPE_WINDOW;
+
+ region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
+ region->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
+ region->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
+ region->v2d.keeptot = V2D_KEEPTOT_STRICT;
+ region->v2d.minzoom = region->v2d.maxzoom = 1.0f;
+ }
+
+ return (SpaceLink *)assets_space;
+}
+
+static void asset_browser_free(SpaceLink * /*sl*/) {}
+
+static void asset_browser_init(wmWindowManager * /*wm*/, ScrArea * /*area*/) {}
+
+static SpaceLink *asset_browser_duplicate(SpaceLink *sl)
+{
+ const SpaceAssets *asset_browser_old = (SpaceAssets *)sl;
+ SpaceAssets *asset_browser_new = reinterpret_cast(
+ MEM_dupallocN(asset_browser_old));
+
+ return (SpaceLink *)asset_browser_new;
+}
+
+static void asset_browser_keymap(wmKeyConfig *keyconf)
+{
+ /* keys for all regions */
+ WM_keymap_ensure(keyconf, "Asset Browser", SPACE_ASSETS, 0);
+}
+
+const char *asset_browser_context_dir[] = {
+ "asset_handle",
+ "asset_library_ref",
+ NULL,
+};
+
+static int /*eContextResult*/ asset_browser_context(const bContext *C,
+ const char *member,
+ bContextDataResult *result)
+{
+ if (CTX_data_dir(member)) {
+ CTX_data_dir_set(result, asset_browser_context_dir);
+ return CTX_RESULT_OK;
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ SpaceAssets *assets_space = CTX_wm_space_assets(C);
+
+ if (CTX_data_equals(member, "asset_library_ref")) {
+ CTX_data_pointer_set(
+ result, &screen->id, &RNA_AssetLibraryReference, &assets_space->asset_library_ref);
+ return CTX_RESULT_OK;
+ }
+
+ if (CTX_data_equals(member, "asset_handle")) {
+ AssetHandle *asset = ED_assetlist_asset_get_by_index(&assets_space->asset_library_ref,
+ assets_space->active_asset_idx);
+ if (!asset) {
+ return CTX_RESULT_NO_DATA;
+ }
+
+ CTX_data_pointer_set(result, &screen->id, &RNA_AssetHandle, asset);
+ return CTX_RESULT_OK;
+ }
+
+ return CTX_RESULT_MEMBER_NOT_FOUND;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Main Region */
+
+static void asset_browser_main_region_init(wmWindowManager *wm, ARegion *region)
+{
+ UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
+
+ {
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Asset Browser", SPACE_ASSETS, 0);
+ WM_event_add_keymap_handler(®ion->handlers, keymap);
+ }
+}
+
+static void asset_browser_main_region_listener(const wmRegionListenerParams *params)
+{
+ const wmNotifier *notifier = params->notifier;
+ ARegion *region = params->region;
+
+ switch (notifier->category) {
+ case NC_ASSET:
+ if (ELEM(notifier->data, ND_SPACE_ASSET_PARAMS)) {
+ ED_region_tag_redraw(region);
+ }
+ break;
+ }
+}
+
+static void asset_browser_main_region_message_subscribe(
+ const wmRegionMessageSubscribeParams *params)
+{
+ struct wmMsgBus *mbus = params->message_bus;
+ bScreen *screen = params->screen;
+ SpaceAssets *assets_space = reinterpret_cast(params->area->spacedata.first);
+
+ wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
+ msg_sub_value_region_tag_redraw.owner = params->region;
+ msg_sub_value_region_tag_redraw.user_data = params->region;
+ msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
+
+ WM_msg_subscribe_rna_prop(mbus,
+ &screen->id,
+ assets_space,
+ SpaceAssetBrowser,
+ catalog_filter,
+ &msg_sub_value_region_tag_redraw);
+}
+
+/* ---------------------------------------------------------------------- */
+/* Header Region */
+
+static void asset_browser_header_init(wmWindowManager * /*wm*/, ARegion *region)
+{
+ ED_region_header_init(region);
+}
+
+static void asset_browser_header_listener(const wmRegionListenerParams * /*params*/) {}
+
+/* ---------------------------------------------------------------------- */
+/* Navigation Region */
+
+static void asset_browser_navigation_region_init(wmWindowManager *wm, ARegion *region)
+{
+ region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+ ED_region_panels_init(wm, region);
+
+ {
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Asset Browser", SPACE_ASSETS, 0);
+ WM_event_add_keymap_handler(®ion->handlers, keymap);
+ }
+}
+
+static void asset_browser_navigation_region_draw(const bContext *C, ARegion *region)
+{
+ ED_region_panels(C, region);
+}
+
+static void asset_browser_navigation_region_listener(
+ const wmRegionListenerParams * /*listener_params*/)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+/* Sidebar Region */
+
+static void asset_browser_sidebar_region_init(wmWindowManager *wm, ARegion *region)
+{
+ region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+ ED_region_panels_init(wm, region);
+
+ {
+ wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Asset Browser", SPACE_ASSETS, 0);
+ WM_event_add_keymap_handler(®ion->handlers, keymap);
+ }
+}
+
+static void asset_browser_sidebar_region_draw(const bContext *C, ARegion *region)
+{
+ ED_region_panels(C, region);
+}
+
+static void asset_browser_sidebar_region_listener(
+ const wmRegionListenerParams * /*listener_params*/)
+{
+}
+
+/* ---------------------------------------------------------------------- */
+/* Asset Browser Space-Type */
+
+void ED_spacetype_assets(void)
+{
+ SpaceType *st = MEM_cnew("spacetype asset browser");
+ ARegionType *art;
+
+ st->spaceid = SPACE_ASSETS;
+ strncpy(st->name, "Asset Browser", BKE_ST_MAXNAME);
+
+ st->create = asset_browser_create;
+ st->free = asset_browser_free;
+ st->init = asset_browser_init;
+ st->duplicate = asset_browser_duplicate;
+ st->operatortypes = asset_browser_operatortypes;
+ st->keymap = asset_browser_keymap;
+ st->context = asset_browser_context;
+
+ /* Main region. */
+ art = MEM_cnew("spacetype asset browser main region");
+ art->regionid = RGN_TYPE_WINDOW;
+ art->init = asset_browser_main_region_init;
+ art->draw = asset_browser_main_region_draw;
+ art->listener = asset_browser_main_region_listener;
+ art->message_subscribe = asset_browser_main_region_message_subscribe;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* Header region. */
+ art = MEM_cnew("spacetype asset browser header region");
+ art->regionid = RGN_TYPE_HEADER;
+ art->prefsizey = HEADERY;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+ art->listener = asset_browser_header_listener;
+ art->init = asset_browser_header_init;
+ art->layout = ED_region_header_layout;
+ art->draw = ED_region_header_draw;
+ BLI_addhead(&st->regiontypes, art);
+
+ /* Navigation region */
+ art = MEM_cnew("spacetype asset browser navigation region");
+ art->regionid = RGN_TYPE_NAV_BAR;
+ art->prefsizex = 240;
+ art->init = asset_browser_navigation_region_init;
+ art->draw = asset_browser_navigation_region_draw;
+ art->listener = asset_browser_navigation_region_listener;
+ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_NAVBAR;
+ asset_browser_navigation_region_panels_register(art);
+ BLI_addhead(&st->regiontypes, art);
+
+ /* Sidebar region */
+ art = MEM_cnew("spacetype asset browser sidebar region");
+ art->regionid = RGN_TYPE_UI;
+ art->prefsizex = 240;
+ art->init = asset_browser_sidebar_region_init;
+ art->draw = asset_browser_sidebar_region_draw;
+ art->listener = asset_browser_sidebar_region_listener;
+ art->keymapflag = ED_KEYMAP_UI;
+ BLI_addhead(&st->regiontypes, art);
+
+ BKE_spacetype_register(st);
+}
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 052c6b22332..febef8442a3 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -37,7 +37,7 @@
using namespace blender;
using namespace blender::asset_system;
-namespace blender::ed::asset_browser {
+namespace blender::ed::space_file::asset_browser {
class AssetCatalogTreeViewAllItem;
@@ -218,11 +218,11 @@ AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
AssetCatalogTreeViewAllItem &item = add_tree_item(IFACE_("All"));
item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
- params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
+ params->asset_catalog_visibility = ASSET_CATALOG_SHOW_ALL_ASSETS;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
item.set_is_active_fn(
- [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
+ [params]() { return params->asset_catalog_visibility == ASSET_CATALOG_SHOW_ALL_ASSETS; });
return item;
}
@@ -234,23 +234,24 @@ void AssetCatalogTreeView::add_unassigned_item()
IFACE_("Unassigned"), ICON_FILE_HIDDEN);
item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) {
- params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
+ params->asset_catalog_visibility = ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
- item.set_is_active_fn(
- [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
+ item.set_is_active_fn([params]() {
+ return params->asset_catalog_visibility == ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG;
+ });
}
void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
{
- params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params_->asset_catalog_visibility = ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG;
params_->catalog_id = catalog_id;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
}
bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
{
- return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
+ return (params_->asset_catalog_visibility == ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG) &&
(params_->catalog_id == catalog_id);
}
@@ -670,98 +671,11 @@ bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(struct bContext *C,
C, get_view(), drag, CatalogID{});
}
-} // namespace blender::ed::asset_browser
+} // namespace blender::ed::space_file::asset_browser
/* ---------------------------------------------------------------------- */
-namespace blender::ed::asset_browser {
-
-class AssetCatalogFilterSettings {
- public:
- eFileSel_Params_AssetCatalogVisibility asset_catalog_visibility;
- bUUID asset_catalog_id;
-
- std::unique_ptr catalog_filter;
-};
-
-} // namespace blender::ed::asset_browser
-
-using namespace blender::ed::asset_browser;
-
-FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings()
-{
- AssetCatalogFilterSettings *filter_settings = MEM_new(__func__);
- return reinterpret_cast(filter_settings);
-}
-
-void file_delete_asset_catalog_filter_settings(
- FileAssetCatalogFilterSettingsHandle **filter_settings_handle)
-{
- AssetCatalogFilterSettings **filter_settings = reinterpret_cast(
- filter_settings_handle);
- MEM_delete(*filter_settings);
- *filter_settings = nullptr;
-}
-
-bool file_set_asset_catalog_filter_settings(
- FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- eFileSel_Params_AssetCatalogVisibility catalog_visibility,
- ::bUUID catalog_id)
-{
- AssetCatalogFilterSettings *filter_settings = reinterpret_cast(
- filter_settings_handle);
- bool needs_update = false;
-
- if (filter_settings->asset_catalog_visibility != catalog_visibility) {
- filter_settings->asset_catalog_visibility = catalog_visibility;
- needs_update = true;
- }
-
- if (filter_settings->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG &&
- !BLI_uuid_equal(filter_settings->asset_catalog_id, catalog_id)) {
- filter_settings->asset_catalog_id = catalog_id;
- needs_update = true;
- }
-
- return needs_update;
-}
-
-void file_ensure_updated_catalog_filter_data(
- FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const asset_system::AssetLibrary *asset_library)
-{
- AssetCatalogFilterSettings *filter_settings = reinterpret_cast(
- filter_settings_handle);
- const AssetCatalogService *catalog_service = asset_library->catalog_service.get();
-
- if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) {
- filter_settings->catalog_filter = std::make_unique(
- catalog_service->create_catalog_filter(filter_settings->asset_catalog_id));
- }
-}
-
-bool file_is_asset_visible_in_catalog_filter_settings(
- const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const AssetMetaData *asset_data)
-{
- const AssetCatalogFilterSettings *filter_settings =
- reinterpret_cast(filter_settings_handle);
-
- switch (filter_settings->asset_catalog_visibility) {
- case FILE_SHOW_ASSETS_WITHOUT_CATALOG:
- return !filter_settings->catalog_filter->is_known(asset_data->catalog_id);
- case FILE_SHOW_ASSETS_FROM_CATALOG:
- return filter_settings->catalog_filter->contains(asset_data->catalog_id);
- case FILE_SHOW_ASSETS_ALL_CATALOGS:
- /* All asset files should be visible. */
- return true;
- }
-
- BLI_assert_unreachable();
- return false;
-}
-
-/* ---------------------------------------------------------------------- */
+namespace asset_browser = blender::ed::space_file::asset_browser;
void file_create_asset_catalog_tree_view_in_layout(::AssetLibrary *asset_library,
uiLayout *layout,
@@ -775,8 +689,7 @@ void file_create_asset_catalog_tree_view_in_layout(::AssetLibrary *asset_library
ui::AbstractTreeView *tree_view = UI_block_add_view(
*block,
"asset catalog tree view",
- std::make_unique(
- asset_library, params, *space_file));
+ std::make_unique(asset_library, params, *space_file));
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 6fcc804443f..06056c8415a 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -215,39 +215,10 @@ void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* asset_catalog_tree_view.cc */
-/* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */
-typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle;
-
void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
struct uiLayout *layout,
- SpaceFile *space_file,
- FileAssetSelectParams *params);
-
-#ifdef __cplusplus
-
-namespace blender::asset_system {
-class AssetLibrary;
-}
-
-FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings(void);
-void file_delete_asset_catalog_filter_settings(
- FileAssetCatalogFilterSettingsHandle **filter_settings_handle);
-/**
- * \return True if the file list should update its filtered results
- * (e.g. because filtering parameters changed).
- */
-bool file_set_asset_catalog_filter_settings(
- FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- eFileSel_Params_AssetCatalogVisibility catalog_visibility,
- bUUID catalog_id);
-void file_ensure_updated_catalog_filter_data(
- FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const blender::asset_system::AssetLibrary *asset_library);
-bool file_is_asset_visible_in_catalog_filter_settings(
- const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
- const AssetMetaData *asset_data);
-
-#endif
+ struct SpaceFile *space_file,
+ struct FileAssetSelectParams *params);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc
index f077b0d54ef..c625559f030 100644
--- a/source/blender/editors/space_file/filelist.cc
+++ b/source/blender/editors/space_file/filelist.cc
@@ -61,6 +61,7 @@
#include "DNA_asset_types.h"
#include "DNA_space_types.h"
+#include "ED_asset_view_catalog_filter.h"
#include "ED_datafiles.h"
#include "ED_fileselect.h"
#include "ED_screen.h"
@@ -197,7 +198,7 @@ struct FileListFilter {
char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
short flags;
- FileAssetCatalogFilterSettingsHandle *asset_catalog_filter;
+ AssetViewCatalogFilterSettingsHandle *asset_catalog_filter;
};
/** #FileListFilter.flags */
@@ -805,7 +806,8 @@ static void prepare_filter_asset_library(const FileList *filelist, FileListFilte
"prepare_filter_asset_library() should only be called when the file browser is "
"in asset browser mode");
- file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library);
+ asset_view_ensure_updated_catalog_filter_data(
+ filter->asset_catalog_filter, reinterpret_cast<::AssetLibrary *>(filelist->asset_library));
}
/**
@@ -835,7 +837,7 @@ static bool is_filtered_asset(FileListInternEntry *file, FileListFilter *filter)
const AssetMetaData *asset_data = filelist_file_internal_get_asset_data(file);
/* Not used yet for the asset view template. */
- if (filter->asset_catalog_filter && !file_is_asset_visible_in_catalog_filter_settings(
+ if (filter->asset_catalog_filter && !asset_view_is_asset_visible_in_catalog_filter_settings(
filter->asset_catalog_filter, asset_data)) {
return false;
}
@@ -1024,17 +1026,16 @@ void filelist_setindexer(FileList *filelist, const FileIndexerType *indexer)
filelist->indexer = indexer;
}
-void filelist_set_asset_catalog_filter_options(
- FileList *filelist,
- eFileSel_Params_AssetCatalogVisibility catalog_visibility,
- const ::bUUID *catalog_id)
+void filelist_set_asset_catalog_filter_options(FileList *filelist,
+ AssetCatalogFilterMode catalog_visibility,
+ const ::bUUID *catalog_id)
{
if (!filelist->filter_data.asset_catalog_filter) {
/* There's no filter data yet. */
- filelist->filter_data.asset_catalog_filter = file_create_asset_catalog_filter_settings();
+ filelist->filter_data.asset_catalog_filter = asset_view_create_catalog_filter_settings();
}
- const bool needs_update = file_set_asset_catalog_filter_settings(
+ const bool needs_update = asset_view_set_catalog_filter_settings(
filelist->filter_data.asset_catalog_filter, catalog_visibility, *catalog_id);
if (needs_update) {
@@ -1468,6 +1469,26 @@ static int filelist_intern_free_main_files(FileList *filelist)
return removed_counter;
}
+int filelist_preview_source_get(int /* eFileSel_File_Types */ file_type)
+{
+ if (file_type & FILE_TYPE_IMAGE) {
+ return THB_SOURCE_IMAGE;
+ }
+ else if (file_type & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
+ return THB_SOURCE_BLEND;
+ }
+ else if (file_type & FILE_TYPE_MOVIE) {
+ return THB_SOURCE_MOVIE;
+ }
+ else if (file_type & FILE_TYPE_FTFONT) {
+ return THB_SOURCE_FONT;
+ }
+ else {
+ BLI_assert_unreachable();
+ return 0;
+ }
+}
+
static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
FileListEntryCache *cache = static_cast(BLI_task_pool_user_data(pool));
@@ -1475,30 +1496,11 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
taskdata);
FileListEntryPreview *preview = preview_taskdata->preview;
- /* XXX #THB_SOURCE_IMAGE for "historic" reasons. The case of an undefined source should be
- * handled better. */
- ThumbSource source = THB_SOURCE_IMAGE;
+ ThumbSource source = static_cast(filelist_preview_source_get(preview->flags));
// printf("%s: Start (%d)...\n", __func__, threadid);
// printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img);
- BLI_assert(preview->flags &
- (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER |
- FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB));
-
- if (preview->flags & FILE_TYPE_IMAGE) {
- source = THB_SOURCE_IMAGE;
- }
- else if (preview->flags &
- (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB)) {
- source = THB_SOURCE_BLEND;
- }
- else if (preview->flags & FILE_TYPE_MOVIE) {
- source = THB_SOURCE_MOVIE;
- }
- else if (preview->flags & FILE_TYPE_FTFONT) {
- source = THB_SOURCE_FONT;
- }
IMB_thumb_path_lock(preview->filepath);
/* Always generate biggest preview size for now, it's simpler and avoids having to re-generate
@@ -1803,7 +1805,7 @@ static void filelist_clear_asset_library(FileList *filelist)
{
/* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */
filelist->asset_library = nullptr;
- file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
+ asset_view_delete_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter);
}
void filelist_clear_ex(FileList *filelist,
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index f42496aa99c..8142ae28cc4 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -55,12 +55,11 @@ void filelist_setfilter_options(struct FileList *filelist,
void filelist_setindexer(struct FileList *filelist, const struct FileIndexerType *indexer);
/**
* \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
- * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
+ * #ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
*/
-void filelist_set_asset_catalog_filter_options(
- struct FileList *filelist,
- eFileSel_Params_AssetCatalogVisibility catalog_visibility,
- const struct bUUID *catalog_id);
+void filelist_set_asset_catalog_filter_options(struct FileList *filelist,
+ AssetCatalogFilterMode catalog_visibility,
+ const struct bUUID *catalog_id);
void filelist_tag_needs_filtering(struct FileList *filelist);
void filelist_filter(struct FileList *filelist);
/**
@@ -79,6 +78,7 @@ struct ImBuf *filelist_file_getimage(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file);
struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index);
int filelist_geticon(struct FileList *filelist, int index, bool is_main);
+int /* ThumbSource */ filelist_preview_source_get(int /* eFileSel_File_Types */ file_type);
struct FileList *filelist_new(short type);
void filelist_settype(struct FileList *filelist, short type);
diff --git a/source/blender/editors/space_file/filesel.cc b/source/blender/editors/space_file/filesel.cc
index ff0e714ebcf..e8b1614ab70 100644
--- a/source/blender/editors/space_file/filesel.cc
+++ b/source/blender/editors/space_file/filesel.cc
@@ -501,7 +501,7 @@ void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID ca
}
FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile);
- params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params->asset_catalog_visibility = ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG;
params->catalog_id = catalog_id;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
}
diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc
index a66d7df93fc..7b11365d4c1 100644
--- a/source/blender/editors/space_node/add_menu_assets.cc
+++ b/source/blender/editors/space_node/add_menu_assets.cc
@@ -112,7 +112,6 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node
const AssetLibraryReference all_library_ref = all_library_reference();
ED_assetlist_storage_fetch(&all_library_ref, &C);
- ED_assetlist_ensure_previews_job(&all_library_ref, &C);
asset_system::AssetLibrary *all_library = get_all_library_once_available();
if (!all_library) {
diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc
index c0ba8cd998e..8ce3fc02ae9 100644
--- a/source/blender/editors/space_node/add_node_search.cc
+++ b/source/blender/editors/space_node/add_node_search.cc
@@ -106,7 +106,6 @@ static void gather_search_items_for_all_assets(const bContext &C,
filter_settings.id_types = FILTER_ID_NT;
ED_assetlist_storage_fetch(&library_ref, &C);
- ED_assetlist_ensure_previews_job(&library_ref, &C);
ED_assetlist_iterate(library_ref, [&](AssetHandle asset) {
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
return true;
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index ae0261a57b9..74558035c4f 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -229,7 +229,6 @@ static void gather_search_link_ops_for_asset_library(const bContext &C,
filter_settings.id_types = FILTER_ID_NT;
ED_assetlist_storage_fetch(&library_ref, &C);
- ED_assetlist_ensure_previews_job(&library_ref, &C);
ED_assetlist_iterate(library_ref, [&](AssetHandle asset) {
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
return true;
diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h
index f984dedaefa..da8c850501a 100644
--- a/source/blender/makesdna/DNA_asset_types.h
+++ b/source/blender/makesdna/DNA_asset_types.h
@@ -201,6 +201,7 @@ typedef struct AssetWeakReference {
#
typedef struct AssetHandle {
const struct FileDirEntry *file_data;
+ struct PreviewImage *preview;
} AssetHandle;
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 2bdb3f09583..5ab9f81b327 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -830,10 +830,10 @@ typedef struct FileAssetSelectParams {
FileSelectParams base_params;
AssetLibraryReference asset_library_ref;
- short asset_catalog_visibility; /* eFileSel_Params_AssetCatalogVisibility */
+ short asset_catalog_visibility; /* AssetCatalogFilterMode */
char _pad[6];
- /** If #asset_catalog_visibility is #FILE_SHOW_ASSETS_FROM_CATALOG, this sets the ID of the
- * catalog to show. */
+ /** If #asset_catalog_visibility is #ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG, this sets the ID of
+ * the catalog to show. */
bUUID catalog_id;
short import_type; /* eFileAssetImportType */
@@ -1040,12 +1040,6 @@ typedef enum eFileSel_Params_Flag {
} eFileSel_Params_Flag;
ENUM_OPERATORS(eFileSel_Params_Flag, FILE_FILTER_ASSET_CATALOG);
-typedef enum eFileSel_Params_AssetCatalogVisibility {
- FILE_SHOW_ASSETS_ALL_CATALOGS,
- FILE_SHOW_ASSETS_FROM_CATALOG,
- FILE_SHOW_ASSETS_WITHOUT_CATALOG,
-} eFileSel_Params_AssetCatalogVisibility;
-
/**
* #FileSelectParams.rename_flag / `sfile->params->rename_flag`.
* \note short flag. Defined as bit-flags, but currently only used as exclusive status markers.
@@ -2036,6 +2030,42 @@ typedef enum eSpreadsheetColumnValueType {
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Asset Browser
+ * \{ */
+
+typedef enum AssetCatalogFilterMode {
+ ASSET_CATALOG_SHOW_ALL_ASSETS,
+ ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG,
+ ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG,
+} AssetCatalogFilterMode;
+
+typedef struct AssetCatalogFilterSettings {
+ short filter_mode; /* AssetCatalogFilterMode */
+ char _pad[6];
+ /** If #visibility_mode is #ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG, this sets the ID of the
+ * catalog to show. */
+ bUUID active_catalog_id;
+} AssetCatalogFilterSettings;
+
+typedef struct SpaceAssets {
+ SpaceLink *next, *prev;
+ /** Storage of regions for inactive spaces. */
+ ListBase regionbase;
+ char spacetype;
+ char link_flag;
+ char _pad0[6];
+ /* End 'SpaceLink' header. */
+
+ AssetLibraryReference asset_library_ref;
+ AssetCatalogFilterSettings catalog_filter;
+ /** For now store active asset as index. In future, this could store an #AssetIdentifier. */
+ int active_asset_idx;
+ char _pad1[4];
+} SpaceAssets;
+
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Space Defines (eSpace_Type)
* \{ */
@@ -2075,9 +2105,10 @@ typedef enum eSpace_Type {
SPACE_CLIP = 20,
SPACE_TOPBAR = 21,
SPACE_STATUSBAR = 22,
- SPACE_SPREADSHEET = 23
+ SPACE_SPREADSHEET = 23,
+ SPACE_ASSETS = 24
-#define SPACE_TYPE_NUM (SPACE_SPREADSHEET + 1)
+#define SPACE_TYPE_NUM (SPACE_ASSETS + 1)
} eSpace_Type;
/* use for function args */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 1d8cb6f7baa..563e6729d5c 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -507,6 +507,7 @@ typedef struct bTheme {
ThemeSpace space_topbar;
ThemeSpace space_statusbar;
ThemeSpace space_spreadsheet;
+ ThemeSpace space_assets;
/* 20 sets of bone colors for this theme */
ThemeWireColor tarm[20];
@@ -524,7 +525,7 @@ typedef struct bTheme {
#define UI_THEMESPACE_START(btheme) \
(CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties))
#define UI_THEMESPACE_END(btheme) \
- (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1))
+ (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_assets) + 1))
typedef struct bAddon {
struct bAddon *next, *prev;
diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c
index b88322e7c25..99e10d419d0 100644
--- a/source/blender/makesrna/intern/rna_asset.c
+++ b/source/blender/makesrna/intern/rna_asset.c
@@ -73,13 +73,17 @@ static int rna_AssetTag_editable(PointerRNA *ptr, const char **r_info)
{
AssetTag *asset_tag = ptr->data;
ID *owner_id = ptr->owner_id;
- if (owner_id && owner_id->asset_data) {
+ if (!owner_id) {
+ return 0;
+ }
+
+ if (owner_id->asset_data) {
BLI_assert_msg(BLI_findindex(&owner_id->asset_data->tags, asset_tag) != -1,
"The owner of the asset tag pointer is not the asset ID containing the tag");
UNUSED_VARS_NDEBUG(asset_tag);
}
- return rna_AssetMetaData_editable_from_owner_id(ptr->owner_id, owner_id->asset_data, r_info) ?
+ return rna_AssetMetaData_editable_from_owner_id(owner_id, owner_id->asset_data, r_info) ?
PROP_EDITABLE :
0;
}
diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c
index e723be2ab71..4aadc3a8bfe 100644
--- a/source/blender/makesrna/intern/rna_context.c
+++ b/source/blender/makesrna/intern/rna_context.c
@@ -140,6 +140,14 @@ static PointerRNA rna_Context_asset_file_handle_get(PointerRNA *ptr)
return newptr;
}
+static PointerRNA rna_Context_asset_handle_get(PointerRNA *ptr)
+{
+ bContext *C = (bContext *)ptr->data;
+ PointerRNA newptr;
+ RNA_pointer_create(NULL, &RNA_AssetHandle, CTX_wm_asset_handle_ptr(C), &newptr);
+ return newptr;
+}
+
static PointerRNA rna_Context_main_get(PointerRNA *ptr)
{
bContext *C = (bContext *)ptr->data;
@@ -298,6 +306,11 @@ void RNA_def_context(BlenderRNA *brna)
"The file of an active asset. Avoid using this, it will be replaced by "
"a proper AssetHandle design");
+ prop = RNA_def_property(srna, "asset_handle", PROP_POINTER, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_struct_type(prop, "AssetHandle");
+ RNA_def_property_pointer_funcs(prop, "rna_Context_asset_handle_get", NULL, NULL, NULL);
+
/* Data */
prop = RNA_def_property(srna, "blend_data", PROP_POINTER, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 282a447f67d..57cd1e81558 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -165,6 +165,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
ICON_PROPERTIES,
"Properties",
"Edit properties of active object and related data-blocks"},
+ {SPACE_ASSETS,
+ "ASSET_BROWSER",
+ ICON_ASSET_MANAGER,
+ "Asset Browser",
+ "Browse in asset libraries"},
{SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"},
{SPACE_SPREADSHEET,
"SPREADSHEET",
@@ -617,6 +622,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr)
return &RNA_SpaceClipEditor;
case SPACE_SPREADSHEET:
return &RNA_SpaceSpreadsheet;
+ case SPACE_ASSETS:
+ return &RNA_SpaceAssetBrowser;
/* Currently no type info. */
case SPACE_SCRIPT:
@@ -859,6 +866,20 @@ static void rna_Space_show_region_hud_update(bContext *C, PointerRNA *ptr)
rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_HUD, RGN_FLAG_HIDDEN_BY_USER);
}
+/* Navigation Region. */
+static bool rna_Space_show_region_nav_bar_get(PointerRNA *ptr)
+{
+ return !rna_Space_bool_from_region_flag_get_by_type(ptr, RGN_TYPE_NAV_BAR, RGN_FLAG_HIDDEN);
+}
+static void rna_Space_show_region_nav_bar_set(PointerRNA *ptr, bool value)
+{
+ rna_Space_bool_from_region_flag_set_by_type(ptr, RGN_TYPE_NAV_BAR, RGN_FLAG_HIDDEN, !value);
+}
+static void rna_Space_show_region_nav_bar_update(bContext *C, PointerRNA *ptr)
+{
+ rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_NAV_BAR, RGN_FLAG_HIDDEN);
+}
+
/** \} */
static bool rna_Space_view2d_sync_get(PointerRNA *ptr)
@@ -3352,7 +3373,7 @@ static void rna_FileAssetSelectParams_catalog_id_set(PointerRNA *ptr, const char
if (value[0] == '\0') {
params->catalog_id = BLI_uuid_nil();
- params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
+ params->asset_catalog_visibility = ASSET_CATALOG_SHOW_ALL_ASSETS;
return;
}
@@ -3363,7 +3384,30 @@ static void rna_FileAssetSelectParams_catalog_id_set(PointerRNA *ptr, const char
}
params->catalog_id = new_uuid;
- params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
+ params->asset_catalog_visibility = ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG;
+}
+
+static int RNA_SpaceAssetBrowser_asset_library_get(PointerRNA *ptr)
+{
+ SpaceAssets *asset_space = ptr->data;
+ return ED_asset_library_reference_to_enum_value(&asset_space->asset_library_ref);
+}
+
+static void RNA_SpaceAssetBrowser_asset_library_set(PointerRNA *ptr, int value)
+{
+ SpaceAssets *asset_space = ptr->data;
+ asset_space->asset_library_ref = ED_asset_library_reference_from_enum_value(value);
+}
+
+static void rna_AssetCatalogFilterSettings_active_catalog_id_get(PointerRNA *ptr, char *value)
+{
+ const AssetCatalogFilterSettings *settings = ptr->data;
+ BLI_uuid_format(value, settings->active_catalog_id);
+}
+
+static int rna_AssetCatalogFilterSettings_active_catalog_id_length(PointerRNA *UNUSED(ptr))
+{
+ return UUID_STRING_LEN - 1;
}
#else
@@ -3463,6 +3507,10 @@ static void rna_def_space_generic_show_region_toggles(StructRNA *srna, int regio
region_type_mask &= ~(1 << RGN_TYPE_HUD);
DEF_SHOW_REGION_PROPERTY(show_region_hud, "Adjust Last Operation", "");
}
+ if (region_type_mask & (1 << RGN_TYPE_NAV_BAR)) {
+ region_type_mask &= ~(1 << RGN_TYPE_NAV_BAR);
+ DEF_SHOW_REGION_PROPERTY(show_region_nav_bar, "Navigation Bar", "");
+ }
BLI_assert(region_type_mask == 0);
}
@@ -8172,6 +8220,83 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
}
+static void rna_def_asset_catalog_filter_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem asset_catalog_filter_mode[] = {
+ {ASSET_CATALOG_SHOW_ALL_ASSETS,
+ "SHOW_ALL_ASSETS",
+ ICON_NONE,
+ "All Assets",
+ "Show all assets, regardless of catalogs"},
+ {ASSET_CATALOG_SHOW_ASSETS_FROM_CATALOG,
+ "SHOW_ASSETS_FROM_CATALOG",
+ ICON_NONE,
+ "From Catalog",
+ "Show assets assigned to a specific catalog"},
+ {ASSET_CATALOG_SHOW_ASSETS_WITHOUT_CATALOG,
+ "SHOW_ASSETS_WITHOUT_CATALOG",
+ ICON_NONE,
+ "Assets Without Catalog",
+ "Show any asset that doesn't have a recognized asset catalog assigned to it"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ srna = RNA_def_struct(brna, "AssetCatalogFilterSettings", NULL);
+ RNA_def_struct_ui_text(
+ srna,
+ "Asset Catalog Filter Settings",
+ "Options to determine how catalogs should affect which assets are visible");
+
+ prop = RNA_def_property(srna, "filter_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, asset_catalog_filter_mode);
+ RNA_def_property_ui_text(prop,
+ "Asset Catalog Filter Mode",
+ "Determine how filtering based on asset catalogs should be done");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "active_catalog_id", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_funcs(prop,
+ "rna_AssetCatalogFilterSettings_active_catalog_id_get",
+ "rna_AssetCatalogFilterSettings_active_catalog_id_length",
+ NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Catalog UUID", "The UUID of the catalog to show assets from");
+}
+
+static void rna_def_space_assets(BlenderRNA *brna)
+{
+ PropertyRNA *prop;
+ StructRNA *srna;
+
+ rna_def_asset_catalog_filter_settings(brna);
+
+ srna = RNA_def_struct(brna, "SpaceAssetBrowser", "Space");
+ RNA_def_struct_sdna(srna, "SpaceAssets");
+ RNA_def_struct_ui_text(srna, "Space Asset Browser", "Asset browser space data");
+
+ rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_NAV_BAR) | (1 << RGN_TYPE_UI));
+
+ prop = rna_def_asset_library_reference_common(
+ srna, "RNA_SpaceAssetBrowser_asset_library_get", "RNA_SpaceAssetBrowser_asset_library_set");
+ RNA_def_property_ui_text(prop, "Asset Library", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "catalog_filter", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "AssetCatalogFilterSettings");
+ RNA_def_property_ui_text(prop,
+ "Asset Catalog Filter",
+ "Parameters to set up rules for filtering assets based on the catalogs "
+ "they are assigned to");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+
+ prop = RNA_def_property(srna, "active_asset_idx", PROP_INT, PROP_NONE);
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL);
+}
+
void RNA_def_space(BlenderRNA *brna)
{
rna_def_space(brna);
@@ -8200,6 +8325,7 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_space_node(brna);
rna_def_space_clip(brna);
rna_def_space_spreadsheet(brna);
+ rna_def_space_assets(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index e24c975bfa3..ce708cce68b 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2522,6 +2522,26 @@ static void rna_def_userdef_theme_space_file(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
+static void rna_def_userdef_theme_space_assets(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* space_file */
+
+ srna = RNA_def_struct(brna, "ThemeAssetBrowser", NULL);
+ RNA_def_struct_sdna(srna, "ThemeSpace");
+ RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
+ RNA_def_struct_ui_text(srna, "Theme Asset Browser", "Theme settings for the Asset Browser");
+
+ rna_def_userdef_theme_spaces_main(srna);
+
+ prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+}
+
static void rna_def_userdef_theme_space_outliner(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3932,6 +3952,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
{12, "OUTLINER", ICON_OUTLINER, "Outliner", ""},
{14, "PREFERENCES", ICON_PREFERENCES, "Preferences", ""},
{15, "INFO", ICON_INFO, "Info", ""},
+ {24, "ASSET_BROWSER", ICON_ASSET_MANAGER, "Asset Browser", ""},
{16, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", ""},
{17, "CONSOLE", ICON_CONSOLE, "Python Console", ""},
{20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""},
@@ -4072,6 +4093,13 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet");
RNA_def_property_struct_type(prop, "ThemeSpreadsheet");
RNA_def_property_ui_text(prop, "Spreadsheet", "");
+
+ prop = RNA_def_property(srna, "asset_browser", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "space_assets");
+ RNA_def_property_struct_type(prop, "ThemeAssetBrowser");
+ RNA_def_property_ui_text(prop, "Asset Browser", "");
+
/* end space types */
prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE);
@@ -4319,6 +4347,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna)
rna_def_userdef_theme_space_view3d(brna);
rna_def_userdef_theme_space_graph(brna);
rna_def_userdef_theme_space_file(brna);
+ rna_def_userdef_theme_space_assets(brna);
rna_def_userdef_theme_space_nla(brna);
rna_def_userdef_theme_space_action(brna);
rna_def_userdef_theme_space_image(brna);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 14ebbf5cef1..c949b2af81a 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -487,10 +487,9 @@ typedef struct wmNotifier {
#define ND_SPACE_SPREADSHEET (22 << 16)
/* NC_ASSET */
-/* Denotes that the AssetList is done reading some previews. NOT that the preview generation of
- * assets is done. */
+/* Denote that something in the contents of an AssetList may have changed. Triggers re-filtering of
+ * items. */
#define ND_ASSET_LIST (1 << 16)
-#define ND_ASSET_LIST_PREVIEW (2 << 16)
#define ND_ASSET_LIST_READING (3 << 16)
/* Catalog data changed, requiring a redraw of catalog UIs. Note that this doesn't denote a
* reloading of asset libraries & their catalogs should happen. That only happens on explicit user
diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc
index 4fb53264dda..211a8c3e865 100644
--- a/source/blender/windowmanager/intern/wm_files.cc
+++ b/source/blender/windowmanager/intern/wm_files.cc
@@ -643,6 +643,10 @@ static void wm_file_read_pre(bool use_data, bool /*use_userdef*/)
UI_view2d_zoom_cache_reset();
ED_preview_restart_queue_free();
+ /* #AssetLibraryService and the contained #AssetLibrary instances are destroyed on file loading.
+ * Asset lists may still reference them, so clear the asset list storage entirely for now. Later
+ * on, asset lists should actually live in the library, so this can be solved differently. */
+ ED_assetlist_storage_exit();
}
/**
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index 3126a06b134..93491393ea8 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -411,6 +411,10 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
else if (STRPREFIX(opname, "FILE_OT")) {
km = WM_keymap_find_all(wm, "File Browser", sl->spacetype, 0);
}
+ /* Asset browser */
+ else if (STRPREFIX(opname, "ASSET_OT")) {
+ km = WM_keymap_find_all(wm, "Asset Browser", sl->spacetype, 0);
+ }
/* Logic Editor */
else if (STRPREFIX(opname, "LOGIC_OT")) {
km = WM_keymap_find_all(wm, "Logic Editor", sl->spacetype, 0);