A simple Undo/Redo feature? (VC# 2008 express + WinForms + SDL.NET)

Started by
-1 comments, last by the_qwert 14 years, 1 month ago
I've been making on a tile editor for a re-make of Legend of Zelda: Link's Awakening I'm working on, an I found myself at a bit of a hold-up when I tried to implement an Undo / Redo feature. The problem I've been having is basically this: I draw a pixel to the image, and hit the redo button, and the program changes the pixel back to it's original state, but only until it updates the surface (via the updateCurrentTile() method below) I have the image stored to, whereupon it brings it back to the state before I hit the undo button (nullifying the effects of the undo). Right now I'm using an instance of the Stack class to store the history states, and I'm pushing a new state on the stack whenever a mouse button is pressed, and popping one off when the user hits Undo. Here's the parts of the source that should be having some effect: Sorry if it's a bit disjointed though, I'm mostly a self-taught programmer, so I'm not sure if I'm doing things as people normally would.

        public struct Tile
        {
            public short DefaultPalette;

            public Surface Image;
            public Surface Image1x;
            public Surface Image2x;
            public Surface ImageFullSize;

            public byte[,] ColorData;

            public double scale;

            public Tile(Tile t)
            {
                this = t.Clone();
            }

            public Tile Clone()
            {
                Tile t = new Tile();

                t.DefaultPalette = this.DefaultPalette;
                t.Image = this.Image;
                t.Image1x = this.Image1x;
                t.Image2x = this.Image2x;
                t.ImageFullSize = this.ImageFullSize;
                t.ColorData = this.ColorData;
                t.scale = this.scale;

                return t;
            }
        }
...

        //The tile that is currently being edited.
        public static Tile curTile;

        //History stack for undo actions.
        public static Stack<Tile> tileUndoStack;

...

        public bool updateCurrentTile()
        {
            Color[,] TileColor = new Color[TileSize, TileSize];

            for (int i = 0; i < TileSize; i++)
            {
                for (int j = 0; j < TileSize; j++)
                {
                    try
                    {
                        byte color = curTile.ColorData[i, j];

                        TileColor[i, j] = Palettes[curPalette].colors;

                        <span class="cpp-comment">//curTile.ColorData[i, j] = color;</span>
                    }
                    <span class="cpp-keyword">catch</span> (Exception ex)
                    {
                        <span class="cpp-keyword">return</span> <span class="cpp-keyword">false</span>;
                    }
                }
            }

            curTile.Image.SetPixels(<span class="cpp-keyword">new</span> Point(<span class="cpp-number">0</span>, <span class="cpp-number">0</span>), TileColor);
            curTile.Image1x = curTile.Image.CreateScaledSurface(curTile.scale, <span class="cpp-keyword">false</span>);
            curTile.Image2x = curTile.Image.CreateScaledSurface(<span class="cpp-number">2</span>.<span class="cpp-number">0</span> * curTile.scale, <span class="cpp-keyword">false</span>);
            curTile.ImageFullSize = curTile.Image.CreateScaledSurface(<span class="cpp-number">10</span>.<span class="cpp-number">0</span> * curTile.scale, <span class="cpp-keyword">false</span>);

            <span class="cpp-keyword">return</span> <span class="cpp-keyword">true</span>;
        }


        <span class="cpp-comment">//Called when a mouse button is clicked over the SDL WinForm control</span>
        <span class="cpp-keyword">private</span> <span class="cpp-keyword">void</span> surfaceControl1_MouseDown(object sender, MouseEventArgs e)
        {

            <span class="cpp-keyword">if</span> (e.X &gt;= <span class="cpp-number">70</span> &amp;&amp; e.X &lt; <span class="cpp-number">390</span>)
            {
                <span class="cpp-keyword">if</span> (e.Y &gt;= <span class="cpp-number">70</span> &amp;&amp; e.Y &lt; <span class="cpp-number">390</span>)<span class="cpp-comment">//If the cursor is over the edit-able tile</span>
                {
                    tileUndoStack.Push(curTile);<span class="cpp-comment">//Make's a history state</span>

                    <span class="cpp-keyword">int</span> x = (<span class="cpp-keyword">int</span>)(Math.Floor(((e.X - <span class="cpp-number">70</span>) / <span class="cpp-number">10</span>.<span class="cpp-number">0</span>) / curTile.scale));
                    <span class="cpp-keyword">int</span> y = (<span class="cpp-keyword">int</span>)(Math.Floor(((e.Y - <span class="cpp-number">70</span>) / <span class="cpp-number">10</span>.<span class="cpp-number">0</span>) / curTile.scale));

                    <span class="cpp-keyword">if</span> (e.Button == MouseButtons.Left)
                    {
                        <span class="cpp-keyword">if</span> (curTile.ColorData[x, y] != curColor[<span class="cpp-number">0</span>])
                        {
                            curTile.ColorData[x, y] = curColor[<span class="cpp-number">0</span>];<span class="cpp-comment">// Change that pixel's color to the currently selected color for the left mouse button</span>
                            updateCurrentTile();
                        }
                    }
                    <span class="cpp-keyword">else</span> <span class="cpp-keyword">if</span> (e.Button == MouseButtons.Right)
                    {
                        <span class="cpp-keyword">if</span> (curTile.ColorData[x, y] != curColor[<span class="cpp-number">1</span>])
                        {
                            curTile.ColorData[x, y] = curColor[<span class="cpp-number">1</span>];<span class="cpp-comment">// Change that pixel's color to the currently selected color for the right mouse button</span>
                            updateCurrentTile();
                        }
                    }
                }
            }
        }


        <span class="cpp-comment">//Called when the user click the undo button</span>
        <span class="cpp-keyword">private</span> <span class="cpp-keyword">void</span> undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            <span class="cpp-keyword">if</span> (Mode == EditorMode.Tile)
            {
                <span class="cpp-keyword">if</span> (tileUndoStack.Count &gt; <span class="cpp-number">0</span>)
                {
                    <span class="cpp-keyword">int</span> index = tileUndoStack.Count - <span class="cpp-number">1</span>;

                    curTile = tileUndoStack.Pop();

                    updateCurrentTile();

                    <span class="cpp-keyword">if</span> (tileUndoStack.Count == <span class="cpp-number">0</span>)
                    {
                        Action enableAction = delegate() { undoToolStripMenuItem.Enabled = <span class="cpp-keyword">false</span>; };
                        <span class="cpp-keyword">this</span>.BeginInvoke(enableAction);

                    }
                }
            }
        }


</pre></div><!–ENDSCRIPT–>

I've found that the problem <i>seems</i> to be occuring when updateCurrentTile is called in undoToolStripMenuItem_Click().

Thanks in advance for any help!

This topic is closed to new replies.

Advertisement