WIP: Brush assets project #106303
|
@ -8779,6 +8779,11 @@ class BrushAssetShelf:
|
|||
|
||||
return asset.metadata.get(cls.mode_prop, False)
|
||||
|
||||
@classmethod
|
||||
def get_active_asset(cls):
|
||||
paint_settings = UnifiedPaintPanel.paint_settings(bpy.context)
|
||||
return paint_settings.brush_asset_reference if paint_settings else None
|
||||
|
||||
|
||||
class VIEW3D_AST_brush_sculpt(BrushAssetShelf, bpy.types.AssetShelf):
|
||||
mode = 'SCULPT'
|
||||
|
|
|
@ -73,6 +73,75 @@ TEST_F(AssetRepresentationTest, weak_reference__custom_library)
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetRepresentationTest, weak_reference__compare)
|
||||
{
|
||||
{
|
||||
AssetWeakReference a;
|
||||
AssetWeakReference b;
|
||||
EXPECT_EQ(a, b);
|
||||
|
||||
/* Arbitrary individual member changes to test how it affects the comparison. */
|
||||
b.asset_library_identifier = "My lib";
|
||||
EXPECT_NE(a, b);
|
||||
a.asset_library_identifier = "My lib";
|
||||
EXPECT_EQ(a, b);
|
||||
a.asset_library_type = ASSET_LIBRARY_ESSENTIALS;
|
||||
EXPECT_NE(a, b);
|
||||
b.asset_library_type = ASSET_LIBRARY_LOCAL;
|
||||
EXPECT_NE(a, b);
|
||||
b.asset_library_type = ASSET_LIBRARY_ESSENTIALS;
|
||||
EXPECT_EQ(a, b);
|
||||
a.relative_asset_identifier = "Foo";
|
||||
EXPECT_NE(a, b);
|
||||
b.relative_asset_identifier = "Bar";
|
||||
EXPECT_NE(a, b);
|
||||
a.relative_asset_identifier = "Bar";
|
||||
EXPECT_EQ(a, b);
|
||||
|
||||
/* Make the destructor work. */
|
||||
a.asset_library_identifier = b.asset_library_identifier = nullptr;
|
||||
a.relative_asset_identifier = b.relative_asset_identifier = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
AssetWeakReference a;
|
||||
a.asset_library_type = ASSET_LIBRARY_LOCAL;
|
||||
a.asset_library_identifier = "My custom lib";
|
||||
a.relative_asset_identifier = "path/to/an/asset";
|
||||
|
||||
AssetWeakReference b;
|
||||
EXPECT_NE(a, b);
|
||||
|
||||
b.asset_library_type = ASSET_LIBRARY_LOCAL;
|
||||
b.asset_library_identifier = "My custom lib";
|
||||
b.relative_asset_identifier = "path/to/an/asset";
|
||||
EXPECT_EQ(a, b);
|
||||
|
||||
/* Make the destructor work. */
|
||||
a.asset_library_identifier = b.asset_library_identifier = nullptr;
|
||||
a.relative_asset_identifier = b.relative_asset_identifier = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
AssetLibrary *const library = service->get_asset_library_on_disk_custom("My custom lib",
|
||||
asset_library_root_);
|
||||
AssetRepresentation &asset = add_dummy_asset(*library, "path/to/an/asset");
|
||||
|
||||
AssetWeakReference *weak_ref = asset.make_weak_reference();
|
||||
AssetWeakReference other;
|
||||
other.asset_library_type = ASSET_LIBRARY_CUSTOM;
|
||||
other.asset_library_identifier = "My custom lib";
|
||||
other.relative_asset_identifier = "path/to/an/asset";
|
||||
EXPECT_EQ(*weak_ref, other);
|
||||
BKE_asset_weak_reference_free(&weak_ref);
|
||||
|
||||
/* Make the destructor work. */
|
||||
other.asset_library_identifier = nullptr;
|
||||
other.relative_asset_identifier = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(AssetRepresentationTest, weak_reference__resolve_to_full_path__current_file)
|
||||
{
|
||||
AssetLibraryService *service = AssetLibraryService::get();
|
||||
|
|
|
@ -78,6 +78,6 @@ void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data)
|
|||
|
||||
/** Frees the weak reference and its data, and nulls the given pointer. */
|
||||
void BKE_asset_weak_reference_free(AssetWeakReference **weak_ref);
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(AssetWeakReference *weak_ref);
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(const AssetWeakReference *weak_ref);
|
||||
void BKE_asset_weak_reference_write(BlendWriter *writer, const AssetWeakReference *weak_ref);
|
||||
void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *weak_ref);
|
||||
|
|
|
@ -540,6 +540,8 @@ struct AssetShelfType {
|
|||
const blender::asset_system::AssetRepresentation *asset,
|
||||
uiLayout *layout);
|
||||
|
||||
const AssetWeakReference *(*get_active_asset)(const AssetShelfType *shelf_type);
|
||||
|
||||
/* RNA integration */
|
||||
ExtensionRNA rna_ext;
|
||||
};
|
||||
|
|
|
@ -46,13 +46,44 @@ AssetWeakReference::~AssetWeakReference()
|
|||
MEM_delete(relative_asset_identifier);
|
||||
}
|
||||
|
||||
AssetWeakReference &AssetWeakReference::operator=(AssetWeakReference &&other)
|
||||
{
|
||||
if (&other == this) {
|
||||
return *this;
|
||||
}
|
||||
asset_library_type = other.asset_library_type;
|
||||
asset_library_identifier = other.asset_library_identifier;
|
||||
relative_asset_identifier = other.relative_asset_identifier;
|
||||
other.asset_library_type = 0; /* Not a valid type. */
|
||||
other.asset_library_identifier = nullptr;
|
||||
other.relative_asset_identifier = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool AssetWeakReference::operator==(const AssetWeakReference &other) const
|
||||
{
|
||||
if (asset_library_type != other.asset_library_type) {
|
||||
return false;
|
||||
}
|
||||
if (StringRef(asset_library_identifier) != StringRef(other.asset_library_identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return StringRef(relative_asset_identifier) == StringRef(other.relative_asset_identifier);
|
||||
}
|
||||
|
||||
bool AssetWeakReference::operator!=(const AssetWeakReference &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void BKE_asset_weak_reference_free(AssetWeakReference **weak_ref)
|
||||
{
|
||||
MEM_delete(*weak_ref);
|
||||
*weak_ref = nullptr;
|
||||
}
|
||||
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(AssetWeakReference *weak_ref)
|
||||
AssetWeakReference *BKE_asset_weak_reference_copy(const AssetWeakReference *weak_ref)
|
||||
{
|
||||
if (weak_ref == nullptr) {
|
||||
return nullptr;
|
||||
|
@ -60,8 +91,8 @@ AssetWeakReference *BKE_asset_weak_reference_copy(AssetWeakReference *weak_ref)
|
|||
|
||||
AssetWeakReference *weak_ref_copy = MEM_new<AssetWeakReference>(__func__);
|
||||
weak_ref_copy->asset_library_type = weak_ref->asset_library_type;
|
||||
weak_ref_copy->asset_library_identifier = BLI_strdup(weak_ref->asset_library_identifier);
|
||||
weak_ref_copy->relative_asset_identifier = BLI_strdup(weak_ref->relative_asset_identifier);
|
||||
weak_ref_copy->asset_library_identifier = BLI_strdup_null(weak_ref->asset_library_identifier);
|
||||
weak_ref_copy->relative_asset_identifier = BLI_strdup_null(weak_ref->relative_asset_identifier);
|
||||
|
||||
return weak_ref_copy;
|
||||
}
|
||||
|
|
|
@ -243,6 +243,9 @@ static void asset_shelf_region_listen(const wmRegionListenerParams *params)
|
|||
ED_region_tag_redraw(region);
|
||||
}
|
||||
break;
|
||||
case NC_ASSET:
|
||||
ED_region_tag_redraw(region);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -597,7 +600,7 @@ int context(const bContext *C, const char *member, bContextDataResult *result)
|
|||
/* XXX hack. Get the asset from the active item, but needs to be the file... */
|
||||
if (CTX_data_equals(member, "active_file")) {
|
||||
const ARegion *region = CTX_wm_region(C);
|
||||
const uiBut *but = UI_region_views_find_active_item_but(region);
|
||||
const uiBut *but = UI_region_views_find_mouse_over_but(CTX_wm_window(C), region);
|
||||
if (!but) {
|
||||
return CTX_RESULT_NO_DATA;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "AS_asset_library.hh"
|
||||
#include "AS_asset_representation.hh"
|
||||
|
||||
#include "BKE_asset.hh"
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
#include "BLI_fnmatch.h"
|
||||
|
@ -40,6 +41,7 @@ namespace blender::ed::asset::shelf {
|
|||
class AssetView : public ui::AbstractGridView {
|
||||
const AssetLibraryReference library_ref_;
|
||||
const AssetShelf &shelf_;
|
||||
AssetWeakReference *active_asset_ = nullptr;
|
||||
/** Copy of the filter string from #AssetShelfSettings, with extra '*' added to the beginning and
|
||||
* end of the string, for `fnmatch()` to work. */
|
||||
char search_string[sizeof(AssetShelfSettings::search_string) + 2] = "";
|
||||
|
@ -50,6 +52,7 @@ class AssetView : public ui::AbstractGridView {
|
|||
|
||||
public:
|
||||
AssetView(const AssetLibraryReference &library_ref, const AssetShelf &shelf);
|
||||
~AssetView();
|
||||
|
||||
void build_items() override;
|
||||
bool begin_filtering(const bContext &C) const override;
|
||||
|
@ -70,6 +73,7 @@ class AssetViewItem : public ui::PreviewGridItem {
|
|||
void disable_asset_drag();
|
||||
void build_grid_tile(uiLayout &layout) const override;
|
||||
void build_context_menu(bContext &C, uiLayout &column) const override;
|
||||
std::optional<bool> should_be_active() const override;
|
||||
bool is_filtered_visible() const override;
|
||||
|
||||
std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
|
||||
|
@ -92,6 +96,14 @@ AssetView::AssetView(const AssetLibraryReference &library_ref, const AssetShelf
|
|||
BLI_strncpy_ensure_pad(
|
||||
search_string, shelf.settings.search_string, '*', sizeof(search_string));
|
||||
}
|
||||
if (shelf.type->get_active_asset) {
|
||||
active_asset_ = BKE_asset_weak_reference_copy(shelf.type->get_active_asset(shelf.type));
|
||||
}
|
||||
}
|
||||
|
||||
AssetView::~AssetView()
|
||||
{
|
||||
BKE_asset_weak_reference_free(&active_asset_);
|
||||
}
|
||||
|
||||
void AssetView::build_items()
|
||||
|
@ -216,6 +228,20 @@ void AssetViewItem::build_context_menu(bContext &C, uiLayout &column) const
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<bool> AssetViewItem::should_be_active() const
|
||||
{
|
||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
||||
if (!asset_view.active_asset_) {
|
||||
return false;
|
||||
}
|
||||
const asset_system::AssetRepresentation *asset = handle_get_representation(&asset_);
|
||||
AssetWeakReference *weak_ref = asset->make_weak_reference();
|
||||
const bool matches = *asset_view.active_asset_ == *weak_ref;
|
||||
|
||||
BKE_asset_weak_reference_free(&weak_ref);
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool AssetViewItem::is_filtered_visible() const
|
||||
{
|
||||
const AssetView &asset_view = dynamic_cast<const AssetView &>(get_view());
|
||||
|
|
|
@ -3418,4 +3418,4 @@ uiViewHandle *UI_region_view_find_at(const ARegion *region, const int xy[2], int
|
|||
uiViewItemHandle *UI_region_views_find_item_at(const ARegion *region, const int xy[2])
|
||||
ATTR_NONNULL();
|
||||
uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region);
|
||||
uiBut *UI_region_views_find_active_item_but(const ARegion *region);
|
||||
uiBut *UI_region_views_find_mouse_over_but(const wmWindow *win, const ARegion *region);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <variant>
|
||||
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "BKE_screen.hh"
|
||||
|
||||
|
@ -199,9 +200,9 @@ uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region)
|
|||
return item_but->view_item;
|
||||
}
|
||||
|
||||
uiBut *UI_region_views_find_active_item_but(const ARegion *region)
|
||||
uiBut *UI_region_views_find_mouse_over_but(const wmWindow *win, const ARegion *region)
|
||||
{
|
||||
return ui_view_item_find_active(region);
|
||||
return ui_view_item_find_mouse_over(region, win->eventstate->xy);
|
||||
}
|
||||
|
||||
namespace blender::ui {
|
||||
|
|
|
@ -1014,6 +1014,7 @@ static int brush_asset_select_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, nullptr);
|
||||
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
|
||||
WM_toolsystem_ref_set_by_id(C, "builtin.brush");
|
||||
|
||||
|
|
|
@ -180,6 +180,10 @@ typedef struct AssetWeakReference {
|
|||
AssetWeakReference(AssetWeakReference &&);
|
||||
AssetWeakReference(const AssetWeakReference &) = delete;
|
||||
~AssetWeakReference();
|
||||
AssetWeakReference &operator=(AssetWeakReference &&);
|
||||
|
||||
bool operator==(const AssetWeakReference &other) const;
|
||||
bool operator!=(const AssetWeakReference &other) const;
|
||||
|
||||
/**
|
||||
* See AssetRepresentation::make_weak_reference(). Must be freed using
|
||||
|
|
|
@ -1145,6 +1145,29 @@ static bool asset_shelf_poll(const bContext *C, const AssetShelfType *shelf_type
|
|||
return is_visible;
|
||||
}
|
||||
|
||||
static const AssetWeakReference *asset_shelf_get_active_asset(const AssetShelfType *shelf_type)
|
||||
{
|
||||
extern FunctionRNA rna_AssetShelf_get_active_asset_func;
|
||||
|
||||
PointerRNA ptr = RNA_pointer_create(nullptr, shelf_type->rna_ext.srna, nullptr); /* dummy */
|
||||
|
||||
FunctionRNA *func = &rna_AssetShelf_get_active_asset_func;
|
||||
// RNA_struct_find_function(&ptr, "get_active_asset");
|
||||
|
||||
ParameterList list;
|
||||
RNA_parameter_list_create(&list, &ptr, func);
|
||||
shelf_type->rna_ext.call(nullptr, &ptr, func, &list);
|
||||
|
||||
void *ret;
|
||||
RNA_parameter_get_lookup(&list, "asset_reference", &ret);
|
||||
/* Get the value before freeing. */
|
||||
AssetWeakReference *active_asset = *(AssetWeakReference **)ret;
|
||||
|
||||
RNA_parameter_list_free(&list);
|
||||
|
||||
return active_asset;
|
||||
}
|
||||
|
||||
static void asset_shelf_draw_context_menu(const bContext *C,
|
||||
const AssetShelfType *shelf_type,
|
||||
const AssetRepresentationHandle *asset,
|
||||
|
@ -1208,7 +1231,7 @@ static StructRNA *rna_AssetShelf_register(Main *bmain,
|
|||
dummy_shelf.type = &dummy_shelf_type;
|
||||
PointerRNA dummy_shelf_ptr = RNA_pointer_create(nullptr, &RNA_AssetShelf, &dummy_shelf);
|
||||
|
||||
bool have_function[3];
|
||||
bool have_function[4];
|
||||
|
||||
/* validate the python class */
|
||||
if (validate(&dummy_shelf_ptr, data, have_function) != 0) {
|
||||
|
@ -1265,7 +1288,8 @@ static StructRNA *rna_AssetShelf_register(Main *bmain,
|
|||
|
||||
shelf_type->poll = have_function[0] ? asset_shelf_poll : nullptr;
|
||||
shelf_type->asset_poll = have_function[1] ? asset_shelf_asset_poll : nullptr;
|
||||
shelf_type->draw_context_menu = have_function[2] ? asset_shelf_draw_context_menu : nullptr;
|
||||
shelf_type->get_active_asset = have_function[2] ? asset_shelf_get_active_asset : nullptr;
|
||||
shelf_type->draw_context_menu = have_function[3] ? asset_shelf_draw_context_menu : nullptr;
|
||||
|
||||
BLI_addtail(&space_type->asset_shelf_types, shelf_type);
|
||||
|
||||
|
@ -2314,6 +2338,19 @@ static void rna_def_asset_shelf(BlenderRNA *brna)
|
|||
parm = RNA_def_pointer(func, "asset", "AssetRepresentation", "", "");
|
||||
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
|
||||
|
||||
func = RNA_def_function(srna, "get_active_asset", nullptr);
|
||||
RNA_def_function_ui_description(
|
||||
func,
|
||||
"Return a reference to the asset that should be highlighted as active in the asset shelf");
|
||||
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL);
|
||||
/* return type */
|
||||
parm = RNA_def_pointer(func,
|
||||
"asset_reference",
|
||||
"AssetWeakReference",
|
||||
"",
|
||||
"The weak reference to the asset to be hightlighted as active, or None");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "draw_context_menu", nullptr);
|
||||
RNA_def_function_ui_description(
|
||||
func, "Draw UI elements into the context menu UI layout displayed on right click");
|
||||
|
|
Loading…
Reference in New Issue