/* selUndo.c - * * This file provides routines for undo-ing and redo-ing the * the selection. Most of the undo-ing is handled automatically * by enabling undo-ing when the selection cell is modified. * All this file does is record things to be redisplayed, since * the normal undo package won't handle that. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[]="$Header: /ufs/repository/magic/select/selUndo.c,v 1.2 2001/01/12 22:13:23 jsolomon Exp $"; #endif not lint #include #include "misc/magic.h" #include "utils/geometry.h" #include "graphics/graphics.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "undo/undo.h" #include "textio/textio.h" #include "select/select.h" #include "select/selInt.h" /* Each selection modification causes two records of the following * format to be added to the undo event list. The first record * is added BEFORE the modification (sue_before is TRUE), and the * second is added afterwards. The reason for doubling the events * is that we can't redisplay selection information until after the * selection has been modified. This requires events to be in * different places depending on whether we're undo-ing or redo-ing. */ typedef struct { CellDef *sue_def; /* Definition in which selection must be * redisplayed. */ Rect sue_area; /* Area of sue_def in which selection info * must be redisplayed. */ bool sue_before; /* TRUE means this entry was made before * the selection modifications. FALSE * means afterwards. */ } SelUndoEvent; /* Identifier for selection undo records: */ UndoType SelUndoClientID; /* * ---------------------------------------------------------------------------- * * SelUndoInit -- * * Adds us as a client to the undo package. * * Results: * None. * * Side effects: * Adds a new client to the undo package, and sets SelUndoClientID. * * ---------------------------------------------------------------------------- */ void SelUndoInit() { extern void SelUndoForw(), SelUndoBack(); SelUndoClientID = UndoAddClient((void (*)()) NULL, (void (*)()) NULL, (UndoEvent *(*)()) NULL, (int (*)()) NULL, SelUndoForw, SelUndoBack, "selection redisplay"); if (SelUndoClientID < (UndoType) 0) TxError("Couldn't add selection as an undo client!\n"); } /* * ---------------------------------------------------------------------------- * * SelRememberForUndo-- * * This routine is called twice whenever the selection is modified. * It must be called once before modifying the selection. In this * case before is TRUE and the other arguments are arbitrary. It * must also be called again after the selection is modified. In * this case before is FALSE and the other fields indicate exactly * which area was modified. * * Results: * None. * * Side effects: * Adds information to the undo list. * * ---------------------------------------------------------------------------- */ void SelRememberForUndo(before, def, area) bool before; /* TRUE means caller is about to modify * the given area of the selection. FALSE * means the caller has just modified * the area. */ CellDef *def; /* Root definition on top of whom selection * information was just modified. */ Rect *area; /* The area of def where selection info * changed. This pointer may be NULL, even * on the second call, if there's no need * to do redisplay during undo's. This is * the case if layout information is being * modified over the area of the selection: * when layout is redisplayed, selection info * will automatically be redisplayed too. */ { SelUndoEvent *sue; static SelUndoEvent *beforeEvent = NULL; static Rect nullRect = {0, 0, -1, -1}; sue = (SelUndoEvent *) UndoNewEvent(SelUndoClientID, sizeof(SelUndoEvent)); if (sue == NULL) return; /* We don't have complete information when the "before" event is * created, so save around its address and fill in the event when * the "after" event is created. */ if (before) { sue->sue_before = TRUE; sue->sue_def = NULL; ASSERT(beforeEvent == NULL, "Forgot to call SelRememberForUndo after"); beforeEvent = sue; } else { if (area == NULL) area = &nullRect; sue->sue_def = def; sue->sue_area = *area; sue->sue_before = before; ASSERT(beforeEvent != NULL, "Forgot to call SelRememberForUndo before"); beforeEvent->sue_def = def; beforeEvent->sue_area = *area; beforeEvent = NULL; } } /* * ---------------------------------------------------------------------------- * * SelUndoForw -- * SelUndoBack -- * * Called to process undo redisplay events. The two procedures * are identical except that each one looks at different events. * The idea is to do the selection redisplay only AFTER the selection * has actually been modified. * * Results: * None. * * Side effects: * Highlights (including the selection) are redisplayed. * * ---------------------------------------------------------------------------- */ void SelUndoForw(sue) SelUndoEvent *sue; /* Event to be redone. */ { if (sue->sue_before) return; if (sue->sue_def == NULL) return; SelSetDisplay(SelectUse, sue->sue_def); SelectRootDef = sue->sue_def; DBReComputeBbox(SelectDef); if (sue->sue_area.r_xbot <= sue->sue_area.r_xtop) DBWHLRedraw(sue->sue_def, &sue->sue_area, TRUE); DBWAreaChanged(SelectDef, &sue->sue_area, DBW_ALLWINDOWS, (TileTypeBitMask *) NULL); } void SelUndoBack(sue) SelUndoEvent *sue; /* Event to be undone. */ { if (!sue->sue_before) return; if (sue->sue_def == NULL) return; SelSetDisplay(SelectUse, sue->sue_def); SelectRootDef = sue->sue_def; DBReComputeBbox(SelectDef); if (sue->sue_area.r_xbot <= sue->sue_area.r_xtop) DBWHLRedraw(sue->sue_def, &sue->sue_area, TRUE); DBWAreaChanged(SelectDef, &sue->sue_area, DBW_ALLWINDOWS, (TileTypeBitMask *) NULL); }