Blender V4.3
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
11#include "AS_asset_library.hh"
13
14#include "BKE_asset.hh"
15#include "BKE_screen.hh"
16
17#include "BLI_fnmatch.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
58 AssetHandle asset_;
59 bool allow_asset_drag_ = true;
60
61 public:
62 AssetViewItem(const AssetHandle &asset,
63 StringRef identifier,
65 int preview_icon_id);
66
67 void disable_asset_drag();
68 void build_grid_tile(const bContext &C, uiLayout &layout) const override;
69 void build_context_menu(bContext &C, uiLayout &column) const override;
70 std::optional<bool> should_be_active() const override;
71 void on_activate(bContext &C) override;
72 bool should_be_filtered_visible(StringRefNull filter_string) const override;
73
74 std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
75};
76
86
87AssetView::AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf)
88 : library_ref_(library_ref), shelf_(shelf)
89{
90 if (shelf.type->get_active_asset) {
91 if (const AssetWeakReference *weak_ref = shelf.type->get_active_asset(shelf.type)) {
92 active_asset_ = *weak_ref;
93 }
94 else {
95 active_asset_.reset();
96 }
97 }
98}
99
101{
103 if (!library) {
104 return;
105 }
106
108 library_ref_,
109 [&](AssetHandle asset_handle) {
111 const bool show_names = (shelf_.settings.display_flag & ASSETSHELF_SHOW_NAMES);
112
113 const StringRef identifier = asset->library_relative_identifier();
114 const int preview_id = handle_get_preview_or_type_icon_id(&asset_handle);
115
117 asset_handle, identifier, asset->get_name(), preview_id);
118 if (!show_names) {
119 item.hide_label();
120 }
122 item.disable_asset_drag();
123 }
124
125 return true;
126 },
127
128 /* prefilter_fn=*/
130 if (shelf_.type->asset_poll && !shelf_.type->asset_poll(shelf_.type, &asset)) {
131 return false;
132 }
133
134 const AssetMetaData &asset_data = asset.get_metadata();
135 if (catalog_filter_ && !catalog_filter_->contains(asset_data.catalog_id)) {
136 /* Skip this asset. */
137 return false;
138 }
139 return true;
140 });
141}
142
144{
145 const ScrArea *area = CTX_wm_area(&C);
146 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
147 if (UI_textbutton_activate_rna(&C, region, &shelf_, "search_filter")) {
148 return true;
149 }
150 }
151
152 return false;
153}
154
156 const std::optional<asset_system::AssetCatalogFilter> &catalog_filter)
157{
158 if (catalog_filter) {
159 catalog_filter_.emplace(*catalog_filter);
160 }
161 else {
162 catalog_filter_ = std::nullopt;
163 }
164}
165
166static std::optional<asset_system::AssetCatalogFilter> catalog_filter_from_shelf_settings(
167 const AssetShelfSettings &shelf_settings, const asset_system::AssetLibrary &library)
168{
169 if (!shelf_settings.active_catalog_path) {
170 return {};
171 }
172
174 shelf_settings.active_catalog_path);
175 if (!active_catalog) {
176 return {};
177 }
178
179 return library.catalog_service().create_catalog_filter(active_catalog->catalog_id);
180}
181
182/* ---------------------------------------------------------------------- */
183
185 StringRef identifier,
187 int preview_icon_id)
188 : ui::PreviewGridItem(identifier, label, preview_icon_id), asset_(asset)
189{
190}
191
193{
194 allow_asset_drag_ = false;
195}
196
201static std::optional<wmOperatorCallParams> create_activate_operator_params(
202 const StringRefNull op_name, const asset_system::AssetRepresentation &asset)
203{
204 if (op_name.is_empty()) {
205 return {};
206 }
207 wmOperatorType *ot = WM_operatortype_find(op_name.c_str(), true);
208 if (!ot) {
209 return {};
210 }
211
212 PointerRNA *op_props = MEM_new<PointerRNA>(__func__);
216}
217
219{
220 const AssetView &asset_view = reinterpret_cast<const AssetView &>(this->get_view());
221 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
223
225 nullptr,
226 &RNA_FileSelectEntry,
227 /* XXX passing file pointer here, should be asset handle or asset representation. */
228 const_cast<FileDirEntry *>(asset_.file_data));
230 reinterpret_cast<uiBut *>(view_item_but_),
231 "active_file",
232 &file_ptr);
233
234 uiBut *item_but = reinterpret_cast<uiBut *>(this->view_item_button());
235 if (std::optional<wmOperatorCallParams> activate_op = create_activate_operator_params(
236 shelf_type.activate_operator, *asset))
237 {
238 /* Attach the operator, but don't call it through the button. We call it using
239 * #on_activate(). */
240 UI_but_operator_set(item_but, activate_op->optype, activate_op->opcontext, activate_op->opptr);
242
243 MEM_delete(activate_op->opptr);
244 }
245 const ui::GridViewStyle &style = this->get_view().get_style();
246 /* Increase background draw size slightly, so highlights are well visible behind previews with an
247 * opaque background. */
249 item_but, style.tile_width + 2 * U.pixelsize, style.tile_height + 2 * U.pixelsize);
250
252 item_but,
253 [](bContext * /*C*/, void *argN, const char * /*tip*/) {
255 static_cast<const asset_system::AssetRepresentation *>(argN);
256 return asset_tooltip(*asset, /*include_name=*/false);
257 },
258 const_cast<asset_system::AssetRepresentation *>(asset),
259 nullptr);
260
261 /* Request preview when drawing. Grid views have an optimization to only draw items that are
262 * actually visible, so only previews scrolled into view will be loaded this way. This reduces
263 * total loading time and memory footprint. */
265 C, &asset_view.library_ref_, const_cast<AssetHandle *>(&asset_));
266
267 const int preview_id = [&]() -> int {
268 if (list::asset_image_is_loading(&asset_view.library_ref_, &asset_)) {
269 return ICON_TEMP;
270 }
272 }();
273
275}
276
278{
279 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
280 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
281 if (shelf_type.draw_context_menu) {
283 shelf_type.draw_context_menu(&C, &shelf_type, asset, &column);
284 }
285}
286
287std::optional<bool> AssetViewItem::should_be_active() const
288{
289 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
290 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
291 if (!shelf_type.get_active_asset) {
292 return {};
293 }
294 if (!asset_view.active_asset_) {
295 return false;
296 }
298 AssetWeakReference weak_ref = asset->make_weak_reference();
299 const bool matches = *asset_view.active_asset_ == weak_ref;
300
301 return matches;
302}
303
305{
306 const AssetView &asset_view = dynamic_cast<const AssetView &>(this->get_view());
307 const AssetShelfType &shelf_type = *asset_view.shelf_.type;
308
309 if (std::optional<wmOperatorCallParams> activate_op = create_activate_operator_params(
310 shelf_type.activate_operator, *handle_get_representation(&asset_)))
311 {
313 &C, activate_op->optype, activate_op->opcontext, activate_op->opptr, nullptr);
314 WM_operator_properties_free(activate_op->opptr);
315 MEM_delete(activate_op->opptr);
316 }
317}
318
320{
321 const StringRefNull asset_name = handle_get_representation(&asset_)->get_name();
322 return fnmatch(filter_string.c_str(), asset_name.c_str(), FNM_CASEFOLD) == 0;
323}
324
325std::unique_ptr<ui::AbstractViewItemDragController> AssetViewItem::create_drag_controller() const
326{
327 if (!allow_asset_drag_) {
328 return nullptr;
329 }
331 return std::make_unique<AssetDragController>(this->get_view(), *asset);
332}
333
334/* ---------------------------------------------------------------------- */
335
336static std::string filter_string_get(const AssetShelf &shelf)
337{
338 /* Copy of the filter string from #AssetShelfSettings, with extra '*' added to the beginning and
339 * end of the string, for `fnmatch()` to work. */
340 char search_string[sizeof(AssetShelfSettings::search_string) + 2];
341 BLI_strncpy_ensure_pad(search_string, shelf.settings.search_string, '*', sizeof(search_string));
342 return search_string;
343}
344
346 const AssetLibraryReference &library_ref,
347 const AssetShelf &shelf,
348 const bContext &C,
349 const ARegion &region)
350{
351 list::storage_fetch(&library_ref, &C);
352 list::previews_fetch(&library_ref, &C);
353
355 if (!library) {
356 return;
357 }
358
359 const float tile_width = shelf::tile_width(shelf.settings);
360 const float tile_height = shelf::tile_height(shelf.settings);
363
364 std::unique_ptr asset_view = std::make_unique<AssetView>(library_ref, shelf);
365 asset_view->set_catalog_filter(catalog_filter_from_shelf_settings(shelf.settings, *library));
366 asset_view->set_tile_size(tile_width, tile_height);
367
368 uiBlock *block = uiLayoutGetBlock(&layout);
370 *block, "asset shelf asset view", std::move(asset_view));
371 grid_view->set_context_menu_title("Asset Shelf");
372
373 ui::GridViewBuilder builder(*block);
374 builder.build_grid_view(C, *grid_view, region.v2d, layout, filter_string_get(shelf));
375}
376
377/* ---------------------------------------------------------------------- */
378/* Dragging. */
379
382 : ui::AbstractViewItemDragController(view), asset_(asset)
383{
384}
385
390
392{
393 ID *local_id = asset_.local_id();
394 if (local_id) {
395 return static_cast<void *>(local_id);
396 }
397
398 const eAssetImportMethod import_method = asset_.get_import_method().value_or(
400
401 return WM_drag_create_asset_data(&asset_, import_method);
402}
403
404} // 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:50
#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
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_set(uiBut *but, uiButToolTipFunc func, void *arg, uiFreeArgFunc free_arg)
uiBlock * uiLayoutGetBlock(uiLayout *layout)
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, const char *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)
@ WM_OP_INVOKE_REGION_WIN
Definition WM_types.hh:219
eWM_DragDataType
Definition WM_types.hh:1152
@ WM_DRAG_ASSET
Definition WM_types.hh:1154
@ WM_DRAG_ID
Definition WM_types.hh:1153
unsigned int U
Definition btGjkEpa3.h:78
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
std::optional< eAssetImportMethod > get_import_method() const
AssetDragController(ui::AbstractGridView &view, asset_system::AssetRepresentation &asset)
void build_grid_tile(const bContext &C, uiLayout &layout) const override
bool should_be_filtered_visible(StringRefNull filter_string) const override
AssetViewItem(const AssetHandle &asset, StringRef identifier, StringRef label, int preview_icon_id)
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:173
bool matches(const AbstractViewItem &other) const override
Definition grid_view.cc:133
ItemT & add_item(Args &&...args)
const GridViewStyle & get_style() const
Definition grid_view.cc:97
uiButViewItem * view_item_button() const
void set_context_menu_title(const std::string &title)
void build_grid_view(const bContext &C, AbstractGridView &grid_view, const View2D &v2d, uiLayout &layout, std::optional< StringRef > search_string={})
Definition grid_view.cc:453
void build_grid_tile_button(uiLayout &layout, BIFIconID override_preview_icon_id=ICON_NONE) const
Definition grid_view.cc:480
const char * label
void storage_fetch(const AssetLibraryReference *library_reference, const bContext *C)
void asset_preview_ensure_requested(const bContext &C, const AssetLibraryReference *library_reference, AssetHandle *asset_handle)
bool asset_image_is_loading(const AssetLibraryReference *library_reference, const AssetHandle *asset_handle)
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
void iterate(const AssetLibraryReference &library_reference, AssetListHandleIterFn fn, FunctionRef< bool(asset_system::AssetRepresentation &)> prefilter_fn=nullptr)
void previews_fetch(const AssetLibraryReference *library_reference, const bContext *C)
void build_asset_view(uiLayout &layout, const AssetLibraryReference &library_ref, const AssetShelf &shelf, const bContext &C, const ARegion &region)
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)
std::string asset_tooltip(const asset_system::AssetRepresentation &asset, const bool include_name)
asset_system::AssetRepresentation * handle_get_representation(const AssetHandle *asset)
int handle_get_preview_or_type_icon_id(const AssetHandle *asset)
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset, PointerRNA &ptr)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
const struct FileDirEntry * file_data
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)
AssetShelfTypeFlag flag
bool(* asset_poll)(const AssetShelfType *shelf_type, const blender::asset_system::AssetRepresentation *asset)
const AssetWeakReference *(* get_active_asset)(const AssetShelfType *shelf_type)
struct AssetShelfType * type
AssetShelfSettings settings
Definition DNA_ID.h:413
wmOperatorType * optype
wmDragAsset * WM_drag_create_asset_data(const blender::asset_system::AssetRepresentation *asset, int import_method)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmOperatorType * ot
Definition wm_files.cc:4125
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)