Brush Assets: Store assets outside Main #117730
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
||||
/**
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -7,15 +7,25 @@
|
|||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#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<AssetWeakReferenceMain> &get_weak_reference_mains()
|
||||
{
|
||||
static Vector<AssetWeakReferenceMain> 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;
|
||||
}
|
||||
|
|
|
@ -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<ID **>(&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<ReuseOldBMainData *>(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<ID *>(new_lb->last); id_iter != nullptr;
|
||||
id_iter = static_cast<ID *>(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<ID *>(old_lb->first);
|
||||
old_id_iter != nullptr;
|
||||
old_id_iter = old_id_iter_next)
|
||||
{
|
||||
old_id_iter_next = static_cast<ID *>(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<ID *>(new_lb->first); new_id_iter != nullptr;
|
||||
new_id_iter = static_cast<ID *>(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
|
||||
|
|
|
@ -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<Brush *>(
|
||||
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<Brush *>(
|
||||
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)
|
||||
|
|
|
@ -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<ID *>(lb->first); id_iter != nullptr;
|
||||
id_iter = static_cast<ID *>(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,
|
||||
|
|
|
@ -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<Brush *>(
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<std::string> shortcut_brush = WM_key_event_operator_string(
|
||||
C,
|
||||
ot->idname,
|
||||
WM_OP_INVOKE_REGION_WIN,
|
||||
static_cast<IDProperty *>(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<std::string> shortcut_toolbar = WM_key_event_operator_string(
|
||||
|
|
|
@ -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<ID *>(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
|
||||
|
|
|
@ -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<Tex *>(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<Tex *>(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 */
|
||||
|
|
|
@ -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<Brush *>(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<Brush *>(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 *>(brush_orig->id.next) :
|
||||
static_cast<Brush *>(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 *>(brush->id.next) :
|
||||
static_cast<Brush *>(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<Brush *>(
|
||||
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<Brush *>(
|
||||
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<Brush *>(
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Library *>(
|
||||
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<ReportList>(__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<uiBlock *>(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<uiBlock *>(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<uiBlock *>(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<wmOpenDraftCheckCallback *>(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<wmGenericCallback *>(arg1);
|
||||
wmOpenDraftCheckCallback *callback_data = static_cast<wmOpenDraftCheckCallback *>(
|
||||
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<wmOpenDraftCheckCallback *>(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<wmOpenDraftCheckCallback>(__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<wmGenericCallback>(__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;
|
||||
}
|
||||
/** \} */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<wmWindowManager *>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue