tkUndo.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:8k
- /*
- * tkUndo.c --
- *
- * This module provides the implementation of an undo stack.
- *
- * Copyright (c) 2002 by Ludwig Callewaert.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkUndo.c,v 1.1.4.2 2006/03/20 22:16:34 dkf Exp $
- */
- #include "tkUndo.h"
- /*
- * TkUndoPushStack
- * Push elem on the stack identified by stack.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- void TkUndoPushStack ( stack, elem )
- TkUndoAtom ** stack;
- TkUndoAtom * elem;
- {
- elem->next = *stack;
- *stack = elem;
- }
- /*
- * TkUndoPopStack --
- * Remove and return the top element from the stack identified by
- * stack.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- TkUndoAtom * TkUndoPopStack ( stack )
- TkUndoAtom ** stack ;
- {
- TkUndoAtom * elem = NULL;
- if (*stack != NULL ) {
- elem = *stack;
- *stack = elem->next;
- }
- return elem;
- }
- /*
- * TkUndoInsertSeparator --
- * insert a separator on the stack, indicating a border for
- * an undo/redo chunk.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- int TkUndoInsertSeparator ( stack )
- TkUndoAtom ** stack;
- {
- TkUndoAtom * separator;
- if ( *stack != NULL && (*stack)->type != TK_UNDO_SEPARATOR ) {
- separator = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
- separator->type = TK_UNDO_SEPARATOR;
- TkUndoPushStack(stack,separator);
- return 1;
- } else {
- return 0;
- }
- }
- /*
- * TkUndoClearStack --
- * Clear an entire undo or redo stack and destroy all elements in it.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
- void TkUndoClearStack ( stack )
- TkUndoAtom ** stack; /* An Undo or Redo stack */
- {
- TkUndoAtom * elem;
- while ( (elem = TkUndoPopStack(stack)) ) {
- if ( elem->type != TK_UNDO_SEPARATOR ) {
- Tcl_DecrRefCount(elem->apply);
- Tcl_DecrRefCount(elem->revert);
- }
- ckfree((char *)elem);
- }
- *stack = NULL;
- }
- /*
- * TkUndoPushAction
- * Push a new elem on the stack identified by stack.
- * action and revert are given through Tcl_DStrings
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- void TkUndoPushAction ( stack, actionScript, revertScript )
- TkUndoRedoStack * stack; /* An Undo or Redo stack */
- Tcl_DString * actionScript; /* The script to get the action (redo) */
- Tcl_DString * revertScript; /* The script to revert the action (undo) */
- {
- TkUndoAtom * atom;
- atom = (TkUndoAtom *) ckalloc(sizeof(TkUndoAtom));
- atom->type = TK_UNDO_ACTION;
- atom->apply = Tcl_NewStringObj(Tcl_DStringValue(actionScript),Tcl_DStringLength(actionScript));
- Tcl_IncrRefCount(atom->apply);
- atom->revert = Tcl_NewStringObj(Tcl_DStringValue(revertScript),Tcl_DStringLength(revertScript));
- Tcl_IncrRefCount(atom->revert);
- TkUndoPushStack(&(stack->undoStack), atom);
- TkUndoClearStack(&(stack->redoStack));
- }
- /*
- * TkUndoInitStack
- * Initialize a new undo/redo stack
- *
- * Results:
- * un Undo/Redo stack pointer
- *
- * Side effects:
- * None.
- */
-
- TkUndoRedoStack * TkUndoInitStack ( interp, maxdepth )
- Tcl_Interp * interp; /* The interpreter */
- int maxdepth; /* The maximum stack depth */
- {
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
- stack = (TkUndoRedoStack *) ckalloc(sizeof(TkUndoRedoStack));
- stack->undoStack = NULL;
- stack->redoStack = NULL;
- stack->interp = interp;
- stack->maxdepth = maxdepth;
- stack->depth = 0;
- return stack;
- }
- /*
- * TkUndoInitStack
- * Initialize a new undo/redo stack
- *
- * Results:
- * un Undo/Redo stack pointer
- *
- * Side effects:
- * None.
- */
-
- void TkUndoSetDepth ( stack, maxdepth )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
- int maxdepth; /* The maximum stack depth */
- {
- TkUndoAtom * elem;
- TkUndoAtom * prevelem;
- int sepNumber = 0;
-
- stack->maxdepth = maxdepth;
- if ((stack->maxdepth > 0) && (stack->depth > stack->maxdepth)) {
- /*
- * Maximum stack depth exceeded. We have to remove the last compound
- * elements on the stack.
- */
- elem = stack->undoStack;
- prevelem = NULL;
- while (elem && (sepNumber <= stack->maxdepth)) {
- if (elem->type == TK_UNDO_SEPARATOR) {
- sepNumber++;
- }
- prevelem = elem;
- elem = elem->next;
- }
- prevelem->next = NULL;
- while ( elem ) {
- prevelem = elem;
- elem = elem->next;
- ckfree((char *) prevelem);
- }
- stack->depth = stack->maxdepth;
- }
- }
- /*
- * TkUndoClearStacks
- * Clear both the undo and redo stack
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- void TkUndoClearStacks ( stack )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
- {
- TkUndoClearStack(&(stack->undoStack));
- TkUndoClearStack(&(stack->redoStack));
- stack->depth = 0;
- }
- /*
- * TkUndoFreeStack
- * Clear both the undo and redo stack
- * also free the memory allocated to the u/r stack pointer
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- void TkUndoFreeStack ( stack )
- TkUndoRedoStack * stack; /* An Undo/Redo stack */
- {
- TkUndoClearStacks(stack);
- /* ckfree((TkUndoRedoStack *) stack); */
- ckfree((char *) stack);
- }
- /*
- * TkUndoInsertUndoSeparator --
- * insert a separator on the undo stack, indicating a border for
- * an undo/redo chunk.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- */
-
- void TkUndoInsertUndoSeparator ( stack )
- TkUndoRedoStack * stack;
- {
- if ( TkUndoInsertSeparator(&(stack->undoStack)) ) {
- ++(stack->depth);
- TkUndoSetDepth(stack,stack->maxdepth);
- }
- }
- /*
- * TkUndoRevert --
- * Undo a compound action on the stack.
- *
- * Results:
- * A TCL status code
- *
- * Side effects:
- * None.
- */
-
- int TkUndoRevert ( stack )
- TkUndoRedoStack * stack;
- {
- TkUndoAtom * elem;
- /* insert a separator on the undo and the redo stack */
- TkUndoInsertUndoSeparator(stack);
- TkUndoInsertSeparator(&(stack->redoStack));
- /* Pop and skip the first separator if there is one*/
- elem = TkUndoPopStack(&(stack->undoStack));
- if ( elem == NULL ) {
- return TCL_ERROR;
- }
- if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
- ckfree((char *) elem);
- elem = TkUndoPopStack(&(stack->undoStack));
- }
-
- while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
- Tcl_EvalObjEx(stack->interp,elem->revert,TCL_EVAL_GLOBAL);
-
- TkUndoPushStack(&(stack->redoStack),elem);
- elem = TkUndoPopStack(&(stack->undoStack));
- }
-
- /* insert a separator on the redo stack */
-
- TkUndoInsertSeparator(&(stack->redoStack));
-
- --(stack->depth);
-
- return TCL_OK;
- }
- /*
- * TkUndoApply --
- * Redo a compound action on the stack.
- *
- * Results:
- * A TCL status code
- *
- * Side effects:
- * None.
- */
-
- int TkUndoApply ( stack )
- TkUndoRedoStack * stack;
- {
- TkUndoAtom *elem;
- /* insert a separator on the undo stack */
- TkUndoInsertSeparator(&(stack->undoStack));
- /* Pop and skip the first separator if there is one*/
- elem = TkUndoPopStack(&(stack->redoStack));
- if ( elem == NULL ) {
- return TCL_ERROR;
- }
- if ( ( elem != NULL ) && ( elem->type == TK_UNDO_SEPARATOR ) ) {
- ckfree((char *) elem);
- elem = TkUndoPopStack(&(stack->redoStack));
- }
- while ( elem && (elem->type != TK_UNDO_SEPARATOR) ) {
- Tcl_EvalObjEx(stack->interp,elem->apply,TCL_EVAL_GLOBAL);
-
- TkUndoPushStack(&(stack->undoStack), elem);
- elem = TkUndoPopStack(&(stack->redoStack));
- }
- /* insert a separator on the undo stack */
-
- TkUndoInsertSeparator(&(stack->undoStack));
- ++(stack->depth);
-
- return TCL_OK;
- }