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