WIP: Rewrite asset browser as separate editor #104978

Closed
Julian Eisel wants to merge 68 commits from asset-browser-grid-view into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
58 changed files with 2428 additions and 344 deletions

View File

@ -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),

View File

@ -1388,6 +1388,42 @@
</space_list>
</ThemeSpreadsheet>
</spreadsheet>
<asset_browser>
<ThemeAssetBrowser
row_alternate="#ffffff0f"
>
<space>
<ThemeSpaceGeneric
back="#999999"
title="#000000"
text="#000000"
text_hi="#ffffff"
header="#adadadff"
header_text="#000000"
header_text_hi="#ffffff"
button="#999999e6"
button_title="#1a1a1a"
button_text="#000000"
button_text_hi="#000000"
navigation_bar="#00000000"
execution_buts="#999999e6"
tab_active="#6697e6"
tab_inactive="#cccccc"
tab_back="#999999ff"
tab_outline="#999999"
>
<panelcolors>
<ThemePanelColors
header="#42424200"
back="#00000028"
sub_back="#00000024"
>
</ThemePanelColors>
</panelcolors>
</ThemeSpaceGeneric>
</space>
</ThemeAssetBrowser>
</asset_browser>
<bone_color_sets>
<ThemeBoneColorSet
normal="#9a0000"

View File

@ -2186,7 +2186,6 @@ def km_info(params):
return keymap
# ------------------------------------------------------------------------------
# Editor (File Browser)
@ -2344,6 +2343,28 @@ def km_file_browser_buttons(_params):
return keymap
# ------------------------------------------------------------------------------
# Editor (Asset Browser)
def km_asset_browser(params):
items = []
keymap = (
"Asset Browser",
{"space_type": 'ASSET_BROWSER', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("wm.context_toggle", {"type": 'T', "value": 'PRESS'},
{"properties": [("data_path", 'space_data.show_region_nav_bar')]}),
*_template_space_region_type_toggle(
sidebar_key={"type": 'N', "value": 'PRESS'},
),
])
return keymap
# ------------------------------------------------------------------------------
# Editor (Dope Sheet)
@ -8057,6 +8078,7 @@ def generate_keymaps(params=None):
km_node_editor(params),
km_spreadsheet_generic(params),
km_info(params),
km_asset_browser(params),
km_file_browser(params),
km_file_browser_main(params),
km_file_browser_buttons(params),

View File

@ -4161,6 +4161,7 @@ def generate_keymaps_impl(params=None):
km_clip_editor(params),
km_clip_graph_editor(params),
km_clip_dopesheet_editor(params),
# TODO asset browser
# Animation.
km_frames(params),

View File

@ -60,6 +60,7 @@ _modules = [
"space_toolsystem_common",
"space_toolsystem_toolbar",
"space_assets",
"space_clip",
"space_console",
"space_dopesheet",

View File

@ -0,0 +1,211 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# <pep8 compliant>
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)

View File

@ -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,
)

View File

@ -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"),
]

View File

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

View File

@ -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<SpaceAssets *>(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<AssetHandle *>(
CTX_data_pointer_get_type(C, "asset_handle", &RNA_AssetHandle).data);
}
AssetRepresentation *CTX_wm_asset(const bContext *C)
{
return static_cast<AssetRepresentation *>(ctx_data_pointer_get(C, "asset"));

View File

@ -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;
}
}
}

View File

@ -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:

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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.
*/

View File

@ -6,6 +6,7 @@
#pragma once
#include <optional>
#include <string>
#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<bool(AssetHandle)>;
using AssetListIterFn = blender::FunctionRef<bool(AssetHandle &)>;
/**
* 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.
*/

View File

@ -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

View File

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

View File

@ -13,6 +13,7 @@
#include <string>
#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<uint32_t, std::unique_ptr<AssetHandle>> 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 &notifier) 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<asset_system::AssetLibrary *>(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>(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 &notifier) 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<AssetLibrary *>(list->asset_library());
}
return nullptr;
}
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{

View File

@ -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;
}

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*/
#include <memory>
#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<asset_system::AssetCatalogFilter> catalog_filter;
};
AssetViewCatalogFilterSettingsHandle *asset_view_create_catalog_filter_settings()
{
AssetViewCatalogFilter *filter_settings = MEM_new<AssetViewCatalogFilter>(__func__);
return reinterpret_cast<AssetViewCatalogFilterSettingsHandle *>(filter_settings);
}
void asset_view_delete_catalog_filter_settings(
AssetViewCatalogFilterSettingsHandle **filter_settings_handle)
{
AssetViewCatalogFilter **filter_settings = reinterpret_cast<AssetViewCatalogFilter **>(
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<AssetViewCatalogFilter *>(
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<AssetViewCatalogFilter *>(
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<asset_system::AssetCatalogFilter>(
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<const AssetViewCatalogFilter *>(
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;
}

View File

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

View File

@ -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<int, 64> widths(gflow->tot_columns);
blender::Array<int, 64> heights(gflow->tot_rows);

View File

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

View File

@ -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++) {

View File

@ -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];

View File

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

View File

@ -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

View File

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

View File

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

View File

@ -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 = &region->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);
}

View File

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

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spassets
*/
#include "asset_browser_intern.hh"
void asset_browser_operatortypes() {}

View File

@ -0,0 +1,81 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spassets
*/
#include <cstring>
#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<PanelType>("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);
}

View File

@ -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 &notifier) 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<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
std::unique_ptr<ui::AbstractViewItemDropTarget> 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<CatalogID> 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<ui::AbstractViewItemDropTarget> 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<ui::AbstractViewItemDropTarget> 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<AssetCatalogTreeViewItem>(
&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<AssetCatalogTreeViewAllItem>(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<AssetCatalogTreeViewUnassignedItem>(
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<AssetCatalogFilterSettings *>(catalog_filter_ptr.data);
}
bool AssetCatalogTreeView::listen(const wmNotifier &notifier) 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<AssetCatalogTreeView &>(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<const AssetCatalogTreeView &>(
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<const AssetCatalogTreeView &>(
get_tree_view());
ED_asset_catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
return true;
}
std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewItem::create_drop_target()
{
return std::make_unique<AssetCatalogDropTarget>(
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
static_cast<AssetCatalogTreeView &>(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<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return drop_assets_into_catalog(C,
get_view<AssetCatalogTreeView>(),
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<CatalogID> 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<AssetCatalogTreeView>().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<AssetCatalogTreeView>();
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<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewAllItem::create_drop_target()
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropTarget>(
static_cast<AssetCatalogTreeView &>(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<AssetCatalogTreeView>().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<AssetCatalogTreeView>().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<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::AbstractViewItemDropTarget> AssetCatalogTreeViewUnassignedItem::
create_drop_target()
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropTarget>(
static_cast<AssetCatalogTreeView &>(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<AssetCatalogTreeView>(), 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<ed::asset_browser::AssetCatalogTreeView>(
asset_library, *catalog_filter_owner_ptr, *catalog_filter_prop, msg_bus));
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
}

View File

@ -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<AssetGridViewItem>(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 &notifier) const
{
return ED_assetlist_listen(&asset_library_ref_, &notifier);
}
/* ---------------------------------------------------------------------- */
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<AssetGridView>(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

View File

@ -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

View File

@ -0,0 +1,312 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spassets
*/
#include <cstring>
#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<SpaceAssets>("asset browser space");
assets_space->spacetype = SPACE_ASSETS;
BKE_asset_library_reference_init_default(&assets_space->asset_library_ref);
{
/* Header. */
ARegion *region = MEM_cnew<ARegion>("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<ARegion>("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<ARegion>("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<ARegion>("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<SpaceAssets *>(
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(&region->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(&region->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<SpaceAssets *>(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(&region->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(&region->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>("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<ARegionType>("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<ARegionType>("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<ARegionType>("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<ARegionType>("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);
}

View File

@ -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<AssetCatalogTreeViewAllItem>(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<AssetCatalogTreeView>(), 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<AssetCatalogFilter> 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<AssetCatalogFilterSettings>(__func__);
return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings);
}
void file_delete_asset_catalog_filter_settings(
FileAssetCatalogFilterSettingsHandle **filter_settings_handle)
{
AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>(
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<AssetCatalogFilterSettings *>(
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<AssetCatalogFilterSettings *>(
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<AssetCatalogFilter>(
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<const AssetCatalogFilterSettings *>(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<ed::asset_browser::AssetCatalogTreeView>(
asset_library, params, *space_file));
std::make_unique<asset_browser::AssetCatalogTreeView>(asset_library, params, *space_file));
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
}

View File

@ -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
}

View File

@ -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<FileListEntryCache *>(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<ThumbSource>(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,

View File

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

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -201,6 +201,7 @@ typedef struct AssetWeakReference {
#
typedef struct AssetHandle {
const struct FileDirEntry *file_data;
struct PreviewImage *preview;
} AssetHandle;
#ifdef __cplusplus

View File

@ -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 */

View File

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

View File

@ -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;
}

View File

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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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();
}
/**

View File

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