Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2021-02-26 13:39:31 +0300
committerJacques Lucke <jacques@blender.org>2021-02-26 13:39:31 +0300
commitb2774b03b906c11ced73484c70887082643bfb20 (patch)
treefc56363f181892bbf4d84084b4d6427f3fa5006b /source
parent81d4e4d35e3330b4735994649e6625937650192e (diff)
parent72ceab8ab256ea53e364a2e9ae9ef3f62b634373 (diff)
Merge branch 'master' into temp-spreadsheet-editor
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h7
-rw-r--r--source/blender/blenkernel/BKE_node.h2
-rw-r--r--source/blender/blenkernel/BKE_screen.h2
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c13
-rw-r--r--source/blender/blenkernel/intern/lib_query.c133
-rw-r--r--source/blender/blenkernel/intern/node.cc9
-rw-r--r--source/blender/blenkernel/intern/screen.c2
-rw-r--r--source/blender/blenkernel/intern/undo_system.c11
-rw-r--r--source/blender/editors/armature/editarmature_undo.c1
-rw-r--r--source/blender/editors/curve/editcurve_undo.c1
-rw-r--r--source/blender/editors/curve/editfont_undo.c19
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt1
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/interface/interface_widgets.c5
-rw-r--r--source/blender/editors/lattice/editlattice_undo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/metaball/editmball_undo.c1
-rw-r--r--source/blender/editors/object/object_select.c3
-rw-r--r--source/blender/editors/physics/CMakeLists.txt1
-rw-r--r--source/blender/editors/physics/particle_edit.c9
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c39
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c16
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c65
-rw-r--r--source/blender/editors/undo/ed_undo.c3
-rw-r--r--source/blender/makesrna/intern/rna_meta.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c13
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c45
-rw-r--r--source/blender/render/RE_pipeline.h2
-rw-r--r--source/blender/render/intern/engine.c10
-rw-r--r--source/blender/render/intern/pipeline.c2
-rw-r--r--source/blender/render/intern/render_types.h2
32 files changed, 326 insertions, 105 deletions
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index bdda5bb0372..f064d03261d 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -175,6 +175,13 @@ void BKE_library_ID_test_usages(struct Main *bmain,
bool *is_used_local,
bool *is_used_linked);
+void BKE_lib_query_unused_ids_tag(struct Main *bmain,
+ const int tag,
+ const bool do_local_ids,
+ const bool do_linked_ids,
+ const bool do_tag_recursive,
+ int *r_num_tagged);
+
void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag);
void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 76d5eb945bb..d675df6d868 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -777,7 +777,7 @@ void BKE_node_preview_free(struct bNodePreview *preview);
void BKE_node_preview_init_tree(struct bNodeTree *ntree,
int xsize,
int ysize,
- int create_previews);
+ bool create_previews);
void BKE_node_preview_free_tree(struct bNodeTree *ntree);
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
void BKE_node_preview_clear(struct bNodePreview *preview);
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 32c888b058f..085851ba5e6 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -404,7 +404,7 @@ void BKE_spacetypes_free(void); /* only for quitting blender */
/* spacedata */
void BKE_spacedata_freelist(ListBase *lb);
void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2);
-void BKE_spacedata_draw_locks(int set);
+void BKE_spacedata_draw_locks(bool set);
struct ARegion *BKE_spacedata_find_region_type(const struct SpaceLink *slink,
const struct ScrArea *area,
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 8075660dcd1..7c5032c97f4 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -305,13 +305,16 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
/* Since we removed ID from Main,
* we also need to unlink its own other IDs usages ourself. */
BKE_libblock_relink_ex(bmain, id, NULL, NULL, 0);
- /* Now we can safely mark that ID as not being in Main database anymore. */
- id->tag |= LIB_TAG_NO_MAIN;
- /* This is needed because we may not have remapped usages
- * of that ID by other deleted ones. */
- // id->us = 0; /* Is it actually? */
}
}
+
+ /* Now we can safely mark that ID as not being in Main database anymore. */
+ /* NOTE: This needs to be done in a separate loop than above, otherwise some usercounts of
+ * deleted IDs may not be properly decreased by the remappings (since `NO_MAIN` ID usercounts
+ * is never affected). */
+ for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
+ id->tag |= LIB_TAG_NO_MAIN;
+ }
}
else {
/* First tag all datablocks directly from target lib.
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 1fd51544ba7..eaf1e2d46e6 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -599,6 +599,139 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
}
/* ***** IDs usages.checking/tagging. ***** */
+static void lib_query_unused_ids_tag_recurse(Main *bmain,
+ const int tag,
+ const bool do_local_ids,
+ const bool do_linked_ids,
+ ID *id,
+ int *r_num_tagged)
+{
+ /* We should never deal with embedded, not-in-main IDs here. */
+ BLI_assert((id->flag & LIB_EMBEDDED_DATA) == 0);
+
+ if ((!do_linked_ids && ID_IS_LINKED(id)) || (!do_local_ids && !ID_IS_LINKED(id))) {
+ return;
+ }
+
+ MainIDRelationsEntry *id_relations = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
+ id);
+ if ((id_relations->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) != 0) {
+ return;
+ }
+ id_relations->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
+
+ if ((id->tag & tag) != 0) {
+ return;
+ }
+
+ if ((id->flag & LIB_FAKEUSER) != 0) {
+ /* This ID is forcefully kept around, and therefore never unused, no need to check it further.
+ */
+ return;
+ }
+
+ if (ELEM(GS(id->name), ID_WM, ID_WS, ID_SCE, ID_SCR, ID_LI)) {
+ /* Some 'root' ID types are never unused (even though they may not have actual users), unless
+ * their actual usercount is set to 0. */
+ return;
+ }
+
+ /* An ID user is 'valid' (i.e. may affect the 'used'/'not used' status of the ID it uses) if it
+ * does not match `ignored_usages`, and does match `required_usages`. */
+ const int ignored_usages = (IDWALK_CB_LOOPBACK | IDWALK_CB_EMBEDDED);
+ const int required_usages = (IDWALK_CB_USER | IDWALK_CB_USER_ONE);
+
+ /* This ID may be tagged as unused if none of its users are 'valid', as defined above.
+ *
+ * First recursively check all its valid users, if all of them can be tagged as
+ * unused, then we can tag this ID as such too. */
+ bool has_valid_from_users = false;
+ for (MainIDRelationsEntryItem *id_from_item = id_relations->from_ids; id_from_item != NULL;
+ id_from_item = id_from_item->next) {
+ if ((id_from_item->usage_flag & ignored_usages) != 0 ||
+ (id_from_item->usage_flag & required_usages) == 0) {
+ continue;
+ }
+
+ ID *id_from = id_from_item->id_pointer.from;
+ if ((id_from->flag & LIB_EMBEDDED_DATA) != 0) {
+ /* Directly 'by-pass' to actual real ID owner. */
+ const IDTypeInfo *type_info_from = BKE_idtype_get_info_from_id(id_from);
+ BLI_assert(type_info_from->owner_get != NULL);
+ id_from = type_info_from->owner_get(bmain, id_from);
+ }
+
+ lib_query_unused_ids_tag_recurse(
+ bmain, tag, do_local_ids, do_linked_ids, id_from, r_num_tagged);
+ if ((id_from->tag & tag) == 0) {
+ has_valid_from_users = true;
+ break;
+ }
+ }
+ if (!has_valid_from_users) {
+ /* This ID has no 'valid' users, tag it as unused. */
+ id->tag |= tag;
+ if (r_num_tagged != NULL) {
+ r_num_tagged[INDEX_ID_NULL]++;
+ r_num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
+ }
+ }
+}
+
+/**
+ * Tag all unused IDs (a.k.a 'orphaned').
+ *
+ * By default only tag IDs with `0` user count.
+ * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually
+ * used in current file, including 'archipelagoes` (i.e. set of IDs referencing each other in
+ * loops, but without any 'external' valid usages.
+ *
+ * Valid usages here are defined as ref-counting usages, which are not towards embedded or
+ * loop-back data.
+ *
+ * \param r_num_tagged If non-NULL, must be a zero-initialized array of #INDEX_ID_MAX integers.
+ * Number of tagged-as-unused IDs is then set for each type, and as total in
+ * #INDEX_ID_NULL item.
+ */
+void BKE_lib_query_unused_ids_tag(Main *bmain,
+ const int tag,
+ const bool do_local_ids,
+ const bool do_linked_ids,
+ const bool do_tag_recursive,
+ int *r_num_tagged)
+{
+ /* First loop, to only check for immediatly unused IDs (those with 0 user count).
+ * NOTE: It also takes care of clearing given tag for used IDs. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if ((!do_linked_ids && ID_IS_LINKED(id)) || (!do_local_ids && !ID_IS_LINKED(id))) {
+ id->tag &= ~tag;
+ }
+ else if (id->us == 0) {
+ id->tag |= tag;
+ if (r_num_tagged != NULL) {
+ r_num_tagged[INDEX_ID_NULL]++;
+ r_num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
+ }
+ }
+ else {
+ id->tag &= ~tag;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ if (!do_tag_recursive) {
+ return;
+ }
+
+ BKE_main_relations_create(bmain, 0);
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ lib_query_unused_ids_tag_recurse(bmain, tag, do_local_ids, do_linked_ids, id, r_num_tagged);
+ }
+ FOREACH_MAIN_ID_END;
+ BKE_main_relations_free(bmain);
+}
+
static int foreach_libblock_used_linked_data_tag_clear_cb(LibraryIDLinkCallbackData *cb_data)
{
ID *self_id = cb_data->id_self;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 58003c03f8c..7bd7fb4a29b 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -2501,7 +2501,7 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
bNodeInstanceKey parent_key,
int xsize,
int ysize,
- int create)
+ bool create_previews)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
@@ -2510,16 +2510,17 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
node->preview_xsize = xsize;
node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create);
+ BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
}
if (node->type == NODE_GROUP && node->id) {
- node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize, create);
+ node_preview_init_tree_recursive(
+ previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
}
}
}
-void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, int create_previews)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
{
if (!ntree) {
return;
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 0538e7f479d..a000b0c89fe 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -539,7 +539,7 @@ void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
/* facility to set locks for drawing to survive (render) threads accessing drawing data */
/* lock can become bitflag too */
/* should be replaced in future by better local data handling for threads */
-void BKE_spacedata_draw_locks(int set)
+void BKE_spacedata_draw_locks(bool set)
{
LISTBASE_FOREACH (SpaceType *, st, &spacetypes) {
LISTBASE_FOREACH (ARegionType *, art, &st->regiontypes) {
diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c
index bb871e84c7b..52f0fe3f5a2 100644
--- a/source/blender/blenkernel/intern/undo_system.c
+++ b/source/blender/blenkernel/intern/undo_system.c
@@ -768,10 +768,13 @@ bool BKE_undosys_step_load_data_ex(UndoStack *ustack,
while (us_target_active != NULL && us_target_active->skip) {
us_target_active = (undo_dir == -1) ? us_target_active->prev : us_target_active->next;
}
- }
- if (us_target_active == NULL) {
- CLOG_ERROR(&LOG, "could not find a valid final active target step");
- return false;
+ if (us_target_active == NULL) {
+ CLOG_INFO(&LOG,
+ 2,
+ "undo/redo did not find a step after stepping over skip-steps "
+ "(undo limit exceeded)");
+ return false;
+ }
}
CLOG_INFO(&LOG,
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index 3768de96340..725945f8edc 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -187,7 +187,6 @@ static void armature_undosys_step_decode(struct bContext *C,
{
ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
- /* Load all our objects into edit-mode, clear everything else. */
ED_undo_object_editmode_restore_helper(
C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 48666821732..b07c3c85f4a 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -248,7 +248,6 @@ static void curve_undosys_step_decode(struct bContext *C,
{
CurveUndoStep *us = (CurveUndoStep *)us_p;
- /* Load all our objects into edit-mode, clear everything else. */
ED_undo_object_editmode_restore_helper(
C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 8f7eb19dfe8..a305a997d50 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -23,6 +23,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "BLI_array_utils.h"
#include "BLI_utildefines.h"
@@ -39,6 +41,7 @@
#include "ED_curve.h"
#include "ED_object.h"
+#include "ED_undo.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -53,6 +56,9 @@
# define ARRAY_CHUNK_SIZE 32
#endif
+/** Only needed this locally. */
+static CLG_LogRef LOG = {"ed.undo.font"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -364,15 +370,22 @@ static void font_undosys_step_decode(struct bContext *C,
const eUndoStepDir UNUSED(dir),
bool UNUSED(is_final))
{
- /* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set_ex(C, OB_MODE_EDIT, false, NULL);
- BLI_assert(font_undosys_poll(C));
FontUndoStep *us = (FontUndoStep *)us_p;
Object *obedit = us->obedit_ref.ptr;
+
+ /* Pass in an array of 1 (typically used for multi-object edit-mode). */
+ ED_undo_object_editmode_restore_helper(C, &obedit, 1, sizeof(Object *));
+
Curve *cu = obedit->data;
undofont_to_editfont(&us->data, cu);
DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+
+ ED_undo_object_set_active_or_warn(
+ CTX_data_scene(C), CTX_data_view_layer(C), obedit, us_p->name, &LOG);
+
+ BLI_assert(font_undosys_poll(C));
+
cu->editfont->needs_flush_to_id = 1;
bmain->is_memfile_undo_flush_needed = true;
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 4c0d1b65465..beb22d43930 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -134,6 +134,7 @@ set(ICON_NAMES
info
sequence
text
+ spreadsheet
sound
action
nla
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index b7eb5cab7f9..f0a4b3c462e 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -173,7 +173,7 @@ DEF_ICON(IMAGE)
DEF_ICON(INFO)
DEF_ICON(SEQUENCE)
DEF_ICON_OBJECT_DATA(TEXT)
-DEF_ICON_BLANK(174)
+DEF_ICON(SPREADSHEET)
DEF_ICON(SOUND)
DEF_ICON(ACTION)
DEF_ICON(NLA)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 5c59d0edeb5..0fa5999976b 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -5237,8 +5237,9 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
const rcti _rect = *rect;
+ const int row_height = BLI_rcti_size_y(rect);
int max_hint_width = INT_MAX;
- int padding = 0.25f * UI_UNIT_X;
+ int padding = 0.25f * row_height;
char *cpoin = NULL;
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
@@ -5249,7 +5250,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle,
/* text location offset */
rect->xmin += padding;
if (iconid) {
- rect->xmin += UI_DPI_ICON_SIZE;
+ rect->xmin += row_height; /* Use square area for icon. */
}
/* cut string in 2 parts? */
diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c
index 2a6edc3249f..d92a81179cc 100644
--- a/source/blender/editors/lattice/editlattice_undo.c
+++ b/source/blender/editors/lattice/editlattice_undo.c
@@ -221,7 +221,6 @@ static void lattice_undosys_step_decode(struct bContext *C,
{
LatticeUndoStep *us = (LatticeUndoStep *)us_p;
- /* Load all our objects into edit-mode, clear everything else. */
ED_undo_object_editmode_restore_helper(
C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 67816f069f6..79385e28aa9 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -775,7 +775,6 @@ static void mesh_undosys_step_decode(struct bContext *C,
{
MeshUndoStep *us = (MeshUndoStep *)us_p;
- /* Load all our objects into edit-mode, clear everything else. */
ED_undo_object_editmode_restore_helper(
C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c
index 457c5330595..a8b471a7c92 100644
--- a/source/blender/editors/metaball/editmball_undo.c
+++ b/source/blender/editors/metaball/editmball_undo.c
@@ -196,7 +196,6 @@ static void mball_undosys_step_decode(struct bContext *C,
{
MBallUndoStep *us = (MBallUndoStep *)us_p;
- /* Load all our objects into edit-mode, clear everything else. */
ED_undo_object_editmode_restore_helper(
C, &us->elems[0].obedit_ref.ptr, us->elems_len, sizeof(*us->elems));
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 398ad89a694..9160190764c 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -1311,7 +1311,8 @@ void OBJECT_OT_select_mirror(wmOperatorType *ot)
/* identifiers */
ot->name = "Select Mirror";
- ot->description = "Select the mirror objects of the selected object e.g. \"L.sword\" and \"R.sword\"";
+ ot->description =
+ "Select the mirror objects of the selected object e.g. \"L.sword\" and \"R.sword\"";
ot->idname = "OBJECT_OT_select_mirror";
/* api callbacks */
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 2b9d9aaa0e1..a607663763e 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -25,6 +25,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/mantaflow/extern
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index ec3eb9c6a3a..1ee17d0e4b0 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -302,7 +302,7 @@ static void pe_update_hair_particle_edit_pointers(PTCacheEdit *edit)
*
* note: this function runs on poll, therefore it can runs many times a second
* keep it fast! */
-static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob, int create)
+static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob, bool create)
{
ParticleEditSettings *pset = PE_settings(scene);
PTCacheEdit *edit = NULL;
@@ -406,12 +406,12 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(depsgraph, scene, ob, 0);
+ return pe_get_current(depsgraph, scene, ob, false);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(depsgraph, scene, ob, 1);
+ return pe_get_current(depsgraph, scene, ob, true);
}
void PE_current_changed(Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -5395,6 +5395,9 @@ static void free_all_psys_edit(Object *object)
void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
+ /* Needed so #ParticleSystemModifierData.mesh_final is set. */
+ BKE_scene_graph_evaluated_ensure(depsgraph, G_MAIN);
+
PTCacheEdit *edit;
ob->mode |= OB_MODE_PARTICLE_EDIT;
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 5d2e0e5b6ef..2c7b5c0de6a 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -27,6 +27,8 @@
#include "MEM_guardedalloc.h"
+#include "CLG_log.h"
+
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
@@ -44,11 +46,15 @@
#include "ED_object.h"
#include "ED_particle.h"
#include "ED_physics.h"
+#include "ED_undo.h"
#include "particle_edit_utildefines.h"
#include "physics_intern.h"
+/** Only needed this locally. */
+static CLG_LogRef LOG = {"ed.undo.particle_edit"};
+
/* -------------------------------------------------------------------- */
/** \name Undo Conversion
* \{ */
@@ -251,26 +257,33 @@ static void particle_undosys_step_decode(struct bContext *C,
bool UNUSED(is_final))
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- /* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set_ex(C, OB_MODE_PARTICLE_EDIT, false, NULL);
- BLI_assert(particle_undosys_poll(C));
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
+
+ ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
+
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- if (edit) {
- undoptcache_to_editcache(&us->data, edit);
- ParticleEditSettings *pset = &scene->toolsettings->particle;
- if ((pset->flag & PE_DRAW_PART) != 0) {
- psys_free_path_cache(NULL, edit);
- BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- }
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
+
+ /* While this shouldn't happen, entering particle edit-mode uses a more complex
+ * setup compared to most other modes which we can't ensure succeeds. */
+ if (UNLIKELY(edit == NULL)) {
BLI_assert(0);
+ return;
+ }
+
+ undoptcache_to_editcache(&us->data, edit);
+ ParticleEditSettings *pset = &scene->toolsettings->particle;
+ if ((pset->flag & PE_DRAW_PART) != 0) {
+ psys_free_path_cache(NULL, edit);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
}
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+
+ ED_undo_object_set_active_or_warn(scene, CTX_data_view_layer(C), ob, us_p->name, &LOG);
+
+ BLI_assert(particle_undosys_poll(C));
}
static void particle_undosys_step_free(UndoStep *us_p)
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 50ba5907703..b525d8a373e 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -800,7 +800,7 @@ static int render_break(void *UNUSED(rjv))
/* runs in thread, no cursor setting here works. careful with notifiers too (malloc conflicts) */
/* maybe need a way to get job send notifier? */
-static void render_drawlock(void *rjv, int lock)
+static void render_drawlock(void *rjv, bool lock)
{
RenderJob *rj = rjv;
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 6df1e449b97..3090cab75ae 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -1213,11 +1213,23 @@ static bool collection_drop_poll(bContext *C,
*r_tooltip = TIP_("Move after collection");
}
break;
- case TE_INSERT_INTO:
+ case TE_INSERT_INTO: {
tselem->flag |= TSE_DRAG_INTO;
changed = true;
- *r_tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)");
+
+ /* Check the type of the drag IDs to avoid the incorrect "Shift to parent"
+ * for collections. Checking the type of the first ID works fine here since
+ * all drag IDs are the same type. */
+ wmDragID *drag_id = (wmDragID *)drag->ids.first;
+ const bool is_object = (GS(drag_id->id->name) == ID_OB);
+ if (is_object) {
+ *r_tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)");
+ }
+ else {
+ *r_tooltip = TIP_("Move inside collection (Ctrl to link)");
+ }
break;
+ }
}
}
if (changed) {
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 7df8e9e1de4..d1260f02c67 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -2267,29 +2267,19 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C)
/** \} */
-static void outliner_orphans_purge_tag(ID *id, int *num_tagged)
-{
- if (id->us == 0) {
- id->tag |= LIB_TAG_DOIT;
- num_tagged[INDEX_ID_NULL]++;
- num_tagged[BKE_idtype_idcode_to_index(GS(id->name))]++;
- }
- else {
- id->tag &= ~LIB_TAG_DOIT;
- }
-}
-
static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt))
{
Main *bmain = CTX_data_main(C);
int num_tagged[INDEX_ID_MAX] = {0};
- /* Tag all IDs having zero users. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- outliner_orphans_purge_tag(id, num_tagged);
- }
- FOREACH_MAIN_ID_END;
+ const bool do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
+ const bool do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
+ const bool do_recursive_cleanup = RNA_boolean_get(op->ptr, "do_recursive");
+
+ /* Tag all IDs to delete. */
+ BKE_lib_query_unused_ids_tag(
+ bmain, LIB_TAG_DOIT, do_local_ids, do_linked_ids, do_recursive_cleanup, num_tagged);
+
RNA_int_set(op->ptr, "num_deleted", num_tagged[INDEX_ID_NULL]);
if (num_tagged[INDEX_ID_NULL] == 0) {
@@ -2298,7 +2288,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
}
DynStr *dyn_str = BLI_dynstr_new();
- BLI_dynstr_append(dyn_str, "Purging unused data-blocks (");
+ BLI_dynstr_appendf(dyn_str, "Purging %d unused data-blocks (", num_tagged[INDEX_ID_NULL]);
bool is_first = true;
for (int i = 0; i < INDEX_ID_MAX - 2; i++) {
if (num_tagged[i] != 0) {
@@ -2332,12 +2322,13 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
int num_tagged[INDEX_ID_MAX] = {0};
if ((num_tagged[INDEX_ID_NULL] = RNA_int_get(op->ptr, "num_deleted")) == 0) {
- /* Tag all IDs having zero users. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- outliner_orphans_purge_tag(id, num_tagged);
- }
- FOREACH_MAIN_ID_END;
+ const bool do_local_ids = RNA_boolean_get(op->ptr, "do_local_ids");
+ const bool do_linked_ids = RNA_boolean_get(op->ptr, "do_linked_ids");
+ const bool do_recursive_cleanup = RNA_boolean_get(op->ptr, "do_recursive");
+
+ /* Tag all IDs to delete. */
+ BKE_lib_query_unused_ids_tag(
+ bmain, LIB_TAG_DOIT, do_local_ids, do_linked_ids, do_recursive_cleanup, num_tagged);
if (num_tagged[INDEX_ID_NULL] == 0) {
BKE_report(op->reports, RPT_INFO, "No orphaned data-blocks to purge");
@@ -2359,8 +2350,10 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
}
DEG_relations_tag_update(bmain);
- WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+ WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL);
+ /* Force full redraw of the UI. */
+ WM_main_add_notifier(NC_WINDOW, NULL);
+
return OPERATOR_FINISHED;
}
@@ -2382,6 +2375,24 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
/* properties */
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+
+ RNA_def_boolean(ot->srna,
+ "do_local_ids",
+ true,
+ "Local Data-blocks",
+ "Include unused local data-blocks into deletion");
+ RNA_def_boolean(ot->srna,
+ "do_linked_ids",
+ true,
+ "Linked Data-blocks",
+ "Include unused linked data-blocks into deletion");
+
+ RNA_def_boolean(ot->srna,
+ "do_recursive",
+ false,
+ "Recursive Delete",
+ "Recursively check for indirectly unused data-blocks, ensuring that no orphaned "
+ "data-blocks remain after execution");
}
/** \} */
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 2e5d233f207..7d8f72f3779 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -863,6 +863,9 @@ void ED_undo_object_set_active_or_warn(
}
}
+/**
+ * Load all our objects from `object_array` into edit-mode, clear everything else.
+ */
void ED_undo_object_editmode_restore_helper(struct bContext *C,
Object **object_array,
uint object_array_len,
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index ffdd75e63ac..d5018a6911d 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -294,8 +294,12 @@ static void rna_def_metaball_elements(BlenderRNA *brna, PropertyRNA *cprop)
func = RNA_def_function(srna, "new", "rna_MetaBall_elements_new");
RNA_def_function_ui_description(func, "Add a new element to the metaball");
- RNA_def_enum(
- func, "type", rna_enum_metaelem_type_items, MB_BALL, "", "Type for the new metaball element");
+ RNA_def_enum(func,
+ "type",
+ rna_enum_metaelem_type_items,
+ MB_BALL,
+ "",
+ "Type for the new metaball element");
parm = RNA_def_pointer(func, "element", "MetaElement", "", "The newly created metaball element");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 9e8a2b83f07..f81f965d0c8 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1921,8 +1921,9 @@ static void rna_def_particle_dupliweight(BlenderRNA *brna)
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ParticleDupliWeight", NULL);
- RNA_def_struct_ui_text(
- srna, "Particle Instance Object Weight", "Weight of a particle instance object in a collection");
+ RNA_def_struct_ui_text(srna,
+ "Particle Instance Object Weight",
+ "Weight of a particle instance object in a collection");
RNA_def_struct_sdna(srna, "ParticleDupliWeight");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
@@ -3170,7 +3171,8 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "ren_child_nbr");
RNA_def_property_range(prop, 0, 100000);
RNA_def_property_ui_range(prop, 0, 10000, 1, -1);
- RNA_def_property_ui_text(prop, "Rendered Children", "Number of children per parent for rendering");
+ RNA_def_property_ui_text(
+ prop, "Rendered Children", "Number of children per parent for rendering");
prop = RNA_def_property(srna, "virtual_parents", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "parents");
@@ -3463,8 +3465,9 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "instance_weights", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "instance_weights", NULL);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
- RNA_def_property_ui_text(
- prop, "Instance Collection Weights", "Weights for all of the objects in the instance collection");
+ RNA_def_property_ui_text(prop,
+ "Instance Collection Weights",
+ "Weights for all of the objects in the instance collection");
prop = RNA_def_property(srna, "active_instanceweight", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "ParticleDupliWeight");
diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c
index bf6eba93b9f..d4127b26629 100644
--- a/source/blender/python/intern/bpy_rna_id_collection.c
+++ b/source/blender/python/intern/bpy_rna_id_collection.c
@@ -304,7 +304,7 @@ static PyObject *bpy_batch_remove(PyObject *UNUSED(self), PyObject *args, PyObje
PyObject *ret = NULL;
static const char *_keywords[] = {"ids", NULL};
- static _PyArg_Parser _parser = {"O:user_map", _keywords, 0};
+ static _PyArg_Parser _parser = {"O:batch_remove", _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &ids)) {
return ret;
}
@@ -353,12 +353,15 @@ PyDoc_STRVAR(bpy_orphans_purge_doc,
"\n"
" Remove (delete) all IDs with no user.\n"
"\n"
- " :return: The number of deleted IDs.\n"
- "\n"
- " WARNING: Considered experimental feature currently.\n");
-static PyObject *bpy_orphans_purge(PyObject *UNUSED(self),
- PyObject *UNUSED(args),
- PyObject *UNUSED(kwds))
+ " :arg do_local_ids: Include unused local IDs in the deletion, defaults to True\n"
+ " :type do_local_ids: bool, optional\n"
+ " :arg do_linked_ids: Include unused linked IDs in the deletion, defaults to True\n"
+ " :type do_linked_ids: bool, optional\n"
+ " :arg do_recursive: Recursively check for unused IDs, ensuring no orphaned one "
+ "remain after a single run of that function, defaults to False\n"
+ " :type do_recursive: bool, optional\n"
+ " :return: The number of deleted IDs.\n");
+static PyObject *bpy_orphans_purge(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
#if 0 /* If someone knows how to get a proper 'self' in that case... */
BPy_StructRNA *pyrna = (BPy_StructRNA *)self;
@@ -367,16 +370,26 @@ static PyObject *bpy_orphans_purge(PyObject *UNUSED(self),
Main *bmain = G_MAIN; /* XXX Ugly, but should work! */
#endif
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->us == 0) {
- id->tag |= LIB_TAG_DOIT;
- }
- else {
- id->tag &= ~LIB_TAG_DOIT;
- }
+ int num_tagged[INDEX_ID_MAX] = {0};
+
+ bool do_local_ids = true;
+ bool do_linked_ids = true;
+ bool do_recursive_cleanup = false;
+
+ static const char *_keywords[] = {"do_local_ids", "do_linked_ids", "do_recursive", NULL};
+ static _PyArg_Parser _parser = {"|$ppp:orphans_purge", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, &do_local_ids, &do_linked_ids, &do_recursive_cleanup)) {
+ return NULL;
+ }
+
+ /* Tag all IDs to delete. */
+ BKE_lib_query_unused_ids_tag(
+ bmain, LIB_TAG_DOIT, do_local_ids, do_linked_ids, do_recursive_cleanup, num_tagged);
+
+ if (num_tagged[INDEX_ID_NULL] == 0) {
+ return PyLong_FromSize_t(0);
}
- FOREACH_MAIN_ID_END;
const size_t num_datablocks_deleted = BKE_id_multi_tagged_delete(bmain);
/* Force full redraw, mandatory to avoid crashes when running this from UI... */
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 688709d55f3..27dcd9e70ed 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -331,7 +331,7 @@ void RE_display_update_cb(struct Render *re,
void (*f)(void *handle, RenderResult *rr, volatile struct rcti *rect));
void RE_stats_draw_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderStats *rs));
void RE_progress_cb(struct Render *re, void *handle, void (*f)(void *handle, float));
-void RE_draw_lock_cb(struct Render *re, void *handle, void (*f)(void *handle, int));
+void RE_draw_lock_cb(struct Render *re, void *handle, void (*f)(void *handle, bool lock));
void RE_test_break_cb(struct Render *re, void *handle, int (*f)(void *handle));
void RE_current_scene_update_cb(struct Render *re,
void *handle,
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index b199b1b0743..a43a78f5d3d 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -757,7 +757,7 @@ static void engine_render_view_layer(Render *re,
{
/* Lock UI so scene can't be edited while we read from it in this render thread. */
if (re->draw_lock) {
- re->draw_lock(re->dlh, 1);
+ re->draw_lock(re->dlh, true);
}
/* Create depsgraph with scene evaluated at render resolution. */
@@ -773,7 +773,7 @@ static void engine_render_view_layer(Render *re,
}
if (re->draw_lock) {
- re->draw_lock(re->dlh, 0);
+ re->draw_lock(re->dlh, false);
}
/* Perform render with engine. */
@@ -824,7 +824,7 @@ bool RE_engine_render(Render *re, bool do_all)
/* Lock drawing in UI during data phase. */
if (re->draw_lock) {
- re->draw_lock(re->dlh, 1);
+ re->draw_lock(re->dlh, true);
}
/* update animation here so any render layer animation is applied before
@@ -852,7 +852,7 @@ bool RE_engine_render(Render *re, bool do_all)
if (re->result == NULL) {
/* Clear UI drawing locks. */
if (re->draw_lock) {
- re->draw_lock(re->dlh, 0);
+ re->draw_lock(re->dlh, false);
}
/* Too small image is handled earlier, here it could only happen if
* there was no sufficient memory to allocate all passes.
@@ -902,7 +902,7 @@ bool RE_engine_render(Render *re, bool do_all)
/* Clear UI drawing locks. */
if (re->draw_lock) {
- re->draw_lock(re->dlh, 0);
+ re->draw_lock(re->dlh, false);
}
/* Render view layers. */
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 0a8b8f24614..92bec9c6fd4 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -1017,7 +1017,7 @@ void RE_progress_cb(Render *re, void *handle, void (*f)(void *handle, float))
re->prh = handle;
}
-void RE_draw_lock_cb(Render *re, void *handle, void (*f)(void *handle, int i))
+void RE_draw_lock_cb(Render *re, void *handle, void (*f)(void *handle, bool lock))
{
re->draw_lock = f;
re->dlh = handle;
diff --git a/source/blender/render/intern/render_types.h b/source/blender/render/intern/render_types.h
index 7a4374dcf7c..0488bf6e87a 100644
--- a/source/blender/render/intern/render_types.h
+++ b/source/blender/render/intern/render_types.h
@@ -141,7 +141,7 @@ struct Render {
void (*progress)(void *handle, float i);
void *prh;
- void (*draw_lock)(void *handle, int i);
+ void (*draw_lock)(void *handle, bool lock);
void *dlh;
int (*test_break)(void *handle);
void *tbh;