diff options
Diffstat (limited to 'source/blender/editors/space_file')
-rw-r--r-- | source/blender/editors/space_file/asset_catalog_tree_view.cc | 259 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_draw.c | 54 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_intern.h | 3 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_ops.c | 32 | ||||
-rw-r--r-- | source/blender/editors/space_file/file_panels.c | 2 | ||||
-rw-r--r-- | source/blender/editors/space_file/filelist.c | 209 | ||||
-rw-r--r-- | source/blender/editors/space_file/filesel.c | 27 | ||||
-rw-r--r-- | source/blender/editors/space_file/space_file.c | 3 |
8 files changed, 421 insertions, 168 deletions
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index c305a11daf4..e6b76e05e16 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -60,6 +60,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView { SpaceFile &space_file_; friend class AssetCatalogTreeViewItem; + friend class AssetCatalogDropController; public: AssetCatalogTreeView(::AssetLibrary *library, @@ -86,25 +87,52 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem { public: AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item); - static bool has_droppable_item(const wmDrag &drag); - static bool drop_into_catalog(const AssetCatalogTreeView &tree_view, - const wmDrag &drag, - CatalogID catalog_id, - StringRefNull simple_name = ""); - void on_activate() override; void build_row(uiLayout &row) override; void build_context_menu(bContext &C, uiLayout &column) const override; - bool can_drop(const wmDrag &drag) const override; - std::string drop_tooltip(const bContext &C, - const wmDrag &drag, - const wmEvent &event) const override; - bool on_drop(const wmDrag &drag) override; - bool can_rename() const override; bool rename(StringRefNull new_name) override; + + /** Add drag support for catalog items. */ + std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override; + /** Add dropping support for catalog items. */ + std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override; +}; + +class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController { + AssetCatalogTreeItem &catalog_item_; + + public: + explicit AssetCatalogDragController(AssetCatalogTreeItem &catalog_item); + + int get_drag_type() const override; + void *create_drag_data() const override; +}; + +class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController { + 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(const wmDrag &drag) override; + + ::AssetLibrary &get_asset_library() const; + + static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint); + static bool drop_assets_into_catalog(const AssetCatalogTreeView &tree_view, + const wmDrag &drag, + CatalogID catalog_id, + StringRefNull simple_name = ""); + + private: + bool drop_asset_catalog_into_catalog(const wmDrag &drag); + 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 @@ -118,11 +146,15 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem { class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { using BasicTreeViewItem::BasicTreeViewItem; - bool can_drop(const wmDrag &drag) const override; - std::string drop_tooltip(const bContext &C, - const wmDrag &drag, - const wmEvent &event) const override; - bool on_drop(const wmDrag &drag) override; + struct DropController : public ui::AbstractTreeViewItemDropController { + 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(const wmDrag &drag) override; + }; + + std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override; }; /* ---------------------------------------------------------------------- */ @@ -219,12 +251,8 @@ void AssetCatalogTreeViewItem::on_activate() void AssetCatalogTreeViewItem::build_row(uiLayout &row) { - if (catalog_item_.has_unsaved_changes()) { - uiItemL(&row, (label_ + "*").c_str(), icon); - } - else { - uiItemL(&row, label_.c_str(), icon); - } + const std::string label_override = catalog_item_.has_unsaved_changes() ? (label_ + "*") : label_; + add_label(row, label_override); if (!is_hovered()) { return; @@ -275,31 +303,80 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column) UI_menutype_draw(&C, mt, &column); } -bool AssetCatalogTreeViewItem::has_droppable_item(const wmDrag &drag) +bool AssetCatalogTreeViewItem::can_rename() const { - const ListBase *asset_drags = WM_drag_asset_list_get(&drag); + return true; +} - /* 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; - } +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::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem:: + create_drop_controller() const +{ + return std::make_unique<AssetCatalogDropController>( + static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_); +} + +std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem:: + create_drag_controller() const +{ + return std::make_unique<AssetCatalogDragController>(catalog_item_); +} + +/* ---------------------------------------------------------------------- */ + +AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view, + AssetCatalogTreeItem &catalog_item) + : ui::AbstractTreeViewItemDropController(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) { + /* Always supported. */ + return true; + } + if (drag.type == WM_DRAG_ASSET_LIST) { + return has_droppable_asset(drag, r_disabled_hint); } return false; } -bool AssetCatalogTreeViewItem::can_drop(const wmDrag &drag) const +std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const { - if (drag.type != WM_DRAG_ASSET_LIST) { - return false; + if (drag.type == WM_DRAG_ASSET_CATALOG) { + return drop_tooltip_asset_catalog(drag); } - return has_droppable_item(drag); + return drop_tooltip_asset_list(drag); } -std::string AssetCatalogTreeViewItem::drop_tooltip(const bContext & /*C*/, - const wmDrag &drag, - const wmEvent & /*event*/) const +std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const { + BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); + + const ::AssetLibrary *asset_library = tree_view<AssetCatalogTreeView>().asset_library_; + bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(asset_library); + wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag); + AssetCatalog *src_catalog = catalog_service->find_catalog(catalog_drag->drag_catalog_id); + + return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " + + IFACE_("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); @@ -312,11 +389,34 @@ std::string AssetCatalogTreeViewItem::drop_tooltip(const bContext & /*C*/, ")"; } -bool AssetCatalogTreeViewItem::drop_into_catalog(const AssetCatalogTreeView &tree_view, - const wmDrag &drag, - CatalogID catalog_id, - StringRefNull simple_name) +bool AssetCatalogDropController::on_drop(const wmDrag &drag) { + if (drag.type == WM_DRAG_ASSET_CATALOG) { + return drop_asset_catalog_into_catalog(drag); + } + return drop_assets_into_catalog(tree_view<AssetCatalogTreeView>(), + drag, + catalog_item_.get_catalog_id(), + catalog_item_.get_simple_name()); +} + +bool AssetCatalogDropController::drop_asset_catalog_into_catalog(const wmDrag &drag) +{ + BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); + wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag); + ED_asset_catalog_move( + &get_asset_library(), catalog_drag->drag_catalog_id, catalog_item_.get_catalog_id()); + + WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr); + return true; +} + +bool AssetCatalogDropController::drop_assets_into_catalog(const 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; @@ -339,28 +439,46 @@ bool AssetCatalogTreeViewItem::drop_into_catalog(const AssetCatalogTreeView &tre return true; } -bool AssetCatalogTreeViewItem::on_drop(const wmDrag &drag) +bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag, + const char **r_disabled_hint) { - const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>( - get_tree_view()); - return drop_into_catalog( - tree_view, drag, catalog_item_.get_catalog_id(), catalog_item_.get_simple_name()); + 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 = "Only assets from this current file can be moved between catalogs"; + return false; } -bool AssetCatalogTreeViewItem::can_rename() const +::AssetLibrary &AssetCatalogDropController::get_asset_library() const { - return true; + return *tree_view<AssetCatalogTreeView>().asset_library_; } -bool AssetCatalogTreeViewItem::rename(StringRefNull new_name) +/* ---------------------------------------------------------------------- */ + +AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeItem &catalog_item) + : catalog_item_(catalog_item) { - /* 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; +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; } /* ---------------------------------------------------------------------- */ @@ -382,17 +500,29 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) /* ---------------------------------------------------------------------- */ -bool AssetCatalogTreeViewUnassignedItem::can_drop(const wmDrag &drag) const +std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem:: + create_drop_controller() const +{ + return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>( + static_cast<AssetCatalogTreeView &>(get_tree_view())); +} + +AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view) + : ui::AbstractTreeViewItemDropController(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 AssetCatalogTreeViewItem::has_droppable_item(drag); + return AssetCatalogDropController::has_droppable_asset(drag, r_disabled_hint); } -std::string AssetCatalogTreeViewUnassignedItem::drop_tooltip(const bContext & /*C*/, - const wmDrag &drag, - const wmEvent & /*event*/) const +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); @@ -401,16 +531,17 @@ std::string AssetCatalogTreeViewUnassignedItem::drop_tooltip(const bContext & /* TIP_("Move asset out of any catalog"); } -bool AssetCatalogTreeViewUnassignedItem::on_drop(const wmDrag &drag) +bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(const wmDrag &drag) { - const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>( - get_tree_view()); /* Assign to nil catalog ID. */ - return AssetCatalogTreeViewItem::drop_into_catalog(tree_view, drag, CatalogID{}); + return AssetCatalogDropController::drop_assets_into_catalog( + tree_view<AssetCatalogTreeView>(), drag, CatalogID{}); } } // namespace blender::ed::asset_browser +/* ---------------------------------------------------------------------- */ + namespace blender::ed::asset_browser { class AssetCatalogFilterSettings { diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 24b24eb81dd..2e2f0c146d6 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -190,6 +190,7 @@ static void file_draw_icon(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), + file->asset_data, asset_params->import_type, icon, preview_image, @@ -242,8 +243,9 @@ static void file_draw_string(int sx, } /** - * \param r_sx, r_sy: The lower right corner of the last line drawn. AKA the cursor position on - * completion. + * \param r_sx, r_sy: The lower right corner of the last line drawn, plus the height of the last + * line. This is the cursor position on completion to allow drawing more text + * behind that. */ static void file_draw_string_multiline(int sx, int sy, @@ -515,6 +517,7 @@ static void file_draw_preview(const SpaceFile *sfile, UI_but_drag_set_asset(but, &(AssetHandle){.file_data = file}, BLI_strdup(blend_path), + file->asset_data, asset_params->import_type, icon, imb, @@ -1064,7 +1067,9 @@ void file_draw_list(const bContext *C, ARegion *region) layout->curr_size = params->thumbnail_size; } -static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion *region) +static void file_draw_invalid_library_hint(const bContext *C, + const SpaceFile *sfile, + ARegion *region) { const FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); @@ -1072,9 +1077,7 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion file_path_to_ui_path(asset_params->base_params.dir, library_ui_path, sizeof(library_ui_path)); uchar text_col[4]; - uchar text_alert_col[4]; UI_GetThemeColor4ubv(TH_TEXT, text_col); - UI_GetThemeColor4ubv(TH_REDALERT, text_alert_col); const View2D *v2d = ®ion->v2d; const int pad = sfile->layout->tile_border_x; @@ -1085,23 +1088,42 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion int sy = v2d->tot.ymax; { - const char *message = TIP_("Library not found"); - const int draw_string_str_len = strlen(message) + 2 + sizeof(library_ui_path); - char *draw_string = alloca(draw_string_str_len); - BLI_snprintf(draw_string, draw_string_str_len, "%s: %s", message, library_ui_path); - file_draw_string_multiline(sx, sy, draw_string, width, line_height, text_alert_col, NULL, &sy); + const char *message = TIP_("Path to asset library does not exist:"); + file_draw_string_multiline(sx, sy, message, width, line_height, text_col, NULL, &sy); + + sy -= line_height; + file_draw_string(sx, sy, library_ui_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col); } - /* Next line, but separate it a bit further. */ - sy -= line_height; + /* Separate a bit further. */ + sy -= line_height * 2.2f; { UI_icon_draw(sx, sy - UI_UNIT_Y, ICON_INFO); const char *suggestion = TIP_( - "Set up the library or edit libraries in the Preferences, File Paths section"); + "Asset Libraries are local directories that can contain .blend files with assets inside.\n" + "Manage Asset Libraries from the File Paths section in Preferences."); file_draw_string_multiline( - sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, NULL); + sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, &sy); + + uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); + uiBut *but = uiDefIconTextButO(block, + UI_BTYPE_BUT, + "SCREEN_OT_userpref_show", + WM_OP_INVOKE_DEFAULT, + ICON_PREFERENCES, + NULL, + sx + UI_UNIT_X, + sy - line_height - UI_UNIT_Y * 1.2f, + UI_UNIT_X * 8, + UI_UNIT_Y, + NULL); + PointerRNA *but_opptr = UI_but_operator_ptr_get(but); + RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS); + + UI_block_end(C, block); + UI_block_draw(C, block); } } @@ -1109,7 +1131,7 @@ static void file_draw_invalid_library_hint(const SpaceFile *sfile, const ARegion * Draw a string hint if the file list is invalid. * \return true if the list is invalid and a hint was drawn. */ -bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region) +bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region) { FileAssetSelectParams *asset_params = ED_fileselect_get_asset_params(sfile); /* Only for asset browser. */ @@ -1122,7 +1144,7 @@ bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region) return false; } - file_draw_invalid_library_hint(sfile, region); + file_draw_invalid_library_hint(C, sfile, region); return true; } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index ba08777e4e2..4be5d6d8008 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -47,7 +47,7 @@ struct View2D; void file_calc_previews(const bContext *C, ARegion *region); void file_draw_list(const bContext *C, ARegion *region); -bool file_draw_hint_if_invalid(const SpaceFile *sfile, const ARegion *region); +bool file_draw_hint_if_invalid(const bContext *C, const SpaceFile *sfile, ARegion *region); void file_draw_check_ex(bContext *C, struct ScrArea *area); void file_draw_check(bContext *C); @@ -79,6 +79,7 @@ void FILE_OT_directory_new(struct wmOperatorType *ot); void FILE_OT_previous(struct wmOperatorType *ot); void FILE_OT_next(struct wmOperatorType *ot); void FILE_OT_refresh(struct wmOperatorType *ot); +void FILE_OT_asset_library_refresh(struct wmOperatorType *ot); void FILE_OT_filenum(struct wmOperatorType *ot); void FILE_OT_delete(struct wmOperatorType *ot); void FILE_OT_rename(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index f647e1d4e4f..4eb10e65867 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1950,8 +1950,36 @@ void FILE_OT_refresh(struct wmOperatorType *ot) /* api callbacks */ ot->exec = file_refresh_exec; - /* Operator works for file or asset browsing */ - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + ot->poll = ED_operator_file_browsing_active; /* <- important, handler is on window level */ +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Refresh Asset Library Operator + * \{ */ + +static int file_asset_library_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) +{ + wmWindowManager *wm = CTX_wm_manager(C); + SpaceFile *sfile = CTX_wm_space_file(C); + + ED_fileselect_clear(wm, sfile); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + + return OPERATOR_FINISHED; +} + +void FILE_OT_asset_library_refresh(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Refresh Asset Library"; + ot->description = "Reread assets and asset catalogs from the asset library on disk"; + ot->idname = "FILE_OT_asset_library_refresh"; + + /* api callbacks */ + ot->exec = file_asset_library_refresh_exec; + ot->poll = ED_operator_asset_browsing_active; } /** \} */ diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 51d0581d6a4..0e468718a04 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -247,7 +247,7 @@ static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *pane uiItemR(row, ¶ms_ptr, "asset_library_ref", 0, "", ICON_NONE); if (params->asset_library_ref.type != ASSET_LIBRARY_LOCAL) { - uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_refresh"); + uiItemO(row, "", ICON_FILE_REFRESH, "FILE_OT_asset_library_refresh"); } uiItemS(col); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index d329a8809c7..a73fa2b9740 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -817,88 +817,85 @@ static bool is_filtered_hidden(const char *filename, return false; } -static bool is_filtered_file(FileListInternEntry *file, - const char *UNUSED(root), - FileListFilter *filter) +/** + * Apply the filter string as file path matching pattern. + * \return true when the file should be in the result set, false if it should be filtered out. */ +static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter) { - bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); + if (filter->filter_search[0] == '\0') { + return true; + } - if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if (filter->filter && (filter->flags & FLF_DO_FILTER)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & - (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } + /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ + return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0; +} + +/** \return true when the file should be in the result set, false if it should be filtered out. */ +static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter) +{ + if (is_filtered_hidden(file->relpath, filter, file)) { + return false; + } + + if (FILENAME_IS_CURRPAR(file->relpath)) { + return false; + } + + /* We only check for types if some type are enabled in filtering. */ + if (filter->filter && (filter->flags & FLF_DO_FILTER)) { + if (file->typeflag & FILE_TYPE_DIR) { + if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { + if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { + return false; } } else { - if (!(file->typeflag & filter->filter)) { - is_filtered = false; + if (!(filter->filter & FILE_TYPE_FOLDER)) { + return false; } } } - /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; + else { + if (!(file->typeflag & filter->filter)) { + return false; } } } + return true; +} - return is_filtered; +/** \return true when the file should be in the result set, false if it should be filtered out. */ +static bool is_filtered_file(FileListInternEntry *file, + const char *UNUSED(root), + FileListFilter *filter) +{ + return is_filtered_file_type(file, filter) && is_filtered_file_relpath(file, filter); } -static bool is_filtered_id_file(const FileListInternEntry *file, - const char *id_group, - const char *name, - const FileListFilter *filter) +static bool is_filtered_id_file_type(const FileListInternEntry *file, + const char *id_group, + const char *name, + const FileListFilter *filter) { - bool is_filtered = !is_filtered_hidden(file->relpath, filter, file); - if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { - /* We only check for types if some type are enabled in filtering. */ - if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { - if (file->typeflag & FILE_TYPE_DIR) { - if (file->typeflag & - (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { - if (!(filter->filter & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP))) { - is_filtered = false; - } - } - else { - if (!(filter->filter & FILE_TYPE_FOLDER)) { - is_filtered = false; - } - } - } - if (is_filtered && id_group) { - if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { - is_filtered = false; - } - else { - uint64_t filter_id = groupname_to_filter_id(id_group); - if (!(filter_id & filter->filter_id)) { - is_filtered = false; - } - } + if (!is_filtered_file_type(file, filter)) { + return false; + } + + /* We only check for types if some type are enabled in filtering. */ + if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { + if (id_group) { + if (!name && (filter->flags & FLF_HIDE_LIB_DIR)) { + return false; } - } - /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ - if (is_filtered && (filter->filter_search[0] != '\0')) { - if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { - is_filtered = false; + + uint64_t filter_id = groupname_to_filter_id(id_group); + if (!(filter_id & filter->filter_id)) { + return false; } } } - return is_filtered; + return true; } /** @@ -921,40 +918,100 @@ static void prepare_filter_asset_library(const FileList *filelist, FileListFilte file_ensure_updated_catalog_filter_data(filter->asset_catalog_filter, filelist->asset_library); } +/** + * Copy a string from source to `dest`, but prefix and suffix it with a single space. + * Assumes `dest` has at least space enough for the two spaces. + */ +static void tag_copy_with_spaces(char *dest, const char *source, const size_t dest_size) +{ + BLI_assert(dest_size > 2); + const size_t source_length = BLI_strncpy_rlen(dest + 1, source, dest_size - 2); + dest[0] = ' '; + dest[source_length + 1] = ' '; + dest[source_length + 2] = '\0'; +} + +/** + * Return whether at least one tag matches the search filter. + * Tags are searched as "entire words", so instead of searching for "tag" in the + * filter string, this function searches for " tag ". Assumes the search filter + * starts and ends with a space. + * + * Here the tags on the asset are written in set notation: + * + * `asset_tag_matches_filter(" some tags ", {"some", "blue"})` -> true + * `asset_tag_matches_filter(" some tags ", {"som", "tag"})` -> false + * `asset_tag_matches_filter(" some tags ", {})` -> false + */ +static bool asset_tag_matches_filter(const char *filter_search, const AssetMetaData *asset_data) +{ + LISTBASE_FOREACH (const AssetTag *, asset_tag, &asset_data->tags) { + char tag_name[MAX_NAME + 2]; /* sizeof(AssetTag::name) + 2 */ + tag_copy_with_spaces(tag_name, asset_tag->name, sizeof(tag_name)); + if (BLI_strcasestr(filter_search, tag_name) != NULL) { + return true; + } + } + return false; +} + 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) { + if (filter->asset_catalog_filter && !file_is_asset_visible_in_catalog_filter_settings( + filter->asset_catalog_filter, asset_data)) { + return false; + } + + if (filter->filter_search[0] == '\0') { + /* If there is no filter text, everything matches. */ return true; } - const AssetMetaData *asset_data = filelist_file_internal_get_asset_data(file); - return file_is_asset_visible_in_catalog_filter_settings(filter->asset_catalog_filter, - asset_data); + /* filter->filter_search contains "*the search text*". */ + char filter_search[66]; /* sizeof(FileListFilter::filter_search) */ + const size_t string_length = STRNCPY_RLEN(filter_search, filter->filter_search); + + /* When doing a name comparison, get rid of the leading/trailing asterisks. */ + filter_search[string_length - 1] = '\0'; + if (BLI_strcasestr(file->name, filter_search + 1) != NULL) { + return true; + } + + /* Replace the asterisks with spaces, so that we can do matching on " sometag "; that way + * an artist searching for "redder" doesn't result in a match for the tag "red". */ + filter_search[string_length - 1] = ' '; + filter_search[0] = ' '; + + return asset_tag_matches_filter(filter_search, asset_data); } -static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +static bool is_filtered_lib_type(FileListInternEntry *file, + const char *root, + FileListFilter *filter) { - bool is_filtered; char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; BLI_join_dirfile(path, sizeof(path), root, file->relpath); if (BLO_library_path_explode(path, dir, &group, &name)) { - is_filtered = is_filtered_id_file(file, group, name, filter); - } - else { - is_filtered = is_filtered_file(file, root, filter); + return is_filtered_id_file_type(file, group, name, filter); } + return is_filtered_file_type(file, filter); +} - return is_filtered; +static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) +{ + return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter); } static bool is_filtered_asset_library(FileListInternEntry *file, const char *root, FileListFilter *filter) { - return is_filtered_lib(file, root, filter) && is_filtered_asset(file, filter); + return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter); } static bool is_filtered_main(FileListInternEntry *file, @@ -969,7 +1026,7 @@ static bool is_filtered_main_assets(FileListInternEntry *file, FileListFilter *filter) { /* "Filtered" means *not* being filtered out... So return true if the file should be visible. */ - return is_filtered_id_file(file, file->relpath, file->name, filter) && + return is_filtered_id_file_type(file, file->relpath, file->name, filter) && is_filtered_asset(file, filter); } @@ -1854,6 +1911,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); } void filelist_clear_ex(struct FileList *filelist, @@ -1953,7 +2011,6 @@ void filelist_free(struct FileList *filelist) filelist->selection_state = NULL; } - file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter); MEM_SAFE_FREE(filelist->asset_library_ref); memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6ab7e4eeecf..ce76fd65a86 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -486,6 +486,18 @@ struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile) return filelist_file_get_id(file); } +void ED_fileselect_activate_asset_catalog(const SpaceFile *sfile, const bUUID catalog_id) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return; + } + + FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile); + params->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG; + params->catalog_id = catalog_id; + WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, NULL); +} + static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data) { ID *asset_id = (ID *)custom_data; @@ -517,14 +529,12 @@ void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool def const FileDirEntry *file = filelist_file_ex(files, file_index, false); if (filelist_file_get_id(file) != asset_id) { - filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); continue; } params->active_file = file_index; filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); - - /* Keep looping to deselect the other files. */ + break; } WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL); @@ -984,6 +994,8 @@ static void file_attribute_columns_init(const FileSelectParams *params, FileLayo void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) { FileSelectParams *params = ED_fileselect_get_active_params(sfile); + /* Request a slightly more compact layout for asset browsing. */ + const bool compact = ED_fileselect_is_asset_browser(sfile); FileLayout *layout = NULL; View2D *v2d = ®ion->v2d; int numfiles; @@ -1003,12 +1015,13 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region) layout->textheight = textheight; if (params->display == FILE_IMGDISPLAY) { + const float pad_fac = compact ? 0.15f : 0.3f; layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; - layout->tile_border_x = 0.3f * UI_UNIT_X; - layout->tile_border_y = 0.3f * UI_UNIT_X; - layout->prv_border_x = 0.3f * UI_UNIT_X; - layout->prv_border_y = 0.3f * UI_UNIT_Y; + layout->tile_border_x = pad_fac * UI_UNIT_X; + layout->tile_border_y = pad_fac * UI_UNIT_X; + layout->prv_border_x = pad_fac * UI_UNIT_X; + layout->prv_border_y = pad_fac * UI_UNIT_Y; layout->tile_w = layout->prv_w + 2 * layout->prv_border_x; layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight; layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index a875b7a2c12..b115c63a569 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -659,7 +659,7 @@ 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(sfile, region)) { + if (!file_draw_hint_if_invalid(C, sfile, region)) { file_draw_list(C, region); } @@ -688,6 +688,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_previous); WM_operatortype_append(FILE_OT_next); WM_operatortype_append(FILE_OT_refresh); + WM_operatortype_append(FILE_OT_asset_library_refresh); WM_operatortype_append(FILE_OT_bookmark_add); WM_operatortype_append(FILE_OT_bookmark_delete); WM_operatortype_append(FILE_OT_bookmark_cleanup); |