Compare commits

...

61 Commits

Author SHA1 Message Date
3a97c4056f Proof of Concept: File Browser thumbnail mode using grid view
This was meant as an experiment to see how tangible it is to rewrite the
File Browser UI code to be based on views, starting with the grid view
for thumbnail mode. See T99890.
My initial conclusion is that porting to views is quite doable, but
we'll need some further UI code features to make certain things
possible. Like big "composed" icons, where a file type icon is displayed
on top of a big, generic file icon.

There is a fair bit of stuff here that I'm not happy with. Plus things
like selection, double clicking to open and renaming don't work yet.
It's a start, a proof of concept even :)
2022-07-21 17:16:10 +02:00
9dbcefb10e Merge branch 'asset-browser-grid-view' into file-browser-grid-view 2022-07-20 17:25:31 +02:00
85f0b2ef5d Merge branch 'master' into asset-browser-grid-view 2022-07-20 17:17:12 +02:00
bffc1fbf31 Apply changes to catalog tree view from master 2022-07-20 16:01:05 +02:00
6bae10ef45 Merge branch 'master' into asset-browser-grid-view 2022-07-20 15:42:58 +02:00
0f8e58e7b8 Merge commit 'c355be6faeac~1' into asset-browser-grid-view 2022-07-20 15:42:48 +02:00
6fc388743d Merge branch 'master' into asset-browser-grid-view 2022-06-15 20:20:21 +02:00
66204860ca Merge branch 'master' into asset-browser-grid-view 2022-06-02 13:01:29 +02:00
e1ced645fa Merge branch 'asset-browser-grid-view' into file-browser-grid-view 2022-05-27 11:33:26 +02:00
5162632a20 Merge branch 'master' into asset-browser-grid-view 2022-05-27 11:33:05 +02:00
3f7015a79f Merge branch 'asset-browser-grid-view' into file-browser-grid-view 2022-05-20 12:01:21 +02:00
560c20e067 Fix wrong data passed after recent changes in master 2022-05-20 12:00:52 +02:00
63cc972402 Fix wrong data passed after recent changes in master 2022-05-20 12:00:16 +02:00
c8c8783088 Merge branch 'master' into asset-browser-grid-view 2022-05-20 11:46:53 +02:00
1049b0c818 Merge branch 'master' into asset-browser-grid-view 2022-05-18 22:43:03 +02:00
46934eaf25 Merge branch 'master' into asset-browser-grid-view 2022-05-10 17:09:32 +02:00
c67a650718 Merge branch 'master' into asset-browser-grid-view 2022-05-10 17:09:13 +02:00
065bc42ce5 Merge branch 'master' into asset-browser-grid-view 2022-04-06 11:37:28 +02:00
063689b8a8 Cleanup: Use new license header convention 2022-03-28 00:14:49 +02:00
eaa58a1607 Adopt to RNA prototypes changes in master (fix compile error) 2022-03-28 00:13:49 +02:00
72e67691ed Merge branch 'master' into asset-browser-grid-view 2022-03-27 23:56:26 +02:00
e1a8a15945 Merge branch 'master' into asset-browser-grid-view 2022-03-02 15:07:28 +01:00
e91e4bf8e5 Merge branch 'master' into asset-browser-grid-view 2022-02-28 14:32:46 +01:00
9ae2259db5 Solve redraw performance issue in huge asset libraries
In a big asset library (>3000 assets in the one I'm testing with), the asset
browser would get a notable redraw lag due to the O(n^2) complexity of the tree
item matching (to recognize items over multiple redraws and keep state like
selection, highlights, renaming, ...).
2022-02-17 23:50:41 +01:00
9bac0894f6 Merge branch 'master' into asset-browser-grid-view 2022-02-17 21:43:07 +01:00
731c1be92a Speedup preview icon loading
Significantly speeds up loading of previews, not just for assets but also
Python loaded custom previews. Patch will be submitted for master.
2022-02-17 21:41:22 +01:00
3d31ad823a Fix missing redraw when switching asset libraries 2022-02-17 21:40:17 +01:00
fdc5301205 Fix crash when loading asset library takes multiple redraws 2022-02-17 21:39:43 +01:00
2ce7f02a06 Fix missing (re)load when changing asset libraries
Logic to compare asset library references was incorrect.
2022-02-17 21:35:34 +01:00
91853d95a9 Merge branch 'master' into asset-browser-grid-view 2022-02-16 18:13:12 +01:00
eafd98c920 Remove preview-caching from asset-list API
This isn't needed anymore, see previous commit.
2022-02-16 18:10:40 +01:00
39eab45c8e Let UI do lazy-loading of previews, rather than file-list cache
This is an important step to decouple the asset-views from the file browser
backend. One downside is that the UI preview loading is much slower than the
file browser one, however, I'm pretty sure I know how to address this.
2022-02-16 17:59:27 +01:00
ef58467594 Store active item, asset metadata sidebar
Also:
- Fix double-free bug when closing Blender
- Fix issues with identifying assets with the same name.
- Add functions to store asset handle as pointer in the asset list storage,
  asset browser exposes it via context.
2022-02-15 21:44:08 +01:00
8f48dd8f72 Merge branch 'master' into asset-browser-grid-view 2022-02-14 17:57:52 +01:00
d46357dd25 Merge branch 'master' into asset-browser-grid-view 2022-02-14 17:57:16 +01:00
696295f849 Support active item
Makes activating assets in the Asset Browser work. The active item is only
stored at the UI level now, so it's not stored in files, not accessible via
context and is lost when changing editors. The Asset Browser itself will have
to get a way to store that.
2022-02-14 17:48:51 +01:00
c9c332f422 Fix failed assert with small region size
If there's not enough space to draw at least one item per row, there would be a
failed assert in the code to skip drawing items scrolled out of view.
2022-02-14 16:15:29 +01:00
18f8749fb7 Only add items to layout that are visible on screen
Basically we skip adding buttons for items that aren't visible, but
scrolled out of view. This already makes scrolling in very large
libraries smoother. However this also prepares the next step, where we
only load previews for items that are currently in view, which should
make the experience with large asset libraries better.
2022-02-11 20:30:54 +01:00
947c73578c Merge branch 'master' into asset-browser-grid-view 2022-02-11 18:18:59 +01:00
f41368cf02 Fix null-reference use 2022-02-11 18:18:15 +01:00
f29fa9895f Bring back editor pulldown menus, get operators to work, T for nav-bar
- Adds the View, Edit & Select pulldown menus
- Makes asset operators work (e.g. catalog management)
- Correct notifiers (fixing missing redraws)
- Add T shortcut to toggle toolbar
2022-02-11 18:13:48 +01:00
ff213c802c Fix failing assert when splitting new asset browser in 2
This is an issue in master already, but for many layouts it just isn't
triggered. Pretty sure the assert just shouldn't be executed in extreme
cases, where there is no width for the layout and max-sizes become < 0.
2022-02-09 19:35:07 +01:00
5fcf6822dd Reduce brightness of grid item highlight
Also show theme settings for the view item in the Theme Preferences.
Called it "Data-View Item" for now, to be evaluated.
2022-02-09 19:33:58 +01:00
9530fb60ad Fix crash when loading files with asset browser open
Some fun with static memory. When loading a file, the asset-library
service was destructed since some while ago. For the old asset browser
that wasn't a problem, since its storage was recreated from scratch. But
the new asset browser accesses the global asset library storage of the
asset system which is static and thus stays alive if a different file is
loaded.

For now just destruct the global asset library storage when loading
a new file.
2022-02-09 19:01:12 +01:00
86ea1ad5df Support reading and writing asset browsers from/to files 2022-02-09 18:53:21 +01:00
2011d1f6d0 Various GUI tweaks
- Tweak tile size to match previous Asset Browser better
- Reduce margins between preview tiles (grid view was ignoring `align`
  parameter).
- Improve placement of text below previews (allowing previews to be
  slightly bigger).
- Tweak margins of main asset browser layout.
2022-02-09 17:59:01 +01:00
f17ea3da02 Add theme colors for view items 2022-02-09 15:04:27 +01:00
400d7235c3 Mouse hover highlight for grid items
Like the tree-view rows, grid items use an overlapping layout to draw
the background and a custom layout on top. There is a new dedicated
button type for the grid view items.
Adds some related bits needed for persistent view-item state storage.
Also a bunch of code for the grid item button type can be shared with
the tree-row one, but I prefer doing that separately.
2022-02-09 14:41:11 +01:00
29fdd43605 Get changes in catalog tree to update the UI correctly
The catalog tree-view now sends appropriate notifiers and messages when
changing data. Either itself or other UIs (like the main asset browser
region) can then listen to these and update.
I try to design this in a way that the views become independent on the
editor displaying them, so the views can be reused in multiple places.
2022-02-08 16:29:49 +01:00
eab2a8479a Move asset catalog filtering to editors/assets
Such general asset-view functionality can go to the general editors
level, I think that makes the most sense.
2022-02-07 18:58:25 +01:00
ee013f44b5 Show asset catalog tree-view in navigation sidebar
Selecting catalogs doesn't work yet.
Includes some temporary changes needed to avoid conflicts between old
File/Asset Browser and new Asset Browser code.
2022-02-07 17:18:08 +01:00
f20814892a Merge branch 'master' into asset-browser-grid-view 2022-02-07 12:20:07 +01:00
39e3580065 Enforce a fixed column number for the grid layout
Avoid stretching items to fit the layout, they should always have a
fixed size.
2022-02-07 12:17:17 +01:00
d2c4918d77 Merge branch 'master' into asset-browser-grid-view 2022-02-07 11:13:31 +01:00
11d0c91ba5 Merge branch 'master' into asset-browser-grid-view 2022-02-04 16:58:04 +01:00
925b82efb0 Basic grid layout with big preview tiles
Draws the asset previews in a grid layout, similar to the "old" Asset
Browser. No interactivity is supported yet.
The layout is managed through the grid-view.
2022-02-04 15:18:40 +01:00
3df2e4e888 Display a basic list of assets, set up scrolling and notifier listening
* Display a non-interactive list of assets, updates as assets get
  loaded.
* Notifier listening happens via the view, so the grid-view supports
  listening to notifiers. This is what triggers regular redraws as
  assets get loaded.
* Scrolling may need more fine tuning, so that scroll-bars are
  hidden if they don't apply (e.g. don't show horizontal scroll-bar for
  the vertically expanding grid-view layout).
2022-02-03 15:36:05 +01:00
a54bd5fe19 Merge branch 'master' into asset-browser-grid-view 2022-01-31 23:51:12 +01:00
4b43bd820e Merge branch 'master' into asset-browser-grid-view 2022-01-31 23:45:08 +01:00
b8b7b0af70 Add basic asset library loading, general cleanups
Adds an asset library selector and prints the list of assets when drawing the
Asset Browser main window.
2022-01-31 23:39:29 +01:00
b3597b1128 Add Asset Browser as own editor
This is part of a (tentative) plan to split off the Asset Browser from
the File Browser, while adding a new grid-view API that generalizes most
of the UI. Both editors can use this and only have to implement their
case-specific logic. This then allows us to add a proper asset system,
that's not tied to the file browser backend anymore.
2022-01-28 19:27:37 +01:00
66 changed files with 2828 additions and 374 deletions

View File

@@ -1082,6 +1082,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

@@ -1363,6 +1363,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

@@ -2187,7 +2187,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)
@@ -7962,6 +7983,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

@@ -4155,6 +4155,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

@@ -57,6 +57,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

@@ -62,7 +62,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:
@@ -620,19 +620,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_edit")
class ASSETBROWSER_MT_view(AssetBrowserMenu, Menu):
class ASSETBROWSEROLD_MT_view(AssetBrowserMenu, Menu):
bl_label = "View"
def draw(self, context):
@@ -653,7 +653,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):
@@ -668,7 +668,7 @@ class ASSETBROWSER_MT_select(AssetBrowserMenu, Menu):
layout.operator("file.select_box")
class ASSETBROWSER_MT_edit(AssetBrowserMenu, Menu):
class ASSETBROWSEROLD_MT_edit(AssetBrowserMenu, Menu):
bl_label = "Edit"
def draw(self, _context):
@@ -678,7 +678,7 @@ class ASSETBROWSER_MT_edit(AssetBrowserMenu, Menu):
layout.operator("asset.catalog_redo", text="Redo")
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'}
@@ -726,7 +726,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):
@@ -741,10 +741,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):
@@ -752,7 +752,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):
@@ -760,7 +760,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)
@@ -768,7 +768,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
@@ -825,15 +825,15 @@ classes = (
FILEBROWSER_MT_context_menu,
ASSETBROWSER_PT_display,
ASSETBROWSER_PT_filter,
ASSETBROWSER_MT_editor_menus,
ASSETBROWSER_MT_view,
ASSETBROWSER_MT_select,
ASSETBROWSER_MT_edit,
ASSETBROWSER_MT_metadata_preview_menu,
ASSETBROWSER_PT_metadata,
ASSETBROWSER_PT_metadata_preview,
ASSETBROWSER_PT_metadata_tags,
ASSETBROWSER_UL_metadata_tags,
ASSETBROWSEROLD_MT_editor_menus,
ASSETBROWSEROLD_MT_view,
ASSETBROWSEROLD_MT_select,
ASSETBROWSEROLD_MT_edit,
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

@@ -1190,8 +1190,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

@@ -192,6 +192,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);
@@ -367,6 +368,7 @@ int 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);
bool CTX_wm_interface_locked(const bContext *C);

View File

@@ -77,7 +77,9 @@ struct PreviewImage;
struct StudioLight;
struct bGPDlayer;
#ifndef __cplusplus
enum eIconSizes;
#endif
void BKE_icons_init(int first_dyn_id);

View File

@@ -947,6 +947,15 @@ struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C)
return NULL;
}
struct SpaceAssets *CTX_wm_space_assets(const bContext *C)
{
ScrArea *area = CTX_wm_area(C);
if (area && area->spacetype == SPACE_ASSETS) {
return area->spacedata.first;
}
return NULL;
}
void CTX_wm_manager_set(bContext *C, wmWindowManager *wm)
{
C->wm.manager = wm;
@@ -1502,6 +1511,16 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid)
return (AssetHandle){0};
}
/**
* \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 CTX_data_pointer_get_type(C, "asset_handle", &RNA_AssetHandle).data;
}
Depsgraph *CTX_data_depsgraph_pointer(const bContext *C)
{
Main *bmain = CTX_data_main(C);

View File

@@ -1340,6 +1340,10 @@ static void write_area(BlendWriter *writer, ScrArea *area)
}
}
}
else if (sl->spacetype == SPACE_ASSETS) {
BLO_write_struct(writer, SpaceAssets, sl);
// SpaceAssets *space_assets = (SpaceAssets *)sl;
}
}
}

View File

@@ -94,6 +94,8 @@ 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;
}

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

@@ -31,6 +31,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
@@ -43,6 +44,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,10 +23,10 @@ struct AssetLibraryReference;
struct bContext;
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);
int ED_asset_handle_get_preview_icon_id(const struct AssetHandle *asset);
void ED_asset_handle_get_full_library_path(const struct bContext *C,
const struct AssetLibraryReference *asset_library_ref,
const struct AssetHandle *asset,

View File

@@ -10,8 +10,10 @@
extern "C" {
#endif
struct AssetCatalogFilterSettings;
struct AssetFilterSettings;
struct AssetHandle;
struct AssetLibrary;
struct AssetLibraryReference;
struct ID;
struct bContext;
@@ -23,10 +25,11 @@ struct wmNotifier;
*/
void ED_assetlist_storage_fetch(const struct AssetLibraryReference *library_reference,
const struct bContext *C);
void ED_assetlist_ensure_previews_job(const struct AssetLibraryReference *library_reference,
struct bContext *C);
void ED_assetlist_catalog_filter_set(const struct AssetLibraryReference *,
const struct AssetCatalogFilterSettings *catalog_filter);
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).
*
@@ -46,9 +49,16 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new);
*/
void ED_assetlist_storage_exit(void);
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);
const char *ED_assetlist_library_path(const struct AssetLibraryReference *library_reference);
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"
@@ -19,6 +20,14 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
const AssetLibraryReference &library_reference,
const AssetHandle &asset_handle);
AssetHandle *ED_assetlist_asset_get_from_index(const AssetLibraryReference *library_reference,
int index);
/* 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.
*/
void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn);

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

@@ -18,6 +18,11 @@ const char *ED_asset_handle_get_name(const AssetHandle *asset)
return asset->file_data->name;
}
const char *ED_asset_handle_get_identifier(const AssetHandle *asset)
{
return asset->file_data->relpath;
}
AssetMetaData *ED_asset_handle_get_metadata(const AssetHandle *asset)
{
return asset->file_data->asset_data;
@@ -33,11 +38,6 @@ ID_Type ED_asset_handle_get_id_type(const AssetHandle *asset)
return static_cast<ID_Type>(asset->file_data->blentype);
}
int ED_asset_handle_get_preview_icon_id(const AssetHandle *asset)
{
return asset->file_data->preview_icon_id;
}
void ED_asset_handle_get_full_library_path(const bContext *C,
const AssetLibraryReference *asset_library_ref,
const AssetHandle *asset,

View File

@@ -20,6 +20,7 @@
#include "DNA_space_types.h"
#include "BKE_icons.h"
#include "BKE_preferences.h"
#include "ED_fileselect.h"
@@ -75,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;
@@ -110,15 +92,17 @@ class AssetList : NonCopyable {
void setup();
void fetch(const bContext &C);
void ensurePreviewsJob(bContext *C);
void setCatalogFilterSettings(const AssetCatalogFilterSettings &settings);
void clear(bContext *C);
bool needsRefetch() const;
AssetHandle &asset_handle_from_file(const FileDirEntry &) const;
void iterate(AssetListIterFn fn) const;
bool listen(const wmNotifier &notifier) const;
int size() const;
void tagMainDataDirty() const;
void remapID(ID *id_old, ID *id_new) const;
AssetLibrary *asset_library() const;
StringRef filepath() const;
};
@@ -148,7 +132,7 @@ void AssetList::setup()
filelist_setlibrary(files, &library_ref_);
filelist_setfilter_options(
files,
false,
true,
true,
true, /* Just always hide parent, prefer to not add an extra user option for this. */
FILE_TYPE_BLENDERLIB,
@@ -177,6 +161,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)) {
@@ -188,11 +173,26 @@ 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_);
}
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(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,6 +220,7 @@ 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);
}
@@ -261,7 +238,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)) {
@@ -301,6 +282,11 @@ StringRef AssetList::filepath() const
return filelist_dir(filelist_);
}
AssetLibrary *AssetList::asset_library() const
{
return filelist_asset_library(filelist_);
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -351,7 +337,7 @@ void AssetListStorage::fetch_library(const AssetLibraryReference &library_refere
void AssetListStorage::destruct()
{
global_storage().~AssetListMap();
global_storage().clear();
}
AssetList *AssetListStorage::lookup_list(const AssetLibraryReference &library_ref)
@@ -422,12 +408,12 @@ void ED_assetlist_storage_fetch(const AssetLibraryReference *library_reference,
AssetListStorage::fetch_library(*library_reference, *C);
}
void ED_assetlist_ensure_previews_job(const AssetLibraryReference *library_reference, 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);
}
}
@@ -492,6 +478,37 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C,
return path;
}
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 = ED_assetlist_asset_filepath_get(
nullptr, *library_reference, *asset_handle);
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);
@@ -502,6 +519,29 @@ ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle)
return filelist_geticon_image_ex(asset_handle->file_data);
}
AssetHandle *ED_assetlist_asset_get_from_index(const AssetLibraryReference *library_reference,
const int index)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (!list) {
return nullptr;
}
AssetHandle *asset = nullptr;
int i = 0;
list->iterate([&](AssetHandle &iter_asset) {
if (i == index) {
asset = &iter_asset;
return false;
}
i++;
return true;
});
return asset;
}
const char *ED_assetlist_library_path(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
@@ -511,6 +551,15 @@ const char *ED_assetlist_library_path(const AssetLibraryReference *library_refer
return nullptr;
}
AssetLibrary *ED_assetlist_library_get(const AssetLibraryReference *library_reference)
{
AssetList *list = AssetListStorage::lookup_list(*library_reference);
if (list) {
return list->asset_library();
}
return nullptr;
}
bool ED_assetlist_listen(const AssetLibraryReference *library_reference,
const wmNotifier *notifier)
{

View File

@@ -433,24 +433,38 @@ 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);
return sfile && ED_fileselect_active_asset_library_get(sfile);
return get_asset_library(C) != nullptr;
}
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::bke::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);
@@ -481,8 +495,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);
bke::CatalogID catalog_id;
if (!BLI_uuid_parse_string(&catalog_id, catalog_id_str)) {
@@ -517,13 +530,16 @@ static void ASSET_OT_catalog_delete(struct wmOperatorType *ot)
static bke::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 BKE_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 BKE_asset_library_get_catalog_service(asset_lib);
}
AssetLibrary *asset_lib = ED_fileselect_active_asset_library_get(sfile);
return BKE_asset_library_get_catalog_service(asset_lib);
return nullptr;
}
static int asset_catalog_undo_exec(bContext *C, wmOperator * /*op*/)
@@ -534,7 +550,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;
}
@@ -564,7 +580,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;
}
@@ -641,8 +657,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));
@@ -677,11 +692,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 "DNA_space_types.h"
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.hh"
#include "ED_asset_view_catalog_filter.h"
namespace bke = blender::bke;
struct AssetViewCatalogFilter {
AssetCatalogFilterSettings filter_settings;
std::unique_ptr<bke::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 bke::AssetCatalogService *catalog_service = BKE_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<bke::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

@@ -194,7 +194,11 @@ class PreviewGridItem : public AbstractGridViewItem {
std::string label{};
int preview_icon_id = ICON_NONE;
PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id);
PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id = ICON_NONE);
uiBut *add_preview_button(uiLayout &layout,
int preview_icon_id,
const uchar mono_color[4] = nullptr) const;
void build_grid_tile(uiLayout &layout) const override;

View File

@@ -1228,6 +1228,15 @@ uiBut *uiDefIconButO_ptr(uiBlock *block,
short width,
short height,
const char *tip);
uiBut *uiDefButPadding(uiBlock *block, int x, int y, short width, short height);
uiBut *uiDefButPreviewTile(uiBlock *block,
int preview_icon_id,
const char *label,
int x,
int y,
short width,
short height,
const uchar mono_color[4]);
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4]);
uiBut *uiDefButAlert(uiBlock *block, int icon, int x, int y, short width, short height);
@@ -1746,6 +1755,7 @@ struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon
int UI_preview_tile_size_x(void);
int UI_preview_tile_size_y(void);
int UI_preview_tile_size_y_no_label(void);
rcti UI_preview_tile_but_preview_rect_get(const uiBut *but);
/* Autocomplete
*

View File

@@ -96,7 +96,8 @@ int UI_icon_preview_to_render_size(enum eIconSizes size);
*/
void UI_icon_draw(float x, float y, int icon_id);
void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha);
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size);
void UI_icon_draw_preview(
float x, float y, int icon_id, float aspect, float alpha, int size, const uchar mono_color[4]);
void UI_icon_draw_ex(float x,
float y,

View File

@@ -4826,6 +4826,37 @@ uiBut *uiDefBut(uiBlock *block,
return but;
}
uiBut *uiDefButPadding(uiBlock *block, int x, int y, short width, short height)
{
uiBut *but = ui_def_but(
block, UI_BTYPE_LABEL, 0, "", x, y, width, height, nullptr, 0, 0, 0, 0, "");
ui_but_update(but);
return but;
}
uiBut *uiDefButPreviewTile(uiBlock *block,
int preview_icon_id,
const char *label,
int x,
int y,
short width,
short height,
const uchar mono_color[4])
{
uiBut *but = ui_def_but(
block, UI_BTYPE_PREVIEW_TILE, 0, label, x, y, width, height, nullptr, 0, 0, 0, 0, "");
ui_def_but_icon(but,
preview_icon_id,
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
if (mono_color) {
copy_v4_v4_uchar(but->col, mono_color);
}
ui_but_update(but);
return but;
}
uiBut *uiDefButImage(
uiBlock *block, void *imbuf, int x, int y, short width, short height, const uchar color[4])
{
@@ -4993,6 +5024,30 @@ int UI_preview_tile_size_y_no_label(void)
return round_fl_to_int((96.0f / 20.0f) * UI_UNIT_Y + 2.0f * pad);
}
#define PREVIEW_PAD 4
rcti UI_preview_tile_but_preview_rect_get(const uiBut *but)
{
rcti rect;
BLI_rcti_rctf_copy_round(&rect, &but->rect);
if (but->drawstr[0]) {
const uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
float font_dims[2] = {0.0f, 0.0f};
UI_fontstyle_set(fstyle);
BLF_width_and_height(
fstyle->uifont_id, but->drawstr, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* draw icon in rect above the space reserved for the label */
rect.ymin += round_fl_to_int(font_dims[1] + 2 * PREVIEW_PAD);
}
return ui_preview_draw_rect_get(&rect);
}
#undef PREVIEW_PAD
#undef PREVIEW_TILE_PAD
static void ui_but_update_and_icon_set(uiBut *but, int icon)

View File

@@ -1503,6 +1503,7 @@ static void icon_draw_rect(float x,
int rh,
uint *rect,
float alpha,
const uchar mono_rgba[4],
const float desaturate)
{
int draw_w = w;
@@ -1518,7 +1519,12 @@ static void icon_draw_rect(float x,
return;
}
/* modulate color */
const float col[4] = {alpha, alpha, alpha, alpha};
float col[4] = {alpha, alpha, alpha, alpha};
if (mono_rgba) {
/* Optionally use a mono color to recolor the image. */
rgba_uchar_to_float(col, mono_rgba);
mul_v4_fl(col, alpha);
}
float scale_x = 1.0f;
float scale_y = 1.0f;
@@ -1813,9 +1819,10 @@ static void icon_draw_size(float x,
if (di->type == ICON_TYPE_IMBUF) {
ImBuf *ibuf = icon->obj;
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
/* TODO preview images are premultiplied apparently (see ICON_TYPE_PREVIEW). */
// GPU_blend(GPU_BLEND_ALPHA_PREMULT);
icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, mono_rgba, desaturate);
// GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_VECTOR) {
/* vector icons use the uiBlock transformation, they are not drawn
@@ -1854,7 +1861,7 @@ static void icon_draw_size(float x,
}
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, desaturate);
icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, NULL, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
else if (di->type == ICON_TYPE_EVENT) {
@@ -1922,7 +1929,7 @@ static void icon_draw_size(float x,
return;
}
icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate);
icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, NULL, desaturate);
}
else if (di->type == ICON_TYPE_PREVIEW) {
PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
@@ -1938,7 +1945,7 @@ static void icon_draw_size(float x,
/* Preview images use premultiplied alpha. */
GPU_blend(GPU_BLEND_ALPHA_PREMULT);
icon_draw_rect(
x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, desaturate);
x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, NULL, desaturate);
GPU_blend(GPU_BLEND_ALPHA);
}
}
@@ -2433,9 +2440,10 @@ void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
}
void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
void UI_icon_draw_preview(
float x, float y, int icon_id, float aspect, float alpha, int size, const uchar mono_color[4])
{
icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, 0.0f, mono_color, false);
}
void UI_icon_draw_ex(float x,

View File

@@ -1236,6 +1236,8 @@ void ui_draw_preview_item(const struct uiFontStyle *fstyle,
int iconid,
int but_flag,
eFontStyle_Align text_align);
rcti ui_preview_draw_rect_get(const rcti *bounds_rect);
/**
* Version of #ui_draw_preview_item() that does not draw the menu background and item text based on
* state. It just draws the preview and text directly.
@@ -1245,6 +1247,7 @@ void ui_draw_preview_item_stateless(const struct uiFontStyle *fstyle,
const char *name,
int iconid,
const uchar text_col[4],
const uchar mono_col[4],
eFontStyle_Align text_align);
#define UI_TEXT_MARGIN_X 0.4f

View File

@@ -4473,8 +4473,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;
int *widths = BLI_array_alloca(widths, gflow->tot_columns);
int *heights = BLI_array_alloca(heights, gflow->tot_rows);

View File

@@ -54,14 +54,15 @@ static void asset_view_item_but_drag_set(uiBut *but,
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),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_asset_handle_get_preview_icon_id(asset_handle),
imbuf,
1.0f);
UI_but_drag_set_asset(
but,
asset_handle,
BLI_strdup(blend_path),
ED_asset_handle_get_metadata(asset_handle),
FILE_ASSET_IMPORT_APPEND,
ED_assetlist_asset_preview_icon_id_request(&list_data->asset_library_ref, asset_handle),
imbuf,
1.0f);
}
}
@@ -85,28 +86,29 @@ 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, list_data, asset_handle);
}
@@ -165,7 +167,7 @@ static void asset_view_template_refresh_asset_collection(
RNA_property_collection_clear(&assets_dataptr, assets_prop);
ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) {
ED_assetlist_iterate(asset_library_ref, [&](AssetHandle &asset) {
if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) {
/* Don't do anything else, but return true to continue iterating. */
return true;
@@ -219,7 +221,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);
asset_view_template_refresh_asset_collection(

View File

@@ -644,6 +644,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

@@ -1316,22 +1316,40 @@ static float widget_alpha_factor(const uiWidgetStateInfo *state)
return 1.0f;
}
static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
rcti ui_preview_draw_rect_get(const rcti *bounds_rect)
{
const int max_width = BLI_rcti_size_x(bounds_rect);
const int max_height = BLI_rcti_size_y(bounds_rect);
rcti rect = {0};
const int draw_size = MIN2(max_width, max_height) - PREVIEW_PAD * 2;
if (draw_size > 0) {
rect.xmin = bounds_rect->xmin + max_width / 2 - draw_size / 2;
rect.ymin = bounds_rect->ymin + max_height / 2 - draw_size / 2;
rect.xmax = rect.xmin + draw_size;
rect.ymax = rect.ymin + draw_size;
}
return rect;
}
static void widget_draw_preview(BIFIconID icon,
float alpha,
const rcti *rect,
const uchar mono_color[4])
{
if (icon == ICON_NONE) {
return;
}
const int w = BLI_rcti_size_x(rect);
const int h = BLI_rcti_size_y(rect);
const int size = MIN2(w, h) - PREVIEW_PAD * 2;
if (size > 0) {
const int x = rect->xmin + w / 2 - size / 2;
const int y = rect->ymin + h / 2 - size / 2;
UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size);
const rcti draw_rect = ui_preview_draw_rect_get(rect);
if (BLI_rcti_is_empty(&draw_rect)) {
return;
}
UI_icon_draw_preview(
draw_rect.xmin, draw_rect.ymin, icon, 1.0f, alpha, BLI_rcti_size_x(&draw_rect), mono_color);
}
static int ui_but_draw_menu_icon(const uiBut *but)
@@ -1346,7 +1364,7 @@ static void widget_draw_icon(
{
if (but->flag & UI_BUT_ICON_PREVIEW) {
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(icon, alpha, rect);
widget_draw_preview(icon, alpha, rect, mono_color);
GPU_blend(GPU_BLEND_NONE);
return;
}
@@ -1625,9 +1643,9 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
}
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
BLI_assert(strwidth <= okwidth);
BLI_assert(strwidth <= okwidth);
}
return strwidth;
}
@@ -2313,7 +2331,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(icon, alpha, rect);
widget_draw_preview(icon, alpha, rect, but->col[3] != 0 ? but->col : NULL);
GPU_blend(GPU_BLEND_NONE);
/* offset rect to draw label in */
@@ -4002,8 +4020,13 @@ static void widget_preview_tile(uiBut *but,
const float UNUSED(zoom))
{
const uiStyle *style = UI_style_get();
ui_draw_preview_item_stateless(
&style->widget, rect, but->drawstr, but->icon, wcol->text, UI_STYLE_TEXT_CENTER);
ui_draw_preview_item_stateless(&style->widget,
rect,
but->drawstr,
but->icon,
wcol->text,
but->col[3] ? but->col : NULL,
UI_STYLE_TEXT_CENTER);
}
static void widget_menuiconbut(uiWidgetColors *wcol,
@@ -5510,34 +5533,33 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
const char *name,
int iconid,
const uchar text_col[4],
const uchar mono_col[4],
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(iconid, 1.0f, rect);
widget_draw_preview(iconid, 1.0f, rect, mono_col);
GPU_blend(GPU_BLEND_NONE);
if (!has_text) {
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];
@@ -5575,7 +5597,7 @@ void ui_draw_preview_item(const uiFontStyle *fstyle,
wt->state(wt, &state, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, &STATE_INFO_NULL, 0, 1.0f);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, text_align);
ui_draw_preview_item_stateless(fstyle, rect, name, iconid, wt->wcol.text, NULL, text_align);
}
/** \} */

View File

@@ -147,6 +147,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

@@ -8,6 +8,7 @@
#include <stdexcept>
#include "BLI_index_range.hh"
#include "BLI_math_vector.h"
#include "WM_types.h"
@@ -410,29 +411,26 @@ PreviewGridItem::PreviewGridItem(StringRef identifier, StringRef label, int prev
{
}
void PreviewGridItem::build_grid_tile(uiLayout &layout) const
uiBut *PreviewGridItem::add_preview_button(uiLayout &layout,
const int preview_icon_id,
const uchar mono_color[4]) const
{
const GridViewStyle &style = get_view().get_style();
uiBlock *block = uiLayoutGetBlock(&layout);
uiBut *but = uiDefBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
label.c_str(),
0,
0,
style.tile_width,
style.tile_height,
nullptr,
0,
0,
0,
0,
"");
ui_def_but_icon(but,
preview_icon_id,
/* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */
UI_HAS_ICON | UI_BUT_ICON_PREVIEW);
return uiDefButPreviewTile(block,
preview_icon_id,
label.c_str(),
0,
0,
style.tile_width,
style.tile_height,
mono_color);
}
void PreviewGridItem::build_grid_tile(uiLayout &layout) const
{
add_preview_button(layout, preview_icon_id);
}
void PreviewGridItem::set_on_activate_fn(ActivateFn fn)

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,37 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
../include
../../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,11 @@
/* 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,726 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spassets
*/
#include "DNA_space_types.h"
#include "BKE_asset.h"
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.hh"
#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 "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
#include "asset_browser_intern.hh"
using namespace blender;
using namespace blender::bke;
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. */
bke::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 AssetCatalogDropController;
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(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::AbstractViewItemDropController> create_drop_controller() const 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 AssetCatalogDropController : public ui::AbstractViewItemDropController {
AssetCatalogTreeItem &catalog_item_;
public:
AssetCatalogDropController(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) 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 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 DropController : public ui::AbstractViewItemDropController {
DropController(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) override;
};
std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
struct DropController : public ui::AbstractViewItemDropController {
DropController(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) override;
};
std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library,
const PointerRNA &catalog_filter_owner,
PropertyRNA &catalog_filter_prop,
wmMsgBus *msg_bus)
: asset_library_(library),
catalog_tree_(BKE_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
{
return true;
}
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::AbstractViewItemDropController> AssetCatalogTreeViewItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogDropController>(
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_);
}
/* ---------------------------------------------------------------------- */
AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
: ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item)
{
}
bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
const AssetCatalog *drag_catalog = get_drag_catalog(drag, get_asset_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 AssetCatalogDropController::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 AssetCatalogDropController::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 AssetCatalogDropController::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 AssetCatalogDropController::on_drop(struct bContext *C, const wmDrag &drag)
{
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 AssetCatalogDropController::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 AssetCatalogDropController::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 *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag,
const ::AssetLibrary &asset_library)
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return nullptr;
}
const bke::AssetCatalogService *catalog_service = BKE_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 AssetCatalogDropController::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;
}
::AssetLibrary &AssetCatalogDropController::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::AbstractViewItemDropController> AssetCatalogTreeViewAllItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()));
}
AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
: ui::AbstractViewItemDropController(tree_view)
{
}
bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
const char **r_disabled_hint) const
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return false;
}
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
drag, *get_view<AssetCatalogTreeView>().asset_library_);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = "Catalog is already placed at the highest level";
return false;
}
return true;
}
std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropController::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::DropController::on_drop(struct bContext *UNUSED(C),
const wmDrag &drag)
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropController::drop_asset_catalog_into_catalog(
drag,
get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewUnassignedItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()));
}
AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
: ui::AbstractViewItemDropController(tree_view)
{
}
bool AssetCatalogTreeViewUnassignedItem::DropController::can_drop(
const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type != WM_DRAG_ASSET_LIST) {
return false;
}
return AssetCatalogDropController::has_droppable_asset(drag, r_disabled_hint);
}
std::string AssetCatalogTreeViewUnassignedItem::DropController::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::DropController::on_drop(struct bContext *C,
const wmDrag &drag)
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::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 builder(*block);
builder.build_tree_view(*tree_view);
}

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);
}
} // 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,321 @@
/* 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 *UNUSED(area), const Scene *UNUSED(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 *UNUSED(sl))
{
}
static void asset_browser_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(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_from_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)
{
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;
}
}
/* FIXME: See comment above #WM_msg_publish_rna_prop(). */
extern "C" {
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 *UNUSED(wm), ARegion *region)
{
ED_region_header_init(region);
}
static void asset_browser_header_listener(const wmRegionListenerParams *UNUSED(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 *UNUSED(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 *UNUSED(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 = UI_COMPACT_PANEL_WIDTH;
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

@@ -28,6 +28,7 @@ set(SRC
file_ops.c
file_panels.c
file_utils.c
file_view_grid.cc
filelist.c
filesel.c
fsmenu.c

View File

@@ -35,7 +35,7 @@
using namespace blender;
using namespace blender::bke;
namespace blender::ed::asset_browser {
namespace blender::ed::space_file::asset_browser {
class AssetCatalogTreeViewAllItem;
@@ -214,11 +214,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;
}
@@ -230,23 +230,23 @@ 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; });
[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);
}
@@ -650,99 +650,11 @@ bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext
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 ::AssetLibrary *asset_library)
{
AssetCatalogFilterSettings *filter_settings = reinterpret_cast<AssetCatalogFilterSettings *>(
filter_settings_handle);
const AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
asset_library);
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,
@@ -756,8 +668,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 builder(*block);
builder.build_tree_view(*tree_view);

View File

@@ -1161,3 +1161,40 @@ bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegio
return true;
}
void file_view_preview_grid_draw(const bContext *C, ARegion *region)
{
SpaceFile *sfile = CTX_wm_space_file(C);
// bScreen *screen = CTX_wm_screen(C);
View2D *v2d = &region->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");
file_grid_view_create_in_layout(sfile->files, 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);
}

View File

@@ -19,6 +19,7 @@ struct ARegion;
struct ARegionType;
struct AssetLibrary;
struct FileAssetSelectParams;
struct FileList;
struct FileSelectParams;
struct SpaceFile;
struct View2D;
@@ -38,6 +39,7 @@ void file_draw_list(const bContext *C, ARegion *region);
* \return true if the list is invalid and a hint was drawn.
*/
bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region);
void file_view_preview_grid_draw(const bContext *C, ARegion *region);
void file_draw_check_ex(bContext *C, struct ScrArea *area);
void file_draw_check(bContext *C);
@@ -196,29 +198,14 @@ void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rct
*/
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
/* file_view_grid.cc */
void file_grid_view_create_in_layout(struct FileList *files,
const View2D *v2d,
struct uiLayout *layout);
/* asset_catalog_tree_view.cc */
/* C-handle for #ed::asset_browser::AssetCatalogFilterSettings. */
typedef struct FileAssetCatalogFilterSettingsHandle FileAssetCatalogFilterSettingsHandle;
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 struct AssetLibrary *asset_library);
bool file_is_asset_visible_in_catalog_filter_settings(
const FileAssetCatalogFilterSettingsHandle *filter_settings_handle,
const AssetMetaData *asset_data);
void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
struct uiLayout *layout,
struct SpaceFile *space_file,

View File

@@ -0,0 +1,190 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spfile
*/
#include "DNA_ID_enums.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
#include "BKE_icons.h"
#include "BLI_fileops.h"
#include "BLI_math_vector.h"
#include "BLI_rect.h"
/* TODO temp for static ImBuf -> icon_id map. */
#include "BLI_map.hh"
#include "IMB_imbuf.h"
#include "ED_fileselect.h"
#include "UI_grid_view.hh"
#include "UI_interface.h"
#include "UI_interface.hh"
#include "file_intern.h"
#include "filelist.h"
namespace blender::ed::file_browser {
class FilePreviewGridView : public ui::AbstractGridView {
friend class FilePreviewGridItem;
FileList &files_;
public:
FilePreviewGridView(FileList &filelist);
void build_items() override;
BIFIconID file_preview_icon_id_get(const FileDirEntry &file);
};
class FilePreviewGridItem : public ui::PreviewGridItem {
const FileDirEntry &file_;
std::string file_identifier_;
/* Index in the file list. */
const int file_idx_;
public:
FilePreviewGridItem(const FileDirEntry &file, int file_idx);
void build_grid_tile(uiLayout &layout) const override;
FileList &get_file_list() const;
void icon_mono_color_get(uchar r_mono_color[4]);
void add_big_combined_file_icon(uiLayout &overlap) const;
};
FilePreviewGridView::FilePreviewGridView(FileList &files) : files_(files)
{
}
void FilePreviewGridView::build_items()
{
const int numfiles = filelist_files_ensure(&files_);
for (int file_idx = 0; file_idx < numfiles; file_idx++) {
const FileDirEntry *file = filelist_file(&files_, file_idx);
add_item<FilePreviewGridItem>(*file, file_idx);
}
}
FilePreviewGridItem::FilePreviewGridItem(const FileDirEntry &file, const int file_idx)
: ui::PreviewGridItem(file.relpath, file.name),
file_(file),
/* Get a copy so the identifier is always available (the file data may be freed). */
file_identifier_(identifier_),
file_idx_(file_idx)
{
/* Update reference so we don't point into the possibly freed file data. */
/* TODO always store the identifier as std::string in the item base class? Avoids these issues.
*/
identifier_ = file_identifier_;
}
FileList &FilePreviewGridItem::get_file_list() const
{
const FilePreviewGridView &view = dynamic_cast<const FilePreviewGridView &>(get_view());
return view.files_;
}
static BIFIconID file_big_file_icon_get(const FileDirEntry &file)
{
/* TODO temp!! Needs proper lifetime/memory management */
static Map<const ImBuf *, BIFIconID> imbuf_icon_map;
ImBuf *imb = filelist_file_geticon_image(&file);
return imbuf_icon_map.lookup_or_add_cb(imb,
[&]() { return (BIFIconID)BKE_icon_imbuf_create(imb); });
}
static void file_icon_mono_color_get(const FileDirEntry &file, uchar r_col[4])
{
uchar col[4] = {255, 255, 255, 255};
if (file.typeflag & FILE_TYPE_DIR) {
UI_GetThemeColor4ubv(TH_ICON_FOLDER, col);
}
else {
UI_GetThemeColor4ubv(TH_TEXT, col);
}
const bool is_hidden = (file.attributes & FILE_ATTR_HIDDEN);
if (is_hidden) {
col[3] *= 0.3f;
}
copy_v4_v4_uchar(r_col, col);
}
void FilePreviewGridItem::add_big_combined_file_icon(uiLayout &layout) const
{
uiLayout *overlap = uiLayoutOverlap(&layout);
BIFIconID file_icon_id = file_big_file_icon_get(file_);
uiBut *preview_but = nullptr;
if (file_icon_id != ICON_NONE) {
uchar mono_col[4];
file_icon_mono_color_get(file_, mono_col);
preview_but = add_preview_button(*overlap, file_icon_id, mono_col);
}
/* Smaller file type icon in the middle of image, scaled to fit container and UI scale */
{
float icon_opacity = 0.3f;
uchar icon_color[4] = {0, 0, 0, 255};
float bgcolor[4];
UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
if (rgb_to_grayscale(bgcolor) < 0.5f) {
icon_color[0] = 255;
icon_color[1] = 255;
icon_color[2] = 255;
}
icon_color[3] *= icon_opacity;
FileList &files = get_file_list();
const int icon_id = filelist_geticon(&files, file_idx_, false);
// uiLayoutSetAlignment(col, UI_LAYOUT_ALIGN_CENTER);
const ui::GridViewStyle &style = get_view().get_style();
int icon_size = style.tile_width / 3.5f;
uiLayout *col = uiLayoutColumn(overlap, false);
uiBlock *block = uiLayoutGetBlock(col);
/* Add padding to vertically center the icon. */
const rcti preview_img_rect = UI_preview_tile_but_preview_rect_get(preview_but);
const int icon_ofs_y = style.tile_height - BLI_rcti_cent_y(&preview_img_rect) -
(icon_size * ((file_.typeflag & FILE_TYPE_DIR) ? 0.78f : 0.75f)) / 2;
uiDefButPadding(block, 0, 0, 0, icon_ofs_y);
uiDefButPreviewTile(block, icon_id, "", 0, 0, icon_size, icon_size, icon_color);
}
}
void FilePreviewGridItem::build_grid_tile(uiLayout &layout) const
{
uiLayout &overlap = *uiLayoutOverlap(&layout);
add_big_combined_file_icon(overlap);
}
} // namespace blender::ed::file_browser
namespace ui = blender::ui;
using namespace blender::ed::file_browser;
void file_grid_view_create_in_layout(FileList *files, const View2D *v2d, uiLayout *layout)
{
uiBlock *block = uiLayoutGetBlock(layout);
UI_block_layout_set_current(block, layout);
ui::AbstractGridView *grid_view = UI_block_add_view(
*block, "file preview grid view", std::make_unique<FilePreviewGridView>(*files));
ui::GridViewBuilder builder(*block);
builder.build_grid_view(*grid_view, *v2d);
}

View File

@@ -55,6 +55,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"
@@ -356,7 +357,7 @@ typedef struct FileListFilter {
char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
short flags;
FileAssetCatalogFilterSettingsHandle *asset_catalog_filter;
AssetViewCatalogFilterSettingsHandle *asset_catalog_filter;
} FileListFilter;
/** #FileListFilter.flags */
@@ -955,7 +956,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,
filelist->asset_library);
}
/**
@@ -985,7 +987,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;
}
@@ -1177,17 +1179,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) {
@@ -1330,6 +1331,11 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index)
return filelist_geticon_image_ex(file);
}
ImBuf *filelist_file_geticon_image(const FileDirEntry *file)
{
return filelist_geticon_image_ex(file);
}
static int filelist_geticon_ex(const FileDirEntry *file,
const char *root,
const bool is_main,
@@ -1612,34 +1618,37 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern)
return removed_counter;
}
int /* ThumbSource */ 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 = BLI_task_pool_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
ThumbSource source = 0;
ThumbSource source = 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
@@ -1936,7 +1945,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 = NULL;
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(struct FileList *filelist,

View File

@@ -66,12 +66,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);
/**
@@ -86,7 +85,9 @@ struct ImBuf *filelist_getimage(struct FileList *filelist, int index);
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);
struct ImBuf *filelist_file_geticon_image(const FileDirEntry *file);
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

@@ -484,7 +484,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, NULL);
}

View File

@@ -653,7 +653,13 @@ static void file_main_region_draw(const bContext *C, ARegion *region)
file_highlight_set(sfile, region, event->xy[0], event->xy[1]);
}
if (!file_draw_hint_if_invalid(C, sfile, region)) {
if (file_draw_hint_if_invalid(C, sfile, region)) {
/* Pass. */
}
else if (params->display == FILE_IMGDISPLAY) {
file_view_preview_grid_draw(C, region);
}
else {
file_draw_list(C, region);
}

View File

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

View File

@@ -824,10 +824,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 */
@@ -1029,12 +1029,6 @@ typedef enum eFileSel_Params_Flag {
FILE_FILTER_ASSET_CATALOG = (1 << 15),
} eFileSel_Params_Flag;
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.
@@ -2027,6 +2021,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)
* \{ */
@@ -2066,9 +2096,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

@@ -492,6 +492,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];
@@ -509,7 +510,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

@@ -59,13 +59,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

@@ -164,6 +164,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",
@@ -605,6 +610,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:
@@ -847,6 +854,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)
@@ -3316,6 +3337,29 @@ static int rna_FileAssetSelectParams_catalog_id_length(PointerRNA *UNUSED(ptr))
return UUID_STRING_LEN - 1;
}
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
static const EnumPropertyItem dt_uv_items[] = {
@@ -3413,6 +3457,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);
}
@@ -8019,6 +8067,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);
@@ -8046,6 +8171,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

@@ -2449,6 +2449,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;
@@ -3854,6 +3874,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", ""},
@@ -3994,6 +4015,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);
@@ -4239,6 +4267,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

@@ -484,10 +484,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

@@ -607,6 +607,10 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(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);