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