Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/paint_undo.c
| Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | typedef struct UndoElem { | ||||
| struct UndoElem *next, *prev; | struct UndoElem *next, *prev; | ||||
| char name[BKE_UNDO_STR_MAX]; | char name[BKE_UNDO_STR_MAX]; | ||||
| uintptr_t undosize; | uintptr_t undosize; | ||||
| ListBase elems; | ListBase elems; | ||||
| UndoRestoreCb restore; | UndoRestoreCb restore; | ||||
| UndoFreeCb free; | UndoFreeCb free; | ||||
| UndoCleanupCb cleanup; | |||||
| } UndoElem; | } UndoElem; | ||||
| typedef struct UndoStack { | typedef struct UndoStack { | ||||
| int type; | int type; | ||||
| ListBase elems; | ListBase elems; | ||||
| UndoElem *current; | UndoElem *current; | ||||
| } UndoStack; | } UndoStack; | ||||
| Show All 11 Lines | |||||
| static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) | static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel) | ||||
| { | { | ||||
| if (uel && uel->free) { | if (uel && uel->free) { | ||||
| uel->free(&uel->elems); | uel->free(&uel->elems); | ||||
| BLI_freelistN(&uel->elems); | BLI_freelistN(&uel->elems); | ||||
| } | } | ||||
| } | } | ||||
| static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free) | static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup) | ||||
| { | { | ||||
| UndoElem *uel; | UndoElem *uel; | ||||
| int nr; | int nr; | ||||
| /* Undo push is split up in begin and end, the reason is that as painting | /* Undo push is split up in begin and end, the reason is that as painting | ||||
| * happens more tiles/nodes are added to the list, and at the very end we | * happens more tiles/nodes are added to the list, and at the very end we | ||||
| * know how much memory the undo used to remove old undo elements */ | * know how much memory the undo used to remove old undo elements */ | ||||
| /* remove all undos after (also when stack->current==NULL) */ | /* remove all undos after (also when stack->current==NULL) */ | ||||
| while (stack->elems.last != stack->current) { | while (stack->elems.last != stack->current) { | ||||
| uel = stack->elems.last; | uel = stack->elems.last; | ||||
| undo_elem_free(stack, uel); | undo_elem_free(stack, uel); | ||||
| BLI_freelinkN(&stack->elems, uel); | BLI_freelinkN(&stack->elems, uel); | ||||
| } | } | ||||
| /* make new */ | /* make new */ | ||||
| stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); | stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file"); | ||||
| uel->restore = restore; | uel->restore = restore; | ||||
| uel->free = free; | uel->free = free; | ||||
| uel->cleanup = cleanup; | |||||
| BLI_addtail(&stack->elems, uel); | BLI_addtail(&stack->elems, uel); | ||||
| /* name can be a dynamic string */ | /* name can be a dynamic string */ | ||||
| BLI_strncpy(uel->name, name, sizeof(uel->name)); | BLI_strncpy(uel->name, name, sizeof(uel->name)); | ||||
| /* limit amount to the maximum amount*/ | /* limit amount to the maximum amount*/ | ||||
| nr = 0; | nr = 0; | ||||
| uel = stack->elems.last; | uel = stack->elems.last; | ||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (uel) { | ||||
| UndoElem *first = stack->elems.first; | UndoElem *first = stack->elems.first; | ||||
| undo_elem_free(stack, first); | undo_elem_free(stack, first); | ||||
| BLI_freelinkN(&stack->elems, first); | BLI_freelinkN(&stack->elems, first); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void undo_stack_cleanup(UndoStack *stack, bContext *C) | |||||
| { | |||||
| UndoElem *uel = stack->elems.first; | |||||
| bool stack_reset = false; | |||||
| while (uel) { | |||||
| if (uel->cleanup && uel->cleanup(C, &uel->elems)) { | |||||
| UndoElem *uel_tmp = uel->next; | |||||
| if (stack->current == uel) { | |||||
| stack->current = NULL; | |||||
| stack_reset = true; | |||||
| } | |||||
| undo_elem_free(stack, uel); | |||||
| BLI_freelinkN(&stack->elems, uel); | |||||
| uel = uel_tmp; | |||||
| } | |||||
| else | |||||
| uel = uel->next; | |||||
| } | |||||
| if (stack_reset) { | |||||
| stack->current = stack->elems.last; | |||||
| } | |||||
| } | |||||
| static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) | static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name) | ||||
| { | { | ||||
| UndoElem *undo; | UndoElem *undo; | ||||
| /* first cleanup any old undo steps that may belong to invalid data */ | |||||
| undo_stack_cleanup(stack, C); | |||||
| if (step == 1) { | if (step == 1) { | ||||
| if (stack->current == NULL) { | if (stack->current == NULL) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else { | else { | ||||
| if (!name || strcmp(stack->current->name, name) == 0) { | if (!name || strcmp(stack->current->name, name) == 0) { | ||||
| if (G.debug & G_DEBUG_WM) { | if (G.debug & G_DEBUG_WM) { | ||||
| printf("%s: undo '%s'\n", __func__, stack->current->name); | printf("%s: undo '%s'\n", __func__, stack->current->name); | ||||
| Show All 32 Lines | for (uel = stack->elems.first; uel; uel = uel->next) | ||||
| undo_elem_free(stack, uel); | undo_elem_free(stack, uel); | ||||
| BLI_freelistN(&stack->elems); | BLI_freelistN(&stack->elems); | ||||
| stack->current = NULL; | stack->current = NULL; | ||||
| } | } | ||||
| /* Exported Functions */ | /* Exported Functions */ | ||||
| void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free) | void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb is_valid) | ||||
| { | { | ||||
| if (type == UNDO_PAINT_IMAGE) | if (type == UNDO_PAINT_IMAGE) | ||||
| undo_stack_push_begin(&ImageUndoStack, name, restore, free); | undo_stack_push_begin(&ImageUndoStack, name, restore, free, is_valid); | ||||
| else if (type == UNDO_PAINT_MESH) | else if (type == UNDO_PAINT_MESH) | ||||
| undo_stack_push_begin(&MeshUndoStack, name, restore, free); | undo_stack_push_begin(&MeshUndoStack, name, restore, free, is_valid); | ||||
| } | } | ||||
| ListBase *undo_paint_push_get_list(int type) | ListBase *undo_paint_push_get_list(int type) | ||||
| { | { | ||||
| if (type == UNDO_PAINT_IMAGE) { | if (type == UNDO_PAINT_IMAGE) { | ||||
| if (ImageUndoStack.current) | if (ImageUndoStack.current) | ||||
| return &ImageUndoStack.current->elems; | return &ImageUndoStack.current->elems; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (uel) { | ||||
| if (active && uel == stack->current) | if (active && uel == stack->current) | ||||
| *active = 1; | *active = 1; | ||||
| return uel->name; | return uel->name; | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| const char *ED_undo_paint_get_name(int type, int nr, int *active) | const char *ED_undo_paint_get_name(bContext *C, int type, int nr, int *active) | ||||
| { | { | ||||
| if (type == UNDO_PAINT_IMAGE) | |||||
| if (type == UNDO_PAINT_IMAGE) { | |||||
| undo_stack_cleanup(&ImageUndoStack, C); | |||||
| return undo_stack_get_name(&ImageUndoStack, nr, active); | return undo_stack_get_name(&ImageUndoStack, nr, active); | ||||
| else if (type == UNDO_PAINT_MESH) | } | ||||
| else if (type == UNDO_PAINT_MESH) { | |||||
| undo_stack_cleanup(&MeshUndoStack, C); | |||||
| return undo_stack_get_name(&MeshUndoStack, nr, active); | return undo_stack_get_name(&MeshUndoStack, nr, active); | ||||
| } | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| bool ED_undo_paint_empty(int type) | bool ED_undo_paint_empty(int type) | ||||
| { | { | ||||
| UndoStack *stack; | UndoStack *stack; | ||||
| if (type == UNDO_PAINT_IMAGE) | if (type == UNDO_PAINT_IMAGE) | ||||
| ▲ Show 20 Lines • Show All 41 Lines • Show Last 20 Lines | |||||