7d7d6ae86909d621765ead3ae0c6305b4b4091b0
[supertux.git] / src / leveleditor.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2003 Ricardo Cruz <rick2@aeiou.pt>
5 //  Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 #include <map>
22 #include <typeinfo>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <SDL.h>
30 #include <SDL_image.h>
31 #include <algorithm>
32
33 #include "leveleditor.h"
34
35 #include "screen/screen.h"
36 #include "defines.h"
37 #include "globals.h"
38 #include "setup.h"
39 #include "sector.h"
40 #include "tilemap.h"
41 #include "gameloop.h"
42 #include "badguy.h"
43 #include "player.h"
44 #include "scene.h"
45 #include "tile.h"
46 #include "resources.h"
47 #include "background.h"
48 #include "camera.h"
49
50 /* definitions to aid development */
51
52 /* definitions that affect gameplay */
53 #define KEY_CURSOR_SPEED 32
54 #define KEY_CURSOR_FASTSPEED 64
55
56 /* when pagedown/up pressed speed:*/
57 #define PAGE_CURSOR_SPEED 13*32
58
59 #define MOUSE_LEFT_MARGIN 80
60 #define MOUSE_RIGHT_MARGIN (560-32)
61
62 /* scolling speed */
63 #define KEYBOARD_SPEED 140
64 #define MOUSE_SPEED    40
65
66 /* look */
67 #define SELECT_W 2 // size of the selections lines
68 #define SELECT_CLR 0, 255, 0, 255  // lines color (R, G, B, A)
69
70 enum { TM_IA, TM_BG, TM_FG };
71
72 LevelEditor::LevelEditor()
73 {
74   level_subsets = dsubdirs("/levels", "level1.stl");
75   le_level_subset = new LevelSubset;
76
77   le_level = NULL;
78   le_levelnb = 1;
79   selected_game_object = NULL;
80
81   active_tm = TM_IA;
82   le_show_grid = true;
83   show_selections = true;
84
85   done = 0;
86   le_frame = 0; /* support for frames in some tiles, like waves and bad guys */
87   le_level_changed = false;
88   le_help_shown = false;
89
90   le_mouse_pressed[LEFT] = false;
91   le_mouse_pressed[RIGHT] = false;
92
93   le_mouse_clicked[LEFT] = false;
94   le_mouse_clicked[RIGHT] = false;
95
96   le_selection = new Surface(datadir + "/images/leveleditor/select.png", USE_ALPHA);
97
98   select_tilegroup_menu_effect.init(false);
99   select_objects_menu_effect.init(false);
100   display_level_info.init(false);
101
102   /* Load buttons */
103   le_save_level_bt = new Button("/images/icons/save.png","Save level", SDLK_F6,screen->w-64,32);
104   le_exit_bt = new Button("/images/icons/exit.png","Exit", SDLK_F10,screen->w-32,32);
105   le_next_level_bt = new Button("/images/icons/next.png","Next level", SDLK_PAGEUP,screen->w-64,0);
106   le_previous_level_bt = new Button("/images/icons/previous.png","Previous level",SDLK_PAGEDOWN,screen->w-32,0);
107   le_rubber_bt = new Button("/images/icons/rubber.png","Rubber",SDLK_DELETE,screen->w-32,48);
108   le_select_mode_one_bt = new Button ("/images/icons/select-mode1.png","Select single tile",SDLK_F3,screen->w-64,48);
109   le_select_mode_two_bt = new Button("/images/icons/select-mode2.png","Select multiple tiles",SDLK_F3,screen->w-64,48);
110   le_test_level_bt = new Button("/images/icons/test-level.png","Test level",SDLK_F4,screen->w-64,screen->h - 64);
111   le_settings_bt = new Button("/images/icons/settings.png","Level settings",SDLK_F5,screen->w-32,screen->h - 64);
112   le_move_left_bt = new Button("/images/icons/left.png","Move left",SDLK_LEFT,screen->w-80-16,0);
113   le_move_right_bt = new Button("/images/icons/right.png","Move right",SDLK_RIGHT,screen->w-80,0);
114   le_move_up_bt = new Button("/images/icons/up.png","Move up",SDLK_UP,screen->w-80,16);
115   le_move_down_bt = new Button("/images/icons/down.png","Move down",SDLK_DOWN,screen->w-80,32);
116   le_tilegroup_bt = new Button("/images/icons/tilegroup.png","Select Tilegroup", SDLK_F7,screen->w-64,64);
117   le_objects_bt = new Button("/images/icons/objects.png","Select Objects", SDLK_F8,screen->w-64,80);
118   le_object_select_bt = new Button("/images/icons/select-one.png","Select an Object", SDLK_s, screen->w - 64, screen->h-98);
119   le_object_properties_bt = new Button("/images/icons/properties.png","Edit object properties", SDLK_p, screen->w - 32, screen->h-98);
120   le_object_properties_bt->set_active(false);
121
122   mouse_select_object = new MouseCursor(datadir + "/images/status/select-cursor.png",1);
123   mouse_select_object->set_mid(16,16);
124
125   le_tilemap_panel = new ButtonPanel(screen->w-64,screen->h-32,32,32);
126   le_tilemap_panel->set_button_size(32,10);
127   le_tilemap_panel->additem(new Button("/images/icons/bkgrd.png","Background",SDLK_b,0,0),TM_BG);
128   le_tilemap_panel->additem(new Button("/images/icons/intact.png","Interactive",SDLK_i,0,0), TM_IA);
129   le_tilemap_panel->additem(new Button("/images/icons/frgrd.png","Foreground",SDLK_f,0,0),TM_FG);
130   le_tilemap_panel->highlight_last(true);
131   le_tilemap_panel->set_last_clicked(TM_IA);
132
133   le_current.Init();
134
135   init_menus();
136
137   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
138 }
139
140 LevelEditor::~LevelEditor()
141 {
142   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
143
144   unload_level();
145   delete le_selection;
146   delete leveleditor_menu;
147   delete subset_load_menu;
148   delete subset_new_menu;
149   delete subset_settings_menu;
150   delete level_settings_menu;
151   delete select_tilegroup_menu;
152   delete select_objects_menu;
153   delete le_save_level_bt;
154   delete le_exit_bt;
155   delete le_test_level_bt;
156   delete le_next_level_bt;
157   delete le_previous_level_bt;
158   delete le_move_right_bt;
159   delete le_move_left_bt;
160   delete le_move_up_bt;
161   delete le_move_down_bt;
162   delete le_rubber_bt;
163   delete le_select_mode_one_bt;
164   delete le_select_mode_two_bt;
165   delete le_settings_bt;
166   delete le_tilegroup_bt;
167   delete le_objects_bt;
168   delete le_tilemap_panel;
169   delete le_object_select_bt;
170   delete le_object_properties_bt;
171   delete mouse_select_object;
172
173   delete le_level_subset;
174   le_level_subset = 0;
175
176   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
177       i != tilegroups_map.end(); ++i)
178   {
179     delete i->second;
180   }
181   for(ButtonPanelMap::iterator i = objects_map.begin();
182       i != objects_map.end(); ++i)
183   {
184     delete i->second;
185   }
186 }
187
188 int LevelEditor::run(char* filename)
189 {
190   int last_time, now_time, i;
191   DrawingContext context;
192
193   le_level = NULL;
194   le_levelnb = 1;
195
196   sound_manager->halt_music();
197
198   while (SDL_PollEvent(&event))
199   {}
200
201   if(filename != NULL)
202     if(load_level_subset(filename))
203       return 1;
204
205   while(true)
206   {
207     last_time = SDL_GetTicks();
208     le_frame++;
209
210     checkevents();
211
212     if(Menu::current() == select_tilegroup_menu)
213     {
214       if(select_tilegroup_menu_effect.check())
215       {
216         select_tilegroup_menu->set_pos(screen->w - 64 + select_tilegroup_menu_effect.get_left(),
217                                        66,-0.5,0.5);
218       }
219       else
220         select_tilegroup_menu->set_pos(screen->w - 64,66,-0.5,0.5);
221     }
222     else if(Menu::current() == select_objects_menu)
223     {
224       if(select_objects_menu_effect.check())
225       {
226         select_objects_menu->set_pos(screen->w - 64 + select_objects_menu_effect.get_left(),82,-0.5,0.5);
227       }
228       else
229         select_objects_menu->set_pos(screen->w - 64,82,-0.5,0.5);
230     }
231
232     if(le_level != NULL)
233     {
234       /* making events results to be in order */
235
236       /* draw the level */
237       drawlevel(context);
238     }
239     else
240       fillrect(0, 0, screen->w, screen->h, 0, 0, 0);
241
242     /* draw editor interface */
243     drawinterface(context);
244
245     Menu* menu = Menu::current();
246     if(menu)
247     {
248       menu->draw(context);
249       menu->action();
250
251       if(menu == leveleditor_menu)
252       {
253         switch (leveleditor_menu->check())
254         {
255         case MNID_RETURNLEVELEDITOR:
256           if(le_level != NULL)
257             Menu::set_current(0);
258           else
259             Menu::set_current(leveleditor_menu);
260           break;
261         case MNID_SUBSETSETTINGS:
262           update_subset_settings_menu();
263           break;
264         case MNID_QUITLEVELEDITOR:
265           done = 1;
266           break;
267         }
268       }
269       else if(menu == level_settings_menu)
270       {
271         switch (level_settings_menu->check())
272         {
273         case MNID_APPLY:
274           apply_level_settings_menu();
275           Menu::set_current(NULL);
276           break;
277
278         default:
279           break;
280         }
281       }
282       else if(menu == select_tilegroup_menu)
283       {
284         int it = -1;
285         switch (it = select_tilegroup_menu->check())
286         {
287         default:
288           if(it >= 0)
289           {
290             cur_tilegroup = select_tilegroup_menu->get_item_by_id(it).text;
291             Menu::set_current(0);
292             cur_objects = "";
293
294           }
295           break;
296         }
297       }
298       else if(menu == select_objects_menu)
299       {
300         int it = -1;
301         switch (it = select_objects_menu->check())
302         {
303         default:
304           if(it >= 0)
305           {
306             cur_objects = select_objects_menu->get_item_by_id(it).text;
307             cur_tilegroup = "";
308
309             Menu::set_current(0);
310           }
311           break;
312         }
313       }
314       else if(menu == subset_load_menu)
315       {
316         switch (i = subset_load_menu->check())
317         {
318         case 0:
319           break;
320         default:
321           if(i >= 1)
322           {
323             if(load_level_subset(level_subsets.item[i-1]))
324               return 1;
325           }
326           break;
327         }
328       }
329       else if(menu == subset_new_menu)
330       {
331         if(subset_new_menu->item[2].input[0] == '\0')
332           subset_new_menu->item[3].kind = MN_DEACTIVE;
333         else
334         {
335           subset_new_menu->item[3].kind = MN_ACTION;
336
337           switch (i = subset_new_menu->check())
338           {
339           case MNID_CREATESUBSET:
340             LevelSubset::create(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
341             le_level_subset->load(subset_new_menu->get_item_by_id(MNID_SUBSETNAME).input);
342             leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
343             goto_level(1);
344             subset_new_menu->get_item_by_id(MNID_SUBSETNAME).change_input("");
345
346             Menu::set_current(subset_settings_menu);
347             break;
348           }
349         }
350       }
351       else if(menu == subset_settings_menu)
352       {
353         if(le_level_subset->title.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETTITLE).input) == 0 && le_level_subset->description.compare(subset_settings_menu->get_item_by_id(MNID_SUBSETDESCRIPTION).input) == 0  )
354           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_DEACTIVE;
355         else
356           subset_settings_menu->get_item_by_id(MNID_SUBSETSAVECHANGES).kind = MN_ACTION;
357
358         switch (i = subset_settings_menu->check())
359         {
360         case MNID_SUBSETSAVECHANGES:
361           save_subset_settings_menu();
362           Menu::set_current(leveleditor_menu);
363           break;
364         }
365       }
366     }
367
368     MouseCursor::current()->draw(context);
369
370     if(done)
371     {
372       return 0;
373     }
374
375     ++global_frame_counter;
376
377     SDL_Delay(25);
378     now_time = SDL_GetTicks();
379     if (now_time < last_time + FPS)
380       SDL_Delay(last_time + FPS - now_time);    /* delay some time */
381
382     context.do_drawing();
383   }
384
385   return done;
386 }
387
388 int LevelEditor::load_level_subset(char *filename)
389 {
390   le_level_subset->load(filename);
391   leveleditor_menu->get_item_by_id(MNID_SUBSETSETTINGS).kind = MN_GOTO;
392   le_levelnb = 1;
393   goto_level(le_levelnb);
394
395   //GameSession* session = new GameSession(datadir + "/levels/" + le_level_subset->name + "/level1.stl", 0, ST_GL_DEMO_GAME);
396
397   Menu::set_current(NULL);
398
399   return 0;
400 }
401
402 void LevelEditor::init_menus()
403 {
404   int i;
405
406   leveleditor_menu = new Menu();
407   subset_load_menu = new Menu();
408   subset_new_menu  = new Menu();
409   subset_settings_menu = new Menu();
410   level_settings_menu  = new Menu();
411   select_tilegroup_menu  = new Menu();
412   select_objects_menu = new Menu();
413
414   leveleditor_menu->additem(MN_LABEL,"Level Editor Menu",0,0);
415   leveleditor_menu->additem(MN_HL,"",0,0);
416   leveleditor_menu->additem(MN_ACTION,"Return To Level Editor",0,0,MNID_RETURNLEVELEDITOR);
417   leveleditor_menu->additem(MN_DEACTIVE,"Level Subset Settings",0,subset_settings_menu,MNID_SUBSETSETTINGS);
418   leveleditor_menu->additem(MN_GOTO,"Load Level Subset",0,subset_load_menu);
419   leveleditor_menu->additem(MN_GOTO,"New Level Subset",0,subset_new_menu);
420   leveleditor_menu->additem(MN_HL,"",0,0);
421   leveleditor_menu->additem(MN_ACTION,"Quit Level Editor",0,0,MNID_QUITLEVELEDITOR);
422
423   Menu::set_current(leveleditor_menu);
424
425   subset_load_menu->additem(MN_LABEL, "Load Level Subset", 0, 0);
426   subset_load_menu->additem(MN_HL, "", 0, 0);
427
428   for(i = 0; i < level_subsets.num_items; ++i)
429   {
430     subset_load_menu->additem(MN_ACTION,level_subsets.item[i],0,0, i+1);
431   }
432   subset_load_menu->additem(MN_HL,"",0,0);
433   subset_load_menu->additem(MN_BACK,"Back",0,0);
434
435   subset_new_menu->additem(MN_LABEL,"New Level Subset",0,0);
436   subset_new_menu->additem(MN_HL,"",0,0);
437   subset_new_menu->additem(MN_TEXTFIELD,"Enter Name",0,0,MNID_SUBSETNAME);
438   subset_new_menu->additem(MN_ACTION,"Create",0,0, MNID_CREATESUBSET);
439   subset_new_menu->additem(MN_HL,"",0,0);
440   subset_new_menu->additem(MN_BACK,"Back",0,0);
441
442   subset_settings_menu->additem(MN_LABEL,"Level Subset Settings",0,0);
443   subset_settings_menu->additem(MN_HL,"",0,0);
444   subset_settings_menu->additem(MN_TEXTFIELD,"Title",0,0,MNID_SUBSETTITLE);
445   subset_settings_menu->additem(MN_TEXTFIELD,"Description",0,0,MNID_SUBSETDESCRIPTION);
446   subset_settings_menu->additem(MN_HL,"",0,0);
447   subset_settings_menu->additem(MN_ACTION,"Save Changes",0,0,MNID_SUBSETSAVECHANGES);
448   subset_settings_menu->additem(MN_HL,"",0,0);
449   subset_settings_menu->additem(MN_BACK,"Back",0,0);
450
451   level_settings_menu->arrange_left = true;
452   level_settings_menu->additem(MN_LABEL,"Level Settings",0,0);
453   level_settings_menu->additem(MN_HL,"",0,0);
454   level_settings_menu->additem(MN_TEXTFIELD,   "Name    ",0,0,MNID_NAME);
455   level_settings_menu->additem(MN_TEXTFIELD,   "Author  ",0,0,MNID_AUTHOR);
456   level_settings_menu->additem(MN_STRINGSELECT,"Song    ",0,0,MNID_SONG);
457   level_settings_menu->additem(MN_STRINGSELECT,"Bg-Image",0,0,MNID_BGIMG);
458   level_settings_menu->additem(MN_STRINGSELECT,"Particle",0,0,MNID_PARTICLE);
459   level_settings_menu->additem(MN_NUMFIELD,    "Length  ",0,0,MNID_LENGTH);
460   level_settings_menu->additem(MN_NUMFIELD,    "Height  ",0,0,MNID_HEIGHT);
461   level_settings_menu->additem(MN_NUMFIELD,    "Time    ",0,0,MNID_TIME);
462   level_settings_menu->additem(MN_NUMFIELD,    "Gravity ",0,0,MNID_GRAVITY);
463   level_settings_menu->additem(MN_NUMFIELD,    "Bg-Img-Speed",0,0,MNID_BGSPEED);
464   level_settings_menu->additem(MN_NUMFIELD,    "Top Red     ",0,0,MNID_TopRed);
465   level_settings_menu->additem(MN_NUMFIELD,    "Top Green   ",0,0,MNID_TopGreen);
466   level_settings_menu->additem(MN_NUMFIELD,    "Top Blue    ",0,0,MNID_TopBlue);
467   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Red  ",0,0,MNID_BottomRed);
468   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Green",0,0,MNID_BottomGreen);
469   level_settings_menu->additem(MN_NUMFIELD,    "Bottom Blue ",0,0,MNID_BottomBlue);
470   level_settings_menu->additem(MN_HL,"",0,0);
471   level_settings_menu->additem(MN_ACTION,"Apply Changes",0,0,MNID_APPLY);
472
473   select_tilegroup_menu->arrange_left = true;
474   select_tilegroup_menu->additem(MN_LABEL,"Tilegroup",0,0);
475   select_tilegroup_menu->additem(MN_HL,"",0,0);
476   std::set<TileGroup>* tilegroups = TileManager::tilegroups();
477   int tileid = 1;
478   for(std::set<TileGroup>::iterator it = tilegroups->begin();
479         it != tilegroups->end(); ++it )
480     {
481       select_tilegroup_menu->additem(MN_ACTION, it->name, 0, 0, tileid);
482       tileid++;
483       tilegroups_map[(*it).name] = new ButtonPanel(screen->w - 64,96, 64, 318);
484       i = 0;
485
486       for(std::vector<int>::const_iterator sit = (*it).tiles.begin();
487           sit != (*it).tiles.end(); ++sit, ++i)
488       {
489         Tile& tile = *(TileManager::instance()->get(*sit));
490         Surface* image;
491         if(tile.editor_images.size() > 0)
492           image = tile.editor_images[0];
493         else if(tile.images.size() > 0)
494           image = tile.images[0];
495         else
496           // TODO use some notile image...
497           image = 0;
498
499         Button* button = new Button(image, it->name, SDLKey(SDLK_a + i),
500                                     0, 0, 32, 32);
501         tilegroups_map[it->name]->additem(button, *sit);
502       }
503     }
504   select_tilegroup_menu->additem(MN_HL,"",0,0);
505
506   select_objects_menu->arrange_left = true;
507   select_objects_menu->additem(MN_LABEL,"Objects",0,0);
508   select_objects_menu->additem(MN_HL,"",0,0);
509   // TODO fix this
510   select_objects_menu->additem(MN_ACTION,"BadGuys",0,0,1);
511   objects_map["BadGuys"] = new ButtonPanel(screen->w - 64,96, 64, 318);
512
513   for(int i = 0; i < NUM_BadGuyKinds; ++i)
514   {
515 //    BadGuy bad_tmp(BadGuyKind(i), 0, 0);
516 //    objects_map["BadGuys"]->additem(new Button(0, "BadGuy",(SDLKey)(i+'a'),0,0,32,32),1000000+i);
517 /* FIXME: maybe addbutton should already have a parameter for the surface
518     objects_map["BadGuys"]->manipulate_button(i)->set_drawable(new
519         BadGuy(BadGuyKind(i),
520           objects_map["BadGuys"]->manipulate_button(i)->get_pos().x,
521           objects_map["BadGuys"]->manipulate_button(i)->get_pos().y
522           ));*/
523   }
524
525   select_objects_menu->additem(MN_HL,"",0,0);
526
527 }
528
529 void LevelEditor::update_level_settings_menu()
530 {
531   char str[80];
532   int i;
533
534   level_settings_menu->get_item_by_id(MNID_NAME).change_input(le_level->name.c_str());
535   level_settings_menu->get_item_by_id(MNID_AUTHOR).change_input(le_level->author.c_str());
536
537   string_list_copy(level_settings_menu->get_item_by_id(MNID_SONG).list, dfiles("music/",NULL, "-fast"));
538   string_list_copy(level_settings_menu->get_item_by_id(MNID_BGIMG).list, dfiles("images/background",NULL, NULL));
539   string_list_add_item(level_settings_menu->get_item_by_id(MNID_BGIMG).list,"");
540   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"");
541   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"snow");
542   string_list_add_item(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,"clouds");
543
544   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_SONG).list,le_level->get_sector("main")->song_title.c_str())) != -1)
545     level_settings_menu->get_item_by_id(MNID_SONG).list->active_item = i;
546   if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_BGIMG).list,le_level->get_sector("main")->background->get_image().c_str())) != -1)
547     level_settings_menu->get_item_by_id(MNID_BGIMG).list->active_item = i;
548 /*  if((i = string_list_find(level_settings_menu->get_item_by_id(MNID_PARTICLE).list,le_level->get_sector("main")->particlesystem.c_str())) != -1)
549     level_settings_menu->get_item_by_id(MNID_PARTICLE).list->active_item = i;*/
550
551   sprintf(str,"%d",le_level->get_sector("main")->solids->get_width());
552   level_settings_menu->get_item_by_id(MNID_LENGTH).change_input(str);
553   sprintf(str,"%d",le_level->get_sector("main")->solids->get_height());
554   level_settings_menu->get_item_by_id(MNID_HEIGHT).change_input(str);
555   sprintf(str,"%d",le_level->time_left);
556   level_settings_menu->get_item_by_id(MNID_TIME).change_input(str);
557   sprintf(str,"%2.0f",le_level->get_sector("main")->gravity);
558   level_settings_menu->get_item_by_id(MNID_GRAVITY).change_input(str);
559   sprintf(str,"%2.2f", le_level->get_sector("main")->background->get_speed());
560   level_settings_menu->get_item_by_id(MNID_BGSPEED).change_input(str);
561   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().red);
562   level_settings_menu->get_item_by_id(MNID_TopRed).change_input(str);
563   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().green);
564   level_settings_menu->get_item_by_id(MNID_TopGreen).change_input(str);
565   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_top().blue);
566   level_settings_menu->get_item_by_id(MNID_TopBlue).change_input(str);
567   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().red);
568   level_settings_menu->get_item_by_id(MNID_BottomRed).change_input(str);
569   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().green);
570   level_settings_menu->get_item_by_id(MNID_BottomGreen).change_input(str);
571   sprintf(str,"%d",le_level->get_sector("main")->background->get_gradient_bottom().blue);
572   level_settings_menu->get_item_by_id(MNID_BottomBlue).change_input(str);
573 }
574
575 void LevelEditor::update_subset_settings_menu()
576 {
577   subset_settings_menu->item[2].change_input(le_level_subset->title.c_str());
578   subset_settings_menu->item[3].change_input(le_level_subset->description.c_str());
579 }
580
581 void LevelEditor::apply_level_settings_menu()
582 {
583   int i;
584   i = false;
585   le_level_changed = true;
586
587   le_level->name = level_settings_menu->get_item_by_id(MNID_NAME).input;
588   le_level->author = level_settings_menu->get_item_by_id(MNID_AUTHOR).input;
589
590   if(le_level->get_sector("main")->background->get_image().compare(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list)) != 0)
591   {
592     le_level->get_sector("main")->background->set_image(string_list_active(level_settings_menu->get_item_by_id(MNID_BGIMG).list), atoi(level_settings_menu->get_item_by_id(MNID_BGSPEED).input));
593     i = true;
594   }
595
596 /*  if(le_level->get_sector("main")->particlesystem.compare(string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list)) != 0)
597   {
598     le_level->->get_sector("main")->particlesystem = string_list_active(level_settings_menu->get_item_by_id(MNID_PARTICLE).list);
599   }*/
600
601 /*  if(i)
602   {
603     le_level->load_gfx();
604   }*/
605
606   le_level->get_sector("main")->song_title = string_list_active(level_settings_menu->get_item_by_id(MNID_SONG).list);
607
608   le_level->get_sector("main")->solids->resize(
609       atoi(level_settings_menu->get_item_by_id(MNID_LENGTH).input),
610       atoi(level_settings_menu->get_item_by_id(MNID_HEIGHT).input));
611   le_level->time_left = atoi(level_settings_menu->get_item_by_id(MNID_TIME).input);
612   le_level->get_sector("main")->gravity = atof(level_settings_menu->get_item_by_id(MNID_GRAVITY).input);
613   le_level->get_sector("main")->background->set_gradient(Color(
614       atoi(level_settings_menu->get_item_by_id(MNID_TopRed).input),
615       atoi(level_settings_menu->get_item_by_id(MNID_TopGreen).input),
616       atoi(level_settings_menu->get_item_by_id(MNID_TopBlue).input)), Color(
617       atoi(level_settings_menu->get_item_by_id(MNID_BottomRed).input),
618       atoi(level_settings_menu->get_item_by_id(MNID_BottomGreen).input),
619       atoi(level_settings_menu->get_item_by_id(MNID_BottomBlue).input)));
620 }
621
622 void LevelEditor::save_subset_settings_menu()
623 {
624   le_level_subset->title = subset_settings_menu->item[2].input;
625   le_level_subset->description = subset_settings_menu->item[3].input;
626   le_level_subset->save();
627   le_level_changed = false;
628 }
629
630 void LevelEditor::unload_level()
631 {
632   if(le_level_changed)
633   {
634     char str[1024];
635     // TODO get level number
636     sprintf(str,"Save changes to level %d of %s?", 0/*le_level*/,le_level_subset->name.c_str());
637     Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
638     if(confirm_dialog(surf, str))
639     {
640       le_level->save(le_level_subset->get_level_filename(le_levelnb));
641     }
642     if(surf != NULL)
643       delete surf;
644   }
645
646   delete le_level;
647   le_level_changed = false;
648 }
649
650 void LevelEditor::goto_level(int levelnb)
651 {
652   unload_level();
653   le_level = new Level();
654   le_level->load(le_level_subset->get_level_filename(levelnb));
655   display_level_info.start(2500);
656   le_levelnb = levelnb;
657 }
658
659 void LevelEditor::drawminimap()
660 {
661 #if 0
662 //  if(le_level == NULL)
663 //    return;
664
665   int mini_tile_width;
666   if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
667     mini_tile_width = 4;
668   else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
669     mini_tile_width = 2;
670   else
671     mini_tile_width = 1;
672   int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
673
674   int mini_tile_height;
675   if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
676     mini_tile_height = 4;
677   else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
678     mini_tile_height = 2;
679   else
680     mini_tile_height = 1;
681
682   for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
683     for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
684     {
685
686       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
687           mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
688
689       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
690           mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
691
692       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
693           mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
694
695     }
696
697   fillrect(left_offset, 0,
698              le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
699              200, 200, 200, 96);
700
701   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
702              (VISIBLE_TILES_X-3)*mini_tile_width, 2,
703              200, 200, 200, 200);
704   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
705              2, (VISIBLE_TILES_Y-1)*mini_tile_height,
706              200, 200, 200, 200);
707   fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
708              2, (VISIBLE_TILES_Y-1)*mini_tile_height,
709              200, 200, 200, 200);
710   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
711              (VISIBLE_TILES_X-3)*mini_tile_width, 2,
712              200, 200, 200, 200);
713 #endif
714 }
715
716 void LevelEditor::drawinterface(DrawingContext &context)
717 {
718   int x,y;
719   char str[80];
720
721   if(le_level != NULL)
722   {
723     /* draw a grid (if selected) */
724     if(le_show_grid)
725     {
726       for(x = 0; x < VISIBLE_TILES_X; x++)
727         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
728       for(y = 0; y < VISIBLE_TILES_Y; y++)
729         fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
730     }
731   }
732
733   if(show_minimap) // use_gl because the minimap isn't shown correctly in software mode. Any idea? FIXME Possible reasons: SDL_SoftStretch is a hack itsself || an alpha blitting issue SDL can't handle in software mode
734     drawminimap();
735
736   if(show_selections && MouseCursor::current() != mouse_select_object)
737   {
738     if(le_selection_mode == CURSOR)
739     {
740       if(le_current.IsTile())
741         context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
742     }
743     else if(le_selection_mode == SQUARE)
744     {
745       int w, h;
746       highlight_selection();
747       /* draw current selection */
748       w = selection.x2 - selection.x1;
749       h = selection.y2 - selection.y1;
750       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
751       context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
752       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
753       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
754     }
755   }
756
757
758   /* draw button bar */
759   context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
760
761   if(le_current.IsTile())
762   {
763 //    le_level->get_sector("main")->solids->draw(context);
764
765 /*screen->w - 32, screen->h - 32, le_current.tile);
766     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
767       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
768   }
769 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
770   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
771   {
772     le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
773     le_current.obj->draw_on_screen(cursor_x,cursor_y);
774   }
775 #endif
776
777   if(mouse_select_object && selected_game_object != NULL)
778   {
779     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,selected_game_object->base.width,3,255,0,0,255);
780     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
781     fillrect(selected_game_object->base.x-pos_x,selected_game_object->base.y-pos_y+selected_game_object->base.height,selected_game_object->base.width,3,255,0,0,255);
782     fillrect(selected_game_object->base.x-pos_x+selected_game_object->base.width,selected_game_object->base.y-pos_y,3,selected_game_object->base.height,255,0,0,255);
783   }
784
785   if(le_level != NULL)
786   {
787     le_save_level_bt->draw(context);
788     le_exit_bt->draw(context);
789     le_test_level_bt->draw(context);
790     le_next_level_bt->draw(context);
791     le_previous_level_bt->draw(context);
792     le_rubber_bt->draw(context);
793     if(le_selection_mode == SQUARE)
794       le_select_mode_one_bt->draw(context);
795     else if(le_selection_mode == CURSOR)
796       le_select_mode_two_bt->draw(context);
797     le_settings_bt->draw(context);
798     le_move_right_bt->draw(context);
799     le_move_left_bt->draw(context);
800     le_move_up_bt->draw(context);
801     le_move_down_bt->draw(context);
802     le_tilegroup_bt->draw(context);
803     le_objects_bt->draw(context);
804     if(!cur_tilegroup.empty())
805       tilegroups_map[cur_tilegroup]->draw(context);
806     else if(!cur_objects.empty())
807     {
808       objects_map[cur_objects]->draw(context);
809     }
810
811     le_tilemap_panel->draw(context);
812
813     if(!cur_objects.empty())
814     {
815       le_object_select_bt->draw(context);
816       le_object_properties_bt->draw(context);
817     }
818
819     sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
820     context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
821
822     if(!le_help_shown)
823       context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
824
825     if(display_level_info.check())
826       context.draw_text_center(white_text, le_level->name.c_str(), Vector(0, 0), LAYER_GUI);
827   }
828   else
829   {
830     if(!Menu::current())
831       context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LAYER_GUI);
832     else
833       context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LAYER_GUI);
834   }
835
836 }
837
838 void LevelEditor::drawlevel(DrawingContext& context)
839 {
840 //  unsigned int y,x;
841 //  Uint8 a;
842
843   /* Draw the real background */
844   le_level->get_sector("main")->background->draw(context);
845
846   if(le_current.IsTile())
847   {
848 le_level->get_sector("main")->solids->draw(context);
849 /*
850     Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
851     if(!TileManager::instance()->get(le_current.tile)->images.empty())
852       fillrect(cursor_x-pos_x,cursor_y-pos_y,TileManager::instance()->get(le_current.tile)->images[0]->w,TileManager::instance()->get(le_current.tile)->images[0]->h,50,50,50,50);*/
853   }
854 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
855   if(le_current.IsObject())
856   {
857     le_current.obj->move_to(cursor_x, cursor_y);
858   }
859 #endif
860
861   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
862
863
864 le_level->get_sector("main")->solids->draw(context);
865
866 // FIXME: make tiles to be drawn semi-transparent when not selected
867 #if 0
868   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
869     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
870     {
871
872       if(active_tm == TM_BG)
873         a = 255;
874       else
875         a = 128;
876
877       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
878           le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() + 
879           (x + (int)(pos_x / 32))],a);
880
881       if(active_tm == TM_IA)
882         a = 255;
883       else
884         a = 128;
885
886       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
887           le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +       
888           (x + (int)(pos_x / 32))],a);
889
890       
891       if(active_tm == TM_FG)
892         a = 255;
893       else
894         a = 128;
895
896       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
897           le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +       
898           (x + (int)(pos_x / 32))],a);
899
900       /* draw whats inside stuff when cursor is selecting those */
901       /* (draw them all the time - is this the right behaviour?) */
902       Tile* edit_image = TileManager::instance()->get(
903           le_level->ia_tiles
904           [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
905       if(edit_image && !edit_image->editor_images.empty())
906         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
907
908     }
909 #endif
910   /* Draw the Bad guys: */
911   for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
912        it != le_level->get_sector("main")->gameobjects.end(); ++it)
913   {
914     BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
915     if(badguy == 0)
916       continue;
917     
918     /* to support frames: img_bsod_left[(frame / 5) % 4] */
919     badguy->draw(context);
920   }
921
922   /* Draw the player: */
923   /* for now, the position is fixed at (100, 240) */
924   largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
925 }
926
927 void LevelEditor::change_object_properties(GameObject *pobj)
928 {
929   DrawingContext context;
930     
931   Menu* object_properties_menu = new Menu();
932   bool loop = true;
933
934   std::string type = typeid(pobj).name();
935   object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
936   object_properties_menu->additem(MN_HL,"",0,0);
937
938   BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
939   if(pobj != 0)
940   {
941     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
942     for(int i = 0; i < NUM_BadGuyKinds; ++i)
943     {
944       string_list_add_item(object_properties_menu->get_item_by_id(1).list,
945           badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
946       if(pbad->kind == i)
947         object_properties_menu->get_item_by_id(1).list->active_item = i;
948     }
949     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
950   }
951
952   object_properties_menu->additem(MN_HL,"",0,0);
953   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
954
955   Menu::set_current(object_properties_menu);
956
957   while(loop)
958   {
959     SDL_Event event;
960
961     while (SDL_PollEvent(&event))
962     {
963       object_properties_menu->event(event);
964     }
965
966     //cap_screen->draw(0,0);
967
968     object_properties_menu->draw(context);
969     object_properties_menu->action();
970
971     switch (object_properties_menu->check())
972     {
973     case 3:
974       {
975       BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
976       if(pbad != 0) {
977         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
978         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
979         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
980       }
981       loop = false;
982       break;
983       }
984     default:
985       break;
986     }
987
988     if(Menu::current() == NULL)
989       loop = false;
990
991     mouse_cursor->draw(context);
992 //    context.draw_filled_rect();
993     SDL_Delay(25);
994   }
995
996   //delete cap_screen;
997   Menu::set_current(0);
998   delete object_properties_menu;
999 }
1000
1001
1002 void LevelEditor::checkevents()
1003 {
1004   SDLKey key;
1005   SDLMod keymod;
1006   Button* pbutton;
1007   int x,y;
1008
1009   keymod = SDL_GetModState();
1010
1011   while(SDL_PollEvent(&event))
1012   {
1013     if (Menu::current())
1014     {
1015       Menu::current()->event(event);
1016       if(!le_level && !Menu::current())
1017         Menu::set_current(leveleditor_menu);
1018     }
1019     else
1020     {
1021       mouse_cursor->set_state(MC_NORMAL);
1022
1023       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1024       if(event.type == SDL_KEYDOWN
1025           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1026               && (event.motion.x > 0
1027                   && event.motion.x < screen->w - 64 &&
1028                   event.motion.y > 0 && event.motion.y < screen->h)))
1029       {
1030         switch(event.type)
1031         {
1032         case SDL_KEYDOWN:       // key pressed
1033           key = event.key.keysym.sym;
1034           switch(key)
1035           {
1036           case SDLK_ESCAPE:
1037             Menu::set_current(leveleditor_menu);
1038             break;
1039           case SDLK_F1:
1040             if(le_level != NULL)
1041               showhelp();
1042             break;
1043           case SDLK_HOME:
1044             cursor_x = 0;
1045             pos_x = cursor_x;
1046             break;
1047           case SDLK_END:
1048             cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1049             pos_x = cursor_x;
1050             break;
1051           case SDLK_F9:
1052             le_show_grid = !le_show_grid;
1053             break;
1054           default:
1055             break;
1056           }
1057           break;
1058         case SDL_MOUSEBUTTONDOWN:
1059           if(event.button.button == SDL_BUTTON_LEFT)
1060           {
1061             le_mouse_pressed[LEFT] = true;
1062
1063             selection.x1 = event.motion.x + pos_x;
1064             selection.y1 = event.motion.y + pos_y;
1065             selection.x2 = event.motion.x + pos_x;
1066             selection.y2 = event.motion.y + pos_y;
1067           }
1068           else if(event.button.button == SDL_BUTTON_RIGHT)
1069           {
1070             le_mouse_pressed[RIGHT] = true;
1071           }
1072           break;
1073         case SDL_MOUSEBUTTONUP:
1074           if(event.button.button == SDL_BUTTON_LEFT)
1075           {
1076             le_mouse_pressed[LEFT] = false;
1077             le_mouse_clicked[LEFT] = true;
1078           }
1079           else if(event.button.button == SDL_BUTTON_RIGHT)
1080           {
1081             le_mouse_pressed[RIGHT] = false;
1082             le_mouse_clicked[RIGHT] = true;
1083           }
1084           break;
1085         case SDL_MOUSEMOTION:
1086
1087           if(!Menu::current())
1088           {
1089             x = event.motion.x;
1090             y = event.motion.y;
1091
1092             if(le_current.IsTile())
1093             {
1094               cursor_x = ((int)(pos_x + x) / 32) * 32;
1095               cursor_y = ((int)(pos_y + y) / 32) * 32;
1096             }
1097             else
1098             {
1099               cursor_x = x;
1100               cursor_y = y;
1101             }
1102
1103             if(le_mouse_pressed[LEFT])
1104             {
1105               selection.x2 = x + pos_x;
1106               selection.y2 = y + pos_y;
1107             }
1108
1109             if(le_mouse_pressed[RIGHT])
1110             {
1111               pos_x += -1 * event.motion.xrel;
1112               pos_y += -1 * event.motion.yrel;
1113             }
1114           }
1115           break;
1116         default:
1117           break;
1118         }
1119       }
1120       else if(event.type == SDL_QUIT) /* window closing */
1121       {
1122       done = 1;
1123       }
1124     }
1125
1126     if(le_level != NULL)
1127     {
1128       if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION) && (event.motion.x > screen->w-64 && event.motion.x < screen->w &&
1129           event.motion.y > 0 && event.motion.y < screen->h)))
1130       {
1131         le_mouse_pressed[LEFT] = false;
1132         le_mouse_pressed[RIGHT] = false;
1133
1134         if(!Menu::current())
1135         {
1136           /* Check for button events */
1137           le_test_level_bt->event(event);
1138           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1139             testlevel();
1140           le_save_level_bt->event(event);
1141           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1142             le_level->save(le_level_subset->name.c_str());
1143           le_exit_bt->event(event);
1144           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1145           {
1146             Menu::set_current(leveleditor_menu);
1147           }
1148           le_next_level_bt->event(event);
1149           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1150           {
1151             if(le_levelnb < le_level_subset->levels)
1152             {
1153               goto_level(le_levelnb+1);
1154             }
1155             else
1156             {
1157               Level new_lev;
1158               char str[1024];
1159               sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1160               Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1161               if(confirm_dialog(surf, str))
1162               {
1163                 new_lev.save(le_level_subset->name.c_str());
1164                 le_level_subset->levels = le_levelnb;
1165                 goto_level(le_levelnb);
1166               }
1167              if(surf != NULL)
1168               delete surf;
1169             }
1170           }
1171           le_previous_level_bt->event(event);
1172           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1173           {
1174             if(le_levelnb > 1)
1175               goto_level(le_levelnb -1);
1176           }
1177           le_rubber_bt->event(event);
1178           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1179             le_current.Tile(0);
1180
1181           if(!cur_objects.empty())
1182           {
1183             le_object_select_bt->event(event);
1184             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1185             {
1186               MouseCursor::set_current(mouse_select_object);
1187             }
1188
1189             le_object_properties_bt->event(event);
1190             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1191             {
1192               change_object_properties(selected_game_object);
1193             }
1194           }
1195
1196
1197           if(le_selection_mode == SQUARE)
1198           {
1199             le_select_mode_one_bt->event(event);
1200             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1201               le_selection_mode = CURSOR;
1202           }
1203           else
1204           {
1205             le_select_mode_two_bt->event(event);
1206             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1207               le_selection_mode = SQUARE;
1208           }
1209           ButtonPanelMap::iterator it;
1210           le_tilegroup_bt->event(event);
1211           switch (le_tilegroup_bt->get_state())
1212           {
1213           case BUTTON_CLICKED:
1214             Menu::set_current(select_tilegroup_menu);
1215             select_tilegroup_menu_effect.start(200);
1216             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1217             break;
1218           case BUTTON_WHEELUP:
1219             if(cur_tilegroup.empty())
1220             {
1221               cur_tilegroup = tilegroups_map.begin()->first;
1222             }
1223             else
1224             {
1225               it = tilegroups_map.find(cur_tilegroup);
1226               if((++it) == tilegroups_map.end())
1227               {
1228                 cur_tilegroup = tilegroups_map.begin()->first;
1229               }
1230               else
1231               {
1232                 cur_tilegroup = (*it).first;
1233               }
1234             }
1235
1236             cur_objects = "";
1237             break;
1238           case BUTTON_WHEELDOWN:
1239             it = tilegroups_map.find(cur_tilegroup);
1240             if(it == tilegroups_map.begin())
1241             {
1242               cur_tilegroup = tilegroups_map.rbegin()->first;
1243               cur_objects = "";
1244               break;
1245             }
1246             if(--it != --tilegroups_map.begin())
1247               cur_tilegroup = (*it).first;
1248             else
1249               cur_tilegroup = tilegroups_map.rbegin()->first;
1250
1251             cur_objects = "";
1252             break;
1253           default:
1254             break;
1255           }
1256
1257           le_objects_bt->event(event);
1258           switch (le_objects_bt->get_state())
1259           {
1260           case BUTTON_CLICKED:
1261             Menu::set_current(select_objects_menu);
1262             select_objects_menu_effect.start(200);
1263             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1264             break;
1265           case BUTTON_WHEELUP:
1266             it = objects_map.find(cur_objects);
1267             if(it == objects_map.end())
1268             {
1269               cur_objects = objects_map.begin()->first;
1270               cur_tilegroup = "";
1271               break;
1272             }
1273             if(++it != objects_map.end())
1274               cur_objects = (*it).first;
1275             else
1276               cur_objects = objects_map.begin()->first;
1277
1278             cur_tilegroup = "";
1279             break;
1280           case BUTTON_WHEELDOWN:
1281             it = objects_map.find(cur_objects);
1282             if(it == objects_map.begin())
1283             {
1284               cur_objects = objects_map.rbegin()->first;
1285               cur_tilegroup = "";
1286               break;
1287             }
1288             if(--it != --objects_map.begin())
1289               cur_objects = (*it).first;
1290             else
1291               cur_objects = objects_map.rbegin()->first;
1292
1293             cur_tilegroup = "";
1294             break;
1295             break;
1296           default:
1297             break;
1298           }
1299
1300           le_settings_bt->event(event);
1301           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1302           {
1303             update_level_settings_menu();
1304             Menu::set_current(level_settings_menu);
1305           }
1306           if(!cur_tilegroup.empty())
1307           {
1308             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1309             {
1310               if(pbutton->get_state() == BUTTON_CLICKED)
1311               {
1312                 le_current.Tile(pbutton->get_tag());
1313               }
1314             }
1315           }
1316           else if(!cur_objects.empty())
1317           {
1318             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1319             {
1320               if(pbutton->get_state() == BUTTON_CLICKED)
1321               {
1322 #if 0   // TODO FIXME XXX: New solution for this?
1323                 le_current.Object(pbutton->get_drawable());
1324 #endif
1325               }
1326             }
1327           }
1328
1329           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1330           {
1331             if(pbutton->get_state() == BUTTON_CLICKED)
1332             {
1333               active_tm = pbutton->get_tag();
1334             }
1335           }
1336         }
1337         else
1338         {
1339           le_settings_bt->event(event);
1340           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1341           {
1342             Menu::set_current(0);
1343           }
1344           le_tilegroup_bt->event(event);
1345           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1346           {
1347             Menu::set_current(0);
1348           }
1349           le_objects_bt->event(event);
1350           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1351           {
1352             Menu::set_current(0);
1353           }
1354         }
1355       }
1356
1357       if(!Menu::current() && !show_minimap)
1358       {
1359         if(le_mouse_pressed[LEFT])
1360         {
1361           if(MouseCursor::current() != mouse_select_object)
1362           {
1363             if(le_current.IsTile())
1364               change(cursor_x, cursor_y, active_tm, le_current.tile);
1365           }
1366         }
1367         else if(le_mouse_clicked[LEFT])
1368         {
1369           if(MouseCursor::current() == mouse_select_object)
1370           {
1371             bool object_got_hit = false;
1372             base_type cursor_base;
1373             if(le_current.IsTile())
1374             {
1375             cursor_base.x = cursor_x;
1376             cursor_base.y = cursor_y;
1377             }
1378             else if(le_current.IsObject())
1379             {
1380             cursor_base.x = cursor_x + pos_x;
1381             cursor_base.y = cursor_y + pos_y;       
1382             }
1383             cursor_base.width = 32;
1384             cursor_base.height = 32;
1385
1386             for(std::vector<GameObject*>::iterator it =
1387                 le_level->get_sector("main")->gameobjects.begin();
1388                 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1389               MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1390               if(!mobj)
1391                 continue;
1392
1393               if(rectcollision(cursor_base, mobj->base))
1394               {
1395                 selected_game_object = mobj;
1396                 object_got_hit = true;
1397                 break;
1398               }
1399             }
1400
1401             if(!object_got_hit)
1402             {
1403               selected_game_object = NULL;
1404               le_object_properties_bt->set_active(false);
1405             }
1406             else
1407               le_object_properties_bt->set_active(true);
1408
1409             MouseCursor::set_current(mouse_cursor);
1410
1411           }
1412           else
1413           {
1414             // FIXME TODO
1415 #if 0
1416 //FIXME: objects interactions with the level editor should have a major improvement
1417             if(le_current.IsObject())
1418             {
1419               le_level_changed  = true;
1420               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1421
1422               if(pbadguy)
1423               {
1424                 Camera& camera = *le_level->get_sector("main")->camera;
1425
1426                 le_level->get_sector("main")->bad_guys.push_back(
1427                     new BadGuy(pbadguy->kind,
1428                       cursor_x + camera.get_translation().x,
1429                       cursor_y + camera.get_translation().y));
1430                 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1431               }
1432             }
1433 #endif
1434
1435           }
1436           
1437           le_mouse_clicked[LEFT] = false;
1438
1439         }
1440       }
1441     }
1442   }
1443   if(!Menu::current())
1444   {
1445     show_minimap = false;
1446
1447     if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1448       show_minimap = true;
1449
1450     le_move_left_bt->event(event);
1451     le_move_right_bt->event(event);
1452     le_move_up_bt->event(event);
1453     le_move_down_bt->event(event);
1454     switch(le_move_left_bt->get_state())
1455     {
1456     case BUTTON_PRESSED:
1457       pos_x -= KEYBOARD_SPEED;
1458       show_minimap = true;
1459       break;
1460     case BUTTON_HOVER:
1461       pos_x -= MOUSE_SPEED;
1462       show_minimap = true;
1463       break;
1464     case BUTTON_CLICKED:
1465       show_minimap = true;
1466       break;
1467     default:
1468       break;
1469     }
1470
1471     switch(le_move_right_bt->get_state())
1472     {
1473     case BUTTON_PRESSED:
1474       pos_x += KEYBOARD_SPEED;
1475       show_minimap = true;
1476       break;
1477     case BUTTON_HOVER:
1478       pos_x += MOUSE_SPEED;
1479       show_minimap = true;
1480       break;
1481     case BUTTON_CLICKED:
1482       show_minimap = true;
1483       break;
1484     default:
1485       break;
1486     }
1487
1488     switch(le_move_up_bt->get_state())
1489     {
1490     case BUTTON_PRESSED:
1491       pos_y -= KEYBOARD_SPEED;
1492       show_minimap = true;
1493       break;
1494     case BUTTON_HOVER:
1495       pos_y -= MOUSE_SPEED;
1496       show_minimap = true;
1497       break;
1498     case BUTTON_CLICKED:
1499       show_minimap = true;
1500       break;
1501     default:
1502       break;
1503     }
1504
1505     switch(le_move_down_bt->get_state())
1506     {
1507     case BUTTON_PRESSED:
1508       pos_y += KEYBOARD_SPEED;
1509       show_minimap = true;
1510       break;
1511     case BUTTON_HOVER:
1512       pos_y += MOUSE_SPEED;
1513       show_minimap = true;
1514       break;
1515     case BUTTON_CLICKED:
1516       show_minimap = true;
1517       break;
1518     default:
1519       break;
1520     }
1521
1522     /* checking if pos_x and pos_y is within the limits... */
1523     if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1524       pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1525     if(pos_x < 0)
1526       pos_x = 0;
1527
1528     if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1529       pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1530     if(pos_y < 0)
1531       pos_y = 0;
1532
1533     le_level->get_sector("main")->camera->set_scrolling(pos_x, pos_y);
1534   }
1535 }
1536
1537 void LevelEditor::highlight_selection()
1538 {
1539   int x1, x2, y1, y2;
1540
1541   if(selection.x1 < selection.x2)
1542   {
1543     x1 = selection.x1;
1544     x2 = selection.x2;
1545   }
1546   else
1547   {
1548     x1 = selection.x2;
1549     x2 = selection.x1;
1550   }
1551   if(selection.y1 < selection.y2)
1552   {
1553     y1 = selection.y1;
1554     y2 = selection.y2;
1555   }
1556   else
1557   {
1558     y1 = selection.y2;
1559     y2 = selection.y1;
1560   }
1561
1562   x1 /= 32;
1563   x2 /= 32;
1564   y1 /= 32;
1565   y2 /= 32;
1566
1567   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1568 }
1569
1570 void LevelEditor::change(float x, float y, int tm, unsigned int c)
1571 {
1572   if(le_level != NULL)
1573   {
1574     int xx,yy;
1575     int x1, x2, y1, y2;
1576
1577     le_level_changed = true;
1578
1579     switch(le_selection_mode)
1580     {
1581     case CURSOR:
1582       change(x,y,tm,c);
1583
1584       base_type cursor_base;
1585       cursor_base.x = x;
1586       cursor_base.y = y;
1587       cursor_base.width = 32;
1588       cursor_base.height = 32;
1589
1590       /* if there is a bad guy over there, remove it */
1591       // XXX TODO
1592       for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1593             it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1594         BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1595         if (badguy)
1596         {
1597           if(rectcollision(cursor_base, badguy->base))
1598           {
1599             delete (*it);
1600             le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1601                le_level->get_sector("main")->gameobjects.end(), *it),
1602                le_level->get_sector("main")->gameobjects.end());
1603             break;
1604           }
1605         }
1606       }
1607
1608       break;
1609     case SQUARE:
1610       if(selection.x1 < selection.x2)
1611       {
1612         x1 = selection.x1;
1613         x2 = selection.x2;
1614       }
1615       else
1616       {
1617         x1 = selection.x2;
1618         x2 = selection.x1;
1619       }
1620       if(selection.y1 < selection.y2)
1621       {
1622         y1 = selection.y1;
1623         y2 = selection.y2;
1624       }
1625       else
1626       {
1627         y1 = selection.y2;
1628         y2 = selection.y1;
1629       }
1630
1631       x1 /= 32;
1632       x2 /= 32;
1633       y1 /= 32;
1634       y2 /= 32;
1635
1636       /* if there is a bad guy over there, remove it */
1637       // TODO FIXME
1638       for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1639           it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1640       {
1641         MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);       
1642         if (pmobject)
1643         {
1644           if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1645               && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1646           {
1647             delete (*it);
1648             le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(), le_level->get_sector("main")->gameobjects.end(), *it), le_level->get_sector("main")->gameobjects.end());
1649             continue;
1650           }
1651           else
1652           {
1653             ++it;
1654           }
1655         }
1656       }
1657
1658       for(xx = x1; xx <= x2; xx++)
1659         for(yy = y1; yy <= y2; yy++)
1660         {
1661           change(xx*32, yy*32, tm, c);
1662
1663         }
1664       break;
1665     default:
1666       break;
1667     }
1668   }
1669 }
1670
1671 void LevelEditor::testlevel()
1672 {
1673   //Make sure a time value is set when testing the level
1674   if(le_level->time_left == 0)
1675     le_level->time_left = 250;
1676
1677   le_level->save("test.stl");
1678
1679   GameSession session("test.stl", ST_GL_TEST);
1680   session.run();
1681   player_status.reset();
1682
1683   sound_manager->halt_music();
1684
1685   Menu::set_current(NULL);
1686 }
1687
1688 void LevelEditor::showhelp()
1689 {
1690   DrawingContext context;
1691
1692   bool tmp_show_grid = le_show_grid;
1693   SelectionMode temp_le_selection_mode = le_selection_mode;
1694   le_selection_mode = NONE;
1695   show_selections = true;
1696   le_show_grid = false;
1697   le_help_shown = true;
1698
1699   SDL_Event event;
1700   unsigned int done_;
1701   char str[1024];
1702   char *text1[] = {
1703
1704                    " - Supertux level editor tutorial - ",
1705                    "",
1706                    "To make your map, click the       ",
1707                    "tilegroup button and choose a     ",
1708                    "tilegroup.",
1709                    "Pick a tile and simply hold down  ",
1710                    "the left mouse button over the map",
1711                    "to \"paint\" your selection over",
1712                    "the screen.",
1713                    "",
1714                    "There are three layers for painting",
1715                    "tiles upon, Background layer,",
1716                    "the Interactive layer, and the",
1717                    "Foreground layer, which can be",
1718                    "toggled by the BkGrd, IntAct and",
1719                    "FrGrd buttons. The Foreground and",
1720                    "Background layers do not effect",
1721                    "Tux in the gameplay, but lie in",
1722                    "front of him or lie behind him in",
1723                    "his adventures.",
1724                  };
1725
1726   char *text2[] = {
1727
1728                     " - Supertux level editor tutorial - ",
1729                     "",
1730                     "The tiles placed on",
1731                     "the Interactive layer are those",
1732                     "which actually effect Tux in the",
1733                     "game.",
1734                     "",
1735                     "Click the objects menu to put ",
1736                     "bad guys and other objects in the",
1737                     "game. Unlike placing tiles, you",
1738                     "cannot \"paint\" enemies. Click",
1739                     "them onto the screen one at a time.",
1740                     "",
1741                     "To change the settings of your",
1742                     "level, click the button with the",
1743                     "screwdriver and wrench. From here",
1744                     "you can change the background,",
1745                     "music, length of the level,",
1746                     "and more."
1747                   };
1748
1749   char *text3[] = {
1750
1751                     " - Supertux level editor tutorial - ",
1752                     "",
1753                     "You may have more than one level.",
1754                     "Pressing the up and down buttons",
1755                     "above the button bar lets you",
1756                     "choose which one you are working on.",
1757                     "",
1758                     "If you would like to speed up your",
1759                     "level editing, a useful trick is",
1760                     "to learn the keyboard shortcuts.",
1761                     "They are easy to learn, just right-",
1762                     "click on the buttons.",
1763                     "",
1764                     "Have fun making levels! If you make",
1765                     "some good ones, send them to us on",
1766                     "the SuperTux mailing list!",
1767                     "- SuperTux team"
1768                   };
1769
1770   char **text[] = { text1, text2, text3 };
1771
1772
1773   for(int i = 0; i < 3; i++)
1774     {
1775     context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1776     drawinterface(context);
1777
1778     context.draw_text_center(blue_text, "- Help -", Vector(0, 30), LAYER_GUI);
1779
1780     for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1781       context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LAYER_GUI);
1782
1783     sprintf(str,"Press any key to continue - Page %d/%d?", i, sizeof(text));
1784     context.draw_text(gold_text, str, Vector(0, 0), LAYER_GUI);
1785
1786     context.do_drawing();
1787
1788     done_ = 0;
1789
1790     while(done_ == 0)
1791       {
1792       done_ = wait_for_event(event);
1793       SDL_Delay(50);
1794       }
1795     }
1796
1797   show_selections = true;
1798   le_show_grid = tmp_show_grid;
1799   le_selection_mode = temp_le_selection_mode;
1800   le_help_shown = false;
1801 }