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