diff options
author | Jacques Lucke <jacques@blender.org> | 2021-02-26 13:39:31 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-02-26 13:39:31 +0300 |
commit | b2774b03b906c11ced73484c70887082643bfb20 (patch) | |
tree | fc56363f181892bbf4d84084b4d6427f3fa5006b /source | |
parent | 81d4e4d35e3330b4735994649e6625937650192e (diff) | |
parent | 72ceab8ab256ea53e364a2e9ae9ef3f62b634373 (diff) |
Merge branch 'master' into temp-spreadsheet-editor
Diffstat (limited to 'source')
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; |