diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-04-01 12:03:25 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-04-01 12:03:25 +0300 |
commit | b65ea517eb932bde950bde51979c6a3fd258efa8 (patch) | |
tree | 8f3a291a7e1778bb3af45cdb1d98a621efbd1a7d /source/blender/editors/util | |
parent | 916c91bd08933d596eaca3e369467daf7964612e (diff) | |
parent | 473f17b3d557adbb06b89e0a186be48a0129086d (diff) |
Merge branch 'master' into blender2.8
- Undo that changes modes currently asserts,
since undo is now screen data.
Most likely we will change how object mode and workspaces work
since it's not practical/maintainable at the moment.
- Removed view_layer from particle settings
(wasn't needed and complicated undo).
Diffstat (limited to 'source/blender/editors/util')
-rw-r--r-- | source/blender/editors/util/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/blender/editors/util/ed_util.c | 18 | ||||
-rw-r--r-- | source/blender/editors/util/editmode_undo.c | 373 | ||||
-rw-r--r-- | source/blender/editors/util/memfile_undo.c | 149 | ||||
-rw-r--r-- | source/blender/editors/util/undo.c | 327 | ||||
-rw-r--r-- | source/blender/editors/util/undo_system_types.c | 74 | ||||
-rw-r--r-- | source/blender/editors/util/util_intern.h | 14 |
7 files changed, 310 insertions, 649 deletions
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 71a3322cb50..bd9077a2fca 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../../../intern/clog ../../../../intern/glew-mx ) @@ -41,9 +42,10 @@ set(INC_SYS set(SRC ed_transverts.c ed_util.c - editmode_undo.c + memfile_undo.c numinput.c undo.c + undo_system_types.c util_intern.h # general includes diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 7a5b8bfbda1..4bec0d9f114 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -62,6 +62,7 @@ #include "BKE_screen.h" #include "BKE_workspace.h" #include "BKE_layer.h" +#include "BKE_undo_system.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -93,13 +94,16 @@ void ED_editors_init(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + wm->undo_stack = BKE_undosys_stack_create(); + } + /* This is called during initialization, so we don't want to store any reports */ ReportList *reports = CTX_wm_reports(C); int reports_flag_prev = reports->flag & ~RPT_STORE; SWAP(int, reports->flag, reports_flag_prev); - /* toggle on modes for objects that were saved with these enabled. for * e.g. linked objects we have to ensure that they are actually the * active object in this scene. */ @@ -150,10 +154,16 @@ void ED_editors_exit(bContext *C) if (!bmain) return; - + /* frees all editmode undos */ - undo_editmode_clear(); - ED_undo_paint_free(); + if (G.main->wm.first) { + wmWindowManager *wm = G.main->wm.first; + /* normally we don't check for NULL undo stack, do here since it may run in different context. */ + if (wm->undo_stack) { + BKE_undosys_stack_destroy(wm->undo_stack); + wm->undo_stack = NULL; + } + } for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->type == OB_MESH) { diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c deleted file mode 100644 index 43d1bfe1e6c..00000000000 --- a/source/blender/editors/util/editmode_undo.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/util/editmode_undo.c - * \ingroup edutil - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_object_types.h" - -#include "BLI_blenlib.h" -#include "BLI_utildefines.h" - -#include "BKE_blender_undo.h" -#include "BKE_context.h" -#include "BKE_global.h" - -#include "DEG_depsgraph.h" - -#include "ED_util.h" -#include "ED_mesh.h" - -#include "util_intern.h" - -/* ****** XXX ***** */ -static void error(const char *UNUSED(arg)) {} -/* ****** XXX ***** */ - -typedef struct UndoElem { - struct UndoElem *next, *prev; - /** copy of edit-mode object ID */ - ID id; - /** pointer to edited object */ - Object *ob; - /** type of edited object */ - int type; - void *undodata; - uintptr_t undosize; - char name[BKE_UNDO_STR_MAX]; - - /** Use context to retrieve current edit-data. */ - void * (*getdata)(bContext * C); - /** Pointer to function freeing data. */ - void (*freedata)(void *); - /** Data to edit-mode conversion. */ - void (*to_editmode)(void *, void *, void *); - /** Edit-mode to data conversion. */ - void * (*from_editmode)(void *, void *); - /** Check if undo data is still valid. */ - int (*validate_undo)(void *, void *); -} UndoElem; - -static ListBase g_undobase = {NULL, NULL}; -static UndoElem *g_curundo = NULL; - -static void undo_restore(UndoElem *undo, void *editdata, void *obdata) -{ - if (undo) { - undo->to_editmode(undo->undodata, editdata, obdata); - } -} - -/** - * name can be a dynamic string - * See #UndoElem for callbacks docs. - * */ -void undo_editmode_push( - bContext *C, const char *name, - void * (*getdata)(bContext * C), - void (*freedata)(void *), - void (*to_editmode)(void *, void *, void *), - void *(*from_editmode)(void *, void *), - int (*validate_undo)(void *, void *)) -{ - UndoElem *uel; - Object *obedit = CTX_data_edit_object(C); - void *editdata; - int nr; - uintptr_t mem_used, mem_total, mem_max; - - /* at first here was code to prevent an "original" key to be inserted twice - * this was giving conflicts for example when mesh changed due to keys or apply */ - - /* remove all undos after (also when g_curundo == NULL) */ - while (g_undobase.last != g_curundo) { - uel = g_undobase.last; - uel->freedata(uel->undodata); - BLI_freelinkN(&g_undobase, uel); - } - - /* make new */ - g_curundo = uel = MEM_callocN(sizeof(UndoElem), "undo editmode"); - BLI_strncpy(uel->name, name, sizeof(uel->name)); - BLI_addtail(&g_undobase, uel); - - uel->getdata = getdata; - uel->freedata = freedata; - uel->to_editmode = to_editmode; - uel->from_editmode = from_editmode; - uel->validate_undo = validate_undo; - - /* limit amount to the maximum amount*/ - nr = 0; - uel = g_undobase.last; - while (uel) { - nr++; - if (nr == U.undosteps) { - break; - } - uel = uel->prev; - } - if (uel) { - while (g_undobase.first != uel) { - UndoElem *first = g_undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&g_undobase, first); - } - } - - /* copy */ - mem_used = MEM_get_memory_in_use(); - editdata = getdata(C); - g_curundo->undodata = g_curundo->from_editmode(editdata, obedit->data); - g_curundo->undosize = MEM_get_memory_in_use() - mem_used; - g_curundo->ob = obedit; - g_curundo->id = obedit->id; - g_curundo->type = obedit->type; - - if (U.undomemory != 0) { - /* limit to maximum memory (afterwards, we can't know in advance) */ - mem_total = 0; - mem_max = ((uintptr_t)U.undomemory) * 1024 * 1024; - - uel = g_undobase.last; - while (uel && uel->prev) { - mem_total += uel->undosize; - if (mem_total > mem_max) { - break; - } - uel = uel->prev; - } - - if (uel) { - if (uel->prev && uel->prev->prev) { - uel = uel->prev; - } - while (g_undobase.first != uel) { - UndoElem *first = g_undobase.first; - first->freedata(first->undodata); - BLI_freelinkN(&g_undobase, first); - } - } - } -} - -/* helper to remove clean other objects from undo stack */ -static void undo_clean_stack(bContext *C) -{ - UndoElem *uel; - Object *obedit = CTX_data_edit_object(C); - - /* global undo changes pointers, so we also allow identical names */ - /* side effect: when deleting/renaming object and start editing new one with same name */ - - uel = g_undobase.first; - while (uel) { - void *editdata = uel->getdata(C); - bool is_valid = false; - UndoElem *uel_next = uel->next; - - /* for when objects are converted, renamed, or global undo changes pointers... */ - if (uel->type == obedit->type) { - if (STREQ(uel->id.name, obedit->id.name)) { - if (uel->validate_undo == NULL) { - is_valid = true; - } - else if (uel->validate_undo(uel->undodata, editdata)) { - is_valid = true; - } - } - } - if (is_valid) { - uel->ob = obedit; - } - else { - if (uel == g_curundo) { - g_curundo = NULL; - } - - uel->freedata(uel->undodata); - BLI_freelinkN(&g_undobase, uel); - } - - uel = uel_next; - } - - if (g_curundo == NULL) { - g_curundo = g_undobase.last; - } -} - -/** - * 1 = an undo, -1 is a redo. - * we have to make sure 'g_curundo' remains at current situation - */ -void undo_editmode_step(bContext *C, int step) -{ - Object *obedit = CTX_data_edit_object(C); - - /* prevent undo to happen on wrong object, stack can be a mix */ - undo_clean_stack(C); - - if (step == 0) { - undo_restore(g_curundo, g_curundo->getdata(C), obedit->data); - } - else if (step == 1) { - if (g_curundo == NULL || g_curundo->prev == NULL) { - error("No more steps to undo"); - } - else { - if (G.debug & G_DEBUG) printf("undo %s\n", g_curundo->name); - g_curundo = g_curundo->prev; - undo_restore(g_curundo, g_curundo->getdata(C), obedit->data); - } - } - else { - /* g_curundo has to remain current situation! */ - if (g_curundo == NULL || g_curundo->next == NULL) { - error("No more steps to redo"); - } - else { - undo_restore(g_curundo->next, g_curundo->getdata(C), obedit->data); - g_curundo = g_curundo->next; - if (G.debug & G_DEBUG) printf("redo %s\n", g_curundo->name); - } - } - - /* special case for editmesh, mode must be copied back to the scene */ - if (obedit->type == OB_MESH) { - EDBM_selectmode_to_scene(C); - } - - DEG_id_tag_update(&obedit->id, OB_RECALC_DATA); - - /* XXX notifiers */ -} - -void undo_editmode_clear(void) -{ - UndoElem *uel; - - uel = g_undobase.first; - while (uel) { - uel->freedata(uel->undodata); - uel = uel->next; - } - BLI_freelistN(&g_undobase); - g_curundo = NULL; -} - -/* based on index nr it does a restore */ -void undo_editmode_number(bContext *C, int nr) -{ - UndoElem *uel; - int a = 1; - - for (uel = g_undobase.first; uel; uel = uel->next, a++) { - if (a == nr) { - break; - } - } - g_curundo = uel; - undo_editmode_step(C, 0); -} - -void undo_editmode_name(bContext *C, const char *undoname) -{ - UndoElem *uel; - - for (uel = g_undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) { - break; - } - } - if (uel && uel->prev) { - g_curundo = uel->prev; - undo_editmode_step(C, 0); - } -} - -/** - * \a undoname is optional, when NULL it just checks for existing undo steps - */ -bool undo_editmode_is_valid(const char *undoname) -{ - if (undoname) { - UndoElem *uel; - - for (uel = g_undobase.last; uel; uel = uel->prev) { - if (STREQ(undoname, uel->name)) { - break; - } - } - return uel != NULL; - } - return g_undobase.last != g_undobase.first; -} - - -/** - * Get name of undo item, return null if no item with this index. - * - * if active pointer, set it to 1 if true - */ -const char *undo_editmode_get_name(bContext *C, int nr, bool *r_active) -{ - UndoElem *uel; - - /* prevent wrong numbers to be returned */ - undo_clean_stack(C); - - if (r_active) { - *r_active = false; - } - - uel = BLI_findlink(&g_undobase, nr); - if (uel) { - if (r_active && (uel == g_curundo)) { - *r_active = true; - } - return uel->name; - } - return NULL; -} - - -void *undo_editmode_get_prev(Object *ob) -{ - UndoElem *ue = g_undobase.last; - if (ue && ue->prev && ue->prev->ob == ob) { - return ue->prev->undodata; - } - return NULL; -} diff --git a/source/blender/editors/util/memfile_undo.c b/source/blender/editors/util/memfile_undo.c new file mode 100644 index 00000000000..95af0c48147 --- /dev/null +++ b/source/blender/editors/util/memfile_undo.c @@ -0,0 +1,149 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/util/memfile_undo.c + * \ingroup edutil + * + * Wrapper between 'BKE_undo.h' and 'BKE_undo_system.h' + */ + +#include "BLI_utildefines.h" +#include "BLI_sys_types.h" + +#include "DNA_object_enums.h" + +#include "BKE_blender_undo.h" +#include "BKE_context.h" +#include "BKE_undo_system.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_util.h" +#include "ED_render.h" + + +#include "../blenloader/BLO_undofile.h" + +#include "util_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Implements ED Undo System + * \{ */ + +typedef struct MemFileUndoStep { + UndoStep step; + MemFileUndoData *data; +} MemFileUndoStep; + +static bool memfile_undosys_poll(bContext *UNUSED(C)) +{ + /* other poll functions must run first, this is a catch-all. */ + + if ((U.uiflag & USER_GLOBALUNDO) == 0) { + return false; + } + return true; +} + +static bool memfile_undosys_step_encode(struct bContext *C, UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + + /* Important we only use 'main' from the context (see: BKE_undosys_stack_init_from_main). */ + struct Main *bmain = CTX_data_main(C); + + /* can be NULL, use when set. */ + MemFileUndoStep *us_prev = (MemFileUndoStep *)BKE_undosys_step_same_type_prev(us_p); + us->data = BKE_memfile_undo_encode(bmain, us_prev ? us_prev->data : NULL); + us->step.data_size = us->data->undo_size; + return true; +} + +static void memfile_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir)) +{ + /* Loading the content will correctly switch into compatible non-object modes. */ + ED_object_mode_set(C, OB_MODE_OBJECT); + + /* This is needed so undoing/redoing doesn't crash with threaded previews going */ + ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + BKE_memfile_undo_decode(us->data, C); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); +} + +static void memfile_undosys_step_free(UndoStep *us_p) +{ + /* To avoid unnecessary slow down, free backwards (so we don't need to merge when clearing all). */ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + if (us_p->next != NULL) { + UndoStep *us_next_p = BKE_undosys_step_same_type_next(us_p); + if (us_next_p != NULL) { + MemFileUndoStep *us_next = (MemFileUndoStep *)us_next_p; + BLO_memfile_merge(&us->data->memfile, &us_next->data->memfile); + } + } + + BKE_memfile_undo_free(us->data); +} + +/* Export for ED_undo_sys. */ +void ED_memfile_undosys_type(UndoType *ut) +{ + ut->name = "Global Undo"; + ut->poll = memfile_undosys_poll; + ut->step_encode = memfile_undosys_step_encode; + ut->step_decode = memfile_undosys_step_decode; + ut->step_free = memfile_undosys_step_free; + + ut->mode = BKE_UNDOTYPE_MODE_STORE; + ut->use_context = true; + + ut->step_size = sizeof(MemFileUndoStep); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ + +/** + * Ideally we wouldn't need to export global undo internals, there are some cases where it's needed though. + */ +static struct MemFile *ed_undosys_step_get_memfile(UndoStep *us_p) +{ + MemFileUndoStep *us = (MemFileUndoStep *)us_p; + return &us->data->memfile; +} + +struct MemFile *ED_undosys_stack_memfile_get_active(UndoStack *ustack) +{ + UndoStep *us = BKE_undosys_stack_active_with_type(ustack, BKE_UNDOSYS_TYPE_MEMFILE); + if (us) { + return ed_undosys_step_get_memfile(us); + } + return NULL; +} + + +/** \} */ diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index b7101e7ae99..99e90eb73e8 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -48,6 +48,7 @@ #include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" #include "DEG_depsgraph.h" @@ -80,42 +81,27 @@ void ED_undo_push(bContext *C, const char *str) { - const WorkSpace *workspace = CTX_wm_workspace(C); - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - - if (G.debug & G_DEBUG) + if (G.debug & G_DEBUG) { printf("%s: %s\n", __func__, str); - - /* Always do it for now, this might need to be refined... */ - BKE_main_override_static_operations_create(CTX_data_main(C)); - - if (obedit) { - if (U.undosteps == 0) return; - - if (obedit->type == OB_MESH) - undo_push_mesh(C, str); - else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) - undo_push_curve(C, str); - else if (obedit->type == OB_FONT) - undo_push_font(C, str); - else if (obedit->type == OB_MBALL) - undo_push_mball(C, str); - else if (obedit->type == OB_LATTICE) - undo_push_lattice(C, str); - else if (obedit->type == OB_ARMATURE) - undo_push_armature(C, str); } - else if (obact && workspace->object_mode & OB_MODE_PARTICLE_EDIT) { - if (U.undosteps == 0) return; + const int steps = U.undosteps; - PE_undo_push(CTX_data_scene(C), CTX_data_view_layer(C), str); + if (steps <= 0) { + return; } - else if (obact && workspace->object_mode & OB_MODE_SCULPT) { - /* do nothing for now */ + + wmWindowManager *wm = CTX_wm_manager(C); + + /* Only apply limit if this is the last undo step. */ + if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) { + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0); } - else { - BKE_undo_write(C, str); + + BKE_undosys_step_push(wm->undo_stack, C, str); + + if (U.undomemory != 0) { + const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024; + BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); } WM_file_tag_modified(); @@ -124,15 +110,10 @@ void ED_undo_push(bContext *C, const char *str) /* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { - const WorkSpace *workspace = CTX_wm_workspace(C); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); + // Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ @@ -140,100 +121,45 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) return OPERATOR_CANCELLED; } + /* TODO(campbell): undo_system: use undo system */ /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { - if (U.uiflag & USER_GLOBALUNDO) { - ED_viewport_render_kill_jobs(wm, bmain, true); - BKE_undo_name(C, undoname); - } - } - - WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + /* Undo System */ + { + if (undoname) { + UndoStep *step_data = BKE_undosys_step_find_by_name(wm->undo_stack, undoname); + BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data); } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - ED_text_undo_step(C, step); - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - if (undoname) - undo_editmode_name(C, undoname); - else - undo_editmode_step(C, step); - - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); + else { + BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step); } } - else { - /* Note: we used to do a fall-through here where if the - * mode-specific undo system had no more steps to undo (or - * redo), the global undo would run. - * - * That was inconsistent with editmode, and also makes for - * unecessarily tricky interaction with the other undo - * systems. */ - if (obact && workspace->object_mode & OB_MODE_TEXTURE_PAINT) { - ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); - } - else if (obact && workspace->object_mode & OB_MODE_SCULPT) { - ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); - } - else if (obact && workspace->object_mode & OB_MODE_PARTICLE_EDIT) { - if (step == 1) - PE_undo(scene, view_layer); - else - PE_redo(scene, view_layer); - } - else if (U.uiflag & USER_GLOBALUNDO) { - // note python defines not valid here anymore. - //#ifdef WITH_PYTHON - // XXX BPY_scripts_clear_pyobjects(); - //#endif - - /* for global undo/redo we should just clear the editmode stack */ - /* for example, texface stores image pointers */ - undo_editmode_clear(); - - ED_viewport_render_kill_jobs(wm, bmain, true); - if (undoname) - BKE_undo_name(C, undoname); - else - BKE_undo_step(C, step); - - scene = CTX_data_scene(C); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); - } - } - WM_event_add_notifier(C, NC_WINDOW, NULL); WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL); if (win) { win->addmousemove = true; } - + return OPERATOR_FINISHED; } void ED_undo_grouped_push(bContext *C, const char *str) { /* do nothing if previous undo task is the same as this one (or from the same undo group) */ - const char *last_undo = BKE_undo_get_name_last(); + { + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack->steps.last) { + const UndoStep *us = wm->undo_stack->steps.last; + if (STREQ(str, us->name)) { + return; + } + } - if (last_undo && STREQ(str, last_undo)) { - return; } /* push as usual */ @@ -274,48 +200,8 @@ void ED_undo_pop_op(bContext *C, wmOperator *op) /* name optionally, function used to check for operator redo panel */ bool ED_undo_is_valid(const bContext *C, const char *undoname) { - const WorkSpace *workspace = CTX_wm_workspace(C); - Object *obedit = CTX_data_edit_object(C); - Object *obact = CTX_data_active_object(C); - ScrArea *sa = CTX_wm_area(C); - - if (sa && sa->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - return 1; - } - } - - if (sa && (sa->spacetype == SPACE_TEXT)) { - return 1; - } - else if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return undo_editmode_is_valid(undoname); - } - } - else { - - /* if below tests fail, global undo gets executed */ - - if (obact && workspace->object_mode & OB_MODE_TEXTURE_PAINT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_IMAGE, undoname)) - return 1; - } - else if (obact && workspace->object_mode & OB_MODE_SCULPT) { - if (ED_undo_paint_is_valid(UNDO_PAINT_MESH, undoname)) - return 1; - } - else if (obact && workspace->object_mode & OB_MODE_PARTICLE_EDIT) { - return PE_undo_is_valid(CTX_data_scene(C), CTX_data_view_layer(C)); - } - - if (U.uiflag & USER_GLOBALUNDO) { - return BKE_undo_is_valid(undoname); - } - } - return 0; + wmWindowManager *wm = CTX_wm_manager(C); + return BKE_undosys_stack_has_undo(wm->undo_stack, undoname); } static int ed_undo_exec(bContext *C, wmOperator *UNUSED(op)) @@ -493,112 +379,45 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_ev /* ************************** */ -enum { - UNDOSYSTEM_GLOBAL = 1, - UNDOSYSTEM_EDITMODE = 2, - UNDOSYSTEM_PARTICLE = 3, - UNDOSYSTEM_IMAPAINT = 4, - UNDOSYSTEM_SCULPT = 5, -}; - -static int get_undo_system(bContext *C) -{ - const WorkSpace *workspace = CTX_wm_workspace(C); - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - ScrArea *sa = CTX_wm_area(C); - - /* first check for editor undo */ - if (sa && (sa->spacetype == SPACE_IMAGE)) { - SpaceImage *sima = (SpaceImage *)sa->spacedata.first; - - if ((obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - } - /* find out which undo system */ - if (obedit) { - if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { - return UNDOSYSTEM_EDITMODE; - } - } - else { - if (obact) { - if (workspace->object_mode & OB_MODE_PARTICLE_EDIT) - return UNDOSYSTEM_PARTICLE; - else if (workspace->object_mode & OB_MODE_TEXTURE_PAINT) { - if (!ED_undo_paint_empty(UNDO_PAINT_IMAGE)) - return UNDOSYSTEM_IMAPAINT; - } - else if (workspace->object_mode & OB_MODE_SCULPT) { - if (!ED_undo_paint_empty(UNDO_PAINT_MESH)) - return UNDOSYSTEM_SCULPT; - } - } - if (U.uiflag & USER_GLOBALUNDO) - return UNDOSYSTEM_GLOBAL; - } - - return 0; -} - /* create enum based on undo items */ -static const EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem) +static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) { EnumPropertyItem item_tmp = {0}, *item = NULL; int i = 0; - bool active; - - while (true) { - const char *name = NULL; - - if (undosys == UNDOSYSTEM_PARTICLE) { - name = PE_undo_get_name(CTX_data_scene(C), CTX_data_view_layer(C), i, &active); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - name = undo_editmode_get_name(C, i, &active); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - name = ED_undo_paint_get_name(C, UNDO_PAINT_MESH, i, &active); - } - else { - name = BKE_undo_get_name(i, &active); - } - - if (name) { - item_tmp.identifier = name; + + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + return NULL; + } + + for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { + if (us->skip == false) { + item_tmp.identifier = us->name; /* XXX This won't work with non-default contexts (e.g. operators) :/ */ - item_tmp.name = IFACE_(name); - if (active) + item_tmp.name = IFACE_(us->name); + if (us == wm->undo_stack->step_active) { item_tmp.icon = ICON_RESTRICT_VIEW_OFF; - else + } + else { item_tmp.icon = ICON_NONE; - item_tmp.value = i++; + } + item_tmp.value = i; RNA_enum_item_add(&item, totitem, &item_tmp); } - else - break; } - RNA_enum_item_end(&item, totitem); - + return item; } static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - int undosys, totitem = 0; - - undosys = get_undo_system(C); - - if (undosys) { - const EnumPropertyItem *item = rna_undo_itemf(C, undosys, &totitem); - + int totitem = 0; + + { + const EnumPropertyItem *item = rna_undo_itemf(C, &totitem); + if (totitem > 0) { uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); @@ -632,30 +451,12 @@ static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE /* note: also check ed_undo_step() in top if you change notifiers */ static int undo_history_exec(bContext *C, wmOperator *op) { - if (RNA_struct_property_is_set(op->ptr, "item")) { - int undosys = get_undo_system(C); - int item = RNA_int_get(op->ptr, "item"); - - if (undosys == UNDOSYSTEM_PARTICLE) { - PE_undo_number(CTX_data_scene(C), CTX_data_view_layer(C), item); - } - else if (undosys == UNDOSYSTEM_EDITMODE) { - undo_editmode_number(C, item + 1); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); - } - else if (undosys == UNDOSYSTEM_IMAPAINT) { - ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item); - } - else if (undosys == UNDOSYSTEM_SCULPT) { - ED_undo_paint_step_num(C, UNDO_PAINT_MESH, item); - } - else { - ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true); - BKE_undo_number(C, item); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C)); - } + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); + if (RNA_property_is_set(op->ptr, prop)) { + int item = RNA_property_int_get(op->ptr, prop); + wmWindowManager *wm = CTX_wm_manager(C); + BKE_undosys_step_undo_from_index(wm->undo_stack, C, item); WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; diff --git a/source/blender/editors/util/undo_system_types.c b/source/blender/editors/util/undo_system_types.c new file mode 100644 index 00000000000..a326d9eb859 --- /dev/null +++ b/source/blender/editors/util/undo_system_types.c @@ -0,0 +1,74 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/util/undo_system_types.c + * \ingroup edutil + */ + +#include <string.h> + +#include "BLI_utildefines.h" + + +#include "ED_armature.h" +#include "ED_curve.h" +#include "ED_lattice.h" +#include "ED_mball.h" +#include "ED_mesh.h" +#include "ED_paint.h" +#include "ED_particle.h" +#include "ED_sculpt.h" +#include "ED_text.h" +#include "ED_util.h" +#include "util_intern.h" + +/* Keep last */ +#include "BKE_undo_system.h" + +void ED_undosys_type_init(void) +{ + /* Edit Modes */ + BKE_undosys_type_append(ED_armature_undosys_type); + BKE_undosys_type_append(ED_curve_undosys_type); + BKE_undosys_type_append(ED_font_undosys_type); + BKE_undosys_type_append(ED_lattice_undosys_type); + BKE_undosys_type_append(ED_mball_undosys_type); + BKE_undosys_type_append(ED_mesh_undosys_type); + + /* Paint Modes */ + BKE_UNDOSYS_TYPE_IMAGE = BKE_undosys_type_append(ED_image_undosys_type); + + BKE_UNDOSYS_TYPE_SCULPT = BKE_undosys_type_append(ED_sculpt_undosys_type); + + BKE_UNDOSYS_TYPE_PARTICLE = BKE_undosys_type_append(ED_particle_undosys_type); + + BKE_UNDOSYS_TYPE_PAINTCURVE = BKE_undosys_type_append(ED_paintcurve_undosys_type); + + /* Text editor */ + BKE_undosys_type_append(ED_text_undosys_type); + + /* Keep global undo last (as a fallback). */ + BKE_UNDOSYS_TYPE_MEMFILE = BKE_undosys_type_append(ED_memfile_undosys_type); +} + +void ED_undosys_type_free(void) +{ + BKE_undosys_type_free_all(); +} diff --git a/source/blender/editors/util/util_intern.h b/source/blender/editors/util/util_intern.h index 0f650330951..6eda3900e91 100644 --- a/source/blender/editors/util/util_intern.h +++ b/source/blender/editors/util/util_intern.h @@ -34,13 +34,11 @@ /* internal exports only */ -/* editmode_undo.c */ -void undo_editmode_name(struct bContext *C, const char *undoname); -bool undo_editmode_is_valid(const char *undoname); -const char *undo_editmode_get_name(struct bContext *C, int nr, bool *r_active); -void *undo_editmode_get_prev(struct Object *ob); -void undo_editmode_step(struct bContext *C, int step); -void undo_editmode_number(struct bContext *C, int nr); +struct UndoType; +struct Main; +struct Scene; -#endif /* __UTIL_INTERN_H__ */ +/* memfile_undo.c */ +void ED_memfile_undosys_type(struct UndoType *ut); +#endif /* __UTIL_INTERN_H__ */ |