diff options
Diffstat (limited to 'ldmicro/undoredo.cpp')
-rw-r--r-- | ldmicro/undoredo.cpp | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/ldmicro/undoredo.cpp b/ldmicro/undoredo.cpp new file mode 100644 index 0000000..915aaa4 --- /dev/null +++ b/ldmicro/undoredo.cpp @@ -0,0 +1,252 @@ +//----------------------------------------------------------------------------- +// Copyright 2007 Jonathan Westhues +// +// This file is part of LDmicro. +// +// LDmicro is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// LDmicro is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with LDmicro. If not, see <http://www.gnu.org/licenses/>. +//------ +// +// Routines to maintain the stack of recent versions of the program that we +// use for the undo/redo feature. Don't be smart at all; keep deep copies of +// the entire program at all times. +// Jonathan Westhues, split May 2005 +//----------------------------------------------------------------------------- +#include "linuxUI.h" +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include "ldmicro.h" + +using namespace std; + +// Store a `deep copy' of the entire program before every change, in a +// circular buffer so that the first one scrolls out as soon as the buffer +// is full and we try to push another one. +#define MAX_LEVELS_UNDO 32 +typedef struct ProgramStackTag { + PlcProgram prog[MAX_LEVELS_UNDO]; + struct { + int gx; + int gy; + } cursor[MAX_LEVELS_UNDO]; + int write; + int count; +} ProgramStack; + +static struct { + ProgramStack undo; + ProgramStack redo; +} Undo; + +//----------------------------------------------------------------------------- +// Make a `deep copy' of a circuit. Used for making a copy of the program +// whenever we change it, for undo purposes. Fast enough that we shouldn't +// need to be smart. +//----------------------------------------------------------------------------- +/*static void *DeepCopy(int which, void *any) +{ + switch(which) { + CASE_LEAF { + ElemLeaf *l = AllocLeaf(); + memcpy(l, any, sizeof(*l)); + l->selectedState = SELECTED_NONE; + return l; + } + case ELEM_SERIES_SUBCKT: { + int i; + ElemSubcktSeries *n = AllocSubcktSeries(); + ElemSubcktSeries *s = (ElemSubcktSeries *)any; + n->count = s->count; + for(i = 0; i < s->count; i++) { + n->contents[i].which = s->contents[i].which; + n->contents[i].d.any = DeepCopy(s->contents[i].which, + s->contents[i].d.any); + } + return n; + } + case ELEM_PARALLEL_SUBCKT: { + int i; + ElemSubcktParallel *n = AllocSubcktParallel(); + ElemSubcktParallel *p = (ElemSubcktParallel *)any; + n->count = p->count; + for(i = 0; i < p->count; i++) { + n->contents[i].which = p->contents[i].which; + n->contents[i].d.any = DeepCopy(p->contents[i].which, + p->contents[i].d.any); + } + return n; + } + default: + oops(); + break; + } +} +*/ +//----------------------------------------------------------------------------- +// Empty out a ProgramStack data structure, either .undo or .redo: set the +// count to zero and free all the program copies in it. +//----------------------------------------------------------------------------- +static void EmptyProgramStack(ProgramStack *ps) +{ + while(ps->count > 0) { + int a = (ps->write - 1); + if(a < 0) a += MAX_LEVELS_UNDO; + ps->write = a; + (ps->count)--; + + int i; + for(i = 0; i < ps->prog[ps->write].numRungs; i++) { + FreeCircuit(ELEM_SERIES_SUBCKT, ps->prog[ps->write].rungs[i]); + } + } +} +/* +//----------------------------------------------------------------------------- +// Push the current program onto a program stack. Can either make a deep or +// a shallow copy of the linked data structures. +//----------------------------------------------------------------------------- +static void PushProgramStack(ProgramStack *ps, BOOL deepCopy) +{ + if(ps->count == MAX_LEVELS_UNDO) { + int i; + for(i = 0; i < ps->prog[ps->write].numRungs; i++) { + FreeCircuit(ELEM_SERIES_SUBCKT, + ps->prog[ps->write].rungs[i]); + } + } else { + (ps->count)++; + } + + memcpy(&(ps->prog[ps->write]), &Prog, sizeof(Prog)); + if(deepCopy) { + int i; + for(i = 0; i < Prog.numRungs; i++) { + ps->prog[ps->write].rungs[i] = + (ElemSubcktSeries *)DeepCopy(ELEM_SERIES_SUBCKT, Prog.rungs[i]); + } + } + + int gx, gy; + if(FindSelected(&gx, &gy)) { + ps->cursor[ps->write].gx = gx; + ps->cursor[ps->write].gy = gy; + } else { + ps->cursor[ps->write].gx = -1; + ps->cursor[ps->write].gy = -1; + } + + int a = (ps->write + 1); + if(a >= MAX_LEVELS_UNDO) a -= MAX_LEVELS_UNDO; + ps->write = a; +} + +//----------------------------------------------------------------------------- +// Pop a program stack onto the current program. Always does a shallow copy. +// Internal error if the stack was empty. +//----------------------------------------------------------------------------- +static void PopProgramStack(ProgramStack *ps) +{ + int a = (ps->write - 1); + if(a < 0) a += MAX_LEVELS_UNDO; + ps->write = a; + (ps->count)--; + + memcpy(&Prog, &ps->prog[ps->write], sizeof(Prog)); + + SelectedGxAfterNextPaint = ps->cursor[ps->write].gx; + SelectedGyAfterNextPaint = ps->cursor[ps->write].gy; +} + +//----------------------------------------------------------------------------- +// Push a copy of the PLC program onto the undo history, replacing (and +// freeing) the oldest one if necessary. +//----------------------------------------------------------------------------- +void UndoRemember(void) +{ + // can't redo after modifying the program + EmptyProgramStack(&(Undo.redo)); + PushProgramStack(&(Undo.undo), TRUE); + + SetUndoEnabled(TRUE, FALSE); +} + +//----------------------------------------------------------------------------- +// Pop the undo history one level, or do nothing if we're out of levels of +// undo. This means that we push the current program on the redo stack, and +// pop the undo stack onto the current program. +//----------------------------------------------------------------------------- +void UndoUndo(void) +{ + if(Undo.undo.count <= 0) return; + + ForgetEverything(); + + PushProgramStack(&(Undo.redo), FALSE); + PopProgramStack(&(Undo.undo)); + + if(Undo.undo.count > 0) { + SetUndoEnabled(TRUE, TRUE); + } else { + SetUndoEnabled(FALSE, TRUE); + } + RefreshControlsToSettings(); + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); +} + +//----------------------------------------------------------------------------- +// Redo an undone operation. Push the current program onto the undo stack, +// and pop the redo stack into the current program. +//----------------------------------------------------------------------------- +void UndoRedo(void) +{ + if(Undo.redo.count <= 0) return; + + ForgetEverything(); + + PushProgramStack(&(Undo.undo), FALSE); + PopProgramStack(&(Undo.redo)); + + if(Undo.redo.count > 0) { + SetUndoEnabled(TRUE, TRUE); + } else { + SetUndoEnabled(TRUE, FALSE); + } + RefreshControlsToSettings(); + RefreshScrollbars(); + InvalidateRect(MainWindow, NULL, FALSE); +} +*/ +//----------------------------------------------------------------------------- +// Empty out our undo history entirely, as when loading a new file. +//----------------------------------------------------------------------------- +void UndoFlush(void) +{ + EmptyProgramStack(&(Undo.undo)); + EmptyProgramStack(&(Undo.redo)); + SetUndoEnabled(FALSE, FALSE); +} + +//----------------------------------------------------------------------------- +// Is it possible to undo some operation? The display code needs to do that, +// due to an ugly hack for handling too-long lines; the only thing that +// notices that easily is the display code, which will respond by undoing +// the last operation, presumably the one that added the long line. +//----------------------------------------------------------------------------- +/*BOOL CanUndo(void) +{ + return (Undo.undo.count > 0); +}*/ + |