diff --git a/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py b/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py index d2bcc07ab47..b0a75563892 100644 --- a/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py +++ b/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py @@ -107,10 +107,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True): kmi_hack_properties = kmi_hack.properties kmi_hack.active = False - kmi_hack_brush_select = keymap.keymap_items.new("paint.brush_select", 'NONE', 'PRESS') - kmi_hack_brush_select_properties = kmi_hack_brush_select.properties - kmi_hack_brush_select.active = False - if use_release_confirm or use_tap_reset: kmi_toolbar = wm.keyconfigs.find_item_from_operator( idname="wm.toolbar", @@ -169,46 +165,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True): include={'KEYBOARD'}, )[1] - if kmi_found is None: - if item.data_block: - # PAINT_OT_brush_select - mode = context.active_object.mode - # See: BKE_paint_get_tool_prop_id_from_paintmode - if space_type == 'IMAGE_EDITOR': - if context.space_data.mode == 'PAINT': - attr = "image_tool" - else: - attr = None - elif space_type == 'VIEW_3D': - attr = { - 'SCULPT': "sculpt_tool", - 'VERTEX_PAINT': "vertex_tool", - 'WEIGHT_PAINT': "weight_tool", - 'TEXTURE_PAINT': "image_tool", - 'PAINT_GPENCIL': "gpencil_tool", - 'VERTEX_GPENCIL': "gpencil_vertex_tool", - 'SCULPT_GPENCIL': "gpencil_sculpt_tool", - 'WEIGHT_GPENCIL': "gpencil_weight_tool", - 'SCULPT_CURVES': "curves_sculpt_tool", - }.get(mode, None) - else: - attr = None - - if attr is not None: - setattr(kmi_hack_brush_select_properties, attr, item.data_block) - kmi_found = wm.keyconfigs.find_item_from_operator( - idname="paint.brush_select", - context='INVOKE_REGION_WIN', - properties=kmi_hack_brush_select_properties, - include={'KEYBOARD'}, - )[1] - elif mode in {'EDIT', 'PARTICLE_EDIT', 'SCULPT_GPENCIL'}: - # Doesn't use brushes - pass - else: - print("Unsupported mode:", mode) - del mode, attr - else: kmi_found = None diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index cd8951f7a54..6fe35665b0d 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -5501,27 +5501,6 @@ def km_sculpt(params): op_menu_pie("VIEW3D_MT_sculpt_automasking_pie", {"type": 'A', "alt": True, "value": 'PRESS'}), op_menu_pie("VIEW3D_MT_sculpt_face_sets_edit_pie", {"type": 'W', "value": 'PRESS', "alt": True}), *_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event), - # Tools - ("paint.brush_select", {"type": 'V', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'DRAW')]}), - ("paint.brush_select", {"type": 'S', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'SMOOTH')]}), - ("paint.brush_select", {"type": 'P', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'PINCH')]}), - ("paint.brush_select", {"type": 'I', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'INFLATE')]}), - ("paint.brush_select", {"type": 'G', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'GRAB')]}), - ("paint.brush_select", {"type": 'T', "value": 'PRESS', "shift": True}, - {"properties": [("sculpt_tool", 'SCRAPE')]}), - ("paint.brush_select", {"type": 'C', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'CLAY_STRIPS')]}), - ("paint.brush_select", {"type": 'C', "value": 'PRESS', "shift": True}, - {"properties": [("sculpt_tool", 'CREASE')]}), - ("paint.brush_select", {"type": 'K', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'SNAKE_HOOK')]}), - ("paint.brush_select", {"type": 'M', "value": 'PRESS'}, - {"properties": [("sculpt_tool", 'MASK'), ("toggle", True), ("create_missing", True)]}), ]) # Lasso Masking. diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index 7b779860e3f..a1ebc5b66c8 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -149,7 +149,7 @@ class BrushSelectPanel(BrushPanel): row = layout.row() # TODO: hide buttons since they are confusing with menu entries. # But some of this functionality may still be needed. - row.column().template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8, hide_buttons=True) + row.column().template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True) if brush is None: return @@ -157,13 +157,7 @@ class BrushSelectPanel(BrushPanel): col = row.column() col.menu("VIEW3D_MT_brush_context_menu", icon='DOWNARROW_HLT', text="") - # TODO: Need actual check if this is an asset from library. - # TODO: why is brush.asset_data None for these? - is_linked = brush.library - is_override = brush.override_library and brush.override_library.reference - is_asset_brush = is_linked or is_override - - if not is_asset_brush: + if not brush.is_asset_library_data and not brush.asset_data: # Legacy custom icon, mostly replaced by asset preview. layout.use_property_split = True layout.use_property_decorate = False diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index 7b13ae6dc99..c7ae171663d 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -46,13 +46,7 @@ class VIEW3D_MT_brush_context_menu(Menu): layout.label(text="No brush selected", icon='INFO') return - # TODO: Need actual check if this is an asset from library. - # TODO: why is brush.asset_data None for these? - is_linked = brush.library - is_override = brush.override_library and brush.override_library.reference - is_asset_brush = is_linked or is_override - - if is_asset_brush: + if brush.is_asset_library_data: layout.operator("brush.asset_save_as", text="Duplicate Asset...", icon='DUPLICATE') layout.operator("brush.asset_delete", text="Delete Asset") diff --git a/source/blender/blenkernel/BKE_asset.hh b/source/blender/blenkernel/BKE_asset.hh index a98a157384d..3920d9e0d08 100644 --- a/source/blender/blenkernel/BKE_asset.hh +++ b/source/blender/blenkernel/BKE_asset.hh @@ -11,6 +11,7 @@ #include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" +#include "DNA_ID_enums.h" #include "DNA_asset_types.h" struct AssetLibraryReference; @@ -20,6 +21,7 @@ struct BlendDataReader; struct BlendWriter; struct ID; struct IDProperty; +struct Main; struct PreviewImage; using PreSaveFn = void (*)(void *asset_ptr, AssetMetaData *asset_data); @@ -78,3 +80,9 @@ void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data) void BKE_asset_weak_reference_write(BlendWriter *writer, const AssetWeakReference *weak_ref); void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference *weak_ref); + +Main *BKE_asset_weak_reference_main(Main *global_main, const ID *id); +void BKE_asset_weak_reference_main_free(); +ID *BKE_asset_weak_reference_ensure(Main &global_main, + ID_Type id_type, + const AssetWeakReference &weak_ref); diff --git a/source/blender/blenkernel/BKE_brush.hh b/source/blender/blenkernel/BKE_brush.hh index 5b959003906..67244f2b6e6 100644 --- a/source/blender/blenkernel/BKE_brush.hh +++ b/source/blender/blenkernel/BKE_brush.hh @@ -31,10 +31,6 @@ struct UnifiedPaintSettings; void BKE_brush_system_init(); void BKE_brush_system_exit(); -/* TODO: Should be somewhere else not specific to brushes. */ -Brush *BKE_brush_asset_runtime_ensure(Main *bmain, - const AssetWeakReference &brush_asset_reference); - /* Data-block functions. */ /** diff --git a/source/blender/blenkernel/BKE_lib_override.hh b/source/blender/blenkernel/BKE_lib_override.hh index 02716511e0b..54243dd2722 100644 --- a/source/blender/blenkernel/BKE_lib_override.hh +++ b/source/blender/blenkernel/BKE_lib_override.hh @@ -84,17 +84,6 @@ bool BKE_lib_override_library_is_user_edited(const ID *id); */ bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id); -/** - * Count the number of liboverride IDs of given `id_type`, using a refererence linked ID from given - * `library`, that are user-edited. - * - * \param r_reports: If not NULL, add one report for each relevant ID. - */ -int BKE_lib_override_user_edited_from_library_count(Main *bmain, - ID_Type id_type, - Library *library, - ReportList *r_reports); - /** * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or * from a driver). diff --git a/source/blender/blenkernel/intern/asset_weak_reference.cc b/source/blender/blenkernel/intern/asset_weak_reference.cc index cb3b9807b45..fe844e13d34 100644 --- a/source/blender/blenkernel/intern/asset_weak_reference.cc +++ b/source/blender/blenkernel/intern/asset_weak_reference.cc @@ -7,15 +7,25 @@ */ #include +#include #include "BLI_string.h" +#include "DNA_space_types.h" + #include "AS_asset_identifier.hh" #include "AS_asset_library.hh" #include "BKE_asset.hh" +#include "BKE_blendfile_link_append.hh" +#include "BKE_idtype.hh" +#include "BKE_lib_id.hh" +#include "BKE_main.hh" + +#include "BLI_vector.hh" #include "BLO_read_write.hh" +#include "BLO_readfile.hh" #include "DNA_asset_types.h" @@ -118,3 +128,131 @@ void BKE_asset_weak_reference_read(BlendDataReader *reader, AssetWeakReference * BLO_read_data_address(reader, &weak_ref->asset_library_identifier); BLO_read_data_address(reader, &weak_ref->relative_asset_identifier); } + +/* Main database for each brush asset blend file. + * + * This avoids mixing asset datablocks in the regular main, which leads to naming conflicts and + * confusing user interface. + * + * TODO: Heavily WIP code. */ + +struct AssetWeakReferenceMain { + /* TODO: not sure if this is the best unique identifier. */ + std::string filepath; + Main *main; + + AssetWeakReferenceMain(std::string filepath) + : filepath(std::move(filepath)), main(BKE_main_new()) + { + } + AssetWeakReferenceMain(const AssetWeakReferenceMain &) = delete; + AssetWeakReferenceMain(AssetWeakReferenceMain &&other) + : filepath(std::exchange(other.filepath, "")), main(std::exchange(other.main, nullptr)) + { + } + + ~AssetWeakReferenceMain() + { + if (main) { + BKE_main_free(main); + } + } +}; + +static Vector &get_weak_reference_mains() +{ + static Vector mains; + return mains; +} + +Main *BKE_asset_weak_reference_main(Main *global_main, const ID *id) +{ + if (!(id->tag & LIB_TAG_ASSET_MAIN)) { + return global_main; + } + + for (const AssetWeakReferenceMain &weak_ref_main : get_weak_reference_mains()) { + /* TODO: Look into make this whole thing more efficient. */ + ListBase *lb = which_libbase(weak_ref_main.main, GS(id->name)); + LISTBASE_FOREACH (ID *, other_id, lb) { + if (id == other_id) { + return weak_ref_main.main; + } + } + } + + BLI_assert_unreachable(); + return nullptr; +} + +static Main &asset_weak_reference_main_ensure(const StringRef filepath) +{ + for (const AssetWeakReferenceMain &weak_ref_main : get_weak_reference_mains()) { + if (weak_ref_main.filepath == filepath) { + return *weak_ref_main.main; + } + } + + get_weak_reference_mains().append_as(filepath); + return *get_weak_reference_mains().last().main; +} + +void BKE_asset_weak_reference_main_free() +{ + get_weak_reference_mains().clear_and_shrink(); +} + +ID *BKE_asset_weak_reference_ensure(Main &global_main, + const ID_Type id_type, + const AssetWeakReference &weak_ref) +{ + char asset_full_path_buffer[FILE_MAX_LIBEXTRA]; + char *asset_lib_path, *asset_group, *asset_name; + + AS_asset_full_path_explode_from_weak_ref( + &weak_ref, asset_full_path_buffer, &asset_lib_path, &asset_group, &asset_name); + + if (asset_lib_path == nullptr && asset_group == nullptr && asset_name == nullptr) { + return nullptr; + } + + BLI_assert(asset_name != nullptr); + + /* If weak reference resolves to a null library path, assume we are in local asset case. */ + Main &bmain = asset_lib_path ? asset_weak_reference_main_ensure(asset_lib_path) : global_main; + + /* Check if we have the asset already, or if it's global main and there is nothing we can add. */ + ID *local_asset = BKE_libblock_find_name(&bmain, id_type, asset_name); + if (local_asset || asset_lib_path == nullptr) { + BLI_assert(local_asset == nullptr || ID_IS_ASSET(local_asset)); + return local_asset; + } + + /* Load asset from asset library. */ + LibraryLink_Params lapp_params{}; + lapp_params.bmain = &bmain; + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_flag_set(lapp_context, BLO_LIBLINK_FORCE_INDIRECT, true); + BKE_blendfile_link_append_context_flag_set(lapp_context, 0, true); + + BKE_blendfile_link_append_context_library_add(lapp_context, asset_lib_path, nullptr); + + BlendfileLinkAppendContextItem *lapp_item = BKE_blendfile_link_append_context_item_add( + lapp_context, asset_name, id_type, nullptr); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0); + + BKE_blendfile_link(lapp_context, nullptr); + BKE_blendfile_append(lapp_context, nullptr); + + local_asset = BKE_blendfile_link_append_context_item_newid_get(lapp_context, lapp_item); + + BKE_blendfile_link_append_context_free(lapp_context); + + /* TODO: only do for new ones? */ + BKE_main_id_tag_all(&bmain, LIB_TAG_ASSET_MAIN, true); + + /* Verify that the name matches. It must for referencing the same asset again to work. */ + BLI_assert(local_asset == nullptr || STREQ(local_asset->name + 2, asset_name)); + + return local_asset; +} diff --git a/source/blender/blenkernel/intern/blendfile.cc b/source/blender/blenkernel/intern/blendfile.cc index b678f17bedc..d32daa7c259 100644 --- a/source/blender/blenkernel/intern/blendfile.cc +++ b/source/blender/blenkernel/intern/blendfile.cc @@ -302,188 +302,6 @@ static bool reuse_bmain_data_remapper_is_id_remapped(id::IDRemapper &remapper, I return false; } -static Library *reuse_bmain_data_dependencies_new_library_get(ReuseOldBMainData *reuse_data, - Library *old_lib) -{ - if (old_lib == nullptr) { - return nullptr; - } - - id::IDRemapper *remapper = reuse_data->remapper; - Library *new_lib = old_lib; - IDRemapperApplyResult result = remapper->apply(reinterpret_cast(&new_lib), - ID_REMAP_APPLY_DEFAULT); - if (result == ID_REMAP_RESULT_SOURCE_UNAVAILABLE) { - /* No matching new library found. Avoid nullptr case when original data was linked, which would - * match against all local IDs. */ - } - BLI_assert_msg(result == ID_REMAP_RESULT_SOURCE_UNASSIGNED || new_lib != nullptr, - "`new_lib` should only ever be NULL here in case the library of the old linked " - "ID is the newly opened .blend file."); - return new_lib; -} - -static int reuse_bmain_data_dependencies_process_cb(LibraryIDLinkCallbackData *cb_data) -{ - ID *id = *cb_data->id_pointer; - - if (id == nullptr) { - return IDWALK_RET_NOP; - } - - ReuseOldBMainData *reuse_data = static_cast(cb_data->user_data); - Main *new_bmain = reuse_data->new_bmain; - Main *old_bmain = reuse_data->old_bmain; - - /* First check if it has already been remapped. */ - id::IDRemapper &remapper = reuse_bmain_data_remapper_ensure(reuse_data); - if (reuse_bmain_data_remapper_is_id_remapped(remapper, id)) { - return IDWALK_RET_STOP_RECURSION; - } - - ListBase *new_lb = which_libbase(new_bmain, GS(id->name)); - ListBase *old_lb = which_libbase(old_bmain, GS(id->name)); - - /* if ID is already in the new_bmain, this should have been detected by the check on `remapper` - * above. */ - BLI_assert(BLI_findindex(new_lb, id) < 0); - BLI_assert(BLI_findindex(old_lb, id) >= 0); - - /* There may be a new library pointer in new_bmain, matching a library in old_bmain, even - * though pointer values are not the same. So we need to check new linked IDs in new_bmain - * against both potential library pointers. */ - Library *old_id_new_lib = reuse_bmain_data_dependencies_new_library_get(reuse_data, id->lib); - - if (ID_IS_LINKED(id)) { - /* In case of linked ID, a 'new' version of the same data may already exist in new_bmain. In - * such case, do not move the old linked ID, but remap its usages to the new one instead. */ - for (ID *id_iter = static_cast(new_lb->last); id_iter != nullptr; - id_iter = static_cast(id_iter->prev)) - { - if (!ELEM(id_iter->lib, id->lib, old_id_new_lib)) { - continue; - } - if (!STREQ(id_iter->name + 2, id->name + 2)) { - continue; - } - - /* NOTE: In case the old ID was from a library that is the newly opened .blend file (i.e. - * `old_id_new_lib` is NULL), this will remap to a local new ID in new_bmain. - * - * This has a potential impact on other ported over linked IDs (which are not allowed to - * use local data), and liboverrides (which are not allowed to have a local reference). - * - * Such cases are checked and 'fixed' later by the call to - * #reuse_bmain_data_invalid_local_usages_fix. */ - remapper.add(id, id_iter); - return IDWALK_RET_STOP_RECURSION; - } - } - - BLI_remlink_safe(old_lb, id); - BKE_main_namemap_remove_name(old_bmain, id, id->name + 2); - - id->lib = old_id_new_lib; - BLI_addtail(new_lb, id); - BKE_id_new_name_validate(new_bmain, new_lb, id, nullptr, true); - /* Remap to itself, to avoid re-processing this ID again. */ - remapper.add(id, id); - - return IDWALK_RET_NOP; -} - -/** - * Selectively 'import' data from old Main into new Main, provided it does not conflict with data - * already present in the new Main (name-wise and library-wise). - * - * Dependencies from moved over old data are also imported into the new Main, (unless, in case of - * linked data, a matching linked ID is already available in new Main). - * - * When a conflict is found, usages of the conflicted ID by the old data are stored in the - * `remapper` of `ReuseOldBMainData` to be remapped to the matching data in the new Main later. - * - * NOTE: This function will never remove any original new data from the new Main, it only moves - * (some of) the old data to the new Main. - */ -static void reuse_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, const short id_code) -{ - Main *new_bmain = reuse_data->new_bmain; - Main *old_bmain = reuse_data->old_bmain; - - ListBase *new_lb = which_libbase(new_bmain, id_code); - ListBase *old_lb = which_libbase(old_bmain, id_code); - - id::IDRemapper &remapper = reuse_bmain_data_remapper_ensure(reuse_data); - - /* Bring back local existing IDs from old_lb into new_lb, if there are no name/library - * conflicts. */ - for (ID *old_id_iter_next, *old_id_iter = static_cast(old_lb->first); - old_id_iter != nullptr; - old_id_iter = old_id_iter_next) - { - old_id_iter_next = static_cast(old_id_iter->next); - - /* Fully local assets are never re-used, since in this case the old file can be considered as - * an asset repository, and its assets should be accessed through the asset system by other - * files. */ - if (!ID_IS_LINKED(old_id_iter) && !ID_IS_OVERRIDE_LIBRARY(old_id_iter) && - ID_IS_ASSET(old_id_iter)) - { - continue; - } - - /* All other IDs can be re-used, provided there is no name/library conflict (i.e. the new bmain - * does not already have the 'same' data). */ - bool can_use_old_id = true; - Library *old_id_new_lib = reuse_bmain_data_dependencies_new_library_get(reuse_data, - old_id_iter->lib); - for (ID *new_id_iter = static_cast(new_lb->first); new_id_iter != nullptr; - new_id_iter = static_cast(new_id_iter->next)) - { - if (!ELEM(new_id_iter->lib, old_id_iter->lib, old_id_new_lib)) { - continue; - } - if (!STREQ(old_id_iter->name + 2, new_id_iter->name + 2)) { - continue; - } - - /* In case we found a matching ID in new_bmain, it can be considered as 'the same' - * as the old ID, so usages of old ID ported over to new main can be remapped. - * - * This is only valid if the old ID was linked though. */ - if (ID_IS_LINKED(old_id_iter)) { - remapper.add(old_id_iter, new_id_iter); - } - can_use_old_id = false; - break; - } - - if (can_use_old_id) { - BLI_remlink_safe(old_lb, old_id_iter); - BKE_main_namemap_remove_name(old_bmain, old_id_iter, old_id_iter->name + 2); - - BLI_addtail(new_lb, old_id_iter); - old_id_iter->lib = old_id_new_lib; - BKE_id_new_name_validate(new_bmain, new_lb, old_id_iter, nullptr, true); - BKE_lib_libblock_session_uid_renew(old_id_iter); - - /* Remap to itself, to avoid re-processing this ID again. */ - remapper.add(old_id_iter, old_id_iter); - - /* Port over dependencies of re-used ID, unless matching already existing ones in - * new_bmain can be found. - * - * NOTE : No pointers are remapped here, this code only moves dependencies from old_bmain - * to new_bmain if needed, and add necessary remapping rules to the reuse_data.remapper. */ - BKE_library_foreach_ID_link(new_bmain, - old_id_iter, - reuse_bmain_data_dependencies_process_cb, - reuse_data, - IDWALK_RECURSE | IDWALK_DO_LIBRARY_POINTER); - } - } -} - /** * Does a complete replacement of data in `new_bmain` by data from `old_bmain. Original new data * are moved to the `old_bmain`, and will be freed together with it. @@ -491,9 +309,8 @@ static void reuse_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, co * WARNING: Currently only expects to work on local data, won't work properly if some of the IDs of * given type are linked. * - * NOTE: Unlike with #reuse_old_bmain_data_for_blendfile, there is no support at all for potential - * dependencies of the IDs moved around. This is not expected to be necessary for the current use - * cases (UI-related IDs). + * NOTE: There is no support at all for potential dependencies of the IDs moved around. This is not + * expected to be necessary for the current use cases (UI-related IDs). */ static void swap_old_bmain_data_for_blendfile(ReuseOldBMainData *reuse_data, const short id_code) { @@ -906,12 +723,6 @@ static void setup_app_data(bContext *C, } BKE_main_idmap_destroy(reuse_data.id_map); - - if (!is_startup) { - /* Keeping old brushes has different conditions, and different behavior, than UI-like ID - * types when actually reading a blendfile. */ - reuse_old_bmain_data_for_blendfile(&reuse_data, ID_BR); - } } /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has, as long diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 89012c781a9..2f7f46df019 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -25,7 +25,6 @@ #include "BLT_translation.hh" #include "BKE_asset.hh" -#include "BKE_blendfile_link_append.hh" #include "BKE_bpath.hh" #include "BKE_brush.hh" #include "BKE_colortools.hh" @@ -526,60 +525,6 @@ static void brush_defaults(Brush *brush) #undef FROM_DEFAULT_PTR } -Brush *BKE_brush_asset_runtime_ensure(Main *bmain, const AssetWeakReference &brush_asset_reference) -{ - char asset_full_path_buffer[FILE_MAX_LIBEXTRA]; - char *asset_lib_path, *asset_group, *asset_name; - - AS_asset_full_path_explode_from_weak_ref( - &brush_asset_reference, asset_full_path_buffer, &asset_lib_path, &asset_group, &asset_name); - - if (asset_lib_path == nullptr && asset_group == nullptr && asset_name == nullptr) { - return nullptr; - } - - BLI_assert(STREQ(asset_group, IDType_ID_BR.name)); - BLI_assert(asset_name != nullptr); - - /* If the weakreference resolves to a null library path, assume that we are in local asset case. - */ - if (asset_lib_path == nullptr) { - Brush *local_brush_asset = reinterpret_cast( - BLI_findstring(&bmain->brushes, asset_name, offsetof(ID, name) + 2)); - - if (local_brush_asset == nullptr || !ID_IS_ASSET(local_brush_asset)) { - return nullptr; - } - return local_brush_asset; - } - - LibraryLink_Params lapp_parameters{}; - lapp_parameters.bmain = bmain; - BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new( - &lapp_parameters); - BKE_blendfile_link_append_context_flag_set(lapp_context, BLO_LIBLINK_FORCE_INDIRECT, true); - BKE_blendfile_link_append_context_flag_set(lapp_context, FILE_LINK, true); - - BKE_blendfile_link_append_context_library_add(lapp_context, asset_lib_path, nullptr); - - BlendfileLinkAppendContextItem *lapp_item = BKE_blendfile_link_append_context_item_add( - lapp_context, asset_name, ID_BR, nullptr); - BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, lapp_item, 0); - - BKE_blendfile_link(lapp_context, nullptr); - BKE_blendfile_override(lapp_context, - eBKELibLinkOverride(BKE_LIBLINK_OVERRIDE_USE_EXISTING_LIBOVERRIDES | - BKE_LIBLINK_OVERRIDE_CREATE_RUNTIME), - nullptr); - - Brush *liboverride_brush = reinterpret_cast( - BKE_blendfile_link_append_context_item_liboverrideid_get(lapp_context, lapp_item)); - - BKE_blendfile_link_append_context_free(lapp_context); - - return liboverride_brush; -} - /* Datablock add/copy/free/make_local */ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode) diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index ac3910d58d1..b176c6db072 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -341,42 +341,6 @@ bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id) return false; } -int BKE_lib_override_user_edited_from_library_count(Main *bmain, - const ID_Type id_type, - Library *library, - ReportList *r_reports) -{ - ListBase *lb = which_libbase(bmain, id_type); - int num_user_edited = 0; - - for (ID *id_iter = static_cast(lb->first); id_iter != nullptr; - id_iter = static_cast(id_iter->next)) - { - if (ID_IS_LINKED(id_iter)) { - break; - } - if (!ID_IS_OVERRIDE_LIBRARY(id_iter)) { - continue; - } - if (id_iter->override_library->reference->lib != library) { - continue; - } - if (!BKE_lib_override_library_is_user_edited(id_iter)) { - continue; - } - - /* NOTE: If changes have been saved in a draft, then the local override is based on said - * draft (using the linked ID from the draft file as reference), so there should be no user - * edited changes anymore. */ - num_user_edited++; - if (r_reports) { - BKE_report(r_reports, RPT_INFO, id_iter->name + 2); - } - } - - return num_user_edited; -} - bool BKE_lib_override_library_property_is_animated( const ID *id, const IDOverrideLibraryProperty *liboverride_prop, diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 7e832558269..8afb6735391 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -668,8 +668,6 @@ const Brush *BKE_paint_brush_for_read(const Paint *p) void BKE_paint_brush_set(Paint *p, Brush *br) { if (p) { - id_us_min((ID *)p->brush); - id_us_plus((ID *)br); p->brush = br; BKE_paint_toolslots_brush_update(p); @@ -678,9 +676,7 @@ void BKE_paint_brush_set(Paint *p, Brush *br) bool BKE_paint_brush_is_valid_asset(const Brush *brush) { - return brush && (ID_IS_ASSET(&brush->id) || - (!ID_IS_LINKED(&brush->id) && ID_IS_OVERRIDE_LIBRARY_REAL(&brush->id) && - ID_IS_ASSET(brush->id.override_library->reference))); + return brush && ID_IS_ASSET(&brush->id); } static void paint_brush_asset_update(Paint &paint, @@ -689,9 +685,7 @@ static void paint_brush_asset_update(Paint &paint, { MEM_delete(paint.brush_asset_reference); - if (brush == nullptr || brush != paint.brush || !ID_IS_OVERRIDE_LIBRARY_REAL(paint.brush) || - !(ID_IS_ASSET(paint.brush) || ID_IS_ASSET(paint.brush->id.override_library->reference))) - { + if (brush == nullptr || brush != paint.brush || !(brush->id.tag & LIB_TAG_ASSET_MAIN)) { return; } @@ -742,7 +736,8 @@ void BKE_paint_brush_asset_restore(Main *bmain, Paint *paint) MEM_delete(paint->brush_asset_reference); paint->brush_asset_reference = nullptr; - Brush *brush_asset = BKE_brush_asset_runtime_ensure(bmain, weak_ref); + Brush *brush_asset = reinterpret_cast( + BKE_asset_weak_reference_ensure(*bmain, ID_BR, weak_ref)); /* Will either re-assign the brush_asset_reference to `paint`, or free it if loading a brush ID * from it failed. */ @@ -1259,20 +1254,6 @@ void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3]) BKE_paint_ensure_from_paintmode(bmain, sce, mode); - /* If there's no brush, create one */ - if (PAINT_MODE_HAS_BRUSH(mode)) { - Brush *brush = BKE_paint_brush(paint); - if (brush == nullptr) { - eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode); - brush = BKE_brush_first_search(bmain, ob_mode); - if (!brush) { - brush = BKE_brush_add(bmain, "Brush", ob_mode); - id_us_min(&brush->id); /* Fake user only. */ - } - BKE_paint_brush_set(paint, brush); - } - } - copy_v3_v3_uchar(paint->paint_cursor_col, col); paint->paint_cursor_col[3] = 128; ups->last_stroke_valid = false; @@ -1302,13 +1283,7 @@ void BKE_paint_copy(const Paint *src, Paint *dst, const int flag) } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - id_us_plus((ID *)dst->brush); id_us_plus((ID *)dst->palette); - if (src->tool_slots != nullptr) { - for (int i = 0; i < dst->tool_slots_len; i++) { - id_us_plus((ID *)dst->tool_slots[i].brush); - } - } } } diff --git a/source/blender/blenkernel/intern/paint_toolslots.cc b/source/blender/blenkernel/intern/paint_toolslots.cc index 4ab9259de8f..fc03248b527 100644 --- a/source/blender/blenkernel/intern/paint_toolslots.cc +++ b/source/blender/blenkernel/intern/paint_toolslots.cc @@ -53,7 +53,6 @@ static void paint_toolslots_init(Main *bmain, Paint *paint) BKE_paint_toolslots_len_ensure(paint, slot_index + 1); if (paint->tool_slots[slot_index].brush == nullptr) { paint->tool_slots[slot_index].brush = brush; - id_us_plus(&brush->id); } } } @@ -120,10 +119,6 @@ void BKE_paint_toolslots_brush_update_ex(Paint *paint, Brush *brush) const int slot_index = BKE_brush_tool_get(brush, paint); BKE_paint_toolslots_len_ensure(paint, slot_index + 1); PaintToolSlot *tslot = &paint->tool_slots[slot_index]; - id_us_plus(&brush->id); - if (tslot->brush) { - id_us_min(&tslot->brush->id); - } tslot->brush = brush; } @@ -147,7 +142,6 @@ void BKE_paint_toolslots_brush_validate(Main *bmain, Paint *paint) if (tslot->brush) { if ((i != BKE_brush_tool_get(tslot->brush, paint)) || (tslot->brush->ob_mode & ob_mode) == 0) { - id_us_min(&tslot->brush->id); tslot->brush = nullptr; } } diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 99187c7e878..d8e7697e73b 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -591,7 +591,7 @@ static void scene_foreach_paint(LibraryForeachIDData *data, SCENE_FOREACH_UNDO_RESTORE, reader, &paint_old->brush, - IDWALK_CB_USER); + IDWALK_CB_NOP); for (int i = 0; i < paint_old->tool_slots_len; i++) { /* This is a bit tricky. @@ -610,7 +610,7 @@ static void scene_foreach_paint(LibraryForeachIDData *data, SCENE_FOREACH_UNDO_RESTORE, reader, &paint_old->tool_slots[i].brush, - IDWALK_CB_USER); + IDWALK_CB_NOP); } Palette *palette_tmp = nullptr; diff --git a/source/blender/editors/interface/interface_region_tooltip.cc b/source/blender/editors/interface/interface_region_tooltip.cc index 23f78aa1d59..e6c8b34ab4e 100644 --- a/source/blender/editors/interface/interface_region_tooltip.cc +++ b/source/blender/editors/interface/interface_region_tooltip.cc @@ -559,7 +559,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is /* There are different kinds of shortcuts: * * - Direct access to the tool (as if the toolbar button is pressed). - * - The key is bound to a brush type (not the exact brush name). * - The key is assigned to the operator itself * (bypassing the tool, executing the operator). * @@ -567,36 +566,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is */ std::string shortcut = UI_but_string_get_operator_keymap(*C, *but); - if (shortcut.empty()) { - const PaintMode paint_mode = BKE_paintmode_get_active_from_context(C); - const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - if (tool_attr != nullptr) { - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - const char *tool_id_lstrip = strrchr(tool_id, '.'); - const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0; - const int i = RNA_enum_from_name(items, tool_id + tool_id_offset); - - if (i != -1) { - wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true); - PointerRNA op_props; - WM_operator_properties_create_ptr(&op_props, ot); - RNA_enum_set(&op_props, tool_attr, items[i].value); - - /* Check for direct access to the tool. */ - if (std::optional shortcut_brush = WM_key_event_operator_string( - C, - ot->idname, - WM_OP_INVOKE_REGION_WIN, - static_cast(op_props.data), - true)) - { - shortcut = *shortcut_brush; - } - WM_operator_properties_free(&op_props); - } - } - } - if (shortcut.empty()) { /* Check for direct access to the tool. */ if (std::optional shortcut_toolbar = WM_key_event_operator_string( diff --git a/source/blender/editors/interface/interface_templates.cc b/source/blender/editors/interface/interface_templates.cc index 9a4cfa5a630..0b3687ad732 100644 --- a/source/blender/editors/interface/interface_templates.cc +++ b/source/blender/editors/interface/interface_templates.cc @@ -43,6 +43,8 @@ #include "BLF_api.hh" #include "BLT_translation.hh" +#include "BKE_action.h" +#include "BKE_asset.hh" #include "BKE_blender_version.h" #include "BKE_blendfile.hh" #include "BKE_colorband.hh" @@ -941,6 +943,8 @@ static void template_id_liboverride_hierarchy_make(bContext *C, static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) { + /* TODO: select appropriate bmain for ID, might need to be asset main, changes in this functions + * are most likely wrong still. */ TemplateID *template_ui = (TemplateID *)arg_litem; PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); ID *id = static_cast(idptr.data); @@ -994,12 +998,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - Main *bmain = CTX_data_main(C); + Main *id_main = BKE_asset_weak_reference_main(CTX_data_main(C), id); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); + template_id_liboverride_hierarchy_make( + C, id_main, template_ui, &idptr, &undo_push_label); } else { - if (BKE_lib_id_make_local(bmain, id, 0)) { + if (BKE_lib_id_make_local(id_main, id, 0)) { BKE_id_newptr_and_tag_clear(id); /* Reassign to get proper updates/notifiers. */ @@ -1015,12 +1020,13 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_OVERRIDE: if (id && ID_IS_OVERRIDE_LIBRARY(id)) { - Main *bmain = CTX_data_main(C); + Main *id_main = BKE_asset_weak_reference_main(CTX_data_main(C), id); if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) { - template_id_liboverride_hierarchy_make(C, bmain, template_ui, &idptr, &undo_push_label); + template_id_liboverride_hierarchy_make( + C, id_main, template_ui, &idptr, &undo_push_label); } else { - BKE_lib_override_library_make_local(bmain, id); + BKE_lib_override_library_make_local(id_main, id); /* Reassign to get proper updates/notifiers. */ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop); RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr, nullptr); @@ -1035,15 +1041,16 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) (template_ui->ptr.type == &RNA_LayerObjects)); /* make copy */ + Main *bmain = CTX_data_main(C); + Main *id_main = BKE_asset_weak_reference_main(bmain, id); + if (do_scene_obj) { - Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ED_object_single_user(bmain, scene, (Object *)id); + ED_object_single_user(id_main, scene, (Object *)id); WM_event_add_notifier(C, NC_WINDOW, nullptr); DEG_relations_tag_update(bmain); } else { - Main *bmain = CTX_data_main(C); id_single_user(C, id, &template_ui->ptr, template_ui->prop); DEG_relations_tag_update(bmain); } @@ -1334,7 +1341,7 @@ static void template_ID(const bContext *C, /* text button with name */ if (id) { char name[UI_MAX_NAME_STR]; - const bool user_alert = (id->us <= 0); + const bool user_alert = (id->us <= 0) && !(id->tag & LIB_TAG_ASSET_MAIN); const int width = template_search_textbut_width(&idptr, RNA_struct_find_property(&idptr, "name")); @@ -1759,10 +1766,15 @@ static void ui_template_id(uiLayout *layout, flag |= UI_ID_OPEN; } + Main *id_main = CTX_data_main(C); + if (ptr->owner_id) { + id_main = BKE_asset_weak_reference_main(id_main, ptr->owner_id); + } + StructRNA *type = RNA_property_pointer_type(ptr, prop); short idcode = RNA_type_to_ID_code(type); template_ui->idcode = idcode; - template_ui->idlb = which_libbase(CTX_data_main(C), idcode); + template_ui->idlb = which_libbase(id_main, idcode); /* create UI elements for this template * - template_ID makes a copy of the template data and assigns it to the relevant buttons diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 6ff7b11b11c..f319c069b83 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -35,6 +35,7 @@ #include "BKE_anim_data.h" #include "BKE_animsys.h" #include "BKE_appdir.hh" +#include "BKE_asset.hh" #include "BKE_blender_copybuffer.hh" #include "BKE_brush.hh" #include "BKE_context.hh" @@ -821,22 +822,26 @@ void MATERIAL_OT_new(wmOperatorType *ot) static int new_texture_exec(bContext *C, wmOperator * /*op*/) { - Tex *tex = static_cast(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); - Main *bmain = CTX_data_main(C); PointerRNA ptr; PropertyRNA *prop; + UI_context_active_but_prop_get_templateID(C, &ptr, &prop); + + Main *id_main = CTX_data_main(C); + if (ptr.owner_id) { + id_main = BKE_asset_weak_reference_main(id_main, ptr.owner_id); + } + /* add or copy texture */ + Tex *tex = static_cast(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); if (tex) { - tex = (Tex *)BKE_id_copy(bmain, &tex->id); + tex = (Tex *)BKE_id_copy(id_main, &tex->id); } else { - tex = BKE_texture_add(bmain, DATA_("Texture")); + tex = BKE_texture_add(id_main, DATA_("Texture")); } /* hook into UI */ - UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - if (prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer use also increases user, so this compensates it */ diff --git a/source/blender/editors/sculpt_paint/paint_ops.cc b/source/blender/editors/sculpt_paint/paint_ops.cc index 817c41d9f4a..8ead0d67d20 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_ops.cc @@ -35,6 +35,7 @@ #include "BKE_image.h" #include "BKE_lib_id.hh" #include "BKE_lib_override.hh" +#include "BKE_lib_remap.hh" #include "BKE_main.hh" #include "BKE_paint.hh" #include "BKE_preferences.h" @@ -66,42 +67,6 @@ #include "paint_intern.hh" #include "sculpt_intern.hh" -/* Brush operators */ -static int brush_add_exec(bContext *C, wmOperator * /*op*/) -{ - // int type = RNA_enum_get(op->ptr, "type"); - Paint *paint = BKE_paint_get_active_from_context(C); - Brush *br = BKE_paint_brush(paint); - Main *bmain = CTX_data_main(C); - PaintMode mode = BKE_paintmode_get_active_from_context(C); - - if (br) { - br = (Brush *)BKE_id_copy(bmain, &br->id); - } - else { - br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paintmode(mode)); - } - id_us_min(&br->id); /* fake user only */ - - BKE_paint_brush_set(paint, br); - - return OPERATOR_FINISHED; -} - -static void BRUSH_OT_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Brush"; - ot->description = "Add brush by mode type"; - ot->idname = "BRUSH_OT_add"; - - /* api callbacks */ - ot->exec = brush_add_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool, enum eContextObjectMode mode) { @@ -194,7 +159,7 @@ static int brush_add_gpencil_exec(bContext *C, wmOperator * /*op*/) { Paint *paint = BKE_paint_get_active_from_context(C); Brush *br = BKE_paint_brush(paint); - Main *bmain = CTX_data_main(C); + Main *bmain = CTX_data_main(C); // TODO: add to asset main? if (br) { br = (Brush *)BKE_id_copy(bmain, &br->id); @@ -789,205 +754,6 @@ static void BRUSH_OT_reset(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -static int brush_tool(const Brush *brush, size_t tool_offset) -{ - return *(((char *)brush) + tool_offset); -} - -static void brush_tool_set(const Brush *brush, size_t tool_offset, int tool) -{ - *(((char *)brush) + tool_offset) = tool; -} - -static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool) -{ - Brush *brush, *first_brush; - - if (!brush_orig && !(brush_orig = static_cast(bmain->brushes.first))) { - return nullptr; - } - - if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) { - /* If current brush's tool is different from what we need, - * start cycling from the beginning of the list. - * Such logic will activate the same exact brush not relating from - * which tool user requests other tool. - */ - - /* Try to tool-slot first. */ - first_brush = BKE_paint_toolslots_brush_get(paint, tool); - if (first_brush == nullptr) { - first_brush = static_cast(bmain->brushes.first); - } - } - else { - /* If user wants to switch to brush with the same tool as - * currently active brush do a cycling via all possible - * brushes with requested tool. */ - first_brush = brush_orig->id.next ? static_cast(brush_orig->id.next) : - static_cast(bmain->brushes.first); - } - - /* get the next brush with the active tool */ - brush = first_brush; - do { - if ((brush->ob_mode & paint->runtime.ob_mode) && - (brush_tool(brush, paint->runtime.tool_offset) == tool)) - { - return brush; - } - - brush = brush->id.next ? static_cast(brush->id.next) : - static_cast(bmain->brushes.first); - } while (brush != first_brush); - - return nullptr; -} - -static Brush *brush_tool_toggle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool) -{ - if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) { - Brush *br; - /* if the current brush is not using the desired tool, look - * for one that is */ - br = brush_tool_cycle(bmain, paint, brush_orig, tool); - /* store the previously-selected brush */ - if (br) { - br->toggle_brush = brush_orig; - } - - return br; - } - if (brush_orig->toggle_brush) { - /* if current brush is using the desired tool, try to toggle - * back to the previously selected brush. */ - return brush_orig->toggle_brush; - } - return nullptr; -} - -static bool brush_generic_tool_set(bContext *C, - Main *bmain, - Paint *paint, - const int tool, - const char *tool_name, - const bool create_missing, - const bool toggle) -{ - Brush *brush, *brush_orig = BKE_paint_brush(paint); - - if (toggle) { - brush = brush_tool_toggle(bmain, paint, brush_orig, tool); - } - else { - brush = brush_tool_cycle(bmain, paint, brush_orig, tool); - } - - if (((brush == nullptr) && create_missing) && - ((brush_orig == nullptr) || brush_tool(brush_orig, paint->runtime.tool_offset) != tool)) - { - brush = BKE_brush_add(bmain, tool_name, eObjectMode(paint->runtime.ob_mode)); - id_us_min(&brush->id); /* fake user only */ - brush_tool_set(brush, paint->runtime.tool_offset, tool); - brush->toggle_brush = brush_orig; - } - - if (brush) { - BKE_paint_brush_set(paint, brush); - BKE_paint_invalidate_overlay_all(); - - WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); - WM_toolsystem_ref_set_by_id(C, "builtin.brush"); - return true; - } - return false; -} - -static const PaintMode brush_select_paint_modes[] = { - PaintMode::Sculpt, - PaintMode::Vertex, - PaintMode::Weight, - PaintMode::Texture3D, - PaintMode::GPencil, - PaintMode::VertexGPencil, - PaintMode::SculptGPencil, - PaintMode::WeightGPencil, - PaintMode::SculptCurves, -}; - -static int brush_select_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - const bool create_missing = RNA_boolean_get(op->ptr, "create_missing"); - const bool toggle = RNA_boolean_get(op->ptr, "toggle"); - const char *tool_name = "Brush"; - int tool = 0; - - PaintMode paint_mode = PaintMode::Invalid; - for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) { - paint_mode = brush_select_paint_modes[i]; - const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id); - if (RNA_property_is_set(op->ptr, prop)) { - tool = RNA_property_enum_get(op->ptr, prop); - break; - } - } - - if (paint_mode == PaintMode::Invalid) { - return OPERATOR_CANCELLED; - } - - Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - if (paint == nullptr) { - return OPERATOR_CANCELLED; - } - - if (brush_generic_tool_set(C, bmain, paint, tool, tool_name, create_missing, toggle)) { - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -static void PAINT_OT_brush_select(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name = "Brush Select"; - ot->description = "Select a paint mode's brush by tool type"; - ot->idname = "PAINT_OT_brush_select"; - - /* api callbacks */ - ot->exec = brush_select_exec; - - /* flags */ - ot->flag = 0; - - /* props */ - /* All properties are hidden, so as not to show the redo panel. */ - for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) { - const PaintMode paint_mode = brush_select_paint_modes[i]; - const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode); - prop = RNA_def_enum( - ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, ""); - RNA_def_property_translation_context( - prop, BKE_paint_get_tool_enum_translation_context_from_paintmode(paint_mode)); - RNA_def_property_flag(prop, PROP_HIDDEN); - } - - prop = RNA_def_boolean( - ot->srna, "toggle", false, "Toggle", "Toggle between two brushes rather than cycling"); - RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); - prop = RNA_def_boolean(ot->srna, - "create_missing", - false, - "Create Missing", - "If the requested brush type does not exist, create a new brush"); - RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); -} - namespace blender::ed::sculpt_paint { /**************************** Brush Assets **********************************/ @@ -997,6 +763,7 @@ static int brush_asset_select_exec(bContext *C, wmOperator *op) /* This operator currently covers both cases: the file/asset browser file list and the asset list * used for the asset-view template. Once the asset list design is used by the Asset Browser, * this can be simplified to just that case. */ + Main *bmain = CTX_data_main(C); const asset_system::AssetRepresentation *asset = asset::operator_asset_reference_props_get_asset_from_all_library(*C, *op->ptr, op->reports); if (!asset) { @@ -1004,7 +771,8 @@ static int brush_asset_select_exec(bContext *C, wmOperator *op) } AssetWeakReference brush_asset_reference = asset->make_weak_reference(); - Brush *brush = BKE_brush_asset_runtime_ensure(CTX_data_main(C), brush_asset_reference); + Brush *brush = reinterpret_cast( + BKE_asset_weak_reference_ensure(*bmain, ID_BR, brush_asset_reference)); Paint *paint = BKE_paint_get_active_from_context(C); @@ -1292,6 +1060,7 @@ static AssetLibraryReference user_library_to_library_ref(const bUserAssetLibrary static int brush_asset_save_as_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr; if (paint == nullptr || brush == nullptr) { @@ -1343,8 +1112,10 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op) library->catalog_service->write_to_disk(filepath); /* Save to asset library. */ + Main *asset_main = BKE_asset_weak_reference_main(bmain, &brush->id); + std::string final_full_asset_filepath; - const bool sucess = brush_asset_write_in_library(CTX_data_main(C), + const bool sucess = brush_asset_write_in_library(asset_main, brush, name, filepath, @@ -1364,8 +1135,8 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op) /* TODO: maybe not needed, even less so if there is more visual confirmation of change. */ BKE_reportf(op->reports, RPT_INFO, "Saved \"%s\"", filepath.c_str()); - Main *bmain = CTX_data_main(C); - brush = BKE_brush_asset_runtime_ensure(bmain, new_brush_weak_ref); + brush = reinterpret_cast( + BKE_asset_weak_reference_ensure(*bmain, ID_BR, new_brush_weak_ref)); if (!BKE_paint_brush_asset_set(paint, brush, new_brush_weak_ref)) { /* Note brush sset was still saved in editable asset library, so was not a no-op. */ @@ -1480,9 +1251,10 @@ static bool brush_asset_delete_poll(bContext *C) static int brush_asset_delete_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + Main *bmain = CTX_data_main(C); + Main *asset_main = BKE_asset_weak_reference_main(bmain, &brush->id); bUserAssetLibrary *library = BKE_preferences_asset_library_find_by_name( &U, paint->brush_asset_reference->asset_library_identifier); @@ -1502,15 +1274,12 @@ static int brush_asset_delete_exec(bContext *C, wmOperator *op) } } - /* Delete from session. If local override, also delete linked one. - * TODO: delete both in one step? */ - ID *original_brush = (!ID_IS_LINKED(&brush->id) && ID_IS_OVERRIDE_LIBRARY_REAL(&brush->id)) ? - brush->id.override_library->reference : - nullptr; - BKE_id_delete(bmain, brush); - if (original_brush) { - BKE_id_delete(bmain, original_brush); + if (asset_main != bmain) { + // TODO: hack: no pointer should exist, should do runtime lookup + BKE_libblock_remap(bmain, brush, nullptr, 0); } + BKE_id_delete(asset_main, brush); + // TODO: delete whole asset main if empty? refresh_asset_library(C, *library); WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_REMOVED, nullptr); @@ -1554,11 +1323,15 @@ static bool brush_asset_update_poll(bContext *C) static int brush_asset_update_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = nullptr; const AssetWeakReference *asset_weak_ref = BKE_paint_brush_asset_get(paint, &brush).value_or(nullptr); + // TODO: maybe can check directly in poll + BLI_assert((brush->id.tag & LIB_TAG_ASSET_MAIN) != 0); + char path_buffer[FILE_MAX_LIBEXTRA]; char *filepath; AS_asset_full_path_explode_from_weak_ref( @@ -1566,8 +1339,9 @@ static int brush_asset_update_exec(bContext *C, wmOperator *op) BLI_assert(BKE_paint_brush_is_valid_asset(brush)); + Main *asset_main = BKE_asset_weak_reference_main(bmain, &brush->id); std::string final_full_asset_filepath; - brush_asset_write_in_library(CTX_data_main(C), + brush_asset_write_in_library(asset_main, brush, brush->id.name + 2, filepath, @@ -1606,12 +1380,21 @@ static int brush_asset_revert_exec(bContext *C, wmOperator * /*op*/) Main *bmain = CTX_data_main(C); Paint *paint = BKE_paint_get_active_from_context(C); Brush *brush = BKE_paint_brush(paint); + Main *asset_main = BKE_asset_weak_reference_main(bmain, &brush->id); - /* TODO: check if doing this for the hierarchy is ok. */ - /* TODO: the overrides don't update immediately when tweaking brush settings. */ - BKE_lib_override_library_id_hierarchy_reset(bmain, &brush->id, false); + // TODO: delete and reload dependencies too? + // TODO: hack to make remapping work, should not be needed + // if we can make brush pointer not part of ID management at all + BLI_remlink(&asset_main->brushes, brush); - WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush); + Brush *new_brush = reinterpret_cast( + BKE_asset_weak_reference_ensure(*bmain, ID_BR, *paint->brush_asset_reference)); + + BKE_libblock_remap(bmain, brush, new_brush, 0); + BLI_addtail(&asset_main->brushes, brush); + BKE_id_delete(asset_main, brush); + + WM_main_add_notifier(NC_BRUSH | NA_EDITED, new_brush); return OPERATOR_FINISHED; } @@ -2081,7 +1864,6 @@ void ED_operatortypes_paint() WM_operatortype_append(PAINTCURVE_OT_cursor); /* brush */ - WM_operatortype_append(BRUSH_OT_add); WM_operatortype_append(BRUSH_OT_add_gpencil); WM_operatortype_append(BRUSH_OT_scale_size); WM_operatortype_append(BRUSH_OT_curve_preset); @@ -2096,9 +1878,6 @@ void ED_operatortypes_paint() WM_operatortype_append(BRUSH_OT_asset_update); WM_operatortype_append(BRUSH_OT_asset_revert); - /* NOTE: particle uses a different system, can be added with existing operators in `wm.py`. */ - WM_operatortype_append(PAINT_OT_brush_select); - /* image */ WM_operatortype_append(PAINT_OT_texture_paint_toggle); WM_operatortype_append(PAINT_OT_image_paint); diff --git a/source/blender/editors/space_image/image_ops.cc b/source/blender/editors/space_image/image_ops.cc index 5f278f15fd0..7441cd24ed2 100644 --- a/source/blender/editors/space_image/image_ops.cc +++ b/source/blender/editors/space_image/image_ops.cc @@ -34,6 +34,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "BKE_asset.hh" #include "BKE_colortools.hh" #include "BKE_context.hh" #include "BKE_global.hh" @@ -2532,7 +2533,7 @@ static int image_new_exec(bContext *C, wmOperator *op) { SpaceImage *sima; Image *ima; - Main *bmain; + Main *id_main; PropertyRNA *prop; char name_buffer[MAX_ID_NAME - 2]; const char *name; @@ -2540,9 +2541,14 @@ static int image_new_exec(bContext *C, wmOperator *op) int width, height, floatbuf, gen_type, alpha; int stereo3d; + ImageNewData *data = image_new_init(C, op); + /* retrieve state */ sima = CTX_wm_space_image(C); - bmain = CTX_data_main(C); + id_main = CTX_data_main(C); + if (data->pprop.ptr.owner_id) { + id_main = BKE_asset_weak_reference_main(id_main, data->pprop.ptr.owner_id); + } prop = RNA_struct_find_property(op->ptr, "name"); RNA_property_string_get(op->ptr, prop, name_buffer); @@ -2566,7 +2572,7 @@ static int image_new_exec(bContext *C, wmOperator *op) color[3] = 1.0f; } - ima = BKE_image_add_generated(bmain, + ima = BKE_image_add_generated(id_main, width, height, name, @@ -2584,8 +2590,6 @@ static int image_new_exec(bContext *C, wmOperator *op) } /* hook into UI */ - ImageNewData *data = image_new_init(C, op); - if (data->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA * pointer use also increases user, so this compensates it */ @@ -2596,7 +2600,7 @@ static int image_new_exec(bContext *C, wmOperator *op) RNA_property_update(C, &data->pprop.ptr, data->pprop.prop); } else if (sima) { - ED_space_image_set(bmain, sima, ima, false); + ED_space_image_set(id_main, sima, ima, false); } else { /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to @@ -2604,7 +2608,7 @@ static int image_new_exec(bContext *C, wmOperator *op) id_us_min(&ima->id); } - BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE); + BKE_image_signal(id_main, ima, (sima) ? &sima->iuser : nullptr, IMA_SIGNAL_USER_NEW_IMAGE); WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 44e45b2f26e..68ae6fc6f08 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -998,6 +998,15 @@ enum { * RESET_NEVER */ LIB_TAG_NOT_ALLOCATED = 1 << 26, + /** + * ID is part of an asset #Main separate from the regular main database. + * + * RESET_NEVER + * + * Datablocks like this can not be linked to and from datablocks in regular main. + * They should stay isolated from each other. + */ + LIB_TAG_ASSET_MAIN = 1 << 20, /* ------------------------------------------------------------------------------------------- */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 3bc2beac71e..df8846ef1dd 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -962,6 +962,11 @@ typedef struct PaintToolSlot { /** Paint Tool Base. */ typedef struct Paint { + /** + * The active brush. Possibly null. Possibly stored in a separate #Main data-base and not user- + * counted. + * //TODO: Or always stored in a separate #Main? + */ struct Brush *brush; /** diff --git a/source/blender/makesrna/intern/makesrna.cc b/source/blender/makesrna/intern/makesrna.cc index c9360b5689f..41f9f85f509 100644 --- a/source/blender/makesrna/intern/makesrna.cc +++ b/source/blender/makesrna/intern/makesrna.cc @@ -1270,6 +1270,8 @@ static char *rna_def_property_set_func( fprintf(f, " }\n"); } + /* TODO: check here for wrong linking between regular and asset main? */ + if (prop->flag & PROP_ID_REFCOUNT) { fprintf(f, "\n if (data->%s) {\n", dp->dnaname); fprintf(f, " id_us_min((ID *)data->%s);\n", dp->dnaname); diff --git a/source/blender/makesrna/intern/rna_ID.cc b/source/blender/makesrna/intern/rna_ID.cc index 343d6995907..e67c900ca7c 100644 --- a/source/blender/makesrna/intern/rna_ID.cc +++ b/source/blender/makesrna/intern/rna_ID.cc @@ -16,6 +16,7 @@ #include "BLI_utildefines.h" +#include "BKE_asset.hh" #include "BKE_icons.h" #include "BKE_lib_id.hh" #include "BKE_main_namemap.hh" @@ -285,12 +286,13 @@ int rna_ID_name_length(PointerRNA *ptr) void rna_ID_name_set(PointerRNA *ptr, const char *value) { ID *id = (ID *)ptr->data; - BLI_assert(BKE_id_is_in_global_main(id)); - BLI_assert(!ID_IS_LINKED(id)); - - BKE_main_namemap_remove_name(G_MAIN, id, id->name + 2); + Main *id_main = BKE_asset_weak_reference_main(G_MAIN, id); + BKE_main_namemap_remove_name(id_main, id, id->name + 2); BLI_strncpy_utf8(id->name + 2, value, sizeof(id->name) - 2); - BKE_libblock_ensure_unique_name(G_MAIN, id); + /* TODO: add BKE_id_is_in_editable_main? */ + /* TODO: this does update immediately in the asset shelf. */ + BLI_assert(BKE_id_is_in_global_main(id) || (id->tag & LIB_TAG_ASSET_MAIN)); + BKE_libblock_ensure_unique_name(id_main, id); if (GS(id->name) == ID_OB) { Object *ob = (Object *)id; @@ -323,7 +325,8 @@ static int rna_ID_name_editable(PointerRNA *ptr, const char **r_info) return 0; } } - else if (!BKE_id_is_in_global_main(id)) { + /* TODO: add BKE_id_is_in_editable_main? */ + else if (!(BKE_id_is_in_global_main(id) || (id->tag & LIB_TAG_ASSET_MAIN))) { if (r_info) { *r_info = N_("Datablocks not in global Main data-base cannot be renamed"); } @@ -1155,9 +1158,11 @@ int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, const PointerRNA *assig short *totcol = BKE_id_material_len_p(id); Material *mat_id = (Material *)assign_ptr->owner_id; if (totcol && (key >= 0 && key < *totcol)) { + Main *id_main = BKE_asset_weak_reference_main(G_MAIN, id); + /* TODO: BKE_id_is_in_editable_main? */ BLI_assert(BKE_id_is_in_global_main(id)); BLI_assert(BKE_id_is_in_global_main(&mat_id->id)); - BKE_id_material_assign(G_MAIN, id, mat_id, key + 1); + BKE_id_material_assign(id_main, id, mat_id, key + 1); return 1; } else { @@ -1213,8 +1218,10 @@ static void rna_IDMaterials_clear_id(ID *id, Main *bmain) static void rna_Library_filepath_set(PointerRNA *ptr, const char *value) { Library *lib = (Library *)ptr->data; + Main *id_main = BKE_asset_weak_reference_main(G_MAIN, &lib->id); + /* TODO: BKE_id_is_in_editable_main? */ BLI_assert(BKE_id_is_in_global_main(&lib->id)); - BKE_library_filepath_set(G_MAIN, lib, value); + BKE_library_filepath_set(id_main, lib, value); } /* ***** ImagePreview ***** */ @@ -2302,6 +2309,14 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Is Indirect", "Is this ID block linked indirectly"); + prop = RNA_def_property(srna, "is_asset_library_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, nullptr, "tag", LIB_TAG_ASSET_MAIN); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, + "Asset Library Data", + "This data-block is part of an asset library blend file, not the blend " + "file opened for editing"); + prop = RNA_def_property(srna, "library", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, nullptr, "lib"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_main_api.cc b/source/blender/makesrna/intern/rna_main_api.cc index acb1d52ff92..584657ba133 100644 --- a/source/blender/makesrna/intern/rna_main_api.cc +++ b/source/blender/makesrna/intern/rna_main_api.cc @@ -27,6 +27,7 @@ # include "BKE_action.h" # include "BKE_armature.hh" +# include "BKE_asset.hh" # include "BKE_brush.hh" # include "BKE_camera.h" # include "BKE_collection.hh" @@ -125,6 +126,18 @@ static void rna_Main_ID_remove(Main *bmain, id->name + 2); return; } + /* TODO: also check reverse case somehow? */ + if (bmain != BKE_asset_weak_reference_main(bmain, id)) { + BKE_reportf(reports, + RPT_ERROR, + "%s '%s' is part of a difference main database and should be removed from there", + BKE_idtype_idcode_to_name(GS(id->name)), + id->name + 2); + return; + } + /* TODO: this will not clear pointers from regular main to this asset. + * Those probably should not exist, and be purely runtime lookups? */ + if (do_unlink) { BKE_id_delete(bmain, id); RNA_POINTER_INVALIDATE(id_ptr); diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 53b223f8fff..26848046c0f 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -146,11 +146,6 @@ static void wm_history_file_write(); static void wm_test_autorun_revert_action_exec(bContext *C); -static bool wm_operator_open_file_draft_check_dialog(bContext *C, - wmOperator *op, - const int num_user_edited_lost, - ReportList *user_edited_lost_reports); - static CLG_LogRef LOG = {"wm.files"}; /* -------------------------------------------------------------------- */ @@ -2830,7 +2825,6 @@ static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatch enum { OPEN_MAINFILE_STATE_DISCARD_CHANGES, OPEN_MAINFILE_STATE_SELECT_FILE_PATH, - OPEN_MAINFILE_STATE_DISCARD_ASSET_DRAFTS, OPEN_MAINFILE_STATE_OPEN, }; @@ -2848,7 +2842,7 @@ static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op) set_next_operator_state(op, OPEN_MAINFILE_STATE_SELECT_FILE_PATH); } else { - set_next_operator_state(op, OPEN_MAINFILE_STATE_DISCARD_ASSET_DRAFTS); + set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN); } if (wm_operator_close_file_dialog_if_needed(C, op, wm_open_mainfile_after_dialog_callback)) { @@ -2888,44 +2882,6 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op) return OPERATOR_RUNNING_MODAL; } -static int wm_open_mainfile__discard_asset_drafts(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - - char filepath[FILE_MAX]; - RNA_string_get(op->ptr, "filepath", filepath); - - set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN); - - Library *lib = static_cast( - BLI_findstring(&bmain->libraries, filepath, offsetof(Library, filepath_abs))); - - if (lib == nullptr) { - return wm_open_mainfile_dispatch(C, op); - } - - /* If new to-be-opened blendfile was a library of the currently opened one, check for potential - * persistent edited assets that would be reset to their library status (only Brushes IDs - * currently). */ - ReportList *reports = MEM_cnew(__func__); - BKE_reports_init(reports, RPT_STORE); - const int num_user_edited_brushes = BKE_lib_override_user_edited_from_library_count( - bmain, ID_BR, lib, reports); - if (num_user_edited_brushes > 0) { - /* NOTE: steals ownership of `user_edited_lost_reports` regardless of its result. */ - if (wm_operator_open_file_draft_check_dialog(C, op, num_user_edited_brushes, reports)) { - return OPERATOR_INTERFACE; - } - reports = nullptr; - } - else { - BKE_reports_clear(reports); - MEM_delete(reports); - } - - return wm_open_mainfile_dispatch(C, op); -} - static int wm_open_mainfile__open(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; @@ -2958,7 +2914,6 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op) static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[] = { {OPEN_MAINFILE_STATE_DISCARD_CHANGES, wm_open_mainfile__discard_changes}, {OPEN_MAINFILE_STATE_SELECT_FILE_PATH, wm_open_mainfile__select_file_path}, - {OPEN_MAINFILE_STATE_DISCARD_ASSET_DRAFTS, wm_open_mainfile__discard_asset_drafts}, {OPEN_MAINFILE_STATE_OPEN, wm_open_mainfile__open}, {0, nullptr}, }; @@ -4529,217 +4484,3 @@ bool wm_operator_close_file_dialog_if_needed(bContext *C, } /** \} */ - -/** - * \name Open Asset Library File Dialog. - * - * This handles cases where user is opening a file that is an asset library, which assets are used - * in the 'user preference' way (i.e. assets are linked, and have runtime-only, session-persistant, - * user-editable overrides of these. - * - * Special warning is necessary because when opening the library file, all non-drafted user edits - * of the relevant assets will be lost. */ -/** \{ */ - -static const char *open_file_draft_check_dialog_name = "open_file_draft_check_popup"; - -typedef struct wmOpenDraftCheckCallback { - IDProperty *op_properties; - - ReportList *user_edited_lost_reports; - int num_user_edited_lost; - - char new_filepath[FILE_MAX]; -} wmOpenDraftCheckCallback; - -static void wm_block_open_file_draft_cancel(bContext *C, void *arg_block, void * /*arg_data*/) -{ - wmWindow *win = CTX_wm_window(C); - UI_popup_block_close(C, win, static_cast(arg_block)); -} - -static void wm_block_open_file_draft_discard(bContext *C, void *arg_block, void *arg_data) -{ - wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data); - - /* Close the popup before executing the callback. Otherwise - * the popup might be closed by the callback, which will lead - * to a crash. */ - wmWindow *win = CTX_wm_window(C); - UI_popup_block_close(C, win, static_cast(arg_block)); - - callback->exec(C, callback->user_data); - WM_generic_callback_free(callback); -} - -static void wm_block_open_file_draft_save(bContext *C, void *arg_block, void *arg_data) -{ - wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data); - bool execute_callback = true; - - wmWindow *win = CTX_wm_window(C); - UI_popup_block_close(C, win, static_cast(arg_block)); - - /* TODO: Actually save the edited lost local runtime assets overrides into drafts. */ - - if (execute_callback) { - callback->exec(C, callback->user_data); - } - WM_generic_callback_free(callback); -} - -static void wm_block_open_file_draft_cancel_button(uiBlock *block, wmGenericCallback *post_action) -{ - uiBut *but = uiDefIconTextBut( - block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); - UI_but_func_set(but, wm_block_open_file_draft_cancel, block, post_action); - UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); -} - -static void wm_block_open_file_draft_discard_button(uiBlock *block, wmGenericCallback *post_action) -{ - uiBut *but = uiDefIconTextBut( - block, UI_BTYPE_BUT, 0, 0, IFACE_("Ignore"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); - UI_but_func_set(but, wm_block_open_file_draft_discard, block, post_action); - UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); -} - -static void wm_block_open_file_draft_save_button(uiBlock *block, wmGenericCallback *post_action) -{ - uiBut *but = uiDefIconTextBut( - block, UI_BTYPE_BUT, 0, 0, IFACE_("Save To Draft"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, ""); - UI_but_func_set(but, wm_block_open_file_draft_save, block, post_action); - UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); -} - -static void wm_open_file_after_draft_check_dialog_callback(bContext *C, void *user_data) -{ - wmOpenDraftCheckCallback *callback_data = static_cast(user_data); - - WM_operator_name_call_with_properties( - C, "WM_OT_open_mainfile", WM_OP_INVOKE_DEFAULT, callback_data->op_properties, nullptr); -} - -static uiBlock *block_create__open_draft_check_file_dialog(struct bContext *C, - struct ARegion *region, - void *arg1) -{ - wmGenericCallback *post_action = static_cast(arg1); - wmOpenDraftCheckCallback *callback_data = static_cast( - post_action->user_data); - - uiBlock *block = UI_block_begin(C, region, open_file_draft_check_dialog_name, UI_EMBOSS); - UI_block_flag_enable( - block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); - UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - - uiLayout *layout = uiItemsAlertBox(block, 34, ALERT_ICON_QUESTION); - - /* Title. */ - uiItemL_ex(layout, TIP_("Save User-Edited Assets to Draft?"), ICON_NONE, true, false); - - char message[2048]; - SNPRINTF(message, - TIP_("The following %d assets have local edits that will be lost"), - callback_data->num_user_edited_lost); - uiItemL(layout, message, ICON_NONE); - uiItemL(layout, "by opening the chosen Blender Asset Library file", ICON_NONE); - uiItemL(layout, callback_data->new_filepath, ICON_NONE); - - /* Draw available report messages. */ - LISTBASE_FOREACH (Report *, report, &callback_data->user_edited_lost_reports->list) { - uiLayout *row = uiLayoutColumn(layout, false); - uiLayoutSetScaleY(row, 0.6f); - uiItemS(row); - - uiItemL_ex(row, report->message, ICON_NONE, false, true); - } - - uiItemS_ex(layout, 4.0f); - - /* Buttons. */ -#ifdef _WIN32 - const bool windows_layout = true; -#else - const bool windows_layout = false; -#endif - - if (windows_layout) { - /* Windows standard layout. */ - - uiLayout *split = uiLayoutSplit(layout, 0.0f, true); - uiLayoutSetScaleY(split, 1.2f); - - uiLayoutColumn(split, false); - wm_block_open_file_draft_save_button(block, post_action); - - uiLayoutColumn(split, false); - wm_block_open_file_draft_discard_button(block, post_action); - - uiLayoutColumn(split, false); - wm_block_open_file_draft_cancel_button(block, post_action); - } - else { - /* Non-Windows layout (macOS and Linux). */ - - uiLayout *split = uiLayoutSplit(layout, 0.3f, true); - uiLayoutSetScaleY(split, 1.2f); - - uiLayoutColumn(split, false); - wm_block_open_file_draft_discard_button(block, post_action); - - uiLayout *split_right = uiLayoutSplit(split, 0.1f, true); - - uiLayoutColumn(split_right, false); - /* Empty space. */ - - uiLayoutColumn(split_right, false); - wm_block_open_file_draft_cancel_button(block, post_action); - - uiLayoutColumn(split_right, false); - wm_block_open_file_draft_save_button(block, post_action); - } - - UI_block_bounds_set_centered(block, int(14 * U.scale_factor)); - return block; -} - -static void wm_free_open_file_draft_check_callback(void *user_data) -{ - wmOpenDraftCheckCallback *callback_data = static_cast(user_data); - - IDP_FreeProperty(callback_data->op_properties); - BKE_reports_clear(callback_data->user_edited_lost_reports); - MEM_delete(callback_data->user_edited_lost_reports); - - MEM_delete(callback_data); -} - -/* NOTE: steals ownership of `user_edited_lost_reports`. */ -static bool wm_operator_open_file_draft_check_dialog(bContext *C, - wmOperator *op, - const int num_user_edited_lost, - ReportList *user_edited_lost_reports) -{ - wmOpenDraftCheckCallback *callback_data = MEM_cnew(__func__); - callback_data->op_properties = IDP_CopyProperty(op->properties); - RNA_string_get(op->ptr, "filepath", callback_data->new_filepath); - callback_data->num_user_edited_lost = num_user_edited_lost; - callback_data->user_edited_lost_reports = user_edited_lost_reports; - - wmGenericCallback *callback = MEM_cnew(__func__); - callback->exec = wm_open_file_after_draft_check_dialog_callback; - callback->user_data = callback_data; - callback->free_user_data = wm_free_open_file_draft_check_callback; - - if (!UI_popup_block_name_exists(CTX_wm_screen(C), open_file_draft_check_dialog_name)) { - UI_popup_block_invoke( - C, block_create__open_draft_check_file_dialog, callback, free_post_file_close_action); - return true; - } - - WM_generic_callback_free(callback); - return false; -} -/** \} */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index d52c6e7d905..7bccf885e3f 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -33,8 +33,11 @@ #include "BLO_undofile.hh" #include "BLO_writefile.hh" +#include "BKE_asset.hh" #include "BKE_blender.hh" #include "BKE_blendfile.hh" +#include "BKE_brush.hh" +#include "BKE_callbacks.hh" #include "BKE_context.hh" #include "BKE_global.hh" #include "BKE_icons.h" @@ -576,6 +579,7 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_ ED_preview_restart_queue_free(); ed::asset::list::storage_exit(); + BKE_asset_weak_reference_main_free(); BKE_tracking_clipboard_free(); BKE_mask_clipboard_free(); BKE_vfont_clipboard_free(); diff --git a/source/blender/windowmanager/intern/wm_toolsystem.cc b/source/blender/windowmanager/intern/wm_toolsystem.cc index 1da5f507b3c..91c585f02db 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.cc +++ b/source/blender/windowmanager/intern/wm_toolsystem.cc @@ -174,43 +174,6 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre } } } - else { - const PaintMode paint_mode = BKE_paintmode_get_from_tool(tref); - BLI_assert(paint_mode != PaintMode::Invalid); - const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode); - BLI_assert(items != nullptr); - - const int i = items ? RNA_enum_from_identifier(items, tref_rt->data_block) : -1; - if (i != -1) { - const int slot_index = items[i].value; - wmWindowManager *wm = static_cast(bmain->wm.first); - LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - if (workspace == WM_window_get_active_workspace(win)) { - Scene *scene = WM_window_get_active_scene(win); - BKE_paint_ensure_from_paintmode(bmain, scene, paint_mode); - Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode); - Brush *brush = BKE_paint_toolslots_brush_get(paint, slot_index); - if (brush == nullptr) { - /* Could make into a function. */ - brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, items[i].name); - if (brush && slot_index == BKE_brush_tool_get(brush, paint)) { - /* pass */ - } - else { - brush = BKE_brush_add(bmain, items[i].name, eObjectMode(paint->runtime.ob_mode)); - - BKE_brush_tool_set(brush, paint, slot_index); - - if (paint_mode == PaintMode::Sculpt) { - BKE_brush_sculpt_reset(brush); - } - } - } - BKE_paint_brush_set(paint, brush); - } - } - } - } } }