1 /*----------------------------------------------------------------------*/
4 /* The comprehensive "undo" and "redo" command handler */
6 /* Copyright (c) 2004 Tim Edwards, Open Circuit Design, Inc., and */
8 /*----------------------------------------------------------------------*/
10 /*----------------------------------------------------------------------*/
11 /* written by Tim Edwards, 1/29/04 */
12 /*----------------------------------------------------------------------*/
14 #define MODE_UNDO (u_char)0
15 #define MODE_REDO (u_char)1
17 #define MAX_UNDO_EVENTS 100
25 #include <X11/Intrinsic.h>
26 #include <X11/StringDefs.h>
29 /*----------------------------------------------------------------------*/
31 /*----------------------------------------------------------------------*/
39 /*----------------------------------------------------------------------*/
40 /* Function prototype declarations */
41 /*----------------------------------------------------------------------*/
42 #include "prototypes.h"
44 /*----------------------------------------------------------------------*/
45 /* Local structure definitions for holding undo information */
46 /*----------------------------------------------------------------------*/
56 /* Smaller data structure used when saving paths in the undo stacks. */
57 /* We don't need the rendering data from points[]. */
73 typedef struct editelem
{
74 genericptr element
; /* element being edited */
76 stringpart
*string
; /* original contents of string, for label */
77 pointlist points
; /* original polygon */
78 arcinfo
*arcspecs
; /* original arc values */
79 pathinfo
*pathspecs
; /* original parts of a path */
80 XPoint instpos
; /* original position, for an object instance */
85 genericptr element
; /* element modified */
86 float scale
; /* old scale value */
90 XPoint rotpos
; /* original position */
91 float rotation
; /* old rotation value */
94 u_char undo_collect
= (u_char
)0;
96 /*----------------------------------------------------------------------*/
97 /* Externally declared variables */
98 /*----------------------------------------------------------------------*/
100 extern Globaldata xobjs
;
101 extern XCWindowData
*areawin
;
103 /*----------------------------------------------------------------------*/
104 /* Attempt to set the window. If the window exists, set it as current */
105 /* and return TRUE. Otherwise, return FALSE. This prevents the undo */
106 /* mechanism from crashing if we close a window and then try to undo */
107 /* events that were created relative to it. */
108 /*----------------------------------------------------------------------*/
110 Boolean
setwindow(XCWindowData
*trywindow
)
112 XCWindowData
*chkwin
;
114 for (chkwin
= xobjs
.windowlist
; chkwin
!= NULL
; chkwin
= chkwin
->next
) {
115 if (chkwin
== trywindow
) {
123 /*----------------------------------------------------------------------*/
124 /* remember_selection --- */
126 /* Copy a selection list into a "uselection" record. The uselection */
127 /* record maintains the order of the elements as well as pointers to */
128 /* each element, so the original element ordering can be recovered. */
129 /*----------------------------------------------------------------------*/
131 uselection
*remember_selection(objinstptr topinst
, short *slist
, int number
)
136 newlist
= (uselection
*)malloc(sizeof(uselection
));
138 newlist
->element
= (genericptr
*)malloc(number
* sizeof(genericptr
));
139 newlist
->idx
= (short *)malloc(number
* sizeof(short));
142 newlist
->element
= NULL
;
145 newlist
->number
= number
;
146 for (i
= 0; i
< number
; i
++) {
148 *(newlist
->element
+ i
) = *(topinst
->thisobject
->plist
+ idx
);
149 *(newlist
->idx
+ i
) = idx
;
154 /*----------------------------------------------------------------------*/
155 /* Create a selection list in areawin from the saved uselection */
157 /*----------------------------------------------------------------------*/
159 short *regen_selection(objinstptr thisinst
, uselection
*srec
)
163 objectptr thisobj
= thisinst
->thisobject
;
164 Boolean reorder
= False
;
167 if (srec
->number
> 0)
168 slist
= (short *)malloc(srec
->number
* sizeof(short));
171 for (i
= 0; i
< srec
->number
; i
++) {
173 /* Use the element address, not the selection order. */
174 egen
= *(srec
->element
+ i
);
175 if (egen
== *(thisobj
->plist
+ *(srec
->idx
+ i
)))
176 j
= *(srec
->idx
+ i
);
179 for (j
= 0; j
< thisobj
->parts
; j
++) {
180 if (egen
== *(thisobj
->plist
+ j
))
184 if (j
< thisobj
->parts
) {
189 Fprintf(stderr
, "Error: element %p in select list but not object\n",
193 /* If the selection order is different from the order in the object, */
194 /* then rearrange the object's list to match the selection order. */
201 if (srec
->number
> 0) free(slist
);
208 /*----------------------------------------------------------------------*/
209 /* Use the selection list in the undo record to reorder parts in the */
210 /* object's part list. Invert the selection list and return it. */
211 /*----------------------------------------------------------------------*/
213 void reorder_selection(Undoptr thisrecord
)
215 short *slist
, *newlist
, snum
, i
;
216 genericptr
*pgen
, *plist
, egen
;
217 objinstptr thisinst
= thisrecord
->thisinst
;
218 objectptr thisobj
= thisinst
->thisobject
;
220 snum
= (short)thisrecord
->idata
;
221 slist
= (short *)thisrecord
->undodata
;
222 plist
= (genericptr
*)malloc(snum
* sizeof(genericptr
));
223 newlist
= (short *)malloc(snum
* sizeof(short));
226 for (pgen
= plist
; pgen
< plist
+ snum
; pgen
++) {
227 egen
= *(thisobj
->plist
+ i
);
228 *(plist
+ *(slist
+ i
)) = egen
;
232 for (pgen
= plist
; pgen
< plist
+ snum
; pgen
++) {
233 *(thisobj
->plist
+ i
) = *pgen
;
234 *(newlist
+ *(slist
+ i
)) = i
;
238 free(thisrecord
->undodata
);
239 thisrecord
->undodata
= (char *)newlist
;
242 /*----------------------------------------------------------------------*/
243 /* free_editelement --- */
245 /* Free memory allocated to an undo record edit element structure. */
246 /*----------------------------------------------------------------------*/
248 void free_editelement(Undoptr thisrecord
)
253 erec
= (editelement
*)thisrecord
->undodata
;
254 switch (erec
->element
->type
) {
256 freelabel(erec
->save
.string
);
258 case POLYGON
: case SPLINE
:
259 free(erec
->save
.points
);
262 free(erec
->save
.arcspecs
);
265 for (ppi
= erec
->save
.pathspecs
; ppi
< erec
->save
.pathspecs
+
266 thisrecord
->idata
; ppi
++)
268 free(erec
->save
.pathspecs
);
274 /*----------------------------------------------------------------------*/
275 /* free_selection --- */
277 /* Free memory allocated to an undo record selection list. */
278 /*----------------------------------------------------------------------*/
280 void free_selection(uselection
*selrec
)
282 if (selrec
->number
> 0) {
283 free(selrec
->element
);
289 /*----------------------------------------------------------------------*/
290 /* get_original_string --- */
292 /* Find the original version of the given label. */
293 /*----------------------------------------------------------------------*/
295 stringpart
*get_original_string(labelptr thislab
)
297 Undoptr chkrecord
, thisrecord
;
301 thisrecord
= xobjs
.undostack
;
302 if (thisrecord
== NULL
) return NULL
;
304 for (chkrecord
= thisrecord
; chkrecord
!= NULL
; chkrecord
= chkrecord
->next
) {
305 switch (chkrecord
->type
) {
307 erec
= (editelement
*)(chkrecord
->undodata
);
308 elab
= (labelptr
)(erec
->element
);
309 if (elab
!= thislab
) return NULL
;
310 return erec
->save
.string
;
316 return NULL
; /* yes, this can be reached, if thisrecord->next == NULL */
319 /*----------------------------------------------------------------------*/
320 /* select_previous --- */
322 /* Set the selection to what was previously selected in the undo list. */
323 /* Return 0 on success, -1 if no previous selection was found. */
324 /*----------------------------------------------------------------------*/
326 int select_previous(Undoptr thisrecord
)
331 clearselects_noundo();
332 for (chkrecord
= thisrecord
->next
; chkrecord
!= NULL
; chkrecord
= chkrecord
->next
) {
334 /* Selections may cross page changes, but only if in the same series */
335 if ((chkrecord
->thisinst
!= thisrecord
->thisinst
) &&
336 (chkrecord
->idx
!= thisrecord
->idx
))
339 switch (chkrecord
->type
) {
340 case XCF_Delete
: case XCF_Pop
: case XCF_Push
:
341 /* Delete/Push/Pop records imply a canceled selection */
345 srec
= (uselection
*)chkrecord
->undodata
;
346 areawin
->selectlist
= regen_selection(thisrecord
->thisinst
, srec
);
347 areawin
->selects
= (areawin
->selectlist
) ? srec
->number
: 0;
354 /*----------------------------------------------------------------------*/
355 /* This is similar to the above routine, but we just return a pointer */
356 /* to the index list in the uselection record. This lets the undelete */
357 /* function restore the original ordering of parts that were deleted. */
358 /*----------------------------------------------------------------------*/
360 short *recover_selectlist(Undoptr thisrecord
)
365 for (chkrecord
= thisrecord
->next
; chkrecord
!= NULL
; chkrecord
= chkrecord
->next
) {
367 /* Selections may cross page changes, but only if in the same series */
368 if ((chkrecord
->thisinst
!= thisrecord
->thisinst
) &&
369 (chkrecord
->idx
!= thisrecord
->idx
))
372 switch (chkrecord
->type
) {
373 case XCF_Delete
: case XCF_Pop
: case XCF_Push
:
374 /* Delete/Push/Pop records imply a canceled selection */
377 /* Copy is the same as Select, but the copied objects are */
378 /* always at the end of the element list. Returning NULL */
379 /* is the same as declaring that elements should be */
380 /* appended to the end of the object's element list. */
383 srec
= (uselection
*)chkrecord
->undodata
;
390 /*----------------------------------------------------------------------*/
391 /* Put element "thiselem" back into object "thisobj". This is only */
392 /* used in the case where the elements were previously at the end of */
393 /* the object's element list. */
394 /*----------------------------------------------------------------------*/
396 void undelete_one_element(objinstptr thisinst
, genericptr thiselem
)
398 objectptr thisobj
= thisinst
->thisobject
;
401 *(thisobj
->plist
+ thisobj
->parts
) = thiselem
;
405 /*----------------------------------------------------------------------*/
406 /* register_for_undo --- */
408 /* Register an event with the undo handler. This creates a record */
409 /* based on the type, which is one of the XCF_* bindings (see */
410 /* xcircuit.h for the list). This is a variable-argument routine, */
411 /* with the arguments dependent on the command. */
413 /* thisinst is the instance of the object in which the event occurred */
414 /* and is registered for every event type. */
416 /* "mode" is UNDO_MORE if one or more undo records are expected to */
417 /* follow in a series, or UNDO_DONE if this completes a series, or is */
418 /* as single undo event. The command-line command "undo series start" */
419 /* forces all events to be UNDO_MORE until "undo series end" is */
421 /*----------------------------------------------------------------------*/
423 void register_for_undo(u_int type
, u_char mode
, objinstptr thisinst
, ...)
426 int drawmode
, nval
, oval
, *idata
, snum
, deltax
, deltay
, i
;
439 /* Do not register new events while running undo/redo actions! */
440 if (eventmode
== UNDO_MODE
) return;
442 /* This action invalidates everything in the "redo" stack, so flush it */
445 /* Create the new record and push it onto the stack */
446 newrecord
= (Undoptr
)malloc(sizeof(Undostack
));
447 newrecord
->next
= xobjs
.undostack
;
448 newrecord
->last
= NULL
;
449 newrecord
->type
= type
;
450 newrecord
->thisinst
= thisinst
;
451 newrecord
->window
= areawin
;
452 newrecord
->undodata
= (char *)NULL
;
453 newrecord
->idata
= 0;
455 if (xobjs
.undostack
) {
456 xobjs
.undostack
->last
= newrecord
;
457 if (xobjs
.undostack
->idx
< 0) {
458 xobjs
.undostack
->idx
= -xobjs
.undostack
->idx
;
459 newrecord
->idx
= xobjs
.undostack
->idx
;
462 newrecord
->idx
= xobjs
.undostack
->idx
+ 1;
467 if (mode
== UNDO_MORE
|| undo_collect
> (u_char
)0)
468 newrecord
->idx
= -newrecord
->idx
;
470 xobjs
.undostack
= newrecord
;
472 va_start(args
, thisinst
);
477 /* delobj = pointer to object containing deleted entries */
478 /* drawmode = true if elements should be erased */
479 delobj
= va_arg(args
, objectptr
);
480 drawmode
= va_arg(args
, int);
481 newrecord
->undodata
= (char *)delobj
;
482 newrecord
->idata
= drawmode
;
485 case XCF_Select_Save
:
487 /* newobj = pointer to instance of new object */
488 newinst
= va_arg(args
, objinstptr
);
489 newrecord
->undodata
= (char *)newinst
;
494 /* oval = original integer value */
495 /* nval = new integer value */
496 oval
= va_arg(args
, int);
497 nval
= va_arg(args
, int);
498 idata
= (int *)malloc(sizeof(int));
500 newrecord
->undodata
= (char *)idata
;
501 newrecord
->idata
= oval
;
505 /* No args; instance to pop is the instance passed. */
510 /* newinst = object instance to push */
511 newinst
= va_arg(args
, objinstptr
);
512 newrecord
->undodata
= (char *)newinst
;
517 case XCF_Library_Pop
:
519 /* slist = current selection list (short *) */
520 /* snum = number of selections (int) */
521 slist
= va_arg(args
, short *);
522 snum
= va_arg(args
, int);
523 srec
= remember_selection(thisinst
, slist
, snum
);
524 newrecord
->undodata
= (char *)srec
;
525 /* Fprintf(stdout, "Undo: registered selection or copy action\n"); */
528 case XCF_Box
: case XCF_Arc
: case XCF_Wire
: case XCF_Text
:
529 case XCF_Pin_Label
: case XCF_Pin_Global
: case XCF_Info_Label
:
530 case XCF_Spline
: case XCF_Dot
: case XCF_Graphic
: case XCF_Join
:
532 /* egen = element just created (genericptr) */
533 egen
= va_arg(args
, genericptr
);
534 newrecord
->undodata
= (char *)egen
;
539 /* egen = element to be edited (genericptr) */
540 egen
= va_arg(args
, genericptr
);
542 /* Create a copy of the element to save */
543 erec
= (editelement
*)malloc(sizeof(editelement
));
544 erec
->element
= egen
;
548 stringcopyall(((labelptr
)egen
)->string
,
549 areawin
->topinstance
);
550 newrecord
->idata
= ((labelptr
)egen
)->anchor
;
553 newrecord
->idata
= ((polyptr
)egen
)->number
;
554 erec
->save
.points
= copypoints(((polyptr
)egen
)->points
,
559 copypoints((pointlist
)((splineptr
)egen
)->ctrl
, 4);
562 erec
->save
.instpos
= ((objinstptr
)egen
)->position
;
565 erec
->save
.arcspecs
= (arcinfo
*)malloc(sizeof(arcinfo
));
566 erec
->save
.arcspecs
->angle1
= ((arcptr
)egen
)->angle1
;
567 erec
->save
.arcspecs
->angle2
= ((arcptr
)egen
)->angle2
;
568 erec
->save
.arcspecs
->radius
= ((arcptr
)egen
)->radius
;
569 erec
->save
.arcspecs
->yaxis
= ((arcptr
)egen
)->yaxis
;
570 erec
->save
.arcspecs
->position
= ((arcptr
)egen
)->position
;
573 newrecord
->idata
= ((pathptr
)egen
)->parts
; /* not needed? */
574 erec
->save
.pathspecs
= (pathinfo
*)malloc(newrecord
->idata
*
576 for (i
= 0; i
< newrecord
->idata
; i
++) {
577 pathinfo
*ppi
= erec
->save
.pathspecs
+ i
;
578 genericptr
*pgen
= ((pathptr
)egen
)->plist
+ i
;
579 switch (ELEMENTTYPE(*pgen
)) {
581 ppi
->number
= (TOPOLY(pgen
))->number
;
582 ppi
->points
= copypoints((TOPOLY(pgen
))->points
,
587 ppi
->points
= copypoints((pointlist
)
588 (TOSPLINE(pgen
))->ctrl
, 4);
594 newrecord
->undodata
= (char *)erec
;
597 case XCF_ChangeStyle
:
601 /* egen = element that was changed (with new value) */
602 /* oval = old style value */
603 egen
= va_arg(args
, genericptr
);
604 oval
= va_arg(args
, int);
605 newrecord
->undodata
= (char *)egen
;
606 newrecord
->idata
= oval
;
611 /* egen = element that was changed (with new value) */
612 /* ofloat = old float value */
614 egen
= va_arg(args
, genericptr
);
615 scale
= va_arg(args
, double); /* warning! only takes "double"! */
617 escale
= (scaleinfo
*)malloc(sizeof(scaleinfo
));
618 escale
->element
= egen
;
619 escale
->scale
= (float)scale
;
621 newrecord
->undodata
= (char *)escale
;
624 case XCF_Flip_X
: case XCF_Flip_Y
:
626 /* fpoint = point of flip (XPoint *) */
627 fpoint
= va_arg(args
, XPoint
*);
628 newrecord
->undodata
= (char *)malloc(sizeof(XPoint
));
629 ((XPoint
*)newrecord
->undodata
)->x
= fpoint
->x
;
630 ((XPoint
*)newrecord
->undodata
)->y
= fpoint
->y
;
635 /* fpoint = point of flip (XPoint *) */
636 /* dir = direction and amount of rotation (float) */
637 fpoint
= va_arg(args
, XPoint
*);
638 dir
= va_arg(args
, double);
639 newrecord
->undodata
= (char *)malloc(sizeof(rotateinfo
));
640 ((rotateinfo
*)newrecord
->undodata
)->rotpos
.x
= fpoint
->x
;
641 ((rotateinfo
*)newrecord
->undodata
)->rotpos
.y
= fpoint
->y
;
642 ((rotateinfo
*)newrecord
->undodata
)->rotation
= (float)dir
;
647 /* deltax = change in x position (int) */
648 /* deltay = change in y position (int) */
649 deltax
= va_arg(args
, int);
650 deltay
= va_arg(args
, int);
651 newrecord
->undodata
= (char *)malloc(sizeof(XPoint
));
652 ((XPoint
*)newrecord
->undodata
)->x
= deltax
;
653 ((XPoint
*)newrecord
->undodata
)->y
= deltay
;
654 /* Fprintf(stdout, "Undo: registered move of delta (%d, %d)\n",
660 /* slist = "before" order of elements */
661 /* snum = number of elements in list (= # parts) */
662 slist
= va_arg(args
, short *);
663 snum
= va_arg(args
, int);
664 newrecord
->undodata
= (char *)slist
;
665 newrecord
->idata
= snum
;
671 /*----------------------------------------------------------------------*/
672 /* undo_one_action --- */
673 /* Play undo record back one in the stack. */
674 /*----------------------------------------------------------------------*/
676 short undo_one_action()
678 Undoptr thisrecord
; /* , chkrecord; (jdk) */
685 XPoint
*delta
, position
;
694 splineptr thisspline
;
695 graphicptr thisgraphic
;
697 XCWindowData
*savewindow
= areawin
;
699 /* Undo the recorded action and shift the undo record pointer. */
701 thisrecord
= xobjs
.undostack
;
702 if (thisrecord
== NULL
) {
703 Fprintf(stderr
, "Nothing to undo!\n");
707 xobjs
.undostack
= thisrecord
->next
;
708 xobjs
.redostack
= thisrecord
;
710 /* Set window, if event occurred in a different window */
711 if (setwindow(thisrecord
->window
) == FALSE
) {
712 Wprintf("Error: Undo event in nonexistant window! Flushing stack.\n");
717 /* Setting eventmode to UNDO_MODE prevents register_for_undo() from */
718 /* being called again while executing the event. */
720 savemode
= eventmode
;
721 eventmode
= UNDO_MODE
;
723 /* type-dependent part */
725 switch(thisrecord
->type
) {
728 thisobj
= (objectptr
)thisrecord
->undodata
;
729 areawin
->selects
= thisobj
->parts
;
730 areawin
->selectlist
= xc_undelete(thisrecord
->thisinst
,
731 thisobj
, (short)thisrecord
->idata
,
732 recover_selectlist(thisrecord
));
733 srec
= remember_selection(thisrecord
->thisinst
, areawin
->selectlist
,
735 thisrecord
->undodata
= (char *)srec
;
739 /* To be finished: Needs to remove the object & instance from */
740 /* the library and library page. Should keep the empty object */
741 /* around so we have the name. */
743 case XCF_Select_Save
:
745 thisinst
= (objinstptr
)thisrecord
->undodata
;
746 thisobj
= thisinst
->thisobject
;
748 /* Remove the instance */
749 i
= thisrecord
->thisinst
->thisobject
->parts
- 1;
750 if ((genericptr
)thisinst
!= *(thisrecord
->thisinst
->thisobject
->plist
+ i
)) {
751 Fprintf(stderr
, "Error: No such element!\n");
752 thisrecord
->undodata
= NULL
;
756 delete_one_element(thisrecord
->thisinst
, (genericptr
)thisinst
);
759 /* Put back all the parts */
760 areawin
->selects
= thisobj
->parts
;
761 areawin
->selectlist
= xc_undelete(thisrecord
->thisinst
,
762 thisobj
, (short)thisrecord
->idata
,
763 recover_selectlist(thisrecord
));
764 srec
= remember_selection(thisrecord
->thisinst
, areawin
->selectlist
,
766 thisrecord
->undodata
= (char *)srec
;
771 popobject(areawin
->area
, 0, NULL
);
775 pushobject((objinstptr
)thisrecord
->thisinst
);
779 newpage(thisrecord
->idata
);
783 thislabel
= (labelptr
)(thisrecord
->undodata
);
784 snum
= thisrecord
->idata
;
785 thisrecord
->idata
= thislabel
->anchor
;
786 thislabel
->anchor
= snum
;
787 areawin
->redraw_needed
= True
;
788 drawarea(areawin
->area
, NULL
, NULL
);
793 /* If there was a previous selection in the undo list, */
796 need_redraw
= (areawin
->selects
> 0) ? True
: False
;
797 select_previous(thisrecord
);
799 areawin
->redraw_needed
= True
;
800 drawarea(areawin
->area
, NULL
, NULL
);
806 case XCF_Box
: case XCF_Arc
: case XCF_Wire
: case XCF_Text
:
807 case XCF_Pin_Label
: case XCF_Pin_Global
: case XCF_Info_Label
:
808 case XCF_Spline
: case XCF_Dot
: case XCF_Graphic
: case XCF_Join
:
809 egen
= (genericptr
)thisrecord
->undodata
;
810 i
= thisrecord
->thisinst
->thisobject
->parts
- 1;
811 if (egen
!= *(thisrecord
->thisinst
->thisobject
->plist
+ i
)) {
812 Fprintf(stderr
, "Error: No such element!\n");
813 thisrecord
->undodata
= NULL
;
816 delete_one_element(thisrecord
->thisinst
, egen
);
817 areawin
->redraw_needed
= True
;
818 drawarea(areawin
->area
, NULL
, NULL
);
823 erec
= (editelement
*)thisrecord
->undodata
;
824 switch (erec
->element
->type
) {
828 labelptr elab
= (labelptr
)(erec
->element
);
830 tmpstr
= elab
->string
;
831 tmpanchor
= (int)elab
->anchor
;
832 elab
->string
= stringcopyback(erec
->save
.string
,
833 thisrecord
->thisinst
);
834 elab
->anchor
= (short)thisrecord
->idata
;
835 erec
->save
.string
= tmpstr
;
836 thisrecord
->idata
= tmpanchor
;
837 resolveparams(thisrecord
->thisinst
);
842 arcptr earc
= (arcptr
)(erec
->element
);
843 tmpinfo
.angle1
= earc
->angle1
;
844 tmpinfo
.angle2
= earc
->angle2
;
845 tmpinfo
.radius
= earc
->radius
;
846 tmpinfo
.yaxis
= earc
->yaxis
;
847 tmpinfo
.position
= earc
->position
;
848 earc
->angle1
= erec
->save
.arcspecs
->angle1
;
849 earc
->angle2
= erec
->save
.arcspecs
->angle2
;
850 earc
->radius
= erec
->save
.arcspecs
->radius
;
851 earc
->yaxis
= erec
->save
.arcspecs
->yaxis
;
852 earc
->position
= erec
->save
.arcspecs
->position
;
853 *(erec
->save
.arcspecs
) = tmpinfo
;
855 areawin
->redraw_needed
= True
;
856 drawarea(areawin
->area
, NULL
, NULL
);
860 objinstptr einst
= (objinstptr
)(erec
->element
);
861 // Swap instance and saved positions.
862 tmppt
= einst
->position
;
863 einst
->position
= erec
->save
.instpos
;
864 erec
->save
.instpos
= tmppt
;
865 areawin
->redraw_needed
= True
;
866 drawarea(areawin
->area
, NULL
, NULL
);
871 polyptr epoly
= (polyptr
)(erec
->element
);
872 tmppts
= epoly
->points
;
873 tmpnum
= epoly
->number
;
874 epoly
->points
= erec
->save
.points
;
875 epoly
->number
= thisrecord
->idata
;
876 erec
->save
.points
= tmppts
;
877 thisrecord
->idata
= tmpnum
;
878 areawin
->redraw_needed
= True
;
879 drawarea(areawin
->area
, NULL
, NULL
);
883 splineptr espline
= (splineptr
)(erec
->element
);
884 tmppts
= copypoints((pointlist
)espline
->ctrl
, 4);
885 for (i
= 0; i
< 4; i
++)
886 espline
->ctrl
[i
] = *(erec
->save
.points
+ i
);
887 free(erec
->save
.points
);
888 erec
->save
.points
= tmppts
;
890 areawin
->redraw_needed
= True
;
891 drawarea(areawin
->area
, NULL
, NULL
);
898 pathptr epath
= (pathptr
)(erec
->element
);
899 for (i
= 0; i
< epath
->parts
; i
++) {
900 genericptr ggen
= *(epath
->plist
+ i
);
901 switch (ELEMENTTYPE(ggen
)) {
903 epoly
= (polyptr
)ggen
;
904 tmppts
= epoly
->points
;
905 tmpnum
= epoly
->number
;
906 epoly
->points
= (erec
->save
.pathspecs
+ i
)->points
;
907 epoly
->number
= (erec
->save
.pathspecs
+ i
)->number
;
908 (erec
->save
.pathspecs
+ i
)->points
= tmppts
;
909 (erec
->save
.pathspecs
+ i
)->number
= tmpnum
;
912 espline
= (splineptr
)ggen
;
913 tmppts
= copypoints((pointlist
)espline
->ctrl
, 4);
914 for (j
= 0; j
< 4; j
++)
915 espline
->ctrl
[j
] = *((erec
->save
.pathspecs
+ i
)->points
+ j
);
916 free((erec
->save
.pathspecs
+ i
)->points
);
917 (erec
->save
.pathspecs
+ i
)->points
= tmppts
;
922 areawin
->redraw_needed
= True
;
923 drawarea(areawin
->area
, NULL
, NULL
);
928 case XCF_Library_Pop
:
929 srec
= (uselection
*)thisrecord
->undodata
;
930 slist
= regen_selection(thisrecord
->thisinst
, srec
);
931 thisobj
= delete_element(thisrecord
->thisinst
, slist
,
934 thisrecord
->undodata
= (char *)thisobj
;
938 clearselects_noundo();
939 srec
= (uselection
*)thisrecord
->undodata
;
940 slist
= regen_selection(thisrecord
->thisinst
, srec
);
941 thisobj
= delete_element(thisrecord
->thisinst
, slist
,
944 thisrecord
->undodata
= (char *)thisobj
;
946 /* Revert selection to previously selected */
947 select_previous(thisrecord
);
948 areawin
->redraw_needed
= True
;
949 drawarea(areawin
->area
, NULL
, NULL
);
953 case XCF_ChangeStyle
:
955 egen
= (genericptr
)thisrecord
->undodata
;
956 snum
= thisrecord
->idata
;
959 thispath
= (pathptr
)(thisrecord
->undodata
);
960 thisrecord
->idata
= thispath
->style
;
961 thispath
->style
= snum
;
964 thispoly
= (polyptr
)(thisrecord
->undodata
);
965 thisrecord
->idata
= thispoly
->style
;
966 thispoly
->style
= snum
;
969 thisarc
= (arcptr
)(thisrecord
->undodata
);
970 thisrecord
->idata
= thisarc
->style
;
971 thisarc
->style
= snum
;
974 thisspline
= (splineptr
)(thisrecord
->undodata
);
975 thisrecord
->idata
= thisspline
->style
;
976 thisspline
->style
= snum
;
979 areawin
->redraw_needed
= True
;
980 drawarea(areawin
->area
, NULL
, NULL
);
985 egen
= (genericptr
)thisrecord
->undodata
;
986 snum
= thisrecord
->idata
;
989 thispath
= (pathptr
)(thisrecord
->undodata
);
990 thisrecord
->idata
= thispath
->color
;
991 thispath
->color
= snum
;
994 thispoly
= (polyptr
)(thisrecord
->undodata
);
995 thisrecord
->idata
= thispoly
->color
;
996 thispoly
->color
= snum
;
999 thisarc
= (arcptr
)(thisrecord
->undodata
);
1000 thisrecord
->idata
= thisarc
->color
;
1001 thisarc
->color
= snum
;
1004 thisspline
= (splineptr
)(thisrecord
->undodata
);
1005 thisrecord
->idata
= thisspline
->color
;
1006 thisspline
->color
= snum
;
1009 areawin
->redraw_needed
= True
;
1010 drawarea(areawin
->area
, NULL
, NULL
);
1014 escale
= (scaleinfo
*)thisrecord
->undodata
;
1015 egen
= escale
->element
;
1016 fnum
= escale
->scale
;
1017 switch(egen
->type
) {
1019 thispath
= (pathptr
)egen
;
1020 escale
->scale
= thispath
->width
;
1021 thispath
->width
= fnum
;
1024 thispoly
= (polyptr
)egen
;
1025 escale
->scale
= thispoly
->width
;
1026 thispoly
->width
= fnum
;
1029 thisarc
= (arcptr
)egen
;
1030 escale
->scale
= thisarc
->width
;
1031 thisarc
->width
= fnum
;
1034 thisspline
= (splineptr
)egen
;
1035 escale
->scale
= thisspline
->width
;
1036 thisspline
->width
= fnum
;
1039 thisinst
= (objinstptr
)egen
;
1040 escale
->scale
= thisinst
->scale
;
1041 thisinst
->scale
= fnum
;
1044 thisgraphic
= (graphicptr
)egen
;
1045 escale
->scale
= thisgraphic
->scale
;
1046 thisgraphic
->scale
= fnum
;
1048 thisgraphic
->valid
= FALSE
;
1049 #endif /* HAVE_CAIRO */
1052 thislabel
= (labelptr
)egen
;
1053 escale
->scale
= thislabel
->scale
;
1054 thislabel
->scale
= fnum
;
1057 areawin
->redraw_needed
= True
;
1058 drawarea(areawin
->area
, NULL
, NULL
);
1062 position
= *((XPoint
*)thisrecord
->undodata
);
1063 elementflip(&position
);
1067 position
= *((XPoint
*)thisrecord
->undodata
);
1068 elementvflip(&position
);
1072 position
= ((rotateinfo
*)thisrecord
->undodata
)->rotpos
;
1073 elementrotate(-((rotateinfo
*)thisrecord
->undodata
)->rotation
, &position
);
1077 delta
= (XPoint
*)thisrecord
->undodata
;
1078 select_connected_pins();
1079 placeselects(-(delta
->x
), -(delta
->y
), NULL
);
1081 areawin
->redraw_needed
= True
;
1082 drawarea(areawin
->area
, NULL
, NULL
);
1083 draw_all_selected();
1087 reorder_selection(thisrecord
);
1088 areawin
->redraw_needed
= True
;
1089 drawarea(areawin
->area
, NULL
, NULL
);
1093 Fprintf(stderr
, "Undo not implemented for this action!\n");
1097 /* Does this need to be set on a per-event-type basis? */
1101 eventmode
= CATALOG_MODE
;
1104 eventmode
= NORMAL_MODE
;
1108 /* Diagnostic, to check if all multiple-event undo series are resolved */
1109 if (thisrecord
->idx
< 0) {
1110 Fprintf(stderr
, "Warning: Unfinished undo series in stack!\n");
1111 thisrecord
->idx
= -thisrecord
->idx
;
1113 areawin
= savewindow
;
1114 return thisrecord
->idx
;
1117 /*----------------------------------------------------------------------*/
1118 /* undo_finish_series --- */
1119 /* Complete a possibly incomplete undo series by forcing the */
1120 /* topmost entry to have a positive index. */
1121 /* Note that for "undo series start|end" to work, undo_collect */
1122 /* must be set to 0 prior to calling undo_finish_series(). */
1123 /*----------------------------------------------------------------------*/
1125 void undo_finish_series()
1127 if (undo_collect
== (u_char
)0)
1128 if (xobjs
.undostack
&& xobjs
.undostack
->idx
< 0)
1129 xobjs
.undostack
->idx
= -xobjs
.undostack
->idx
;
1132 /*----------------------------------------------------------------------*/
1133 /* undo_action --- */
1134 /* Play undo record back to the completion of a series. */
1135 /*----------------------------------------------------------------------*/
1141 // Cannot undo while in the middle of an undo series. Failsafe.
1142 if (undo_collect
!= (u_char
)0) return;
1144 idx
= undo_one_action();
1145 while (xobjs
.undostack
&& xobjs
.undostack
->idx
== idx
)
1149 /*----------------------------------------------------------------------*/
1150 /* redo_one_action --- */
1151 /* Play undo record forward one in the stack. */
1152 /*----------------------------------------------------------------------*/
1154 short redo_one_action()
1160 XPoint
*delta
, position
;
1170 splineptr thisspline
;
1172 graphicptr thisgraphic
;
1173 objinstptr thisinst
;
1174 XCWindowData
*savewindow
= areawin
;
1176 /* Undo the recorded action and shift the undo record pointer. */
1178 thisrecord
= xobjs
.redostack
;
1179 if (thisrecord
== NULL
) {
1180 Fprintf(stderr
, "Nothing to redo!\n");
1183 xobjs
.undostack
= thisrecord
;
1184 xobjs
.redostack
= thisrecord
->last
;
1186 /* Set window, if event occurred in a different window */
1187 if (setwindow(thisrecord
->window
) == FALSE
) {
1188 Wprintf("Error: Undo event in nonexistant window! Flushing stack.\n");
1193 savemode
= eventmode
;
1194 eventmode
= UNDO_MODE
;
1196 /* type-dependent part */
1198 switch(thisrecord
->type
) {
1200 srec
= (uselection
*)thisrecord
->undodata
;
1201 slist
= regen_selection(thisrecord
->thisinst
, srec
);
1202 thisobj
= delete_element(thisrecord
->thisinst
, slist
,
1203 srec
->number
, DRAW
);
1205 thisrecord
->undodata
= (char *)thisobj
;
1206 thisrecord
->idata
= (int)DRAW
;
1208 areawin
->redraw_needed
= True
;
1209 drawarea(areawin
->area
, NULL
, NULL
);
1213 case XCF_Select_Save
:
1214 srec
= (uselection
*)thisrecord
->undodata
;
1215 slist
= regen_selection(thisrecord
->thisinst
, srec
);
1219 newpage(*((int *)thisrecord
->undodata
));
1223 thislabel
= (labelptr
)(thisrecord
->undodata
);
1224 snum
= thisrecord
->idata
;
1225 thisrecord
->idata
= thislabel
->anchor
;
1226 thislabel
->anchor
= snum
;
1227 areawin
->redraw_needed
= True
;
1228 drawarea(areawin
->area
, NULL
, NULL
);
1232 popobject(areawin
->area
, 0, NULL
);
1236 pushobject((objinstptr
)thisrecord
->undodata
);
1241 srec
= (uselection
*)thisrecord
->undodata
;
1242 areawin
->selectlist
= regen_selection(thisrecord
->thisinst
, srec
);
1243 areawin
->selects
= (areawin
->selectlist
) ? srec
->number
: 0;
1244 draw_all_selected();
1247 case XCF_Library_Pop
:
1248 thisobj
= (objectptr
)thisrecord
->undodata
;
1249 if (thisobj
!= NULL
) {
1251 snum
= thisobj
->parts
;
1252 slist
= xc_undelete(thisrecord
->thisinst
, thisobj
, DRAW
, NULL
);
1253 thisrecord
->undodata
= (char *)remember_selection(thisrecord
->thisinst
,
1260 thisobj
= (objectptr
)thisrecord
->undodata
;
1261 if (thisobj
!= NULL
) {
1263 areawin
->selects
= thisobj
->parts
;
1264 areawin
->selectlist
= xc_undelete(thisrecord
->thisinst
, thisobj
, DRAW
,
1266 thisrecord
->undodata
= (char *)remember_selection(thisrecord
->thisinst
,
1267 areawin
->selectlist
, areawin
->selects
);
1268 draw_all_selected();
1272 case XCF_Box
: case XCF_Arc
: case XCF_Wire
: case XCF_Text
:
1273 case XCF_Pin_Label
: case XCF_Pin_Global
: case XCF_Info_Label
:
1274 case XCF_Spline
: case XCF_Dot
: case XCF_Graphic
: case XCF_Join
:
1275 egen
= (genericptr
)thisrecord
->undodata
;
1276 undelete_one_element(thisrecord
->thisinst
, egen
);
1277 areawin
->redraw_needed
= True
;
1278 drawarea(areawin
->area
, NULL
, NULL
);
1282 erec
= (editelement
*)thisrecord
->undodata
;
1283 switch (erec
->element
->type
) {
1287 labelptr elab
= (labelptr
)(erec
->element
);
1289 tmpstr
= elab
->string
;
1290 tmpanchor
= (int)elab
->anchor
;
1291 elab
->string
= stringcopyback(erec
->save
.string
,
1292 thisrecord
->thisinst
);
1293 elab
->anchor
= (short)thisrecord
->idata
;
1294 erec
->save
.string
= tmpstr
;
1295 thisrecord
->idata
= tmpanchor
;
1296 resolveparams(thisrecord
->thisinst
);
1301 objinstptr einst
= (objinstptr
)(erec
->element
);
1302 // Swap instance position and saved position
1303 tmppt
= einst
->position
;
1304 einst
->position
= erec
->save
.instpos
;
1305 erec
->save
.instpos
= tmppt
;
1306 areawin
->redraw_needed
= True
;
1307 drawarea(areawin
->area
, NULL
, NULL
);
1311 arcptr earc
= (arcptr
)(erec
->element
);
1312 tmpinfo
.angle1
= earc
->angle1
;
1313 tmpinfo
.angle2
= earc
->angle2
;
1314 tmpinfo
.radius
= earc
->radius
;
1315 tmpinfo
.yaxis
= earc
->yaxis
;
1316 tmpinfo
.position
= earc
->position
;
1317 earc
->angle1
= erec
->save
.arcspecs
->angle1
;
1318 earc
->angle2
= erec
->save
.arcspecs
->angle2
;
1319 earc
->radius
= erec
->save
.arcspecs
->radius
;
1320 earc
->yaxis
= erec
->save
.arcspecs
->yaxis
;
1321 earc
->position
= erec
->save
.arcspecs
->position
;
1322 *(erec
->save
.arcspecs
) = tmpinfo
;
1324 areawin
->redraw_needed
= True
;
1325 drawarea(areawin
->area
, NULL
, NULL
);
1330 polyptr epoly
= (polyptr
)(erec
->element
);
1331 tmppts
= epoly
->points
;
1332 tmpnum
= epoly
->number
;
1333 epoly
->points
= erec
->save
.points
;
1334 epoly
->number
= thisrecord
->idata
;
1335 erec
->save
.points
= tmppts
;
1336 thisrecord
->idata
= tmpnum
;
1337 areawin
->redraw_needed
= True
;
1338 drawarea(areawin
->area
, NULL
, NULL
);
1342 splineptr espline
= (splineptr
)(erec
->element
);
1343 tmppts
= copypoints((pointlist
)espline
->ctrl
, 4);
1344 for (i
= 0; i
< 4; i
++)
1345 espline
->ctrl
[i
] = *(erec
->save
.points
+ i
);
1346 free(erec
->save
.points
);
1347 erec
->save
.points
= tmppts
;
1348 calcspline(espline
);
1349 areawin
->redraw_needed
= True
;
1350 drawarea(areawin
->area
, NULL
, NULL
);
1357 pathptr epath
= (pathptr
)(erec
->element
);
1358 for (i
= 0; i
< epath
->parts
; i
++) {
1359 genericptr ggen
= *(epath
->plist
+ i
);
1360 switch (ELEMENTTYPE(ggen
)) {
1362 epoly
= (polyptr
)ggen
;
1363 tmppts
= epoly
->points
;
1364 tmpnum
= epoly
->number
;
1365 epoly
->points
= (erec
->save
.pathspecs
+ i
)->points
;
1366 epoly
->number
= (erec
->save
.pathspecs
+ i
)->number
;
1367 (erec
->save
.pathspecs
+ i
)->points
= tmppts
;
1368 (erec
->save
.pathspecs
+ i
)->number
= tmpnum
;
1371 espline
= (splineptr
)ggen
;
1372 tmppts
= copypoints((pointlist
)espline
->ctrl
, 4);
1373 for (j
= 0; j
< 4; j
++)
1374 espline
->ctrl
[j
] = *((erec
->save
.pathspecs
+ i
)->points
+ j
);
1375 free((erec
->save
.pathspecs
+ i
)->points
);
1376 (erec
->save
.pathspecs
+ i
)->points
= tmppts
;
1377 calcspline(espline
);
1381 areawin
->redraw_needed
= True
;
1382 drawarea(areawin
->area
, NULL
, NULL
);
1388 position
= *((XPoint
*)thisrecord
->undodata
);
1389 elementflip(&position
);
1393 position
= *((XPoint
*)thisrecord
->undodata
);
1394 elementvflip(&position
);
1397 case XCF_ChangeStyle
:
1399 egen
= (genericptr
)thisrecord
->undodata
;
1400 snum
= thisrecord
->idata
;
1401 switch(egen
->type
) {
1403 thispath
= (pathptr
)(thisrecord
->undodata
);
1404 thisrecord
->idata
= thispath
->style
;
1405 thispath
->style
= snum
;
1408 thispoly
= (polyptr
)(thisrecord
->undodata
);
1409 thisrecord
->idata
= thispoly
->style
;
1410 thispoly
->style
= snum
;
1413 thisarc
= (arcptr
)(thisrecord
->undodata
);
1414 thisrecord
->idata
= thisarc
->style
;
1415 thisarc
->style
= snum
;
1418 thisspline
= (splineptr
)(thisrecord
->undodata
);
1419 thisrecord
->idata
= thisspline
->style
;
1420 thisspline
->style
= snum
;
1423 areawin
->redraw_needed
= True
;
1424 drawarea(areawin
->area
, NULL
, NULL
);
1429 egen
= (genericptr
)thisrecord
->undodata
;
1430 snum
= thisrecord
->idata
;
1431 switch(egen
->type
) {
1433 thispath
= (pathptr
)(thisrecord
->undodata
);
1434 thisrecord
->idata
= thispath
->color
;
1435 thispath
->color
= snum
;
1438 thispoly
= (polyptr
)(thisrecord
->undodata
);
1439 thisrecord
->idata
= thispoly
->color
;
1440 thispoly
->color
= snum
;
1443 thisarc
= (arcptr
)(thisrecord
->undodata
);
1444 thisrecord
->idata
= thisarc
->color
;
1445 thisarc
->color
= snum
;
1448 thisspline
= (splineptr
)(thisrecord
->undodata
);
1449 thisrecord
->idata
= thisspline
->color
;
1450 thisspline
->color
= snum
;
1453 areawin
->redraw_needed
= True
;
1454 drawarea(areawin
->area
, NULL
, NULL
);
1458 escale
= (scaleinfo
*)thisrecord
->undodata
;
1459 egen
= escale
->element
;
1460 fnum
= escale
->scale
;
1461 switch(egen
->type
) {
1463 thispath
= (pathptr
)egen
;
1464 escale
->scale
= thispath
->width
;
1465 thispath
->width
= fnum
;
1468 thispoly
= (polyptr
)egen
;
1469 escale
->scale
= thispoly
->width
;
1470 thispoly
->width
= fnum
;
1473 thisarc
= (arcptr
)egen
;
1474 escale
->scale
= thisarc
->width
;
1475 thisarc
->width
= fnum
;
1478 thisspline
= (splineptr
)egen
;
1479 escale
->scale
= thisspline
->width
;
1480 thisspline
->width
= fnum
;
1483 thisinst
= (objinstptr
)egen
;
1484 escale
->scale
= thisinst
->scale
;
1485 thisinst
->scale
= fnum
;
1488 thisgraphic
= (graphicptr
)egen
;
1489 escale
->scale
= thisgraphic
->scale
;
1490 thisgraphic
->scale
= fnum
;
1492 thisgraphic
->valid
= FALSE
;
1493 #endif /* HAVE_CAIRO */
1496 thislabel
= (labelptr
)egen
;
1497 escale
->scale
= thislabel
->scale
;
1498 thislabel
->scale
= fnum
;
1501 areawin
->redraw_needed
= True
;
1502 drawarea(areawin
->area
, NULL
, NULL
);
1506 position
= ((rotateinfo
*)thisrecord
->undodata
)->rotpos
;
1507 elementrotate(((rotateinfo
*)thisrecord
->undodata
)->rotation
, &position
);
1511 delta
= (XPoint
*)thisrecord
->undodata
;
1512 select_connected_pins();
1513 placeselects(delta
->x
, delta
->y
, NULL
);
1515 areawin
->redraw_needed
= True
;
1516 drawarea(areawin
->area
, NULL
, NULL
);
1520 reorder_selection(thisrecord
);
1521 areawin
->redraw_needed
= True
;
1522 drawarea(areawin
->area
, NULL
, NULL
);
1526 Fprintf(stderr
, "Undo not implemented for this action!\n");
1530 /* Does this need to be set on a per-event-type basis? */
1534 eventmode
= CATALOG_MODE
;
1537 eventmode
= NORMAL_MODE
;
1541 areawin
= savewindow
;
1543 return thisrecord
->idx
;
1546 /*----------------------------------------------------------------------*/
1547 /* redo_action --- */
1548 /* Play undo record forward to the completion of a series. */
1549 /*----------------------------------------------------------------------*/
1555 // Cannot redo while in the middle of an undo series. Failsafe.
1556 if (undo_collect
!= (u_char
)0) return;
1558 idx
= redo_one_action();
1559 while (xobjs
.redostack
&& xobjs
.redostack
->idx
== idx
)
1563 /*----------------------------------------------------------------------*/
1564 /* flush_redo_stack --- */
1565 /* Free all memory allocated to the redo stack due to the */
1566 /* insertion of a new undo record. */
1567 /*----------------------------------------------------------------------*/
1569 void flush_redo_stack()
1571 Undoptr thisrecord
, nextrecord
;
1573 if (xobjs
.redostack
== NULL
) return; /* no redo stack */
1575 thisrecord
= xobjs
.redostack
;
1577 while (thisrecord
!= NULL
) {
1578 nextrecord
= thisrecord
->last
;
1579 free_redo_record(thisrecord
);
1580 thisrecord
= nextrecord
;
1582 xobjs
.redostack
= NULL
;
1584 if (xobjs
.undostack
)
1585 xobjs
.undostack
->last
= NULL
;
1588 /*----------------------------------------------------------------------*/
1589 /* flush_undo_stack --- */
1590 /* Free all memory allocated to the undo and redo stacks. */
1591 /*----------------------------------------------------------------------*/
1593 void flush_undo_stack()
1595 Undoptr thisrecord
, nextrecord
;
1599 thisrecord
= xobjs
.undostack
;
1601 while (thisrecord
!= NULL
) {
1602 nextrecord
= thisrecord
->next
;
1603 free_undo_record(thisrecord
);
1604 thisrecord
= nextrecord
;
1606 xobjs
.undostack
= NULL
;
1609 /*----------------------------------------------------------------------*/
1610 /* free_undo_data --- */
1611 /* Free memory allocated to the "undodata" part of the undo */
1612 /* record, based on the record type. */
1614 /* "mode" specifies whether this is for an "undo" or a "redo" event. */
1616 /* Note that the action taken for a specific record may *NOT* be */
1617 /* the same for a record in the undo stack as it is for a record */
1618 /* in the redo stack, because the data types are changed when */
1619 /* moving from one record to the next. */
1620 /*----------------------------------------------------------------------*/
1622 void free_undo_data(Undoptr thisrecord
, u_char mode
)
1629 type
= thisrecord
->type
;
1632 if (mode
== MODE_UNDO
) {
1633 uobj
= (objectptr
)thisrecord
->undodata
;
1634 reset(uobj
, DESTROY
);
1636 else { /* MODE_REDO */
1637 srec
= (uselection
*)thisrecord
->undodata
;
1638 free_selection(srec
);
1642 case XCF_Box
: case XCF_Arc
: case XCF_Wire
: case XCF_Text
:
1643 case XCF_Pin_Label
: case XCF_Pin_Global
: case XCF_Info_Label
:
1644 case XCF_Spline
: case XCF_Dot
: case XCF_Graphic
: case XCF_Join
:
1645 /* if MODE_UNDO, the element is on the page, so don't destroy it! */
1646 if (mode
== MODE_REDO
)
1647 free(thisrecord
->undodata
);
1651 erec
= (editelement
*)thisrecord
->undodata
;
1652 free_editelement(thisrecord
);
1656 case XCF_Library_Pop
:
1657 if (mode
== MODE_UNDO
) {
1658 srec
= (uselection
*)thisrecord
->undodata
;
1659 free_selection(srec
);
1661 else { /* MODE_REDO */
1662 uobj
= (objectptr
)thisrecord
->undodata
;
1663 if (uobj
) reset(uobj
, DESTROY
);
1668 case XCF_ChangeStyle
:
1671 /* Do nothing --- undodata points to a valid element */
1675 srec
= (uselection
*)thisrecord
->undodata
;
1676 free_selection(srec
);
1680 if (thisrecord
->undodata
!= NULL
)
1681 free(thisrecord
->undodata
);
1684 thisrecord
->undodata
= NULL
;
1688 /*----------------------------------------------------------------------*/
1689 /* free_undo_record --- */
1690 /* Free allocated memory for one record in the undo stack. */
1691 /*----------------------------------------------------------------------*/
1693 void free_undo_record(Undoptr thisrecord
)
1695 /* Undoptr nextrecord, lastrecord; (jdk) */
1697 /* Reset the master list pointers */
1699 if (xobjs
.undostack
== thisrecord
)
1700 xobjs
.undostack
= thisrecord
->next
;
1702 /* Relink the stack pointers */
1704 if (thisrecord
->last
)
1705 thisrecord
->last
->next
= thisrecord
->next
;
1707 if (thisrecord
->next
)
1708 thisrecord
->next
->last
= thisrecord
->last
;
1710 /* Free memory allocated to the record */
1712 free_undo_data(thisrecord
, MODE_UNDO
);
1716 /*----------------------------------------------------------------------*/
1717 /* free_redo_record --- */
1718 /* Free allocated memory for one record in the redo stack. */
1719 /*----------------------------------------------------------------------*/
1721 void free_redo_record(Undoptr thisrecord
)
1723 /* Undoptr nextrecord, lastrecord; (jdk) */
1725 /* Reset the master list pointers */
1727 if (xobjs
.redostack
== thisrecord
)
1728 xobjs
.redostack
= thisrecord
->last
;
1730 /* Relink the stack pointers */
1732 if (thisrecord
->next
)
1733 thisrecord
->next
->last
= thisrecord
->last
;
1735 if (thisrecord
->last
)
1736 thisrecord
->last
->next
= thisrecord
->next
;
1738 /* Free memory allocated to the record */
1740 free_undo_data(thisrecord
, MODE_REDO
);
1744 /*----------------------------------------------------------------------*/
1745 /* truncate_undo_stack --- */
1746 /* If the limit MAX_UNDO_EVENTS has been reached, discard the */
1747 /* last undo series on the stack (index = 1) and renumber the */
1748 /* others by decrementing. */
1749 /*----------------------------------------------------------------------*/
1751 void truncate_undo_stack()
1753 Undoptr thisrecord
, nextrecord
;
1755 thisrecord
= xobjs
.undostack
;
1756 while (thisrecord
!= NULL
) {
1757 nextrecord
= thisrecord
->next
;
1758 if (thisrecord
->idx
> 1)
1761 free_undo_record(thisrecord
);
1762 thisrecord
= nextrecord
;
1768 /* Calls from the Xt menus (see menus.h) */
1769 /* These are wrappers for undo_action and redo_action */
1771 void undo_call(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
1776 void redo_call(xcWidget button
, caddr_t clientdata
, caddr_t calldata
)
1782 /*----------------------------------------------------------------------*/