summaryrefslogtreecommitdiff
path: root/app/bin/cundo.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/cundo.c')
-rw-r--r--app/bin/cundo.c745
1 files changed, 519 insertions, 226 deletions
diff --git a/app/bin/cundo.c b/app/bin/cundo.c
index 1ed5588..b58d541 100644
--- a/app/bin/cundo.c
+++ b/app/bin/cundo.c
@@ -1,5 +1,5 @@
/** \file cundo.c
- * Undo / redo functions.
+ * Undo / redo functions.
*/
/* XTrkCad - Model Railroad CAD
@@ -17,25 +17,116 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <stdlib.h>
-#include <time.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <string.h>
+/*
+ * Implements Undo/Redo
+ *
+ * Each action/change (New/Modify/Delete) is recorded by UndoNew(), UndoModify(), UndoDelete() within an undo transaction (initiated by UndoStart().
+ *
+ * New tracks are added to the end of the tracklist (headed by to_first).
+ *
+ * Modify/Delete generate an undo record (WriteObject) in undoStream.
+ * Each record contains:
+ * - op (ModifyOp or DeleteOp)
+ * - address for the existing track
+ * - copy of the track
+ * - endpts, extradata, extra-extradata
+ *
+ * Undo pulls records from the undoStream (ReadObject) for the current transation
+ * to recreate modified and deleted tracks.
+ * New tracks are snipped from the tracklist
+ *
+ * Undone records can be copied to redoStream for susequent redo ops
+ *
+ * The undo transactions are stored in a circular buffer (undoStack).
+ * When this buffer wraps around, the old transaction is recycled,
+ * At this point, any DeleteOp records in the old transaction are processed
+ * (DeleteInStream) and the deleted track is Free'd
+ *
+ * The streams are expandable ring buffers.
+ * When the transaction buffer wraps, the unreferenced start of the undoStreams is trimmed.
+ * THe redoStream is purged for every transaction.
+ *
+ *
+ * Note on Delete
+ *
+ * UndoDelete does 2 things:
+ * 1 Marks the track's transaction record with DeleteOp
+ * When the transaction record is recycled, the old track object will be Free'd.
+ * 2 Sets the .delete flag in the track object
+ * For the most part (except dcar.c and cundo.c) IsTrackDeleted() is used in CHECKs
+ * There are a few cases where we have to deal with deleted track.
+ * In general, we do not need to look inside a deleted track and
+ * GET_EXTRA_DATA will complain if we try (FreeTrack is the exception)
+ */
#include "cselect.h"
#include "custom.h"
#include "fileio.h"
-#include "i18n.h"
-#include "messages.h"
#include "paths.h"
#include "track.h"
-#include "trackx.h"
+// We need to fiddle with the track list
+#include "trackx.h" // tempTrk, to_first, to_last
+#include "trkendpt.h"
+#include "draw.h"
#include "cundo.h"
+#include "common-ui.h"
+#include "ctrain.h"
+#include <inttypes.h>
+
+#include <stdint.h>
+
+#define SLOG_FMT "0x%.12" PRIxPTR
+
+
+/****************************************************************************
+ *
+ * RPRINTF
+ *
+ */
+
+
+#define RBUFF_SIZE (8192)
+static char rbuff[RBUFF_SIZE+1];
+static int roff;
+static int rbuff_record = 0;
+
+EXPORT void Rdump( FILE * outf )
+{
+ fprintf( outf, "Record Buffer:\n" );
+ rbuff[RBUFF_SIZE] = '\0';
+ fprintf( outf, "%s", rbuff+roff );
+ rbuff[roff] = '\0';
+ fprintf( outf, "%s", rbuff );
+ memset( rbuff, 0, sizeof rbuff );
+ roff = 0;
+}
+
+
+static void Rprintf(
+ char * format,
+ ... )
+{
+ static char buff[STR_SIZE];
+ char * cp;
+ va_list ap;
+ va_start( ap, format );
+ vsprintf( buff, format, ap );
+ va_end( ap );
+ if (rbuff_record >= 1) {
+ lprintf( buff );
+ }
+ for ( cp=buff; *cp; cp++ ) {
+ rbuff[roff] = *cp;
+ roff++;
+ if (roff>=RBUFF_SIZE) {
+ roff=0;
+ }
+ }
+}
/*****************************************************************************
*
@@ -48,20 +139,20 @@ static int log_undo = 0; /**< loglevel, can only be set at compile time */
#define UNDO_STACK_SIZE (10)
typedef struct {
- wIndex_t modCnt;
- wIndex_t newCnt;
- wIndex_t delCnt;
- wIndex_t trackCount;
- track_p newTrks;
- long undoStart;
- long undoEnd;
- long redoStart;
- long redoEnd;
- BOOL_T needRedo;
- track_p * oldTail;
- track_p * newTail;
- char * label;
- } undoStack_t, *undoStack_p;
+ wIndex_t modCnt;
+ wIndex_t newCnt;
+ wIndex_t delCnt;
+ wIndex_t trackCount;
+ track_p newTrks;
+ uintptr_t undoStart;
+ uintptr_t undoEnd;
+ uintptr_t redoStart;
+ uintptr_t redoEnd;
+ BOOL_T needRedo;
+ track_p * oldTail;
+ track_p * newTail;
+ char * label;
+} undoStack_t, *undoStack_p;
static undoStack_t undoStack[UNDO_STACK_SIZE];
static wIndex_t undoHead = -1;
@@ -76,6 +167,8 @@ static BOOL_T recordUndo = 1;
#define UASSERT( ARG, VAL ) \
if (!(ARG)) return UndoFail( #ARG, VAL, __FILE__, __LINE__ )
+#define UASSERT2( ARG, VAL ) \
+ if (!(ARG)) { UndoFail( #ARG, VAL, __FILE__, __LINE__ ); return; }
#define INC_UNDO_INX( INX ) {\
if (++INX >= UNDO_STACK_SIZE) \
@@ -90,11 +183,11 @@ static BOOL_T recordUndo = 1;
typedef char streamBlocks_t[BSTREAM_SIZE];
typedef streamBlocks_t *streamBlocks_p;
typedef struct {
- dynArr_t stream_da;
- long startBInx;
- long end;
- long curr;
- } stream_t;
+ dynArr_t stream_da;
+ long startBInx;
+ uintptr_t end;
+ uintptr_t curr;
+} stream_t;
typedef stream_t *stream_p;
static stream_t undoStream;
static stream_t redoStream;
@@ -118,7 +211,7 @@ static void DumpStream( FILE * outf, stream_p stream, char * name )
{
long binx;
long i, j;
- long off;
+ uintptr_t off;
streamBlocks_p blk;
int zeroCnt;
static char zeros[16] = { 0 };
@@ -131,62 +224,78 @@ static void DumpStream( FILE * outf, stream_p stream, char * name )
if ( memcmp( &((*blk)[i]), zeros, 16 ) == 0 ) {
zeroCnt++;
} else {
- if ( zeroCnt == 2 )
- fprintf( outf, "%6.6lx 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n", off-16 );
+ if ( zeroCnt == 2 ) {
+ fprintf( outf, "%6.6lx 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n",
+ (unsigned long)off-16 );
+ }
zeroCnt = 0;
}
if ( zeroCnt <= 1 ) {
- fprintf( outf, "%6.6lx ", off );
+ fprintf( outf, SLOG_FMT" ", off );
for ( j=0; j<16; j++ ) {
fprintf( outf, "%2.2x ", (unsigned char)((*blk)[i+j]) );
}
fprintf( outf, "\n" );
} else if ( zeroCnt == 3 ) {
- fprintf( outf, "%6.6lx .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..\n", off );
+ fprintf( outf, SLOG_FMT" .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..\n",
+ off );
}
off += 16;
}
}
- if ( zeroCnt > 2 )
- fprintf( outf, "%6.6lx 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n", off-16 );
+ if ( zeroCnt > 2 ) {
+ fprintf( outf, SLOG_FMT" 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\n",
+ off-16 );
+ }
}
-static BOOL_T UndoFail( char * cause, long val, char * fileName, int lineNumber )
+static BOOL_T UndoFail( char * cause, uintptr_t val, char * fileName,
+ int lineNumber )
{
int inx, cnt;
undoStack_p us;
FILE * outf;
time_t clock;
- char *temp;
- NoticeMessage( MSG_UNDO_ASSERT, _("Ok"), NULL, fileName, lineNumber, val, val, cause );
+ char *temp;
+ NoticeMessage( MSG_UNDO_ASSERT, _("Ok"), NULL, fileName, lineNumber, val, val,
+ cause );
MakeFullpath(&temp, workingDir, sUndoF, NULL);
outf = fopen( temp, "a+" );
free(temp);
if ( outf == NULL ) {
- NoticeMessage( MSG_OPEN_FAIL, _("Ok"), NULL, _("Undo Trace"), temp, strerror(errno) );
+ NoticeMessage( MSG_OPEN_FAIL, _("Ok"), NULL, _("Undo Trace"), temp,
+ strerror(errno) );
return FALSE;
}
time( &clock );
- fprintf(outf, "\nUndo Assert: %s @ %s:%d (%s)\n", cause, fileName, lineNumber, ctime(&clock) );
- fprintf(outf, "Val = %ld(%lx)\n", val, val );
- fprintf(outf, "to_first=%lx, to_last=%lx\n", (long)to_first, (long)to_last );
- fprintf(outf, "undoHead=%d, doCount=%d, undoCount=%d\n", undoHead, doCount, undoCount );
- if (undoHead >= 0 && undoHead < UNDO_STACK_SIZE)
+
+ fprintf(outf, "\nUndo Assert: %s @ %s:%d (%s)\n", cause, fileName, lineNumber,
+ ctime(&clock) );
+ fprintf(outf, "Val = %lld(" SLOG_FMT ")\n", (long long)val, val );
+ fprintf(outf, "to_first="SLOG_FMT", to_last="SLOG_FMT"\n", (uintptr_t)to_first,
+ (uintptr_t)to_last );
+ fprintf(outf, "undoHead=%d, doCount=%d, undoCount=%d\n", undoHead, doCount,
+ undoCount );
+ if (undoHead >= 0 && undoHead < UNDO_STACK_SIZE) {
inx=undoHead;
- else
+ } else {
inx = 0;
+ }
for (cnt=0; cnt<UNDO_STACK_SIZE; cnt++) {
us = &undoStack[inx];
- fprintf( outf, "US[%d]: M:%d N:%d D:%d TC:%d NT:%lx OT:%lx NT:%lx US:%lx UE:%lx RS:%lx RE:%lx NR:%d\n",
- inx, us->modCnt, us->newCnt, us->delCnt, us->trackCount,
- (long)us->newTrks, (long)us->oldTail, (long)us->newTail,
- us->undoStart, us->undoEnd, us->redoStart, us->redoEnd, us->needRedo );
+ fprintf( outf,
+ "US[%d]: M:%d N:%d D:%d TC:%d NT:"SLOG_FMT" OT:"SLOG_FMT" NT:"SLOG_FMT" US:"SLOG_FMT" UE:"SLOG_FMT" RS:"SLOG_FMT" RE:"SLOG_FMT" NR:%d\n",
+ inx, us->modCnt, us->newCnt, us->delCnt, us->trackCount,
+ (uintptr_t)us->newTrks, (uintptr_t)us->oldTail, (uintptr_t)us->newTail,
+ us->undoStart, us->undoEnd, us->redoStart, us->redoEnd, us->needRedo );
INC_UNDO_INX(inx);
}
- fprintf( outf, "Undo: SBI:%ld E:%lx C:%lx SC:%d SM:%d\n",
- undoStream.startBInx, undoStream.end, undoStream.curr, undoStream.stream_da.cnt, undoStream.stream_da.max );
- fprintf( outf, "Redo: SBI:%ld E:%lx C:%lx SC:%d SM:%d\n",
- redoStream.startBInx, redoStream.end, redoStream.curr, redoStream.stream_da.cnt, redoStream.stream_da.max );
+ fprintf( outf, "Undo: SBI:%ld E:"SLOG_FMT" C:"SLOG_FMT" SC:%d SM:%d\n",
+ undoStream.startBInx, undoStream.end, undoStream.curr, undoStream.stream_da.cnt,
+ undoStream.stream_da.max );
+ fprintf( outf, "Redo: SBI:%ld E:"SLOG_FMT" C:"SLOG_FMT" SC:%d SM:%d\n",
+ redoStream.startBInx, redoStream.end, redoStream.curr, redoStream.stream_da.cnt,
+ redoStream.stream_da.max );
DumpStream( outf, &undoStream, "undoStream" );
DumpStream( outf, &redoStream, "redoStream" );
Rdump(outf);
@@ -199,13 +308,15 @@ static BOOL_T UndoFail( char * cause, long val, char * fileName, int lineNumber
BOOL_T ReadStream( stream_t * stream, void * ptr, int size )
{
- long binx, boff, brem;
+ size_t binx, boff, brem;
streamBlocks_p blk;
if ( stream->curr+size > stream->end ) {
- UndoFail( "Overrun on stream", (long)(stream->curr+size), __FILE__, __LINE__ );
+ UndoFail( "Overrun on stream", (uintptr_t)(stream->curr+size), __FILE__,
+ __LINE__ );
return FALSE;
}
-LOG( log_undo, 5, ( "ReadStream( , %lx, %d ) %ld %ld %ld\n", (long)ptr, size, stream->startBInx, stream->curr, stream->end ) )
+ LOG( log_undo, 5, ( "ReadStream( , "SLOG_FMT", %d ) %ld %ld %ld\n",
+ (uintptr_t)ptr, size, stream->startBInx, stream->curr, stream->end ) )
binx = stream->curr/BSTREAM_SIZE;
boff = stream->curr%BSTREAM_SIZE;
stream->curr += size;
@@ -231,11 +342,14 @@ LOG( log_undo, 5, ( "ReadStream( , %lx, %d ) %ld %ld %ld\n", (long)ptr, size, st
BOOL_T WriteStream( stream_p stream, void * ptr, int size )
{
- long binx, boff, brem;
+ size_t binx, boff, brem;
streamBlocks_p blk;
-LOG( log_undo, 5, ( "WriteStream( , %lx, %d ) %ld %ld %ld\n", (long)ptr, size, stream->startBInx, stream->curr, stream->end ) )
- if (size == 0)
+ LOG( log_undo, 5,
+ ( "WriteStream( , "SLOG_FMT", %d ) %ld "SLOG_FMT" "SLOG_FMT"\n", (uintptr_t)ptr,
+ size, stream->startBInx, stream->curr, stream->end ) )
+ if (size == 0) {
return TRUE;
+ }
binx = stream->end/BSTREAM_SIZE;
boff = stream->end%BSTREAM_SIZE;
stream->end += size;
@@ -254,7 +368,7 @@ LOG( log_undo, 5, ( "WriteStream( , %lx, %d ) %ld %ld %ld\n", (long)ptr, size, s
if (size > brem) {
memcpy( &(*blk)[boff], ptr, (size_t)brem );
ptr = (char*)ptr + brem;
- size -= (size_t)brem;
+ size -= (int)brem;
binx++;
boff = 0;
brem = BSTREAM_SIZE;
@@ -266,26 +380,30 @@ LOG( log_undo, 5, ( "WriteStream( , %lx, %d ) %ld %ld %ld\n", (long)ptr, size, s
return TRUE;
}
-BOOL_T TrimStream( stream_p stream, long off )
+BOOL_T TrimStream( stream_p stream, uintptr_t off )
{
- long binx, cnt, inx;
+ size_t binx, cnt, inx;
streamBlocks_p blk;
-LOG( log_undo, 3, ( "TrimStream( , %ld )\n", off ) )
+ LOG( log_undo, 3, ( " TrimStream( , %ld )\n", off ) )
binx = off/BSTREAM_SIZE;
cnt = binx-stream->startBInx;
- if (recordUndo)
- Rprintf("Trim(%ld) %ld blocks (out of %d)\n", off, cnt, stream->stream_da.cnt);
+ if (recordUndo) {
+ Rprintf("Trim("SLOG_FMT") %ld blocks (out of %d)\n", off, cnt,
+ stream->stream_da.cnt);
+ }
UASSERT( cnt >= 0 && cnt <= stream->stream_da.cnt, cnt );
- if (cnt == 0)
+ if (cnt == 0) {
return TRUE;
+ }
for (inx=0; inx<cnt; inx++) {
blk = DYNARR_N( streamBlocks_p, stream->stream_da, inx );
MyFree( blk );
}
for (inx=cnt; inx<stream->stream_da.cnt; inx++ ) {
- DYNARR_N( streamBlocks_p, stream->stream_da, inx-cnt ) = DYNARR_N( streamBlocks_p, stream->stream_da, inx );
+ DYNARR_N( streamBlocks_p, stream->stream_da,
+ inx-cnt ) = DYNARR_N( streamBlocks_p, stream->stream_da, inx );
}
- stream->startBInx = binx;
+ stream->startBInx =(long)binx;
stream->stream_da.cnt -= (wIndex_t)cnt;
UASSERT( stream->stream_da.cnt >= 0, stream->stream_da.cnt );
return TRUE;
@@ -300,32 +418,37 @@ void ClearStream( stream_p stream )
blk = DYNARR_N( streamBlocks_p, stream->stream_da, inx );
MyFree( blk );
}
- stream->stream_da.cnt = 0;
- stream->startBInx = stream->end = stream->curr = 0;
+ DYNARR_RESET( streamBlocks_p, stream->stream_da );
+ stream->startBInx = 0;
+ stream->end = stream->curr = 0;
}
-BOOL_T TruncateStream( stream_p stream, long off )
+BOOL_T TruncateStream( stream_p stream, uintptr_t off )
{
- long binx, boff, cnt, inx;
+ size_t binx, boff, cnt, inx;
streamBlocks_p blk;
-LOG( log_undo, 3, ( "TruncateStream( , %ld )\n", off ) )
+ LOG( log_undo, 3, ( "TruncateStream( , %ld )\n", off ) )
binx = off/BSTREAM_SIZE;
boff = off%BSTREAM_SIZE;
- if (boff!=0)
+ if (boff!=0) {
binx++;
+ }
binx -= stream->startBInx;
cnt = stream->stream_da.cnt-binx;
- if (recordUndo)
- Rprintf("Truncate(%ld) %ld blocks (out of %d)\n", off, cnt, stream->stream_da.cnt);
+ if (recordUndo) {
+ Rprintf("Truncate("SLOG_FMT") %ld blocks (out of %d)\n", off, cnt,
+ stream->stream_da.cnt);
+ }
UASSERT( cnt >= 0 && cnt <= stream->stream_da.cnt, cnt );
- if (cnt == 0)
+ if (cnt == 0) {
return TRUE;
+ }
for (inx=binx; inx<stream->stream_da.cnt; inx++) {
blk = DYNARR_N( streamBlocks_p, stream->stream_da, inx );
MyFree( blk );
}
- stream->stream_da.cnt = (wIndex_t)binx;
+ DYNARR_SET( streamBlocks_p, stream->stream_da, (wIndex_t)binx );
stream->end = off;
UASSERT( stream->stream_da.cnt >= 0, stream->stream_da.cnt );
return TRUE;
@@ -337,76 +460,115 @@ BOOL_T WriteObject( stream_p stream, char op, track_p trk )
void * buff = NULL;
long len = 0;
if (!WriteStream( stream, &op, sizeof op ) ||
- !WriteStream( stream, &trk, sizeof trk ) ||
- !WriteStream( stream, trk, sizeof *trk ) ||
- !WriteStream( stream, trk->endPt, trk->endCnt * sizeof trk->endPt[0] ) ||
- !WriteStream( stream, trk->extraData, trk->extraSize ))
+ !WriteStream( stream, &trk, sizeof trk ) ||
+ !WriteStream( stream, trk, sizeof *trk ) ||
+ !WriteStream( stream, trk->endPt, EndPtSize(trk->endCnt) ) ||
+ !WriteStream( stream, trk->extraData, trk->extraSize )) {
return FALSE;
+ }
/* Add a copy of the any type specific data before it is tampered with, for example */
- StoreTrackData(trk,&buff,&len);
- if (!WriteStream( stream, &len, sizeof len ))
+ if ( !IsTrackDeleted(trk) ) {
+ StoreTrackData(trk,&buff,&len);
+ } else {
+ len = 0;
+ buff = NULL;
+ }
+ if (!WriteStream( stream, &len, sizeof len )) {
return FALSE;
+ }
if (len)
- if (!WriteStream( stream, buff, len ))
+ if (!WriteStream( stream, buff, len )) {
return FALSE;
+ }
return TRUE;
}
+/**
+ * Read an object from a stream
+ *
+ * \param stream
+ * \param needRedo copy current object to redoStream
+ *
+ */
static BOOL_T ReadObject( stream_p stream, BOOL_T needRedo )
{
track_p trk;
track_t tempTrk;
char op;
- if (!ReadStream( stream, &op, sizeof op ))
+ if (!ReadStream( stream, &op, sizeof op )) {
return FALSE;
- if (!ReadStream( stream, &trk, sizeof trk ))
+ }
+ if (!ReadStream( stream, &trk, sizeof trk )) {
return FALSE;
+ }
+ LOG( log_undo, 4, ( " @ " SLOG_FMT " %s\n", stream->curr-1,
+ op==ModifyOp?"Mod":"Del" ) );
if (needRedo) {
- if (!WriteObject( &redoStream, op, trk ))
+ if (!WriteObject( &redoStream, op, trk )) {
return FALSE;
+ }
}
- if (!ReadStream( stream, &tempTrk, sizeof tempTrk ))
+ if (!ReadStream( stream, &tempTrk, sizeof tempTrk )) {
return FALSE;
- if (tempTrk.endCnt != trk->endCnt)
- tempTrk.endPt = MyRealloc( trk->endPt, tempTrk.endCnt * sizeof tempTrk.endPt[0] );
- else
+ }
+ if (op == ModifyOp) {
+ UASSERT( (op==ModifyOp) && !IsTrackDeleted(&tempTrk), GetTrkIndex(&tempTrk) );
+ }
+ // op==DeleteOp doesnot imply that tmpTrk.delete == TRUE: SetDeleteOpInStream
+ if (tempTrk.endCnt != trk->endCnt) {
+ tempTrk.endPt = MyRealloc( trk->endPt, EndPtSize(tempTrk.endCnt) );
+ } else {
tempTrk.endPt = trk->endPt;
- if (!ReadStream( stream, tempTrk.endPt, tempTrk.endCnt * sizeof tempTrk.endPt[0] ))
+ }
+ if (!ReadStream( stream, tempTrk.endPt, EndPtSize(tempTrk.endCnt) )) {
return FALSE;
- if (tempTrk.extraSize != trk->extraSize)
- tempTrk.extraData = MyRealloc( trk->extraData, tempTrk.extraSize );
- else
+ }
+ if (tempTrk.extraSize != trk->extraSize) {
+ tempTrk.extraData = (extraDataBase_t*)MyRealloc( trk->extraData,
+ tempTrk.extraSize );
+ } else {
tempTrk.extraData = trk->extraData;
- if (!ReadStream( stream, tempTrk.extraData, tempTrk.extraSize ))
+ }
+ if (!ReadStream( stream, tempTrk.extraData, tempTrk.extraSize )) {
return FALSE;
+ }
long Addsize;
void * tempBuff;
/* Fix up pts to be as big as it was before -> because it may have changed since */
- if (!ReadStream (stream, &Addsize, sizeof Addsize))
+ if (!ReadStream (stream, &Addsize, sizeof Addsize)) {
return FALSE;
+ }
if (Addsize) {
tempBuff = MyMalloc(Addsize);
- if (!ReadStream( stream, tempBuff, Addsize ))
+ if (!ReadStream( stream, tempBuff, Addsize )) {
return FALSE;
- ReplayTrackData(&tempTrk, tempBuff, Addsize);
+ }
+ if ( ! IsTrackDeleted(&tempTrk) ) {
+ ReplayTrackData(&tempTrk, tempBuff, Addsize);
+ }
MyFree(tempBuff);
}
- RebuildTrackSegs(&tempTrk); //If we had an array of Segs - recreate it
- if (recordUndo) Rprintf( "Restore T%D(%d) @ %lx\n", trk->index, tempTrk.index, (long)trk );
+ if ( ! IsTrackDeleted(&tempTrk) ) {
+ RebuildTrackSegs(&tempTrk); //If we had an array of Segs - recreate it
+ }
+ if (recordUndo) { Rprintf( "Restore T%D(%d) @ "SLOG_FMT"\n", trk->index, tempTrk.index, (uintptr_t)trk ); }
tempTrk.index = trk->index;
tempTrk.next = trk->next;
- if ( (tempTrk.bits&TB_CARATTACHED) != 0 )
+ if ( (tempTrk.bits&TB_CARATTACHED) != 0 ) {
needAttachTrains = TRUE;
+ }
tempTrk.bits &= ~TB_TEMPBITS;
*trk = tempTrk;
- if (!trk->deleted)
+ if (!IsTrackDeleted(trk)) {
ClrTrkElev( trk );
+ }
return TRUE;
}
-static BOOL_T RedrawInStream( stream_p stream, long start, long end, BOOL_T draw )
+static BOOL_T RedrawInStream( stream_p stream, uintptr_t start, uintptr_t end,
+ BOOL_T draw )
{
char op;
track_p trk;
@@ -414,49 +576,70 @@ static BOOL_T RedrawInStream( stream_p stream, long start, long end, BOOL_T draw
stream->curr = start;
while (stream->curr < end ) {
if (!ReadStream( stream, &op, sizeof op ) ||
- !ReadStream( stream, &trk, sizeof trk ) ||
- !ReadStream( stream, &tempTrk, sizeof tempTrk ) )
+ !ReadStream( stream, &trk, sizeof trk ) ||
+ !ReadStream( stream, &tempTrk, sizeof tempTrk ) ) {
return FALSE;
- stream->curr += tempTrk.extraSize + tempTrk.endCnt*sizeof tempTrk.endPt[0];;
+ }
+ stream->curr += tempTrk.extraSize + EndPtSize(tempTrk.endCnt);
long Addsize;
- if (!ReadStream( stream, &Addsize, sizeof Addsize ))
- return FALSE;
+ if (!ReadStream( stream, &Addsize, sizeof Addsize )) {
+ return FALSE;
+ }
stream->curr += Addsize;
- if (!trk->deleted) {
- if (draw)
+ if (!IsTrackDeleted(trk)) {
+ if (draw) {
DrawNewTrack( trk );
- else
+ } else {
UndrawNewTrack( trk );
+ }
}
}
return TRUE;
}
-static BOOL_T DeleteInStream( stream_p stream, long start, long end )
+/**
+ * Delete unreferenced objects from stream
+ *
+ * \param stream
+ * \param start
+ * \param end
+ *
+ * The current transaction is being recycled:
+ * unlink and free any deleted objects from the old transaction
+ */
+static BOOL_T DeleteInStream( stream_p stream, uintptr_t start, uintptr_t end )
{
char op;
track_p trk;
track_p *ptrk;
track_t tempTrk;
int delCount = 0;
-LOG( log_undo, 3, ( "DeleteInSteam( , %ld, %ld )\n", start, end ) )
+ LOG( log_undo, 3, ( " DeleteInStream( , "SLOG_FMT", "SLOG_FMT" )\n", start,
+ end ) )
stream->curr = start;
while (stream->curr < end ) {
- if (!ReadStream( stream, &op, sizeof op ))
+ if (!ReadStream( stream, &op, sizeof op )) {
return FALSE;
+ }
UASSERT( op == ModifyOp || op == DeleteOp, (long)op );
+ LOG( log_undo, 4, ( " @ " SLOG_FMT " %s\n", stream->curr-1,
+ op==ModifyOp?"Mod":"Del" ) );
if (!ReadStream( stream, &trk, sizeof trk ) ||
- !ReadStream( stream, &tempTrk, sizeof tempTrk ))
+ !ReadStream( stream, &tempTrk, sizeof tempTrk )) {
return FALSE;
- stream->curr += tempTrk.extraSize + tempTrk.endCnt*sizeof tempTrk.endPt[0];
+ }
+ stream->curr += tempTrk.extraSize + EndPtSize(tempTrk.endCnt);
long Addsize;
- if (!ReadStream( stream, &Addsize, sizeof Addsize ))
+ if (!ReadStream( stream, &Addsize, sizeof Addsize )) {
return FALSE;
+ }
stream->curr += Addsize;
if (op == DeleteOp) {
- if (recordUndo) Rprintf( " Free T%D(%d) @ %lx\n", trk->index, tempTrk.index, (long)trk );
- UASSERT( IsTrackDeleted(trk), (long)trk );
+ if (recordUndo) { Rprintf( " Free T%D(%d) @ "SLOG_FMT"\n", trk->index, tempTrk.index, (uintptr_t)trk ); }
+ LOG( log_undo, 3, ( " Free T%d @ "SLOG_FMT"\n", GetTrkIndex(trk),
+ (uintptr_t)trk ) );
+ UASSERT( IsTrackDeleted(trk), GetTrkIndex(trk) );
trk->index = -1;
delCount++;
}
@@ -465,8 +648,9 @@ LOG( log_undo, 3, ( "DeleteInSteam( , %ld, %ld )\n", start, end ) )
if (delCount) {
for (ptrk=&to_first; *ptrk; ) {
if ((*ptrk)->index == -1) {
+ // old track to be discarded: Unlink and Free it
trk = *ptrk;
- UASSERT( IsTrackDeleted(trk), (long)trk );
+ UASSERT( IsTrackDeleted(trk), (uintptr_t)trk );
*ptrk = trk->next;
FreeTrack(trk);
} else {
@@ -479,36 +663,57 @@ LOG( log_undo, 3, ( "DeleteInSteam( , %ld, %ld )\n", start, end ) )
}
-static BOOL_T SetDeleteOpInStream( stream_p stream, long start, long end, track_p trk0 )
+/**
+ * Find undo record for 'trk' and change op from Modify to Delete
+ *
+ * \param stream
+ * \param start
+ * \param end
+ * \param trk
+ *
+ * Note: does not set trk->delete flag
+ */
+static BOOL_T SetDeleteOpInStream( stream_p stream, uintptr_t start,
+ uintptr_t end, track_p trk0 )
{
char op;
track_p trk;
track_t tempTrk;
- long binx, boff;
+ size_t binx, boff;
streamBlocks_p blk;
+ LOG( log_undo, 3, ( " SetDeleteOpInStream T%d @ "SLOG_FMT"\n",
+ GetTrkIndex(trk0), (uintptr_t)trk0) );
stream->curr = start;
while (stream->curr < end) {
binx = stream->curr/BSTREAM_SIZE;
binx -= stream->startBInx;
boff = stream->curr%BSTREAM_SIZE;
- if (!ReadStream( stream, &op, sizeof op ))
+ if (!ReadStream( stream, &op, sizeof op )) {
return FALSE;
+ }
UASSERT( op == ModifyOp || op == DeleteOp, (long)op );
- if (!ReadStream( stream, &trk, sizeof trk ) )
+ LOG( log_undo, 4, ( " @ " SLOG_FMT " %s\n", stream->curr-1,
+ op==ModifyOp?"Mod":"Del" ) );
+ if (!ReadStream( stream, &trk, sizeof trk ) ) {
+ return FALSE;
+ }
+ if (!ReadStream( stream, &tempTrk, sizeof tempTrk )) {
return FALSE;
+ }
if (trk == trk0) {
UASSERT( op == ModifyOp, (long)op );
blk = DYNARR_N( streamBlocks_p, stream->stream_da, binx );
memcpy( &(*blk)[boff], &DeleteOp, sizeof DeleteOp );
+ // Should set .delete flag in stream
+ LOG( log_undo, 3, ( " -> Delete\n") );
return TRUE;
}
- if (!ReadStream( stream, &tempTrk, sizeof tempTrk ))
- return FALSE;
- stream->curr += tempTrk.extraSize + tempTrk.endCnt*sizeof tempTrk.endPt[0];
+ stream->curr += tempTrk.extraSize + EndPtSize(tempTrk.endCnt);
long Addsize;
- if (!ReadStream( stream, &Addsize, sizeof Addsize))
- return FALSE;
+ if (!ReadStream( stream, &Addsize, sizeof Addsize)) {
+ return FALSE;
+ }
stream->curr += Addsize;
}
UASSERT( "Cannot find undo record to convert to DeleteOp", 0 );
@@ -553,23 +758,34 @@ static track_p * FindParent( track_p trk, int lineNum )
{
track_p *ptrk;
ptrk = &to_first;
- while ( 1 ) {
- if ( *ptrk == trk )
+ while ( 1 ) {
+ if ( *ptrk == trk ) {
return ptrk;
- if (*ptrk == NULL)
+ }
+ if (*ptrk == NULL) {
break;
+ }
ptrk = &(*ptrk)->next;
}
- UndoFail( "Cannot find trk on list", (long)trk, "cundo.c", lineNum );
+ UndoFail( "Cannot find trk on list", (uintptr_t)trk, "cundo.c", lineNum );
return NULL;
}
static int undoIgnoreEmpty = 0;
+
+/**
+ * Start an Undo transcation
+ *
+ * \param label help text for balloon help
+ * \param format logging info
+ *
+ *
+ */
void UndoStart(
- char * label,
- char * format,
- ... )
+ char * label,
+ char * format,
+ ... )
{
static char buff[STR_SIZE];
va_list ap;
@@ -578,22 +794,21 @@ void UndoStart(
int inx;
int usp;
-LOG( log_undo, 1, ( "UndoStart(%s) [%d] d:%d u:%d us:%ld\n", label, undoHead, doCount, undoCount, undoStream.end ) )
+ LOG( log_undo, 1, ( "UndoStart[%d] (%s) d:%d u:%d us:"SLOG_FMT"\n", undoHead,
+ label, undoHead, doCount, undoCount, undoStream.end ) )
if (recordUndo) {
va_start( ap, format );
vsprintf( buff, format, ap );
va_end( ap );
- Rprintf( "Start(%s)[%d] d:%d u:%d us:%ld\n", buff, undoHead, doCount, undoCount, undoStream.end );
+ Rprintf( "Start(%s)[%d] d:%d u:%d us:"SLOG_FMT"\n", buff, undoHead, doCount,
+ undoCount, undoStream.end );
}
if ( undoHead >= 0 ) {
us = &undoStack[undoHead];
if ( us->modCnt == 0 && us->delCnt == 0 && us->newCnt == 0 ) {
-#ifndef WINDOWS
-#ifdef DEBUG
- printf( "undoStart noop: %s - %s\n", us->label?us->label:"<>", label?label:"<>" );
-#endif
-#endif
+ LOG( log_undo, 1, ( " noop: %s - %s\n", us->label?us->label:"<>",
+ label?label:"<>" ) );
if ( undoIgnoreEmpty ) {
us->label = label;
return;
@@ -603,36 +818,41 @@ LOG( log_undo, 1, ( "UndoStart(%s) [%d] d:%d u:%d us:%ld\n", label, undoHead, do
INC_UNDO_INX(undoHead);
us = &undoStack[undoHead];
- changed++;
- SetWindowTitle();
+
+ SetFileChanged();
if (doCount == UNDO_STACK_SIZE) {
- if (recordUndo) Rprintf( " Wrapped N:%d M:%d D:%d\n", us->newCnt, us->modCnt, us->delCnt );
+ if (recordUndo) { Rprintf( " Wrapped N:%d M:%d D:%d\n", us->newCnt, us->modCnt, us->delCnt ); }
/* wrapped around stack */
/* if track saved in undoStream is deleted then really deleted since
we can't get it back */
- if (!DeleteInStream( &undoStream, us->undoStart, us->undoEnd ))
+ if (!DeleteInStream( &undoStream, us->undoStart, us->undoEnd )) {
return;
+ }
/* strip off unused head of stream */
- if (!TrimStream( &undoStream, us->undoEnd ))
+ if (!TrimStream( &undoStream, us->undoEnd )) {
return;
+ }
} else if (undoCount != 0) {
- if (recordUndo) Rprintf( " Undid N:%d M:%d D:%d\n", us->newCnt, us->modCnt, us->delCnt );
+ if (recordUndo) { Rprintf( " Undid N:%d M:%d D:%d\n", us->newCnt, us->modCnt, us->delCnt ); }
/* reusing an undid entry */
/* really delete all new tracks since this point */
for( inx=0,usp = undoHead; inx<undoCount; inx++ ) {
us1 = &undoStack[usp];
- if (recordUndo) Rprintf(" U[%d] N:%d\n", usp, us1->newCnt );
+ if (recordUndo) { Rprintf(" U[%d] N:%d\n", usp, us1->newCnt ); }
for (trk=us1->newTrks; trk; trk=next) {
- if (recordUndo) Rprintf( " Free T%d @ %lx\n", trk->index, (long)trk );
- /*ASSERT( IsTrackDeleted(trk) );*/
+ if (recordUndo) { Rprintf( " Free T%d @ "SLOG_FMT"\n", trk->index, (uintptr_t)trk ); }
+ // trk->delete may not be TRUE, see SetDeleteOpInStream
+ LOG( log_undo, 4, (" Free T%d @ "SLOG_FMT"\n", trk->index,
+ (uintptr_t)trk ) );
next = trk->next;
FreeTrack( trk );
}
INC_UNDO_INX(usp);
}
/* strip off unused tail of stream */
- if (!TruncateStream( &undoStream, us->undoStart ))
+ if (!TruncateStream( &undoStream, us->undoStart )) {
return;
+ }
}
us->label = label;
us->modCnt = 0;
@@ -653,31 +873,44 @@ LOG( log_undo, 1, ( "UndoStart(%s) [%d] d:%d u:%d us:%ld\n", label, undoHead, do
trk->modified = FALSE;
trk->new = FALSE;
}
- if (doCount < UNDO_STACK_SIZE)
+ if (doCount < UNDO_STACK_SIZE) {
doCount++;
+ }
SetButtons( TRUE, FALSE );
}
+/**
+ * Record Modify'd track for Undo
+ * \param trk
+ *
+ * If track has not been previously recorded in these Undo transaction
+ * or is not 'new' write the track to the undoStream which a ModifyOp flag
+ */
BOOL_T UndoModify( track_p trk )
{
undoStack_p us;
- if ( !undoActive ) return TRUE;
- if (trk == NULL) return TRUE;
+ if ( !undoActive ) { return TRUE; }
+ if (trk == NULL) { return TRUE; }
UASSERT(undoCount==0, undoCount);
UASSERT(undoHead >= 0, undoHead);
- UASSERT(!IsTrackDeleted(trk), (long)trk);
- if (trk->modified || trk->new)
+ UASSERT(!IsTrackDeleted(trk), GetTrkIndex(trk));
+ if (trk->modified || trk->new) {
return TRUE;
-LOG( log_undo, 2, ( " UndoModify( T%d, E%d, X%ld )\n", trk->index, trk->endCnt, trk->extraSize ) )
- if ( (GetTrkBits(trk)&TB_CARATTACHED)!=0 )
+ }
+ LOG( log_undo, 2, ( " UndoModify( T%d, E%d, X%ld @ "SLOG_FMT"\n", trk->index,
+ trk->endCnt, trk->extraSize, (uintptr_t)trk ) )
+ if ( (GetTrkBits(trk)&TB_CARATTACHED)!=0 ) {
needAttachTrains = TRUE;
+ }
us = &undoStack[undoHead];
- if (recordUndo)
- Rprintf( " MOD T%d @ %lx\n", trk->index, (long)trk );
- if (!WriteObject( &undoStream, ModifyOp, trk ))
+ if (recordUndo) {
+ Rprintf( " MOD T%d @ "SLOG_FMT"\n", trk->index, (uintptr_t)trk );
+ }
+ if (!WriteObject( &undoStream, ModifyOp, trk )) {
return FALSE;
+ }
us->undoEnd = undoStream.end;
trk->modified = TRUE;
us->modCnt++;
@@ -685,32 +918,52 @@ LOG( log_undo, 2, ( " UndoModify( T%d, E%d, X%ld )\n", trk->index, trk->endCn
}
+/**
+ * Record that the track has been deleted
+ *
+ * \param trk
+ *
+ * If the track has been Modified, then update undoStream to change op to DeleteOp
+ * If the track is not New, then write the record to the undoSteam with a DeleteOp
+ * When this undo transaction is recycled, DeleteOp records will unlinked and freed.
+ *
+ * Otherwise, we're deleting a New track: remove it from track list and discard it
+ */
BOOL_T UndoDelete( track_p trk )
{
undoStack_p us;
- if ( !undoActive ) return TRUE;
-LOG( log_undo, 2, ( " UndoDelete( T%d, E%d, X%ld )\n", trk->index, trk->endCnt, trk->extraSize ) )
- if ( (GetTrkBits(trk)&TB_CARATTACHED)!=0 )
+ if ( !undoActive ) { return TRUE; }
+ LOG( log_undo, 2, ( " UndoDelete( T%d, E%d, X%ld @ "SLOG_FMT" )\n",
+ trk->index, trk->endCnt, trk->extraSize, (uintptr_t)trk ) )
+ if ( (GetTrkBits(trk)&TB_CARATTACHED)!=0 ) {
needAttachTrains = TRUE;
+ }
us = &undoStack[undoHead];
- if (recordUndo)
- Rprintf( " DEL T%d @ %lx\n", trk->index, (long)trk );
- UASSERT( !IsTrackDeleted(trk), (long)trk );
+ if (recordUndo) {
+ Rprintf( " DEL T%d @ "SLOG_FMT"\n", trk->index, (uintptr_t)trk );
+ }
+ UASSERT( !IsTrackDeleted(trk), trk->index );
if ( trk->modified ) {
- if (!SetDeleteOpInStream( &undoStream, us->undoStart, us->undoEnd, trk ))
+ if (!SetDeleteOpInStream( &undoStream, us->undoStart, us->undoEnd, trk )) {
return FALSE;
+ }
} else if ( !trk->new ) {
- if (!WriteObject( &undoStream, DeleteOp, trk ))
- return FALSE;
+ LOG( log_undo, 3, ( " Write DeleteOp object\n" ) );
+ if (!WriteObject( &undoStream, DeleteOp, trk )) {
+ return FALSE;
+ }
us->undoEnd = undoStream.end;
} else {
+ LOG( log_undo, 3, ( " Remove New object\n" ) );
track_p * ptrk;
- if (us->newTrks == trk)
+ if (us->newTrks == trk) {
us->newTrks = trk->next;
- if (!(ptrk = FindParent( trk, __LINE__ )))
+ }
+ if (!(ptrk = FindParent( trk, __LINE__ ))) {
return FALSE;
+ }
if (trk->next == NULL) {
- UASSERT( to_last == &(*ptrk)->next, (long)&(*ptrk)->next );
+ UASSERT( to_last == &(*ptrk)->next, (uintptr_t)&(*ptrk)->next );
to_last = ptrk;
}
*ptrk = trk->next;
@@ -718,37 +971,52 @@ LOG( log_undo, 2, ( " UndoDelete( T%d, E%d, X%ld )\n", trk->index, trk->endCn
us->newCnt--;
return TRUE;
}
+ ClrTrkBits( trk, TB_SELECTED );
trk->deleted = TRUE;
us->delCnt++;
return TRUE;
}
-
+/**
+ * Record a New track for Undo
+ *
+ * \param trk
+ *
+ * New tracks are added to the end of the Track list
+ * Save the begining of New tracks in this Undo transaction in us->newTrks
+ */
BOOL_T UndoNew( track_p trk )
{
- undoStack_p us;
- if (!undoActive)
+ undoStack_p us;
+ if (!undoActive) {
return TRUE;
+ }
+
+ LOG( log_undo, 2, ( " UndoNew( T%d @ "SLOG_FMT")\n", trk->index,
+ (uintptr_t)trk ) )
-LOG( log_undo, 2, ( " UndoNew( T%d )\n", trk->index ) )
-
- if (recordUndo)
- Rprintf( " NEW T%d @%lx\n", trk->index, (long)trk );
+ if (recordUndo) {
+ Rprintf( " NEW T%d @"SLOG_FMT"\n", trk->index, (uintptr_t)trk );
+ }
UASSERT(undoCount==0, undoCount);
UASSERT(undoHead >= 0, undoHead);
us = &undoStack[undoHead];
trk->new = TRUE;
- if (us->newTrks == NULL)
+ if (us->newTrks == NULL) {
us->newTrks = trk;
+ }
us->newCnt++;
-
+
return TRUE;
}
+/**
+ * End of a Undo transaction
+ */
void UndoEnd( void )
{
- if (recordUndo) Rprintf( "End[%d] d:%d\n", undoHead, doCount );
+ if (recordUndo) { Rprintf( "End[%d] d:%d\n", undoHead, doCount ); }
/*undoActive = FALSE;*/
if ( needAttachTrains ) {
AttachTrains();
@@ -758,10 +1026,13 @@ void UndoEnd( void )
}
+/**
+ * Reset the Undo state
+ */
void UndoClear( void )
{
int inx;
-LOG( log_undo, 2, ( " UndoClear()\n" ) )
+ LOG( log_undo, 2, ( " UndoClear()\n" ) )
undoActive = FALSE;
undoHead = -1;
undoCount = 0;
@@ -775,8 +1046,19 @@ LOG( log_undo, 2, ( " UndoClear()\n" ) )
}
-BOOL_T UndoUndo( void )
+EXPORT wBool_t undoStatus = TRUE;
+
+/**
+ * Undo the last transaction
+ *
+ * Move any New tracks from the end of the Track list
+ * Cut the Track list at us->newTrks
+ * Read Modified/Deleted tracks from undoSteam
+ * Cleanup: redraw, update elevs, cars, counts, ...
+ */
+void UndoUndo( void * unused )
{
+ undoStatus = FALSE;
undoStack_p us;
track_p trk;
wIndex_t oldCount;
@@ -784,44 +1066,45 @@ BOOL_T UndoUndo( void )
if (doCount <= 0) {
ErrorMessage( MSG_NO_UNDO );
- return FALSE;
+ return;
}
ConfirmReset( FALSE );
wDrawDelayUpdate( mainD.d, TRUE );
us = &undoStack[undoHead];
-LOG( log_undo, 1, ( " undoUndo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt ) )
- if (recordUndo) Rprintf( "Undo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt );
+ LOG( log_undo, 1, ( " UndoUndo[%d] d:%d u:%d N:%d M:%d D:%d %s\n", undoHead,
+ doCount, undoCount, us->newCnt, us->modCnt, us->delCnt,
+ us->needRedo?"Redo":"" ) )
+ if (recordUndo) { Rprintf( "Undo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt ); }
//redrawAll = (us->newCnt+us->modCnt) > incrementalDrawLimit;
- redrawAll = TRUE;
+ redrawAll = TRUE;
if (!redrawAll) {
- for (trk=us->newTrks; trk; trk=trk->next )
+ for (trk=us->newTrks; trk; trk=trk->next ) {
UndrawNewTrack( trk );
+ }
RedrawInStream( &undoStream, us->undoStart, us->undoEnd, FALSE );
}
- if (us->needRedo)
+ if (us->needRedo) {
us->redoStart = us->redoEnd = redoStream.end;
- for (trk=us->newTrks; trk; trk=trk->next ) {
- if (recordUndo) Rprintf(" Deleting New Track T%d @ %lx\n", trk->index, (long)trk );
- UASSERT( !IsTrackDeleted(trk), (long)trk );
- trk->deleted = TRUE;
}
- if (!(us->oldTail=FindParent(us->newTrks,__LINE__)))
- return FALSE;
+ if (!(us->oldTail=FindParent(us->newTrks,__LINE__))) {
+ return;
+ }
us->newTail = to_last;
to_last = us->oldTail;
*to_last = NULL;
-
needAttachTrains = FALSE;
undoStream.curr = us->undoStart;
while ( undoStream.curr < us->undoEnd ) {
- if (!ReadObject( &undoStream, us->needRedo ))
- return FALSE;
+ if (!ReadObject( &undoStream, us->needRedo )) {
+ return;
+ }
}
- if (us->needRedo)
+ if (us->needRedo) {
us->redoEnd = redoStream.end;
+ }
us->needRedo = FALSE;
if ( needAttachTrains ) {
@@ -829,10 +1112,11 @@ LOG( log_undo, 1, ( " undoUndo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doC
needAttachTrains = FALSE;
}
UpdateAllElevations();
- if (!redrawAll)
+ if (!redrawAll) {
RedrawInStream( &undoStream, us->undoStart, us->undoEnd, TRUE );
- else
+ } else {
DoRedraw();
+ }
oldCount = trackCount;
trackCount = us->trackCount;
@@ -847,12 +1131,21 @@ LOG( log_undo, 1, ( " undoUndo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doC
SetButtons( doCount>0, TRUE );
wBalloonHelpUpdate();
wDrawDelayUpdate( mainD.d, FALSE );
- return TRUE;
+ undoStatus = TRUE;
+ return;
}
-BOOL_T UndoRedo( void )
+/**
+ * Undo and last Undo op
+ *
+ * Attach the New tracks to the end of the Track list
+ * Read Modified/Deleted object from redoStream
+ * Cleanup: redraw, update elevs, cars, counts, ...
+ */
+void UndoRedo( void * unused )
{
+ undoStatus = FALSE;
undoStack_p us;
wIndex_t oldCount;
BOOL_T redrawAll;
@@ -860,38 +1153,35 @@ BOOL_T UndoRedo( void )
if (undoCount <= 0) {
ErrorMessage( MSG_NO_REDO );
- return FALSE;
+ return;
}
ConfirmReset( FALSE );
wDrawDelayUpdate( mainD.d, TRUE );
INC_UNDO_INX( undoHead );
us = &undoStack[undoHead];
-LOG( log_undo, 1, ( " undoRedo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt ) )
- if (recordUndo) Rprintf( "Redo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt );
+ LOG( log_undo, 1, ( " UndoRedo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead,
+ doCount, undoCount, us->newCnt, us->modCnt, us->delCnt ) )
+ if (recordUndo) { Rprintf( "Redo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doCount, undoCount, us->newCnt, us->modCnt, us->delCnt ); }
//redrawAll = (us->newCnt+us->modCnt) > incrementalDrawLimit;
- redrawAll = TRUE;
+ redrawAll = TRUE;
if (!redrawAll) {
RedrawInStream( &redoStream, us->redoStart, us->redoEnd, FALSE );
}
- for (trk=us->newTrks; trk; trk=trk->next ) {
- if (recordUndo) Rprintf(" Undeleting New Track T%d @ %lx\n", trk->index, (long)trk );
- UASSERT( IsTrackDeleted(trk), (long)trk );
- trk->deleted = FALSE;
- }
- UASSERT( us->newTail != NULL, (long)us->newTail );
+ UASSERT2( us->newTail != NULL, (uintptr_t)us->newTail );
*to_last = us->newTrks;
to_last = us->newTail;
- UASSERT( (*to_last) == NULL, (long)*to_last );
+ UASSERT2( (*to_last) == NULL, (uintptr_t)*to_last );
RenumberTracks();
needAttachTrains = FALSE;
redoStream.curr = us->redoStart;
while ( redoStream.curr < us->redoEnd ) {
- if (!ReadObject( &redoStream, FALSE ))
- return FALSE;
+ if (!ReadObject( &redoStream, FALSE )) {
+ return;
+ }
}
if ( needAttachTrains ) {
@@ -900,11 +1190,13 @@ LOG( log_undo, 1, ( " undoRedo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doC
}
UpdateAllElevations();
if (!redrawAll) {
- for (trk=us->newTrks; trk; trk=trk->next )
+ for (trk=us->newTrks; trk; trk=trk->next ) {
DrawNewTrack( trk );
+ }
RedrawInStream( &redoStream, us->redoStart, us->redoEnd, TRUE );
- } else
+ } else {
DoRedraw();
+ }
oldCount = trackCount;
trackCount = us->trackCount;
@@ -919,7 +1211,8 @@ LOG( log_undo, 1, ( " undoRedo[%d] d:%d u:%d N:%d M:%d D:%d\n", undoHead, doC
SetButtons( TRUE, undoCount>0 );
wBalloonHelpUpdate();
wDrawDelayUpdate( mainD.d, FALSE );
- return TRUE;
+ undoStatus = TRUE;
+ return;
}