Blender  V2.93
gpencil_undo.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "MEM_guardedalloc.h"
28 
29 #include "DNA_gpencil_types.h"
30 #include "DNA_listBase.h"
31 #include "DNA_object_types.h"
33 
34 #include "BLI_listbase.h"
35 
36 #include "BKE_blender_undo.h"
37 #include "BKE_context.h"
38 #include "BKE_gpencil.h"
39 #include "BKE_undo_system.h"
40 
41 #include "ED_gpencil.h"
42 
43 #include "WM_api.h"
44 #include "WM_types.h"
45 
46 #include "DEG_depsgraph.h"
47 
48 #include "gpencil_intern.h"
49 
50 typedef struct bGPundonode {
51  struct bGPundonode *next, *prev;
52 
54  struct bGPdata *gpd;
56 
59 
61 {
62  return (BLI_listbase_is_empty(&undo_nodes) == false);
63 }
64 
68 int ED_undo_gpencil_step(bContext *C, const int step)
69 {
70  bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
71 
73 
74  const eUndoStepDir undo_step = (eUndoStepDir)step;
75  if (undo_step == STEP_UNDO) {
76  if (cur_node->prev) {
78  new_gpd = cur_node->gpd;
79  }
80  }
81  else if (undo_step == STEP_REDO) {
82  if (cur_node->next) {
84  new_gpd = cur_node->gpd;
85  }
86  }
87 
88  if (new_gpd) {
89  if (gpd_ptr) {
90  if (*gpd_ptr) {
91  bGPdata *gpd = *gpd_ptr;
92  bGPDlayer *gpld;
93 
95 
96  /* copy layers */
98 
99  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
100  /* make a copy of source layer and its data */
101  gpld = BKE_gpencil_layer_duplicate(gpl, true, true);
102  BLI_addtail(&gpd->layers, gpld);
103  }
104  }
105  }
106  /* drawing batch cache is dirty now */
108  new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
109  }
110 
112 
113  return OPERATOR_FINISHED;
114 }
115 
117 {
118  gpencil_undo_push(gpd);
119 }
120 
121 static void gpencil_undo_free_node(bGPundonode *undo_node)
122 {
123  /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
124  * or else the real copy will segfault when accessed
125  */
126  undo_node->gpd->adt = NULL;
127 
128  BKE_gpencil_free(undo_node->gpd, false);
129  MEM_freeN(undo_node->gpd);
130 }
131 
133 {
134  bGPundonode *undo_node;
135 
136  // printf("\t\tGP - undo push\n");
137 
138  if (cur_node) {
139  /* Remove all undone nodes from stack. */
140  undo_node = cur_node->next;
141 
142  while (undo_node) {
143  bGPundonode *next_node = undo_node->next;
144 
145  gpencil_undo_free_node(undo_node);
146  BLI_freelinkN(&undo_nodes, undo_node);
147 
148  undo_node = next_node;
149  }
150  }
151 
152  /* limit number of undo steps to the maximum undo steps
153  * - to prevent running out of memory during **really**
154  * long drawing sessions (triggering swapping)
155  */
156  /* TODO: Undo-memory constraint is not respected yet,
157  * but can be added if we have any need for it. */
158  if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
159  /* remove anything older than n-steps before cur_node */
160  int steps = 0;
161 
162  undo_node = (cur_node) ? cur_node : undo_nodes.last;
163  while (undo_node) {
164  bGPundonode *prev_node = undo_node->prev;
165 
166  if (steps >= U.undosteps) {
167  gpencil_undo_free_node(undo_node);
168  BLI_freelinkN(&undo_nodes, undo_node);
169  }
170 
171  steps++;
172  undo_node = prev_node;
173  }
174  }
175 
176  /* create new undo node */
177  undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
178  undo_node->gpd = BKE_gpencil_data_duplicate(NULL, gpd, true);
179 
180  cur_node = undo_node;
181 
182  BLI_addtail(&undo_nodes, undo_node);
183 }
184 
186 {
187  bGPundonode *undo_node = undo_nodes.first;
188 
189  while (undo_node) {
190  gpencil_undo_free_node(undo_node);
191  undo_node = undo_node->next;
192  }
193 
195 
196  cur_node = NULL;
197 }
#define BKE_UNDO_STR_MAX
struct bGPDlayer * BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src, const bool dup_frames, const bool dup_strokes)
void BKE_gpencil_free(struct bGPdata *gpd, bool free_all)
Definition: gpencil.c:493
struct bGPdata * BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy)
void BKE_gpencil_free_layers(struct ListBase *list)
Definition: gpencil.c:469
eUndoStepDir
@ STEP_UNDO
@ STEP_REDO
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ 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.
@ OPERATOR_FINISHED
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define NA_EDITED
Definition: WM_types.h:462
#define NC_GPENCIL
Definition: WM_types.h:300
unsigned int U
Definition: btGjkEpa3.h:78
void gpencil_undo_push(bGPdata *gpd)
Definition: gpencil_undo.c:132
void gpencil_undo_init(bGPdata *gpd)
Definition: gpencil_undo.c:116
static void gpencil_undo_free_node(bGPundonode *undo_node)
Definition: gpencil_undo.c:121
int ED_gpencil_session_active(void)
Definition: gpencil_undo.c:60
int ED_undo_gpencil_step(bContext *C, const int step)
Definition: gpencil_undo.c:68
struct bGPundonode bGPundonode
void gpencil_undo_finish(void)
Definition: gpencil_undo.c:185
static ListBase undo_nodes
Definition: gpencil_undo.c:57
static bGPundonode * cur_node
Definition: gpencil_undo.c:58
bGPdata ** ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static const int steps
Definition: sky_nishita.cpp:28
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
ListBase layers
struct AnimData * adt
char name[BKE_UNDO_STR_MAX]
Definition: gpencil_undo.c:53
struct bGPdata * gpd
Definition: gpencil_undo.c:54
struct bGPundonode * next
Definition: gpencil_undo.c:51
struct bGPundonode * prev
Definition: gpencil_undo.c:51
void WM_event_add_notifier(const bContext *C, uint type, void *reference)