the app that was used to edit supertux.stgt for the new tiles
authorMatthias Braun <matze@braunis.de>
Mon, 22 Nov 2004 01:49:43 +0000 (01:49 +0000)
committerMatthias Braun <matze@braunis.de>
Mon, 22 Nov 2004 01:49:43 +0000 (01:49 +0000)
SVN-Revision: 2127

contrib/tilemanager/Application.cs [new file with mode: 0644]
contrib/tilemanager/Lexer.cs [new file with mode: 0644]
contrib/tilemanager/LispWriter.cs [new file with mode: 0644]
contrib/tilemanager/Parser.cs [new file with mode: 0644]
contrib/tilemanager/README [new file with mode: 0644]
contrib/tilemanager/TODO [new file with mode: 0644]
contrib/tilemanager/Tile.cs [new file with mode: 0644]
contrib/tilemanager/TileSet.cs [new file with mode: 0644]
contrib/tilemanager/tiler.glade [new file with mode: 0644]

diff --git a/contrib/tilemanager/Application.cs b/contrib/tilemanager/Application.cs
new file mode 100644 (file)
index 0000000..49fa912
--- /dev/null
@@ -0,0 +1,478 @@
+using System;
+using System.IO;
+using System.Collections;
+using Gtk;
+using Gdk;
+using Gnome;
+using Glade;
+
+public class Application {
+    [Glade.Widget]
+    private Gtk.Window MainWindow;
+    [Glade.Widget]
+    private Gtk.DrawingArea DrawingArea;
+    [Glade.Widget]
+    private Gtk.CheckButton SolidCheckButton;
+    [Glade.Widget]
+    private Gtk.CheckButton UniSolidCheckButton;
+    [Glade.Widget]
+    private Gtk.CheckButton IceCheckButton;
+    [Glade.Widget]
+    private Gtk.CheckButton WaterCheckButton;
+    [Glade.Widget]
+    private Gtk.CheckButton SlopeCheckButton;
+    [Glade.Widget]
+    private Gtk.CheckButton DontUseCheckButton;
+    [Glade.Widget]
+    private Gtk.Entry DataEntry;
+    [Glade.Widget]
+    private Gtk.Entry AnimSpeedEntry;
+    [Glade.Widget]                 
+    private Gtk.Entry IDEntry;
+    [Glade.Widget]
+    private Gnome.AppBar AppBar;
+    [Glade.Widget]
+    private Gtk.VBox MainLayout;
+    [Glade.Widget]
+    private Gtk.TreeView TileList;
+    [Glade.Widget]
+    private Gtk.Combo TileGroupComboBox;
+    [Glade.Widget]
+    private Gtk.MenuItem AddTileGroupMenu;
+
+    private string tilesetdir;
+    private string tilesetfile;
+    private TileSet tileset;
+    private TileGroup selectedgroup;
+
+    private Tile[] Tiles;
+    private bool[] SelectionArray;
+    private ArrayList Selection = new ArrayList();
+    private int TilesX;
+    private int TilesY;
+    private bool toggling;
+    private bool selecting;
+
+    private string currentimage;
+    private Gdk.Pixbuf pixbuf;
+    
+    public static int Main(string[] args) {
+        Program kit = new Program("tiler", "0.0.1", Modules.UI, args);
+
+        Application app = new Application();
+
+        kit.Run();
+        return 0;
+    }
+
+    public Application() {
+        Glade.XML gxml = new Glade.XML("tiler.glade", null, null);
+        gxml.Autoconnect(this);
+
+        if(MainWindow == null || DrawingArea == null || AppBar == null)
+            throw new Exception("soem widgets not found");
+
+        DrawingArea.AddEvents((int) Gdk.EventMask.ButtonPressMask);
+        DrawingArea.AddEvents((int) Gdk.EventMask.ButtonReleaseMask);
+        DrawingArea.AddEvents((int) Gdk.EventMask.ButtonMotionMask);
+
+        // libglade missed interactivity property :-/
+        MainLayout.Remove(AppBar);
+        AppBar = new AppBar(true, true, PreferencesType.Always);
+        AppBar.UserResponse += new EventHandler(OnAppBarUserResponse);
+        MainLayout.PackStart(AppBar, false, false, 0);
+        AppBar.Show();
+
+        TileGroupComboBox.Entry.Activated 
+            += new EventHandler (OnTileGroupComboBoxEntryActivated);
+        
+        MainWindow.Show();
+    }
+
+    private void OnOpen(object o, EventArgs e) {
+        FileSelection selection = new FileSelection("Select TileSet");
+        selection.OkButton.Clicked += new EventHandler(OnSelectTileSetOk);
+        selection.CancelButton.Clicked += new EventHandler(OnSelectImageCancel);
+        selection.Show();
+    }
+
+    private void OnSelectTileSetOk(object o, EventArgs e) {
+        FileSelection selection = ((FileSelection.FSButton) o).FileSelection;
+        string file = selection.Filename;
+        selection.Destroy();
+
+        try {
+            tileset = new TileSet();
+            tileset.Parse(file);
+            tilesetfile = file;
+            tilesetdir = new FileInfo(file).Directory.ToString();
+        } catch(Exception exception) {
+            ShowException(exception);
+        }
+
+        Selection.Clear();
+        SelectionChanged();
+        FillTileGroupComboBox();
+        FillTileList();
+    }
+
+    private void OnImportImage(object o, EventArgs e) {
+        FileSelection selection = new FileSelection("Select ImageFile");
+        selection.OkButton.Clicked += new EventHandler(OnSelectImageOk);
+        selection.CancelButton.Clicked += new EventHandler(OnSelectImageCancel);
+        selection.Show();                           
+    }
+
+    private void OnSelectImageCancel(object o, EventArgs args) {
+        FileSelection selection = ((FileSelection.FSButton) o).FileSelection;
+        selection.Destroy();
+    }
+    
+    private void OnSelectImageOk(object o, EventArgs args) {
+        FileSelection selection = ((FileSelection.FSButton) o).FileSelection;
+        string file = selection.Filename;
+        selection.Destroy();
+
+        ChangeImage(new FileInfo(file).Name);
+        
+        int startid = tileset.Tiles.Count;
+        for(int y = 0; y < TilesY; ++y) {
+            for(int x = 0; x < TilesX; ++x) {
+                int i = y*TilesX+x;
+                Tile tile = new Tile();                                   
+                tile.ID = startid + i;
+                ImageRegion region = new ImageRegion();
+                region.ImageFile = currentimage;
+                region.Region = new Rectangle(x*32, y*32, 32, 32);
+                tile.Images.Add(region);
+                if(Tiles[i] != null) {
+                    Console.WriteLine(
+                            "Warning Tile in this region already existed...");
+                }
+                Tiles[i] = tile;
+                tileset.Tiles.Add(tile);
+            }
+        }
+
+        FillTileList();
+    }
+
+    private void ChangeImage(string file) {
+        if(file == "") {
+            currentimage = "";
+            pixbuf = null;
+            return;
+        }
+        try {
+            pixbuf = new Pixbuf(tilesetdir + "/" + file);
+            if(pixbuf.Width % 32 != 0 || pixbuf.Height % 32 != 0)
+                throw new Exception(
+                        "Image Width or Height is not a multiple of 32");
+        } catch(Exception e) {
+            ShowException(e);
+            return;
+        }
+        currentimage = new FileInfo(file).Name;
+        TilesX = pixbuf.Width / 32;
+        TilesY = pixbuf.Height / 32;
+        SelectionArray = new bool[TilesX * TilesY];
+        Tiles = new Tile[TilesX * TilesY];
+        
+        // search tileset for tiles with matching image
+        foreach(Tile tile in tileset.Tiles) {
+            if(tile == null)
+                continue;
+            if(tile.Images.Count == 0)
+                continue;
+            ImageRegion region = (ImageRegion) tile.Images[0];
+            if(region.ImageFile == currentimage) {
+                int px = region.Region.X / 32;
+                int py = region.Region.Y / 32;
+                int i = py*TilesX+px;
+                if(i < 0 || i >= Tiles.Length) {
+                    Console.WriteLine("Invalid Imageregion at tile " +
+                            tile.ID);
+                    continue;
+                }
+                if(Tiles[i] != null) {
+                    Console.WriteLine("Multiple tiles for region " +
+                            px*32 + " , " + py*32);
+                    continue;
+                }
+                Tiles[i] = tile;
+            }
+        } 
+
+        /*   DrawingArea.Allocation 
+            = new Gdk.Rectangle(0, 0, pixbuf.Width, pixbuf.Height);*/
+        DrawingArea.WidthRequest = pixbuf.Width;
+        DrawingArea.HeightRequest = pixbuf.Height;
+        DrawingArea.QueueResize();
+    }
+
+    private void OnSave(object o, EventArgs e) {
+        tileset.Write(tilesetfile);
+    }
+
+    private void OnQuit(object o, EventArgs e) {
+        Gtk.Application.Quit();
+    }
+
+    private void OnAbout(object o, EventArgs e) {
+    }
+
+    private void OnRemapTiles(object o, EventArgs e) {
+        AppBar.SetPrompt("Start-ID:", true);
+    }
+
+    private void OnCreateTileGroup(object o, EventArgs e) {
+    }
+
+    private void OnRenameTileGroup(object o, EventArgs e) {
+    }
+
+    private void OnAppBarUserResponse(object o, EventArgs e) {
+        try {
+            if(AppBar.Response == null || AppBar.Response == "" 
+                    || Tiles == null)
+                return;
+        
+            // remap tiles
+            int id;
+            try {
+                id = Int32.Parse(AppBar.Response);
+            } catch(Exception exception) {
+                ShowException(exception);
+                return;
+            }
+            foreach(Tile tile in Selection) {
+                if(tile.ID != -1)
+                    tile.ID = id++;
+            }
+            FillTileList();
+            SelectionChanged();
+        } finally {
+            AppBar.ClearPrompt();
+        }
+    }
+
+    private void OnDrawingAreaExpose(object o, ExposeEventArgs e) {
+        if(pixbuf == null)
+            return;
+
+        Drawable drawable = e.Event.Window;
+        Gdk.GC gc = new Gdk.GC(drawable);
+        drawable.DrawPixbuf(gc, pixbuf, 0, 0, 0, 0,
+                pixbuf.Width, pixbuf.Height, RgbDither.None, 0, 0);
+
+        gc.RgbFgColor = new Color(0xff, 0, 0);
+        foreach(Tile tile in Selection) {
+            System.Drawing.Rectangle rect 
+                = ((ImageRegion) tile.Images[0]).Region;
+            drawable.DrawRectangle(gc, false, rect.X, rect.Y, rect.Width,
+                    rect.Height);
+        }
+
+        e.RetVal = false;
+    }
+
+    private void OnDrawingAreaButtonPress(object o, ButtonPressEventArgs e) {
+        selecting = true;
+        
+        for(int i = 0; i < SelectionArray.Length; ++i)
+            SelectionArray[i] = false;
+        select((int) e.Event.X, (int) e.Event.Y);
+    }
+
+    private void select(int x, int y) {
+        int tile = y/32 * TilesX + x/32;
+        if(tile < 0 || tile >= SelectionArray.Length)
+            return;
+
+        SelectionArray[tile] = true;
+        SelectionArrayChanged();
+    }
+
+    private void OnDrawingAreaMotionNotify(object i, MotionNotifyEventArgs e) {
+        if(!selecting)
+            return;
+        select((int) e.Event.X, (int) e.Event.Y);
+    }
+
+    private void OnDrawingAreaButtonRelease(object o, ButtonPressEventArgs e) {
+        selecting = false;
+    }
+
+    private void OnCheckButtonToggled(object sender, EventArgs e) {
+        if(toggling)
+            return;
+        foreach(Tile tile in Selection) {
+            if(sender == SolidCheckButton)
+                tile.Solid = SolidCheckButton.Active;
+            if(sender == UniSolidCheckButton)
+                tile.UniSolid = UniSolidCheckButton.Active;
+            if(sender == IceCheckButton)
+                tile.Ice = IceCheckButton.Active;
+            if(sender == WaterCheckButton)
+                tile.Water = WaterCheckButton.Active;
+            if(sender == SlopeCheckButton)
+                tile.Slope = SlopeCheckButton.Active;
+            if(sender == DontUseCheckButton)
+                tile.ID = DontUseCheckButton.Active ? -1 : 0;
+        }
+    }
+
+    private void OnEntryChanged(object sender, EventArgs e) {
+        if(toggling)
+            return;
+        foreach(Tile tile in Selection) {
+            try {
+                if(sender == IDEntry)
+                    tile.ID = Int32.Parse(IDEntry.Text);
+                if(sender == DataEntry)
+                    tile.Data = Int32.Parse(DataEntry.Text);
+                if(sender == AnimSpeedEntry)
+                    tile.AnimSpeed = Int32.Parse(AnimSpeedEntry.Text);
+            } catch(Exception exception) {
+                // ignore parse errors for now...
+            }
+        }
+    }
+
+    private void SelectionArrayChanged() {
+        Selection.Clear();
+        for(int i = 0; i < SelectionArray.Length; ++i) {
+            if(!SelectionArray[i])
+                continue;
+            
+            if(Tiles[i] == null) {
+                Console.WriteLine("Tile doesn't exist yet");
+                // TODO ask user to create new tile...
+                continue;
+            }
+            Selection.Add(Tiles[i]);
+        }
+
+        SelectionChanged();
+    }
+
+    private void SelectionChanged() {
+        bool first = true;
+        toggling = true;
+        string nextimage = "";
+        foreach(Tile tile in Selection) {
+            if(first) {
+                SolidCheckButton.Active = tile.Solid;
+                UniSolidCheckButton.Active = tile.UniSolid;
+                IceCheckButton.Active = tile.Ice;
+                WaterCheckButton.Active = tile.Water;
+                SlopeCheckButton.Active = tile.Slope;
+                DontUseCheckButton.Active = tile.ID == -1;
+                DataEntry.Text = tile.Data.ToString();
+                AnimSpeedEntry.Text = tile.AnimSpeed.ToString();
+                IDEntry.Text = tile.ID.ToString();
+                IDEntry.Editable = true;
+                first = false;
+
+                if(tile.Images.Count > 0) {
+                    nextimage = ((ImageRegion) tile.Images[0]).ImageFile;
+                }
+            } else {
+                IDEntry.Text += "," + tile.ID.ToString();
+                IDEntry.Editable = false;
+                if(tile.Images.Count > 0 
+                        && ((ImageRegion) tile.Images[0]).ImageFile != nextimage) {
+                    nextimage = "";
+                    pixbuf = null;       
+                }
+            }
+        }
+        if(nextimage != currentimage)
+            ChangeImage(nextimage);
+        toggling = false;
+        DrawingArea.QueueDraw();
+    }
+
+    private void FillTileList() {
+        TileList.HeadersVisible = true;
+        if(TileList.Columns.Length == 0)
+            TileList.AppendColumn("Tile", new CellRendererText(), "text", 0);
+
+        ListStore store = new ListStore(typeof(string));
+
+        if(selectedgroup == null) {
+            foreach(Tile tile in tileset.Tiles) {
+                if(tile == null)
+                    continue;
+                store.AppendValues(new object[] { tile.ID.ToString() });
+            }
+        } else {
+            foreach(int id in selectedgroup.Tiles) {
+                Tile tile = (Tile) tileset.Tiles[id];
+                if(tile == null) {
+                    Console.WriteLine("tilegroup contains deleted tile");
+                    continue;
+                }
+                store.AppendValues(new object[] { id.ToString() });
+            }
+        }
+        
+        TileList.Model = store;
+        TileList.Selection.Mode = SelectionMode.Multiple;
+    }
+
+    private void FillTileGroupComboBox() {
+        string[] groups = new string[tileset.TileGroups.Count+1];
+        groups[0] = "All";
+
+        //Submenu submenu = new Submenu();
+        for(int i = 0; i < tileset.TileGroups.Count; ++i) {
+            String tilegroup = ((TileGroup) tileset.TileGroups[i]).Name;
+            groups[i+1] = tilegroup;
+            //submenu.Add(new MenuItem(tilegroup));
+        }
+        TileGroupComboBox.PopdownStrings = groups;
+        TileGroupComboBox.Entry.Editable = false;
+
+        //AddTileGroupMenu.Submenu = submenu;
+    }
+
+    private void OnTileGroupComboBoxEntryActivated(object o, EventArgs args) {
+        if(TileGroupComboBox.Entry.Text == "All") {
+            selectedgroup = null;
+        } else {
+            foreach(TileGroup tilegroup in tileset.TileGroups) {
+                if(tilegroup.Name == TileGroupComboBox.Entry.Text) {
+                    selectedgroup = tilegroup;
+                    break;
+                }
+            }
+        }
+        FillTileList();
+    }
+
+    private void OnTileListCursorChanged(object sender, EventArgs e) {
+        Console.WriteLine("Cursor changed.");
+        TreeModel model;
+        TreePath[] selectpaths =
+            TileList.Selection.GetSelectedRows(out model); 
+
+        Selection.Clear();
+        foreach(TreePath path in selectpaths) {
+            TreeIter iter;
+            model.GetIter(out iter, path);
+            int id = Int32.Parse(model.GetValue(iter, 0).ToString());
+            Selection.Add(tileset.Tiles[id]);
+        }
+        SelectionChanged();
+    }
+
+    private void ShowException(Exception e) {
+        MessageDialog dialog = new MessageDialog(MainWindow,
+                DialogFlags.Modal | DialogFlags.DestroyWithParent,
+                MessageType.Error, ButtonsType.Ok,
+                e.Message);
+        dialog.Run();
+        dialog.Destroy();
+    }
+}
diff --git a/contrib/tilemanager/Lexer.cs b/contrib/tilemanager/Lexer.cs
new file mode 100644 (file)
index 0000000..28df77a
--- /dev/null
@@ -0,0 +1,163 @@
+using System;
+using System.Text;
+using System.IO;
+
+namespace Lisp {
+
+public class Lexer {
+    private StreamReader stream;
+    private char[] buffer;
+    private char c;
+    int bufpos;
+    int buflen;
+
+    public class EOFException : Exception {
+    };
+        
+    public enum TokenType {
+        EOF,
+        OPEN_PAREN,
+        CLOSE_PAREN,
+        SYMBOL,
+        STRING,
+        INTEGER,
+        REAL,
+        TRUE,
+        FALSE
+    };
+
+    private StringBuilder TokenStringBuilder;
+    public string TokenString {
+        get { return TokenStringBuilder.ToString(); }
+    }
+    public int LineNumber;
+
+    public Lexer(StreamReader stream) {
+        this.stream = stream;
+        buffer = new char[1025];
+        NextChar();
+    }
+
+    public TokenType GetNextToken() {
+        try {
+            while(Char.IsWhiteSpace(c)) {
+                NextChar();
+                if(c == '\n')
+                    LineNumber++;
+            }
+
+            TokenStringBuilder = new StringBuilder();
+
+            switch(c) {
+                case ';': // comment
+                    while(true) {
+                        NextChar();
+                        if(c == '\n') {
+                            LineNumber++;
+                            break;
+                        }
+                    }
+                    NextChar();
+                    return GetNextToken();
+                case '(':
+                    NextChar();
+                    return TokenType.OPEN_PAREN;
+                case ')':
+                    NextChar();
+                    return TokenType.CLOSE_PAREN;
+                case '"': { // string
+                    int startline = LineNumber;
+                    while(true) {
+                        NextChar();
+                        if(c == '"')
+                            break;
+
+                        if(c == '\\') {
+                            NextChar();
+                            switch(c) {
+                                case 'n':
+                                    c = '\n';
+                                    break;
+                                case 't':
+                                    c = '\t';
+                                    break;
+                            }
+                        }
+                        TokenStringBuilder.Append(c);
+                    }
+                    NextChar();
+                    return TokenType.STRING;
+                }
+                case '#': // constant
+                    NextChar();
+                    while(Char.IsLetterOrDigit(c) || c == '_') {
+                        TokenStringBuilder.Append(c);
+                        NextChar();
+                    }
+                    if(TokenString == "t")
+                        return TokenType.TRUE;
+                    if(TokenString == "f")
+                        return TokenType.FALSE;
+
+                    throw new Exception("Unknown constant '" 
+                            + TokenString + "'");
+                default:
+                    if(Char.IsDigit(c) || c == '-') {
+                        bool have_nondigits = false;
+                        bool have_digits = false;
+                        int have_floating_point = 0;
+
+                        do {
+                            if(Char.IsDigit(c))
+                                have_digits = true;
+                            else if(c == '.')
+                                have_floating_point++;
+                            else if(Char.IsLetter(c) || c == '_')
+                                have_nondigits = true;
+
+                            TokenStringBuilder.Append(c);
+                            NextChar();
+                        } while(!Char.IsWhiteSpace(c) && c != '\"' && c != '('
+                                && c != ')' && c != ';');
+                        
+                        if(have_nondigits || !have_digits
+                                || have_floating_point > 1)
+                            return TokenType.SYMBOL;
+                        else if(have_floating_point == 1)
+                            return TokenType.REAL;
+                        else
+                            return TokenType.INTEGER;
+                    } else {
+                        do {
+                            TokenStringBuilder.Append(c);
+                            NextChar();
+                        } while(!Char.IsWhiteSpace(c) && c != '\"' && c != '('
+                                && c != ')' && c != ';');
+                        
+                        return TokenType.SYMBOL;
+                    }
+            }
+        } catch(EOFException e) {
+            return TokenType.EOF;
+        }
+    }
+
+    private void NextChar() {
+        if(bufpos >= buflen) {
+            if(!stream.BaseStream.CanRead)
+                throw new EOFException();
+            buflen = stream.Read(buffer, 0, 1024);
+            bufpos = 0;
+            // following hack appends an additional ' ' at the end of the file
+            // to avoid problems when parsing symbols/elements and a sudden EOF:
+            // This way we can avoid the need for an unget function.
+            if(!stream.BaseStream.CanRead) {
+                buffer[buflen] = ' ';
+                ++buflen;
+            }
+        }
+        c = buffer[bufpos++];
+    }
+}
+
+}
diff --git a/contrib/tilemanager/LispWriter.cs b/contrib/tilemanager/LispWriter.cs
new file mode 100644 (file)
index 0000000..0ec3a38
--- /dev/null
@@ -0,0 +1,74 @@
+using System;
+using System.IO;
+using System.Collections;
+
+public class LispWriter {
+    private TextWriter stream;
+    private int IndentDepth;
+    private Stack lists = new Stack();
+    
+    public LispWriter(TextWriter stream) {
+        this.stream = stream;
+    }
+
+    public void WriteComment(string comment) {
+        stream.WriteLine("; " + comment);
+    }
+
+    public void StartList(string name) {
+        indent();
+        stream.WriteLine("(" + name);
+        IndentDepth += 2;
+        lists.Push(name);
+    }
+
+    public void EndList(string name) {
+        if(lists.Count == 0)
+            throw new Exception("Trying to close list while none is open");
+        string back = (string) lists.Pop();
+        if(name != back)
+            throw new Exception(
+                    String.Format("Trying to close {0} which is not open", name));
+
+        IndentDepth -= 2;
+        indent();
+        stream.WriteLine(")");
+    }
+
+    public void Write(string name, object value) {
+        indent();
+        stream.Write("(" + name);
+        if(value is string) {
+            stream.Write(" \"" + value.ToString() + "\"");
+        } else if(value is IEnumerable) {
+            foreach(object o in (IEnumerable) value) {
+                stream.Write(" ");
+                WriteValue(o);
+            }
+        } else {
+            stream.Write(" ");
+            WriteValue(value);
+        }
+        stream.WriteLine(")");
+    }
+
+    private void WriteValue(object val) {
+        if(val is bool) {
+            stream.Write((bool) val ? "#t" : "#f");
+        } else if(val is int || val is float) {
+            stream.Write(val.ToString());
+        } else {
+            stream.Write("\"" + val.ToString() + "\"");
+        }
+    }
+
+    public void WriteVerbatimLine(string line) {
+        indent();
+        stream.WriteLine(line);
+    }
+
+    private void indent() {
+        for(int i = 0; i < IndentDepth; ++i)
+            stream.Write(" ");
+    }
+}
diff --git a/contrib/tilemanager/Parser.cs b/contrib/tilemanager/Parser.cs
new file mode 100644 (file)
index 0000000..784893f
--- /dev/null
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+namespace Lisp
+{
+
+public class Parser {
+    public enum LispType {
+        START_LIST,
+        END_LIST,
+        SYMBOL,
+        INTEGER,       
+        STRING,
+        REAL,
+        BOOLEAN
+    };
+    private Lexer lexer;
+    private Lexer.TokenType token;
+    
+    public Parser(StreamReader stream) {
+        lexer = new Lexer(stream);
+    }
+
+    public bool Parse() {
+        token = lexer.GetNextToken();
+        if(delayinc) {
+            depth++;
+            delayinc = false;
+        }
+        if(token == Lexer.TokenType.EOF) {
+            depth = 0;
+            return false;
+        }
+       
+        /*
+        Console.WriteLine("Token: " + token.ToString() + " - " +
+                lexer.TokenString);
+        */
+        switch(token) {
+            case Lexer.TokenType.CLOSE_PAREN:
+                if(depth == 0)
+                    throw new Exception("Parse Error: unexpected )");
+                depth--;
+                type = LispType.END_LIST;
+                break;
+            case Lexer.TokenType.OPEN_PAREN:
+                type = LispType.START_LIST;
+                delayinc = true;
+                break;
+            case Lexer.TokenType.SYMBOL:
+                type = LispType.SYMBOL;
+                break;
+            case Lexer.TokenType.STRING:
+                type = LispType.STRING;
+                break;
+            case Lexer.TokenType.TRUE:
+                type = LispType.BOOLEAN;
+                break;
+            case Lexer.TokenType.INTEGER:
+                type = LispType.INTEGER;
+                break;
+        }
+        return true;
+    }
+
+    private LispType type;
+    public LispType Type {
+        get { return type; }
+    }
+    private bool delayinc;
+    private int depth;
+    public int Depth {
+        get { return depth; }
+    }
+    //public int IntValue
+    public string SymbolValue {
+        get { return lexer.TokenString; }
+    }
+    public string StringValue {
+        get { return lexer.TokenString; }
+    }
+    public int IntegerValue {
+        get { return Int32.Parse(lexer.TokenString); }
+    }
+    public bool BoolValue {
+        get { return StringValue == "t" ? true : false; }
+    }
+}
+
+}
diff --git a/contrib/tilemanager/README b/contrib/tilemanager/README
new file mode 100644 (file)
index 0000000..abc4b0c
--- /dev/null
@@ -0,0 +1,6 @@
+This Tool allows to edit supertux .stgt files in a comfortable manner.
+Warning: This tool is pre-alpha and meant for developers only.
+
+Compilation: You need to have mono and gtk-sharp (with gnome support) installed
+in order to compile and run the app.
+
diff --git a/contrib/tilemanager/TODO b/contrib/tilemanager/TODO
new file mode 100644 (file)
index 0000000..9c2987a
--- /dev/null
@@ -0,0 +1,4 @@
+-display and allow editing of tilegroups
+-show tile images next to tile numbers
+-allow removing of tiles
+-undo ?
diff --git a/contrib/tilemanager/Tile.cs b/contrib/tilemanager/Tile.cs
new file mode 100644 (file)
index 0000000..5c03147
--- /dev/null
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Drawing;
+using Lisp;
+
+public class ImageRegion {
+    public String ImageFile;
+    public Rectangle Region;
+}
+
+public class Tile {
+    public int ID;
+    public bool Solid;
+    public bool UniSolid;
+    public bool Ice;
+    public bool Water;
+    public bool Slope;
+    public bool Spike;
+    public bool FullBox;
+    public bool Brick;
+    public bool Coin;
+    public bool Goal;
+    public int NextTile;
+    public int Data;
+    public int AnimSpeed;
+    public string EditorImage;
+    public ArrayList Images = new ArrayList();
+
+    public Tile() {
+        ID = -1;
+        NextTile = -1;
+        AnimSpeed = 25;
+    }
+
+    public void Write(LispWriter writer) {
+        writer.StartList("tile");
+        writer.Write("id", ID);
+
+        if(Images.Count > 0) {
+            writer.StartList("images");
+            foreach(ImageRegion region in Images) {
+                if(region.Region.Width != 0) {
+                    writer.WriteVerbatimLine(
+                            String.Format("(region \"{0}\" {1} {2} {3} {4})",
+                                region.ImageFile, region.Region.Left,
+                                region.Region.Top, region.Region.Width,
+                                region.Region.Height));
+                } else {
+                    writer.WriteVerbatimLine(
+                            "\"" + region.ImageFile + "\"");
+                }
+            }
+            writer.EndList("images");
+        } else {
+            Console.WriteLine("no images on tile " + ID);
+        }
+        
+        if(Solid)
+            writer.Write("solid", true);
+        if(UniSolid)
+            writer.Write("unisolid", true);
+        if(Ice)
+            writer.Write("ice", true);
+        if(Water)
+            writer.Write("water", true);
+        if(Slope)
+            writer.Write("slope-type", Data);
+        if(Spike)
+            writer.Write("spike", true);
+        if(Coin)
+            writer.Write("distro", true);
+        if(FullBox)
+            writer.Write("fullbox", true);
+        if(Brick)
+            writer.Write("brick", true);
+        if(NextTile >= 0)
+            writer.Write("next-tile", NextTile);
+        if(Goal)
+            writer.Write("goal", true);
+        if(EditorImage != null)
+            writer.Write("editor-images", EditorImage);
+        if(Data != 0)
+            writer.Write("data", Data);
+        if(AnimSpeed != 25)
+            writer.Write("animspeed", AnimSpeed);
+        writer.EndList("tile");
+    }
+
+    public void Parse(Lisp.Parser parser) {
+        int d = parser.Depth;
+        while(parser.Parse() && parser.Depth >= d) {
+            if(parser.Depth == d+1) {
+                if(parser.Type != Parser.LispType.SYMBOL)
+                    throw new Exception("expected SYMBOL");
+                string symbol = parser.SymbolValue;
+                parser.Parse();
+                switch(symbol) {
+                    case "id":
+                        ID = parser.IntegerValue;
+                    break;
+                    case "images":
+                        ParseTileImages(parser);
+                        break;
+                    case "editor-images":
+                        EditorImage = parser.StringValue;
+                        break;
+                    case "solid":
+                        Solid = parser.BoolValue;
+                        break;
+                    case "unisolid":
+                        UniSolid = parser.BoolValue;
+                        break;
+                    case "ice":
+                        Ice = parser.BoolValue;
+                        break;
+                    case "water":
+                        Water = parser.BoolValue;
+                        break;
+                    case "slope-type":
+                        Slope = true;
+                        Data = parser.IntegerValue;
+                        break;
+                    case "anim-speed":
+                        AnimSpeed = parser.IntegerValue;
+                        break;
+                    case "spike":
+                        Spike = parser.BoolValue;
+                        break;
+                    case "data":
+                        Data = parser.IntegerValue;
+                        break;
+                    case "next-tile":
+                        Data = parser.IntegerValue;
+                        break;
+                    case "brick":
+                        Brick = parser.BoolValue;
+                        break;
+                    case "fullbox":
+                        FullBox = parser.BoolValue;
+                        break;
+                    case "distro":
+                        Coin = parser.BoolValue;
+                        break;
+                    case "goal":
+                        Goal = parser.BoolValue;
+                        break;
+                    default:
+                        Console.WriteLine("Unknown tile element " + symbol);
+                        break;
+                }
+            }
+        }
+    }
+
+    private void ParseTileImages(Lisp.Parser parser) {
+        if(parser.Type == Parser.LispType.END_LIST)
+            return;
+
+        int d = parser.Depth;
+        do {
+            ImageRegion region = new ImageRegion();
+            if(parser.Type == Parser.LispType.STRING) {
+                region.ImageFile = parser.StringValue;
+            } else if(parser.Type == Parser.LispType.START_LIST) {
+                ParseImageRegion(parser, region);
+            } else {
+                throw new Exception("unexpected lisp data: " + parser.Type);
+            }
+            Images.Add(region);
+        } while(parser.Parse() && parser.Depth >= d);
+    }
+
+    private void ParseImageRegion(Lisp.Parser parser, ImageRegion region) {
+        parser.Parse();
+        if(parser.Type != Parser.LispType.SYMBOL)
+            throw new Exception("expected symbol");
+        if(parser.SymbolValue != "region")
+            throw new Exception("expected region symbol");
+        parser.Parse();
+        if(parser.Type != Parser.LispType.STRING)
+            throw new Exception("expected string");
+        region.ImageFile = parser.StringValue;
+
+        parser.Parse();
+        if(parser.Type != Parser.LispType.INTEGER)
+            throw new Exception("expected integer");
+        region.Region.X = parser.IntegerValue;
+
+        parser.Parse();
+        if(parser.Type != Parser.LispType.INTEGER)
+            throw new Exception("expected integer");
+        region.Region.Y = parser.IntegerValue;
+
+        parser.Parse();
+        if(parser.Type != Parser.LispType.INTEGER)
+            throw new Exception("expected integer");
+        region.Region.Width = parser.IntegerValue;
+
+        parser.Parse();                                    
+        if(parser.Type != Parser.LispType.INTEGER)
+            throw new Exception("expected integer");
+        region.Region.Height = parser.IntegerValue;
+
+        parser.Parse();
+        if(parser.Type != Parser.LispType.END_LIST)
+            throw new Exception("expected END_LIST");
+    }
+}
+
diff --git a/contrib/tilemanager/TileSet.cs b/contrib/tilemanager/TileSet.cs
new file mode 100644 (file)
index 0000000..ec99ecf
--- /dev/null
@@ -0,0 +1,137 @@
+using System;
+using System.IO;
+using System.Collections;
+using Lisp;
+
+public class TileGroup {
+    public string Name;
+    public ArrayList Tiles = new ArrayList();
+
+    public void Write(LispWriter writer) {
+        writer.StartList("tilegroup");
+
+        writer.Write("name", Name);
+        writer.Write("tiles", Tiles);
+
+        writer.EndList("tilegroup");
+    }
+
+    public void Parse(Lisp.Parser parser) {
+        int d = parser.Depth;
+        while(parser.Parse() && parser.Depth >= d) {
+            if(parser.Depth == d+1) {
+                if(parser.Type != Parser.LispType.SYMBOL)
+                    throw new Exception("expected SYMBOL");
+                string symbol = parser.SymbolValue;
+                parser.Parse();
+                switch(symbol) {
+                    case "name":
+                        Name = parser.StringValue;
+                        break;
+                    case "tiles":
+                        do {
+                            Tiles.Add(parser.IntegerValue);
+                        } while(parser.Parse() 
+                                && parser.Type == Parser.LispType.INTEGER);
+                        break;
+                    default:
+                        Console.WriteLine("Unknown section " + symbol);
+                        break;
+                }
+            }
+        }
+    }
+}
+
+public class TileSet {
+    public ArrayList Tiles = new ArrayList();
+    public ArrayList TileGroups = new ArrayList();
+
+    public void Write(string filename) {
+        FileStream fs = new FileStream(filename, FileMode.Create);
+       
+        TextWriter tw = new StreamWriter(fs);
+        LispWriter writer = new LispWriter(tw);
+
+        writer.WriteComment("Generated by tiler");
+        writer.StartList("supertux-tiles");
+        foreach(TileGroup tilegroup in TileGroups) {
+            tilegroup.Write(writer);
+        }
+        foreach(Tile tile in Tiles) {
+            if(tile == null)
+                continue;
+            if(tile.ID >= 0)
+                tile.Write(writer);
+        }
+        writer.EndList("supertux-tiles");
+        tw.Close();
+        fs.Close();
+    }
+    
+    public void Parse(string filename) {
+        FileStream fs = new FileStream(filename, FileMode.Open);
+        StreamReader stream = new StreamReader(fs);
+
+        Lisp.Parser parser = new Lisp.Parser(stream);
+        parser.Parse();
+        if(parser.Type != Parser.LispType.START_LIST)
+            throw new Exception("Expected START_LIST");
+        parser.Parse();
+        if(parser.Type != Parser.LispType.SYMBOL)
+            throw new Exception("Expected symbol");
+        if(parser.SymbolValue != "supertux-tiles")
+            throw new Exception("not a supertux tile files but " +
+                    parser.SymbolValue);
+        ParseTiles(parser);
+
+        stream.Close();
+        fs.Close();
+    }
+
+    public void ParseTiles(Lisp.Parser parser) {
+        Console.WriteLine("ParseTiles...");
+        int d = parser.Depth;
+        while(parser.Parse() && parser.Depth >= d) {
+            if(parser.Depth == d && parser.Type != Parser.LispType.START_LIST) {
+                Console.WriteLine("non-cons type in list...");
+                continue;
+            }
+
+            if(parser.Depth == d+1) {
+                if(parser.Type != Parser.LispType.SYMBOL) {
+                    throw new Exception("Expected symbol in list element");
+                }
+                switch(parser.SymbolValue) {
+                    case "properties":
+                        SkipList(parser);
+                        break;
+                    case "tilegroup":
+                        TileGroup tilegroup = new TileGroup();
+                        tilegroup.Parse(parser);
+                        TileGroups.Add(tilegroup);
+                        break;
+                    case "tile":
+                        Tile tile = new Tile();
+                        tile.Parse(parser);
+                        Console.WriteLine("***ID: " + tile.ID);
+
+                        while(tile.ID >= Tiles.Count)
+                            Tiles.Add(null);
+                        Tiles[tile.ID] = tile;
+                        break;
+                    default:
+                        throw new Exception("Unexpected listentry: " +
+                                parser.SymbolValue);
+                }
+            }
+        }
+    }
+
+    private void SkipList(Lisp.Parser parser) {
+        int d = parser.Depth;
+        while(parser.Parse() && parser.Depth >= d)
+            ;
+    }
+}
+
diff --git a/contrib/tilemanager/tiler.glade b/contrib/tilemanager/tiler.glade
new file mode 100644 (file)
index 0000000..a840818
--- /dev/null
@@ -0,0 +1,623 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkWindow" id="MainWindow">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Tile Manager</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_CENTER</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="delete_event" handler="OnQuit" last_modification_time="Sun, 21 Nov 2004 12:26:12 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="MainLayout">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkMenuBar" id="menubar1">
+         <property name="visible">True</property>
+
+         <child>
+           <widget class="GtkMenuItem" id="menuitem1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Datei</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="menuitem1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="open">
+                     <property name="visible">True</property>
+                     <property name="label">gtk-open</property>
+                     <property name="use_stock">True</property>
+                     <signal name="activate" handler="OnOpen" last_modification_time="Sun, 21 Nov 2004 12:08:44 GMT"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save">
+                     <property name="visible">True</property>
+                     <property name="label">gtk-save</property>
+                     <property name="use_stock">True</property>
+                     <signal name="activate" handler="OnSave" last_modification_time="Sun, 21 Nov 2004 14:26:54 GMT"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="beenden1">
+                     <property name="visible">True</property>
+                     <property name="label">gtk-quit</property>
+                     <property name="use_stock">True</property>
+                     <signal name="activate" handler="OnQuit" last_modification_time="Sun, 21 Nov 2004 12:21:15 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="edit1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">Edit</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="edit1_menu">
+
+                 <child>
+                   <widget class="GtkMenuItem" id="import_image1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Import Image</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="OnImportImage" last_modification_time="Sun, 21 Nov 2004 22:13:54 GMT"/>
+                     <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkMenuItem" id="remap_tiles1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Remap Tiles</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="OnRemapTiles" last_modification_time="Sun, 21 Nov 2004 15:18:43 GMT"/>
+                     <accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="trennlinie1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkMenuItem" id="create_tilegroup1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Create TileGroup</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="OnCreateTileGroup" last_modification_time="Mon, 22 Nov 2004 00:20:28 GMT"/>
+                     <accelerator key="C" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkMenuItem" id="item2">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Rename TileGroup</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="OnRenameTileGroup" last_modification_time="Mon, 22 Nov 2004 00:21:52 GMT"/>
+                     <accelerator key="R" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkMenuItem" id="AddTileGroupMenu">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Add Tiles To Group</property>
+                     <property name="use_underline">True</property>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="menuitem4">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Hilfe</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="menuitem4_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="info1">
+                     <property name="visible">True</property>
+                     <property name="label">gtk-dialog-info</property>
+                     <property name="use_stock">True</property>
+                     <signal name="activate" handler="OnAbout" last_modification_time="Sun, 21 Nov 2004 12:08:44 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHPaned" id="hpaned1">
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="position">180</property>
+
+         <child>
+           <widget class="GtkVBox" id="vbox3">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow1">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+                 <property name="shadow_type">GTK_SHADOW_NONE</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTreeView" id="TileList">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="headers_visible">True</property>
+                     <property name="rules_hint">False</property>
+                     <property name="reorderable">False</property>
+                     <property name="enable_search">True</property>
+                     <signal name="cursor_changed" handler="OnTileListCursorChanged" last_modification_time="Sun, 21 Nov 2004 23:04:22 GMT"/>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkCombo" id="TileGroupComboBox">
+                 <property name="visible">True</property>
+                 <property name="value_in_list">False</property>
+                 <property name="allow_empty">True</property>
+                 <property name="case_sensitive">False</property>
+                 <property name="enable_arrow_keys">True</property>
+                 <property name="enable_arrows_always">False</property>
+
+                 <child internal-child="entry">
+                   <widget class="GtkEntry" id="entry1">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">True</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                   </widget>
+                 </child>
+
+                 <child internal-child="list">
+                   <widget class="GtkList" id="list1">
+                     <property name="visible">True</property>
+                     <property name="selection_mode">GTK_SELECTION_BROWSE</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVBox" id="vbox2">
+             <property name="visible">True</property>
+             <property name="homogeneous">False</property>
+             <property name="spacing">0</property>
+
+             <child>
+               <widget class="GtkDrawingArea" id="DrawingArea">
+                 <property name="visible">True</property>
+                 <signal name="expose_event" handler="OnDrawingAreaExpose" last_modification_time="Sun, 21 Nov 2004 13:01:22 GMT"/>
+                 <signal name="button_press_event" handler="OnDrawingAreaButtonPress" last_modification_time="Sun, 21 Nov 2004 13:18:28 GMT"/>
+                 <signal name="motion_notify_event" handler="OnDrawingAreaMotionNotify" last_modification_time="Sun, 21 Nov 2004 13:18:45 GMT"/>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkLabel" id="label2">
+                 <property name="visible">True</property>
+                 <property name="label" translatable="yes">Flags:</property>
+                 <property name="use_underline">False</property>
+                 <property name="use_markup">False</property>
+                 <property name="justify">GTK_JUSTIFY_LEFT</property>
+                 <property name="wrap">False</property>
+                 <property name="selectable">False</property>
+                 <property name="xalign">0.5</property>
+                 <property name="yalign">0.5</property>
+                 <property name="xpad">0</property>
+                 <property name="ypad">0</property>
+               </widget>
+               <packing>
+                 <property name="padding">6</property>
+                 <property name="expand">False</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkTable" id="table1">
+                 <property name="border_width">6</property>
+                 <property name="visible">True</property>
+                 <property name="n_rows">6</property>
+                 <property name="n_columns">2</property>
+                 <property name="homogeneous">False</property>
+                 <property name="row_spacing">6</property>
+                 <property name="column_spacing">6</property>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="SolidCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">Solid</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 13:41:46 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">0</property>
+                     <property name="bottom_attach">1</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="UniSolidCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">UniSolid</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 13:42:00 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">0</property>
+                     <property name="bottom_attach">1</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="IceCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">Ice</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 13:42:08 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">1</property>
+                     <property name="bottom_attach">2</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="WaterCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">Water</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 13:42:17 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">1</property>
+                     <property name="bottom_attach">2</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="SlopeCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">Slope</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 13:42:25 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">2</property>
+                     <property name="bottom_attach">3</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label3">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">Data:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">3</property>
+                     <property name="bottom_attach">4</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkEntry" id="DataEntry">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">True</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                     <signal name="changed" handler="OnEntryChanged" last_modification_time="Sun, 21 Nov 2004 13:42:39 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">3</property>
+                     <property name="bottom_attach">4</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label4">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">AnimSpeed:</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">4</property>
+                     <property name="bottom_attach">5</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkEntry" id="AnimSpeedEntry">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">True</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                     <signal name="changed" handler="OnEntryChanged" last_modification_time="Sun, 21 Nov 2004 13:42:48 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">4</property>
+                     <property name="bottom_attach">5</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkLabel" id="label5">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">ID</property>
+                     <property name="use_underline">False</property>
+                     <property name="use_markup">False</property>
+                     <property name="justify">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap">False</property>
+                     <property name="selectable">False</property>
+                     <property name="xalign">0</property>
+                     <property name="yalign">0.5</property>
+                     <property name="xpad">0</property>
+                     <property name="ypad">0</property>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">0</property>
+                     <property name="right_attach">1</property>
+                     <property name="top_attach">5</property>
+                     <property name="bottom_attach">6</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkEntry" id="IDEntry">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">True</property>
+                     <property name="visibility">True</property>
+                     <property name="max_length">0</property>
+                     <property name="text" translatable="yes"></property>
+                     <property name="has_frame">True</property>
+                     <property name="invisible_char" translatable="yes">*</property>
+                     <property name="activates_default">False</property>
+                     <signal name="changed" handler="OnEntryChanged" last_modification_time="Sun, 21 Nov 2004 13:42:57 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">5</property>
+                     <property name="bottom_attach">6</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckButton" id="DontUseCheckButton">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="label" translatable="yes">Don't Use</property>
+                     <property name="use_underline">True</property>
+                     <property name="relief">GTK_RELIEF_NORMAL</property>
+                     <property name="focus_on_click">True</property>
+                     <property name="active">False</property>
+                     <property name="inconsistent">False</property>
+                     <property name="draw_indicator">True</property>
+                     <signal name="toggled" handler="OnCheckButtonToggled" last_modification_time="Sun, 21 Nov 2004 15:16:11 GMT"/>
+                   </widget>
+                   <packing>
+                     <property name="left_attach">1</property>
+                     <property name="right_attach">2</property>
+                     <property name="top_attach">2</property>
+                     <property name="bottom_attach">3</property>
+                     <property name="x_options">fill</property>
+                     <property name="y_options"></property>
+                   </packing>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="padding">0</property>
+                 <property name="expand">True</property>
+                 <property name="fill">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GnomeAppBar" id="AppBar">
+         <property name="visible">True</property>
+         <property name="has_progress">True</property>
+         <property name="has_status">True</property>
+         <signal name="user_response" handler="OnAppBarUserResponse" last_modification_time="Sun, 21 Nov 2004 15:23:58 GMT"/>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>