3 using System.Collections;
9 public class Application {
11 private Gtk.Window MainWindow;
13 private Gtk.DrawingArea DrawingArea;
15 private Gtk.CheckButton SolidCheckButton;
17 private Gtk.CheckButton UniSolidCheckButton;
19 private Gtk.CheckButton IceCheckButton;
21 private Gtk.CheckButton WaterCheckButton;
23 private Gtk.CheckButton SlopeCheckButton;
25 private Gtk.CheckButton DontUseCheckButton;
27 private Gtk.CheckButton HiddenCheckButton;
29 private Gtk.Entry DataEntry;
31 private Gtk.Entry AnimFpsEntry;
33 private Gtk.Entry IDEntry;
35 private Gnome.AppBar AppBar;
37 private Gtk.VBox MainLayout;
39 private Gtk.TreeView TileList;
41 private Gtk.Combo TileGroupComboBox;
43 private Gtk.MenuItem AddTileGroupMenu;
45 private string tilesetdir;
46 private string tilesetfile;
47 private TileSet tileset;
48 private TileGroup selectedgroup;
51 private bool[] SelectionArray;
52 private ArrayList Selection = new ArrayList();
55 private bool toggling;
56 private bool selecting;
58 private string currentimage;
59 private Gdk.Pixbuf pixbuf;
61 public static int Main(string[] args) {
62 Gtk.Application.Init();
64 Application app = new Application();
66 /* that's no proper commandlineparsing, but who'll notice... */
68 app.LoadTileSet(args[0]);
70 Gtk.Application.Run();
74 public Application() {
75 Glade.XML gxml = new Glade.XML(null, "tiler.glade", null, null);
76 gxml.Autoconnect(this);
78 if(MainWindow == null || DrawingArea == null || AppBar == null)
79 throw new Exception("some widgets not found");
81 DrawingArea.AddEvents((int) Gdk.EventMask.ButtonPressMask);
82 DrawingArea.AddEvents((int) Gdk.EventMask.ButtonReleaseMask);
83 DrawingArea.AddEvents((int) Gdk.EventMask.ButtonMotionMask);
85 // libglade missed interactivity property :-/
86 MainLayout.Remove(AppBar);
87 AppBar = new AppBar(true, true, PreferencesType.Always);
88 AppBar.UserResponse += new EventHandler(OnAppBarUserResponse);
89 MainLayout.PackStart(AppBar, false, false, 0);
95 protected void OnOpen(object o, EventArgs e) {
96 FileChooserDialog fileChooser = new FileChooserDialog("Select TileSet", MainWindow, FileChooserAction.Open, new object[] {});
98 fileChooser.AddButton(Gtk.Stock.Cancel, Gtk.ResponseType.Cancel);
99 fileChooser.AddButton(Gtk.Stock.Ok, Gtk.ResponseType.Ok);
100 fileChooser.DefaultResponse = Gtk.ResponseType.Ok;
101 Gtk.FileFilter filter;
102 filter = new Gtk.FileFilter();
103 filter.Name = "Supertux 0.1.x tilesets";
104 filter.AddPattern("*.stgt");
105 fileChooser.AddFilter( filter );
106 filter = new Gtk.FileFilter();
107 filter.Name = "Supertux tilesets";
108 filter.AddPattern("*.strf");
109 filter.AddPattern("*.stgt");
110 fileChooser.AddFilter( filter );
111 filter = new Gtk.FileFilter();
112 filter.Name = "Supertux 0.3.x tilesets";
113 filter.AddPattern("*.strf");
114 fileChooser.AddFilter( filter );
115 Gtk.FileFilter all = new Gtk.FileFilter();
116 all.Name = "All Files";
118 fileChooser.AddFilter( all );
119 int result = fileChooser.Run();
122 if(result != (int) ResponseType.Ok)
125 LoadTileSet(fileChooser.Filename);
128 private void LoadTileSet(string file) {
130 tileset = new TileSet();
133 tilesetdir = new FileInfo(file).Directory.ToString();
134 } catch(Exception exception) {
135 ShowException(exception);
140 FillTileGroupComboBox();
144 protected void OnImportImage(object o, EventArgs e) {
145 FileChooserDialog fileChooser = new FileChooserDialog("Select ImageFile", MainWindow, FileChooserAction.Open, new object[] {});
147 fileChooser.AddButton(Gtk.Stock.Cancel, Gtk.ResponseType.Cancel);
148 fileChooser.AddButton(Gtk.Stock.Ok, Gtk.ResponseType.Ok);
149 fileChooser.DefaultResponse = Gtk.ResponseType.Ok;
150 Gtk.FileFilter all = new Gtk.FileFilter();
151 all.Name = "All Files";
153 fileChooser.AddFilter( all );
154 int result = fileChooser.Run();
157 if(result != (int) ResponseType.Ok)
160 string file = fileChooser.Filename;
161 string trim = tilesetdir + "/";
163 if (!file.StartsWith(trim)){
165 "Imported file must be located inside tileset directory");
169 ChangeImage(file.TrimStart(trim.ToCharArray()));
171 int startid = tileset.Tiles.Count;
172 for(int y = 0; y < TilesY; ++y) {
173 for(int x = 0; x < TilesX; ++x) {
175 Tile tile = new Tile();
176 tile.ID = startid + i;
177 ImageRegion region = new ImageRegion();
178 region.ImageFile = currentimage;
179 region.Region = new System.Drawing.Rectangle(x*32, y*32, 32, 32);
180 tile.Images.Add(region);
181 if(Tiles[i] != null) {
183 "Warning Tile in this region already existed...");
186 tileset.Tiles.Add(tile);
193 private void ChangeImage(string file) {
200 pixbuf = new Pixbuf(tilesetdir + "/" + file);
201 if(pixbuf.Width % 32 != 0 || pixbuf.Height % 32 != 0)
202 Console.WriteLine("Warning: Image Width or Height is not a multiple of 32");
203 } catch(Exception e) {
207 currentimage = new FileInfo(file).Name;
208 TilesX = pixbuf.Width / 32;
209 TilesY = pixbuf.Height / 32;
210 SelectionArray = new bool[TilesX * TilesY];
211 Tiles = new Tile[TilesX * TilesY];
213 // search tileset for tiles with matching image
214 foreach(Tile tile in tileset.Tiles) {
217 if(tile.Images.Count == 0)
219 ImageRegion region = (ImageRegion) tile.Images[0];
220 if(region.ImageFile == currentimage) {
221 int px = region.Region.X / 32;
222 int py = region.Region.Y / 32;
223 int i = py*TilesX+px;
224 if(i < 0 || i >= Tiles.Length) {
225 Console.WriteLine("Invalid Imageregion at tile " +
229 if(Tiles[i] != null) {
230 Console.WriteLine("Multiple tiles for region " +
231 px*32 + " , " + py*32);
238 /* DrawingArea.Allocation
239 = new Gdk.Rectangle(0, 0, pixbuf.Width, pixbuf.Height);*/
240 DrawingArea.WidthRequest = pixbuf.Width;
241 DrawingArea.HeightRequest = pixbuf.Height;
242 DrawingArea.QueueResize();
245 protected void OnSave(object o, EventArgs e) {
248 "Sorry, the file you are editing is too new, there will be huge data loss if you save this.");
250 tileset.Write(tilesetfile);
253 protected void OnQuit(object o, EventArgs e) {
254 Gtk.Application.Quit();
257 protected void OnDeleteQuit(object o, DeleteEventArgs e) {
258 Gtk.Application.Quit();
261 protected void OnAbout(object o, EventArgs e) {
262 // string[] authors = new string[]{
266 Gtk.AboutDialog dialog = new Gtk.AboutDialog();
267 // dialog.Icon = <icon>;
268 dialog.ProgramName = "SuperTux Tiler";
269 dialog.Version = "0.0.3";
270 dialog.Comments = "A tileset editor for SuperTux 0.1.x";
271 // dialog.Authors = authors;
272 dialog.Copyright = "Copyright (c) 2006 SuperTux Devel Team";
274 "This program is free software; you can redistribute it and/or modify" + Environment.NewLine +
275 "it under the terms of the GNU General Public License as published by" + Environment.NewLine +
276 "the Free Software Foundation; either version 2 of the License, or" + Environment.NewLine +
277 "(at your option) any later version." + Environment.NewLine +
278 Environment.NewLine +
279 "This program is distributed in the hope that it will be useful," + Environment.NewLine +
280 "but WITHOUT ANY WARRANTY; without even the implied warranty of" + Environment.NewLine +
281 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" + Environment.NewLine +
282 "GNU General Public License for more details." + Environment.NewLine +
283 Environment.NewLine +
284 "You should have received a copy of the GNU General Public License" + Environment.NewLine +
285 "along with this program; if not, write to the Free Software Foundation, Inc.," + Environment.NewLine +
286 "59 Temple Place, Suite 330, Boston, MA 02111-1307 USA" + Environment.NewLine;
287 dialog.Website = "http://supertux.lethargik.org/";
288 dialog.WebsiteLabel = "SuperTux on the Web";
293 protected void OnRemapTiles(object o, EventArgs e) {
294 AppBar.SetPrompt("Start-ID:", true);
297 protected void OnCreateTileGroup(object o, EventArgs e) {
300 protected void OnRenameTileGroup(object o, EventArgs e) {
303 protected void OnAppBarUserResponse(object o, EventArgs e) {
305 if(AppBar.Response == null || AppBar.Response == ""
312 id = Int32.Parse(AppBar.Response);
313 } catch(Exception exception) {
314 ShowException(exception);
319 AppBar.ClearPrompt();
323 protected void RemapTiles(int startID) {
329 foreach(Tile tile in Selection) {
335 // remap in all tilegroups...
336 foreach(TileGroup tilegroup in tileset.TileGroups) {
337 int idx = tilegroup.Tiles.IndexOf(oldid);
339 tilegroup.Tiles[idx] = tile.ID;
347 protected void OnDrawingAreaExpose(object o, ExposeEventArgs e) {
351 Drawable drawable = e.Event.Window;
352 Gdk.GC gc = new Gdk.GC(drawable);
353 drawable.DrawPixbuf(gc, pixbuf, 0, 0, 0, 0,
354 pixbuf.Width, pixbuf.Height, RgbDither.None, 0, 0);
356 gc.RgbFgColor = new Color(0xff, 0, 0);
357 foreach(Tile tile in Selection) {
358 System.Drawing.Rectangle rect
359 = ((ImageRegion) tile.Images[0]).Region;
360 drawable.DrawRectangle(gc, false, rect.X, rect.Y, rect.Width,
367 protected void OnDrawingAreaButtonPress(object o, ButtonPressEventArgs e) {
368 if(SelectionArray == null)
373 for(int i = 0; i < SelectionArray.Length; ++i)
374 SelectionArray[i] = false;
375 select((int) e.Event.X, (int) e.Event.Y);
378 private void select(int x, int y) {
379 int tile = y/32 * TilesX + x/32;
380 if(tile < 0 || tile >= SelectionArray.Length)
383 SelectionArray[tile] = true;
384 SelectionArrayChanged();
387 protected void OnDrawingAreaMotionNotify(object i, MotionNotifyEventArgs e) {
390 select((int) e.Event.X, (int) e.Event.Y);
393 protected void OnDrawingAreaButtonRelease(object o, ButtonPressEventArgs e) {
397 protected void OnCheckButtonToggled(object sender, EventArgs e) {
400 foreach(Tile tile in Selection) {
401 if(sender == SolidCheckButton)
402 tile.Solid = SolidCheckButton.Active;
403 if(sender == UniSolidCheckButton)
404 tile.UniSolid = UniSolidCheckButton.Active;
405 if(sender == IceCheckButton)
406 tile.Ice = IceCheckButton.Active;
407 if(sender == WaterCheckButton)
408 tile.Water = WaterCheckButton.Active;
409 if(sender == SlopeCheckButton)
410 tile.Slope = SlopeCheckButton.Active;
411 if(sender == HiddenCheckButton)
412 tile.Hidden = HiddenCheckButton.Active;
413 if(sender == DontUseCheckButton)
414 tile.ID = DontUseCheckButton.Active ? -1 : 0;
418 protected void OnEntryChanged(object sender, EventArgs e) {
421 foreach(Tile tile in Selection) {
423 if(sender == IDEntry)
424 tile.ID = Int32.Parse(IDEntry.Text);
425 if(sender == DataEntry)
426 tile.Data = Int32.Parse(DataEntry.Text);
427 if(sender == AnimFpsEntry)
428 tile.AnimFps = Single.Parse(AnimFpsEntry.Text);
430 // ignore parse errors for now...
435 private void SelectionArrayChanged() {
437 for(int i = 0; i < SelectionArray.Length; ++i) {
438 if(!SelectionArray[i])
441 if(Tiles[i] == null) {
442 Console.WriteLine("Tile doesn't exist yet");
443 // TODO ask user to create new tile...
446 Selection.Add(Tiles[i]);
452 private void SelectionChanged() {
455 string nextimage = "";
456 foreach(Tile tile in Selection) {
458 SolidCheckButton.Active = tile.Solid;
459 UniSolidCheckButton.Active = tile.UniSolid;
460 IceCheckButton.Active = tile.Ice;
461 WaterCheckButton.Active = tile.Water;
462 SlopeCheckButton.Active = tile.Slope;
463 HiddenCheckButton.Active = tile.Hidden;
464 DontUseCheckButton.Active = tile.ID == -1;
465 DataEntry.Text = tile.Data.ToString();
466 AnimFpsEntry.Text = tile.AnimFps.ToString();
467 IDEntry.Text = tile.ID.ToString();
468 IDEntry.IsEditable = true;
471 if(tile.Images.Count > 0) {
472 nextimage = ((ImageRegion) tile.Images[0]).ImageFile;
475 IDEntry.Text += "," + tile.ID.ToString();
476 IDEntry.IsEditable = false;
477 if(tile.Images.Count > 0
478 && ((ImageRegion) tile.Images[0]).ImageFile != nextimage) {
484 if(nextimage != currentimage)
485 ChangeImage(nextimage);
487 DrawingArea.QueueDraw();
490 private void FillTileList() {
491 TileList.HeadersVisible = true;
492 if(TileList.Columns.Length == 0)
493 TileList.AppendColumn("Tile", new CellRendererText(), "text", 0);
495 ListStore store = new ListStore(typeof(string));
497 if(selectedgroup == null) {
498 foreach(Tile tile in tileset.Tiles) {
501 store.AppendValues(new object[] { tile.ID.ToString() });
504 foreach(int id in selectedgroup.Tiles) {
506 if (id >= tileset.Tiles.Count){
507 Console.WriteLine("Tile ID is above Tiles.Count: " + id.ToString());
510 tile = (Tile) tileset.Tiles[id];
513 Console.WriteLine("tilegroup contains deleted tile");
516 store.AppendValues(new object[] { id.ToString() });
520 TileList.Model = store;
521 TileList.Selection.Mode = SelectionMode.Multiple;
524 private void FillTileGroupComboBox() {
525 string[] groups = new string[tileset.TileGroups.Count+1];
528 //Submenu submenu = new Submenu();
529 for(int i = 0; i < tileset.TileGroups.Count; ++i) {
530 String tilegroup = ((TileGroup) tileset.TileGroups[i]).Name;
531 groups[i+1] = tilegroup;
532 //submenu.Add(new MenuItem(tilegroup));
534 TileGroupComboBox.PopdownStrings = groups;
535 TileGroupComboBox.Entry.IsEditable = false;
537 //AddTileGroupMenu.Submenu = submenu;
540 protected void OnTileGroupComboBoxEntryActivated(object o, EventArgs args) {
541 if(TileGroupComboBox.Entry.Text == "All") {
542 selectedgroup = null;
544 foreach(TileGroup tilegroup in tileset.TileGroups) {
545 if(tilegroup.Name == TileGroupComboBox.Entry.Text) {
546 selectedgroup = tilegroup;
554 protected void OnTileListCursorChanged(object sender, EventArgs e) {
556 TreePath[] selectpaths =
557 TileList.Selection.GetSelectedRows(out model);
560 foreach(TreePath path in selectpaths) {
562 model.GetIter(out iter, path);
563 int id = Int32.Parse(model.GetValue(iter, 0).ToString());
564 Selection.Add(tileset.Tiles[id]);
569 private void ShowException(Exception e) {
570 MessageDialog dialog = new MessageDialog(MainWindow,
571 DialogFlags.Modal | DialogFlags.DestroyWithParent,
572 MessageType.Error, ButtonsType.Ok,