From 937731dff1af4910dc94646904106432c14b2042 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 7 Feb 2019 20:27:11 +1100 Subject: Fix T61272: Undo fails to track multi-edit mode enter/exit Objects leaving edit-mode weren't restored by edit-mode undo steps. --- .../blender/editors/armature/editarmature_undo.c | 13 +++++---- source/blender/editors/curve/editcurve_undo.c | 14 +++++---- source/blender/editors/include/ED_undo.h | 6 ++++ source/blender/editors/lattice/editlattice_undo.c | 13 +++++---- source/blender/editors/mesh/editmesh_undo.c | 14 ++++----- source/blender/editors/metaball/editmball_undo.c | 13 +++++---- source/blender/editors/undo/ed_undo.c | 33 ++++++++++++++++++++++ 7 files changed, 78 insertions(+), 28 deletions(-) (limited to 'source/blender/editors') diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index f88054f20c8..3e76a66e891 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -146,9 +146,11 @@ static bool armature_undosys_step_encode(struct bContext *C, struct Main *UNUSED { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); us->elems_len = objects_len; @@ -168,12 +170,13 @@ static bool armature_undosys_step_encode(struct bContext *C, struct Main *UNUSED static void armature_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) { - /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_EDIT); - BLI_assert(armature_undosys_poll(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)); + + BLI_assert(armature_undosys_poll(C)); + for (uint i = 0; i < us->elems_len; i++) { ArmatureUndoStep_Elem *elem = &us->elems[i]; Object *obedit = elem->obedit_ref.ptr; diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index a586e94a6f9..e9586594274 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -213,9 +213,11 @@ static bool curve_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bm { CurveUndoStep *us = (CurveUndoStep *)us_p; + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); us->elems_len = objects_len; @@ -234,12 +236,14 @@ static bool curve_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bm static void curve_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) { - /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_EDIT); - BLI_assert(curve_undosys_poll(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)); + + BLI_assert(curve_undosys_poll(C)); + for (uint i = 0; i < us->elems_len; i++) { CurveUndoStep_Elem *elem = &us->elems[i]; Object *obedit = elem->obedit_ref.ptr; diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h index 3486761c19f..3a45e2c3b68 100644 --- a/source/blender/editors/include/ED_undo.h +++ b/source/blender/editors/include/ED_undo.h @@ -23,7 +23,9 @@ #include "BLI_compiler_attrs.h" struct CLG_LogRef; +struct Object; struct UndoStack; +struct ViewLayer; struct bContext; struct wmOperator; struct wmOperatorType; @@ -51,6 +53,10 @@ bool ED_undo_is_valid(const struct bContext *C, const char *undoname); bool ED_undo_is_memfile_compatible(const struct bContext *C); +void ED_undo_object_editmode_restore_helper( + struct bContext *C, + struct Object **object_array, uint object_array_len, uint object_array_stride); + struct UndoStack *ED_undo_stack_get(void); /* helpers */ diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index c6c0ad542d1..8dddec3ed6d 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -148,9 +148,11 @@ static bool lattice_undosys_step_encode(struct bContext *C, struct Main *UNUSED( { LatticeUndoStep *us = (LatticeUndoStep *)us_p; + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); us->elems_len = objects_len; @@ -170,12 +172,13 @@ static bool lattice_undosys_step_encode(struct bContext *C, struct Main *UNUSED( static void lattice_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) { - /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_EDIT); - BLI_assert(lattice_undosys_poll(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)); + + BLI_assert(lattice_undosys_poll(C)); + for (uint i = 0; i < us->elems_len; i++) { LatticeUndoStep_Elem *elem = &us->elems[i]; Object *obedit = elem->obedit_ref.ptr; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 7af7204deab..5ed4395a740 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -698,9 +698,11 @@ static bool mesh_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bma { MeshUndoStep *us = (MeshUndoStep *)us_p; + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); us->elems_len = objects_len; @@ -718,16 +720,12 @@ static bool mesh_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bma return true; } -static void mesh_undosys_step_decode(struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir)) +static void mesh_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) { MeshUndoStep *us = (MeshUndoStep *)us_p; - Scene *scene = CTX_data_scene(C); - for (uint i = 0; i < us->elems_len; i++) { - MeshUndoStep_Elem *elem = &us->elems[i]; - Object *obedit = elem->obedit_ref.ptr; - ED_object_editmode_enter_ex(bmain, scene, obedit, EM_NO_CONTEXT); - } + /* 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)); BLI_assert(mesh_undosys_poll(C)); diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index c526edd7bd2..160b43b7065 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -156,9 +156,11 @@ static bool mball_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bm { MBallUndoStep *us = (MBallUndoStep *)us_p; + /* Important not to use the 3D view when getting objects because all objects + * outside of this list will be moved out of edit-mode when reading back undo steps. */ ViewLayer *view_layer = CTX_data_view_layer(C); uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len); + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, NULL, &objects_len); us->elems = MEM_callocN(sizeof(*us->elems) * objects_len, __func__); us->elems_len = objects_len; @@ -178,12 +180,13 @@ static bool mball_undosys_step_encode(struct bContext *C, struct Main *UNUSED(bm static void mball_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, int UNUSED(dir)) { - /* TODO(campbell): undo_system: use low-level API to set mode. */ - ED_object_mode_set(C, OB_MODE_EDIT); - BLI_assert(mball_undosys_poll(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)); + + BLI_assert(mball_undosys_poll(C)); + for (uint i = 0; i < us->elems_len; i++) { MBallUndoStep_Elem *elem = &us->elems[i]; Object *obedit = elem->obedit_ref.ptr; diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 69e02148ba5..ffe752e11b1 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -653,4 +653,37 @@ void ED_undo_object_set_active_or_warn(ViewLayer *view_layer, Object *ob, const } } +void ED_undo_object_editmode_restore_helper( + struct bContext *C, Object **object_array, uint object_array_len, uint object_array_stride) +{ + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + uint bases_len = 0; + /* Don't request unique data because we wan't to de-select objects when exiting edit-mode + * for that to be done on all objects we can't skip ones that share data. */ + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( + view_layer, NULL, &bases_len); + for (uint i = 0; i < bases_len; i++) { + ((ID *)bases[i]->object->data)->tag |= LIB_TAG_DOIT; + } + Scene *scene = CTX_data_scene(C); + Object **ob_p = object_array; + for (uint i = 0; i < object_array_len; i++, ob_p = POINTER_OFFSET(ob_p, object_array_stride)) { + Object *obedit = *ob_p; + ED_object_editmode_enter_ex(bmain, scene, obedit, EM_NO_CONTEXT); + ((ID *)obedit->data)->tag &= ~LIB_TAG_DOIT; + } + for (uint i = 0; i < bases_len; i++) { + ID *id = bases[i]->object->data; + if (id->tag & LIB_TAG_DOIT) { + ED_object_editmode_exit_ex(bmain, scene, bases[i]->object, EM_FREEDATA); + /* Ideally we would know the selection state it was before entering edit-mode, + * for now follow the convention of having them unselected when exiting the mode. */ + ED_object_base_select(bases[i], BA_DESELECT); + + } + } + MEM_freeN(bases); +} + /** \} */ -- cgit v1.2.3