Blender V4.3
gpencil_undo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdlib>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
15#include "DNA_listBase.h"
16#include "DNA_object_types.h"
18
19#include "BLI_listbase.h"
20
21#include "BKE_blender_undo.hh"
22#include "BKE_gpencil_legacy.h"
23#include "BKE_undo_system.hh"
24
25#include "ED_gpencil_legacy.hh"
26
27#include "WM_api.hh"
28#include "WM_types.hh"
29
30#include "DEG_depsgraph.hh"
31
32#include "gpencil_intern.hh"
33
40
41static ListBase undo_nodes = {nullptr, nullptr};
42static bGPundonode *cur_node = nullptr;
43
45{
46 return (BLI_listbase_is_empty(&undo_nodes) == false);
47}
48
49int ED_undo_gpencil_step(bContext *C, const int step)
50{
51 bGPdata **gpd_ptr = nullptr, *new_gpd = nullptr;
52
53 gpd_ptr = ED_gpencil_data_get_pointers(C, nullptr);
54
55 const eUndoStepDir undo_step = (eUndoStepDir)step;
56 if (undo_step == STEP_UNDO) {
57 if (cur_node->prev) {
59 new_gpd = cur_node->gpd;
60 }
61 }
62 else if (undo_step == STEP_REDO) {
63 if (cur_node->next) {
65 new_gpd = cur_node->gpd;
66 }
67 }
68
69 if (new_gpd) {
70 if (gpd_ptr) {
71 if (*gpd_ptr) {
72 bGPdata *gpd = *gpd_ptr;
73 bGPDlayer *gpld;
74
76
77 /* copy layers */
79
80 LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
81 /* make a copy of source layer and its data */
82 gpld = BKE_gpencil_layer_duplicate(gpl, true, true);
83 BLI_addtail(&gpd->layers, gpld);
84 }
85 }
86 }
87 /* drawing batch cache is dirty now */
89 new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
90 }
91
93
94 return OPERATOR_FINISHED;
95}
96
98{
100}
101
102static void gpencil_undo_free_node(bGPundonode *undo_node)
103{
104 /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
105 * or else the real copy will segfault when accessed
106 */
107 undo_node->gpd->adt = nullptr;
108
109 BKE_gpencil_free_data(undo_node->gpd, false);
110 MEM_freeN(undo_node->gpd);
111}
112
114{
115 bGPundonode *undo_node;
116
117 if (cur_node) {
118 /* Remove all undone nodes from stack. */
119 undo_node = cur_node->next;
120
121 while (undo_node) {
122 bGPundonode *next_node = undo_node->next;
123
124 gpencil_undo_free_node(undo_node);
125 BLI_freelinkN(&undo_nodes, undo_node);
126
127 undo_node = next_node;
128 }
129 }
130
131 /* limit number of undo steps to the maximum undo steps
132 * - to prevent running out of memory during **really**
133 * long drawing sessions (triggering swapping)
134 */
135 /* TODO: Undo-memory constraint is not respected yet,
136 * but can be added if we have any need for it. */
137 if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
138 /* remove anything older than n-steps before cur_node */
139 int steps = 0;
140
141 undo_node = (cur_node) ? cur_node : static_cast<bGPundonode *>(undo_nodes.last);
142 while (undo_node) {
143 bGPundonode *prev_node = undo_node->prev;
144
145 if (steps >= U.undosteps) {
146 gpencil_undo_free_node(undo_node);
147 BLI_freelinkN(&undo_nodes, undo_node);
148 }
149
150 steps++;
151 undo_node = prev_node;
152 }
153 }
154
155 /* create new undo node */
156 undo_node = MEM_cnew<bGPundonode>("gpencil undo node");
157 undo_node->gpd = BKE_gpencil_data_duplicate(nullptr, gpd, true);
158
159 cur_node = undo_node;
160
161 BLI_addtail(&undo_nodes, undo_node);
162}
163
165{
166 bGPundonode *undo_node = static_cast<bGPundonode *>(undo_nodes.first);
167
168 while (undo_node) {
169 gpencil_undo_free_node(undo_node);
170 undo_node = undo_node->next;
171 }
172
174
175 cur_node = nullptr;
176}
#define BKE_UNDO_STR_MAX
void BKE_gpencil_free_data(struct bGPdata *gpd, bool free_all)
struct bGPdata * BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy)
struct bGPDlayer * BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src, bool dup_frames, bool dup_strokes)
void BKE_gpencil_free_layers(struct ListBase *list)
eUndoStepDir
@ STEP_UNDO
@ STEP_REDO
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ GP_DATA_CACHE_IS_DIRTY
These structs are the foundation for all linked lists in the library system.
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
unsigned int U
Definition btGjkEpa3.h:78
void gpencil_undo_push(bGPdata *gpd)
void gpencil_undo_init(bGPdata *gpd)
static void gpencil_undo_free_node(bGPundonode *undo_node)
int ED_undo_gpencil_step(bContext *C, const int step)
void gpencil_undo_finish()
int ED_gpencil_session_active()
static ListBase undo_nodes
static bGPundonode * cur_node
bGPdata ** ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static const int steps
void * last
void * first
struct AnimData * adt
bGPdata * gpd
bGPundonode * next
bGPundonode * prev
void WM_event_add_notifier(const bContext *C, uint type, void *reference)