1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
/*
* tkTextUndo.h --
*
* The implementation of an undo/redo stack. The design and implementation
* of tkUndo is not useful for our purposes:
*
* 1. We are not pushing an undo/redo pair on the stack. Our stack is only
* pushing the undo item, and applying this undo item will replace this
* item by a redo item (and vice versa when performing the redo; in fact
* there is no difference between an undo and redo item - the undo of
* insert is delete, the undo of delete is insert, and the same applies
* to redo). The advantage is that our undo (or redo) item for insert
* contains exact zero characters, contrary to the undo/redo pairs in
* tkUndo, one of the undo/redo items in this pair always contains a
* copy of the text content (a waste of memory).
*
* 2. tkUndo expects a script, our stack expects memory addresses (it's also
* an general implementation which can be shared).
*
* 3. Our stack allows to control the undo and redo stacks separately.
*
* 4. Moreover our stack supports to limit the size, not only the depth.
*
* Copyright (c) 2015-2017 Gregor Cramer.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef _TKTEXTUNDO
#define _TKTEXTUNDO
#include "tkInt.h"
#include "tkBool.h"
/*
* Our (private) stack type.
*/
struct TkTextUndoStack;
typedef struct TkTextUndoStack * TkTextUndoStack;
/*
* The generic context type.
*/
typedef void * TkTextUndoContext;
/*
* Basic type of an undo/redo item, the user has to know the real type.
*/
typedef void * TkTextUndoItem;
/*
* Struct defining a single action, one or more of which may be defined (and
* stored in a linked list) separately for each undo and redo action of an
* undo atom.
*/
typedef struct TkTextUndoSubAtom {
TkTextUndoItem item; /* The data of this undo/redo item. */
uint32_t size:31; /* Size info for this item. */
uint32_t redo:1; /* Is redo item? */
} TkTextUndoSubAtom;
/*
* Struct representing a single undo+redo atom to be placed in the stack.
*/
typedef struct TkTextUndoAtom {
uint32_t arraySize; /* Number of elements in this array. */
uint32_t size:31; /* Total size of all items. */
uint32_t redo:1; /* Is redo atom? */
const TkTextUndoSubAtom array[1];
/* Array of undo/redo actions. */
} TkTextUndoAtom;
/*
* Callback to carry out undo or redo actions. This function may
* push redo (undo) items for this undo (redo) onto the stack.
* The user should push the reverting items while this action will
* be performed.
*
* Note that the atom is given as a const value, but it's allowed
* to change/reset the items of the sub-atoms.
*/
typedef void (TkTextUndoPerformProc)(TkTextUndoStack stack, const TkTextUndoAtom *atom);
/*
* Callback proc type to free undo/redo items. This function will be
* called when the user is clearing the stack (destroying the stack
* is implicitly clearing the stack), or when the push operation
* is deleting the oldest undo atom (for keeping the max. depth and
* max. size).
*/
typedef void (TkTextUndoFreeProc)(const TkTextUndoStack stack, const TkTextUndoSubAtom *atom);
/*
* Callback proc type for stack changes. Every time when the stack is
* changing this callback function will be triggered.
*/
typedef void (TkTextUndoStackContentChangedProc)(const TkTextUndoStack stack);
/*
* Functions for constructing/destructing the stack. Use zero for unlimited
* stack depth, also use zero for unlimited size. 'freeProc' can be NULL,
* but normally this function is required. It's clear that 'undoProc' is
* mandatory. 'informStackChangeProc' and pushSeparatorProc can also be NULL.
*/
TkTextUndoStack TkTextUndoCreateStack(
unsigned maxUndoDepth, int maxRedoDepth, unsigned maxSize,
TkTextUndoPerformProc undoProc, TkTextUndoFreeProc freeProc,
TkTextUndoStackContentChangedProc contentChangedProc);
void TkTextUndoDestroyStack(TkTextUndoStack *stackPtr);
/*
* Managing the stack. Use zero for unlimited stack depth, also use zero
* for unlimited size. Setting a lower limit than the current depth is
* reducing the stack immediately. Setting a lower limit than the current
* size is also reducing the stack immediately iff 'applyImmediately' is
* 'true', otherwise the size will shrink when performing undo actions.
* It is not allowed to use these functions while an undo/redo action is
* performed, TCL_ERROR will be returned in this case.
*
* For convenience the functions TkTextUndoResetStack, TkTextUndoClearStack,
* TkTextUndoClearUndoStack, and TkTextUndoClearRedoStack, are allowing
* NULL arguments.
*/
int TkTextUndoSetMaxStackDepth(TkTextUndoStack stack,
unsigned maxUndoDepth, int maxRedoDepth);
int TkTextUndoSetMaxStackSize(TkTextUndoStack stack,
unsigned maxSize, bool applyImmediately);
int TkTextUndoResetStack(TkTextUndoStack stack);
int TkTextUndoClearStack(TkTextUndoStack stack);
int TkTextUndoClearUndoStack(TkTextUndoStack stack);
int TkTextUndoClearRedoStack(TkTextUndoStack stack);
/*
* Functions to set/get the context. This is an additional information
* for the user.
*/
inline void TkTextUndoSetContext(TkTextUndoStack stack, TkTextUndoContext context);
inline TkTextUndoContext TkTextUndoGetContext(const TkTextUndoStack stack);
/*
* Accessing attributes.
*
* The content is irreversible if:
* 1. The stack has exceeded the depth/size limit when adding undo atoms.
* 2. Setting a lower limit has caused the deletion of undo atoms.
* 3. Performing an redo did not push undo items.
* Clearing the stack is resetting this state to false.
*
* The content is modified if undo stack is not empty, or the content
* is irreversible.
*/
inline unsigned TkTextUndoGetMaxUndoDepth(const TkTextUndoStack stack);
inline int TkTextUndoGetMaxRedoDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetMaxSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentUndoStackDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentRedoStackDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountUndoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountRedoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentUndoSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentRedoSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountCurrentUndoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountCurrentRedoItems(const TkTextUndoStack stack);
inline bool TkTextUndoContentIsIrreversible(const TkTextUndoStack stack);
inline bool TkTextUndoContentIsModified(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingUndo(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingRedo(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingUndoRedo(const TkTextUndoStack stack);
inline const TkTextUndoAtom *TkTextUndoCurrentUndoAtom(const TkTextUndoStack stack);
inline const TkTextUndoAtom *TkTextUndoCurrentRedoAtom(const TkTextUndoStack stack);
inline const TkTextUndoSubAtom *TkTextUndoGetLastUndoSubAtom(const TkTextUndoStack stack);
/*
* Stack iterator functions.
*/
const TkTextUndoAtom *TkTextUndoFirstUndoAtom(TkTextUndoStack stack);
const TkTextUndoAtom *TkTextUndoNextUndoAtom(TkTextUndoStack stack);
const TkTextUndoAtom *TkTextUndoFirstRedoAtom(TkTextUndoStack stack);
const TkTextUndoAtom *TkTextUndoNextRedoAtom(TkTextUndoStack stack);
/* For convenience these functions are allowing NULL for the stack argument. */
inline bool TkTextUndoUndoStackIsFull(const TkTextUndoStack stack);
inline bool TkTextUndoRedoStackIsFull(const TkTextUndoStack stack);
bool TkTextUndoStackIsFull(const TkTextUndoStack stack);
/*
* Push the items. Pushing a separator will group items into compound edit
* actions. Pushing a separator without existing items will be ignored.
*
* While an undo/redo action is still in progress pushing separators will be
* ignored, in this case the undo/action will push automatically a single
* separator after the action is completed.
*/
int TkTextUndoPushItem(TkTextUndoStack stack, TkTextUndoItem item, unsigned size);
void TkTextUndoPushSeparator(TkTextUndoStack stack, bool immediately);
/*
* Normally redo items will be pushed while undo will be performed. The next function
* is only useful for the reconstruction of the stack.
*/
int TkTextUndoPushRedoItem(TkTextUndoStack stack, TkTextUndoItem item, unsigned size);
/*
* Swap newest undo item with given item. Returns the old item. Note that this
* function does not check whether the maximal undo byte size will be exceeded.
*
* Parameter 'size':
* In: size of given item.
* Out: size of returned item.
*/
TkTextUndoItem TkTextUndoSwapLastItem(TkTextUndoStack stack, TkTextUndoItem item, unsigned *size);
/*
* Perform undo/redo operations. Before the action starts a separator will be
* pushed. Returns an error (TCL_ERROR) if no undo (redo) action is possible.
*/
int TkTextUndoDoUndo(TkTextUndoStack stack);
int TkTextUndoDoRedo(TkTextUndoStack stack);
#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextUndoPriv.h"
#endif
#endif /* _TKTEXTUNDO */
/* vi:set ts=8 sw=4: */
|