Blender V4.5
asset_shelf_asset_view.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "AS_asset_library.hh"
13
14#include "BKE_screen.hh"
15
16#include "BLI_fnmatch.h"
17#include "BLI_listbase.h"
18#include "BLI_string.h"
19
20#include "DNA_asset_types.h"
21#include "DNA_screen_types.h"
22
23#include "ED_asset.hh"
25#include "ED_asset_shelf.hh"
26
27#include "UI_grid_view.hh"
28#include "UI_interface.hh"
29
30#include "RNA_access.hh"
31#include "RNA_prototypes.hh"
32
33#include "WM_api.hh"
34
35#include "asset_shelf.hh"
36
38
40 const AssetLibraryReference library_ref_;
41 const AssetShelf &shelf_;
42 std::optional<AssetWeakReference> active_asset_;
43 std::optional<asset_system::AssetCatalogFilter> catalog_filter_ = std::nullopt;
44
45 friend class AssetViewItem;
46 friend class AssetDragController;
47
48 public:
49 AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf);
50
51 void build_items() override;
52 bool begin_filtering(const bContext &C) const override;
53
54 void set_catalog_filter(const std::optional<asset_system::AssetCatalogFilter> &catalog_filter);
55};
56
59 int asset_index_;
60 bool allow_asset_drag_ = true;
61
62 public:
64 int asset_index,
65 StringRef identifier,
67
68 void disable_asset_drag();
69 void build_grid_tile(const bContext &C, uiLayout &layout) const override;
70 void build_context_menu(bContext &C, uiLayout &column) const override;
71 std::optional<bool> should_be_active() const override;
72 void on_activate(bContext &C) override;
73 bool should_be_filtered_visible(StringRefNull filter_string) const override;
74
75 std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
76};
77
87
89 : library_ref_(library_ref), shelf_(shelf)
90{
91 if (shelf.type->get_active_asset) {
92 if (const AssetWeakReference *weak_ref = shelf.type->get_active_asset(shelf.type)) {
93 active_asset_ = *weak_ref;
94 }
95 else {
96 active_asset_.reset();
97 }
98 }
99}
100
102{
104 if (!library) {
105 return;
106 }
107
108 list::iterate(library_ref_, [&](asset_system::AssetRepresentation &asset, int asset_index) {
109 if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, &asset)) {
110 return true;
111 }
112
113 const AssetMetaData &asset_data = asset.get_metadata();
114 if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
115 /* Skip this asset. */
116 return true;
117 }
118
119 const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
120 const StringRef identifier = asset.library_relative_identifier();
121
123 asset, asset_index, identifier, asset.get_name());
124 if (!show_names) {
125 item.hide_label();
126 }
127 if (shelf_.type->flag & ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG) {
128 item.disable_asset_drag();
129 }
130
131 return true;
132 });
133}
134
136{
137 const ScrArea *area = CTX_wm_area(&C);
138 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
139 if (UI_textbutton_activate_rna(&C, region, &shelf_, "search_filter")) {
140 return true;
141 }
142 }
143
144 return false;
145}
146
148 const std::optional<asset_system::AssetCatalogFilter> &catalog_filter)
149{
150 if (catalog_filter) {
151 catalog_filter_.emplace(*catalog_filter);
152 }
153 else {
154 catalog_filter_ = std::nullopt;
155 }
156}
157
158static std::optional<asset_system::AssetCatalogFilter> catalog_filter_from_shelf_settings(
159 const AssetShelfSettings &shelf_settings, const asset_system::AssetLibrary &library)
160{
161 if (!shelf_settings.active_catalog_path) {
162 return {};
163 }
164
166 shelf_settings.active_catalog_path);
167 if (!active_catalog) {
168 return {};
169 }
170
171 return library.catalog_service().create_catalog_filter(active_catalog->catalog_id);
172}
173
174/* ---------------------------------------------------------------------- */
175
177 int asset_index,
178 StringRef identifier,
180 : ui::PreviewGridItem(identifier, label, ICON_NONE), asset_(asset), asset_index_(asset_index)
181{
182}
183
185{
186 allow_asset_drag_ = false;
187}
188
193static std::optional<wmOperatorCallParams> create_activate_operator_params(
195{
196 if (op_name.is_empty()) {
197 return {};
198 }
199 wmOperatorType *ot = WM_operatortype_find(op_name.c_str(), true);
200 if (!ot) {
201 return {};
202 }
203
204 PointerRNA *op_props = MEM_new<PointerRNA>(__func__);
208}
209
210void AssetViewItem::build_grid_tile(const bContext & /*C*/, uiLayout &layout) const
211{
212 const AssetView &asset_view = reinterpret_cast<const AssetView &>(this->get_view());
213 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
214
215 AssetHandle asset_handle = list::asset_handle_get_by_index(&asset_view.library_ref_,
216 asset_index_);
217
219 nullptr,
220 &RNA_FileSelectEntry,
221 /* XXX passing file pointer here, should be asset handle or asset representation. */
222 const_cast<FileDirEntry *>(asset_handle.file_data));
224 reinterpret_cast<uiBut *>(view_item_but_),
225 "active_file",
226 &file_ptr);
227
228 uiBut *item_but = reinterpret_cast<uiBut *>(this->view_item_button());
229 if (std::optional<wmOperatorCallParams> activate_op = create_activate_operator_params(
230 shelf_type.activate_operator, asset_))
231 {
232 /* Attach the operator, but don't call it through the button. We call it using
233 * #on_activate(). */
234 UI_but_operator_set(item_but, activate_op->optype, activate_op->opcontext, activate_op->opptr);
236
237 MEM_delete(activate_op->opptr);
238 }
239 const ui::GridViewStyle &style = this->get_view().get_style();
240 /* Increase background draw size slightly, so highlights are well visible behind previews with an
241 * opaque background. */
243 item_but, style.tile_width + 2 * U.pixelsize, style.tile_height + 2 * U.pixelsize);
244
246 item_but,
247 [](bContext & /*C*/, uiTooltipData &tip, void *argN) {
249 static_cast<const asset_system::AssetRepresentation *>(argN);
250 asset_tooltip(*asset, tip);
251 },
252 (&asset_),
253 nullptr);
254
255 /* Request preview when drawing. Grid views have an optimization to only draw items that are
256 * actually visible, so only previews scrolled into view will be loaded this way. This reduces
257 * total loading time and memory footprint. */
258 asset_.ensure_previewable();
259
260 const int preview_id = [&]() -> int {
261 /* Show loading icon while list is loading still. Previews might get pushed out of view again
262 * while the list grows, which can cause a lot of flickering. Note that this also means the
263 * actual loading of previews is delayed, because that only happens when a preview icon-ID is
264 * attached to a button. */
265 if (!list::is_loaded(&asset_view.library_ref_)) {
266 return ICON_PREVIEW_LOADING;
267 }
268 return asset_preview_or_icon(asset_);
269 }();
270
272}
273
275{
276 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
277 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
278 if (shelf_type.draw_context_menu) {
279 shelf_type.draw_context_menu(&C, &shelf_type, &asset_, &column);
280 }
281}
282
283std::optional<bool> AssetViewItem::should_be_active() const
284{
285 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
286 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
287 if (!shelf_type.get_active_asset) {
288 return {};
289 }
290 if (!asset_view.active_asset_) {
291 return false;
292 }
293 AssetWeakReference weak_ref = asset_.make_weak_reference();
294 const bool matches = *asset_view.active_asset_ == weak_ref;
295
296 return matches;
297}
298
300{
301 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
302 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
303
304 if (std::optional<wmOperatorCallParams> activate_op = create_activate_operator_params(
305 shelf_type.activate_operator, asset_))
306 {
308 &C, activate_op->optype, activate_op->opcontext, activate_op->opptr, nullptr);
309 WM_operator_properties_free(activate_op->opptr);
310 MEM_delete(activate_op->opptr);
311 }
312}
313
315{
316 const StringRefNull asset_name = asset_.get_name();
317 return fnmatch(filter_string.c_str(), asset_name.c_str(), FNM_CASEFOLD) == 0;
318}
319
320std::unique_ptr<ui::AbstractViewItemDragController> AssetViewItem::create_drag_controller() const
321{
322 if (!allow_asset_drag_) {
323 return nullptr;
324 }
325 return std::make_unique<AssetDragController>(this->get_view(), asset_);
326}
327
328/* ---------------------------------------------------------------------- */
329
330static std::string filter_string_get(const AssetShelf &shelf)
331{
332 /* Copy of the filter string from #AssetShelfSettings, with extra '*' added to the beginning and
333 * end of the string, for `fnmatch()` to work. */
334 char search_string[sizeof(AssetShelfSettings::search_string) + 2];
335 BLI_strncpy_ensure_pad(search_string, shelf.settings.search_string, '*', sizeof(search_string));
336 return search_string;
337}
338
340 const AssetLibraryReference &library_ref,
341 const AssetShelf &shelf,
342 const bContext &C)
343{
344 list::storage_fetch(&library_ref, &C);
345
347 if (!library) {
348 return;
349 }
350
351 const float tile_width = shelf::tile_width(shelf.settings);
352 const float tile_height = shelf::tile_height(shelf.settings);
355
356 std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf);
357 asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf.settings, *library));
358 asset_view->set_tile_size(tile_width, tile_height);
359
360 uiBlock *block = uiLayoutGetBlock(&layout);
362 *block, "asset shelf asset view", std::move(asset_view));
363 grid_view->set_context_menu_title("Asset Shelf");
364
365 ui::GridViewBuilder builder(*block);
366 builder.build_grid_view(C, *grid_view, layout, filter_string_get(shelf));
367}
368
369/* ---------------------------------------------------------------------- */
370/* Dragging. */
371
377
379{
380 return asset_.is_local_id() ? WM_DRAG_ID : WM_DRAG_ASSET;
381}
382
384{
385 ID *local_id = asset_.local_id();
386 if (local_id) {
387 return static_cast<void *>(local_id);
388 }
389
390 const eAssetImportMethod import_method = asset_.get_import_method().value_or(
392 AssetImportSettings import_settings{};
393 import_settings.method = import_method;
394 import_settings.use_instance_collections = false;
395
396 return WM_drag_create_asset_data(&asset_, import_settings);
397}
398
399} // namespace blender::ed::asset::shelf
Main runtime representation of an asset.
ScrArea * CTX_wm_area(const bContext *C)
@ ASSET_SHELF_TYPE_FLAG_NO_ASSET_DRAG
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char char * BLI_strncpy_ensure_pad(char *__restrict dst, const char *__restrict src, char pad, size_t dst_maxncpy) ATTR_NONNULL(1
eAssetImportMethod
@ ASSET_IMPORT_APPEND_REUSE
@ ASSETSHELF_SHOW_NAMES
static AppView * view
#define C
Definition RandGen.cpp:29
blender::ui::AbstractGridView * UI_block_add_view(uiBlock &block, blender::StringRef idname, std::unique_ptr< blender::ui::AbstractGridView > grid_view)
bool UI_textbutton_activate_rna(const bContext *C, ARegion *region, const void *rna_poin_data, const char *rna_prop_id)
void UI_but_func_tooltip_custom_set(uiBut *but, uiButToolTipCustomFunc func, void *arg, uiFreeArgFunc free_arg)
void UI_but_operator_set(uiBut *but, wmOperatorType *optype, wmOperatorCallContext opcontext, const PointerRNA *opptr=nullptr)
void UI_but_context_ptr_set(uiBlock *block, uiBut *but, blender::StringRef name, const PointerRNA *ptr)
void UI_but_operator_set_never_call(uiBut *but)
void UI_but_view_item_draw_size_set(uiBut *but, const std::optional< int > draw_width=std::nullopt, const std::optional< int > draw_height=std::nullopt)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:239
eWM_DragDataType
Definition WM_types.hh:1197
@ WM_DRAG_ASSET
Definition WM_types.hh:1199
@ WM_DRAG_ID
Definition WM_types.hh:1198
#define U
constexpr bool is_empty() const
constexpr const char * c_str() const
AssetCatalogFilter create_catalog_filter(CatalogID active_catalog_id) const
AssetCatalog * find_catalog_by_path(const AssetCatalogPath &path) const
AssetCatalogService & catalog_service() const
AssetDragController(ui::AbstractGridView &view, asset_system::AssetRepresentation &asset)
AssetViewItem(asset_system::AssetRepresentation &asset_, int asset_index, StringRef identifier, StringRef label)
void build_grid_tile(const bContext &C, uiLayout &layout) const override
bool should_be_filtered_visible(StringRefNull filter_string) const override
void build_context_menu(bContext &C, uiLayout &column) const override
std::unique_ptr< ui::AbstractViewItemDragController > create_drag_controller() const override
std::optional< bool > should_be_active() const override
bool begin_filtering(const bContext &C) const override
AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf)
void set_catalog_filter(const std::optional< asset_system::AssetCatalogFilter > &catalog_filter)
AbstractGridView & get_view() const
Definition grid_view.cc:174
bool matches(const AbstractViewItem &other) const override
Definition grid_view.cc:134
ItemT & add_item(Args &&...args)
const GridViewStyle & get_style() const
Definition grid_view.cc:98
uiButViewItem * view_item_button() const
void set_context_menu_title(const std::string &title)
void build_grid_view(const bContext &C, AbstractGridView &grid_view, uiLayout &layout, std::optional< StringRef > search_string={})
Definition grid_view.cc:454
PreviewGridItem(StringRef identifier, StringRef label, int preview_icon_id)
Definition grid_view.cc:478
void build_grid_tile_button(uiLayout &layout, BIFIconID override_preview_icon_id=ICON_NONE) const
Definition grid_view.cc:483
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
bool is_loaded(const AssetLibraryReference *library_reference)
AssetHandle asset_handle_get_by_index(const AssetLibraryReference *library_reference, int asset_index)
void iterate(const AssetLibraryReference &library_reference, AssetListIndexIterFn fn)
static std::optional< wmOperatorCallParams > create_activate_operator_params(const StringRefNull op_name, const asset_system::AssetRepresentation &asset)
static std::optional< asset_system::AssetCatalogFilter > catalog_filter_from_shelf_settings(const AssetShelfSettings &shelf_settings, const asset_system::AssetLibrary &library)
int tile_height(const AssetShelfSettings &settings)
int tile_width(const AssetShelfSettings &settings)
static std::string filter_string_get(const AssetShelf &shelf)
void build_asset_view(uiLayout &layout, const AssetLibraryReference &library_ref, const AssetShelf &shelf, const bContext &C)
void asset_tooltip(const asset_system::AssetRepresentation &asset, uiTooltipData &tip, const bool include_name)
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset, PointerRNA &ptr)
BIFIconID asset_preview_or_icon(const asset_system::AssetRepresentation &asset)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
const struct FileDirEntry * file_data
eAssetImportMethod method
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
struct bUUID catalog_id
const char * active_catalog_path
std::string activate_operator
void(* draw_context_menu)(const bContext *C, const AssetShelfType *shelf_type, const blender::asset_system::AssetRepresentation *asset, uiLayout *layout)
const AssetWeakReference *(* get_active_asset)(const AssetShelfType *shelf_type)
struct AssetShelfType * type
Definition DNA_ID.h:404
ListBase regionbase
wmOperatorType * optype
wmDragAsset * WM_drag_create_asset_data(const blender::asset_system::AssetRepresentation *asset, const AssetImportSettings &import_settings)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmOperatorType * ot
Definition wm_files.cc:4226
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)