b4893557a162fd3c6f65de7a33e264b79053f97e
[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,"%2.2f", 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     // TODO get level number
693     sprintf(str,"Save changes to level %d of %s?", 0/*le_level*/,le_level_subset->name.c_str());
694     Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
695     if(confirm_dialog(surf, str))
696     {
697       le_level->save(le_level_subset->get_level_filename(le_levelnb));
698     }
699     if(surf != NULL)
700       delete surf;
701   }
702
703   delete le_level;
704   le_level_changed = false;
705 }
706
707 void le_goto_level(int levelnb)
708 {
709   le_unload_level();
710   le_level = new Level();
711   le_level->load(le_level_subset->get_level_filename(levelnb));
712   display_level_info.start(2500);
713   le_levelnb = levelnb;
714 }
715
716 void le_quit(void)
717 {
718   SDL_EnableKeyRepeat(0, 0);    // disables key repeating
719
720   le_unload_level();
721   delete le_selection;
722   delete leveleditor_menu;
723   delete subset_load_menu;
724   delete subset_new_menu;
725   delete subset_settings_menu;
726   delete level_settings_menu;
727   delete select_tilegroup_menu;
728   delete select_objects_menu;
729   delete le_save_level_bt;
730   delete le_exit_bt;
731   delete le_test_level_bt;
732   delete le_next_level_bt;
733   delete le_previous_level_bt;
734   delete le_move_right_bt;
735   delete le_move_left_bt;
736   delete le_move_up_bt;
737   delete le_move_down_bt;
738   delete le_rubber_bt;
739   delete le_select_mode_one_bt;
740   delete le_select_mode_two_bt;
741   delete le_settings_bt;
742   delete le_tilegroup_bt;
743   delete le_objects_bt;
744   delete le_tilemap_panel;
745   delete le_object_select_bt;
746   delete le_object_properties_bt;
747   delete mouse_select_object;
748
749   delete le_level_subset;
750   le_level_subset = 0;
751
752   for(ButtonPanelMap::iterator i = tilegroups_map.begin();
753       i != tilegroups_map.end(); ++i)
754   {
755     delete i->second;
756   }
757   for(ButtonPanelMap::iterator i = objects_map.begin();
758       i != objects_map.end(); ++i)
759   {
760     delete i->second;
761   }
762 }
763
764 void le_drawminimap()
765 {
766 #if 0
767 //  if(le_level == NULL)
768 //    return;
769
770   int mini_tile_width;
771   if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 4)
772     mini_tile_width = 4;
773   else if((unsigned)screen->w - 64 > le_level->get_sector("main")->solids->get_width() * 2)
774     mini_tile_width = 2;
775   else
776     mini_tile_width = 1;
777   int left_offset = (screen->w - 64 - le_level->get_sector("main")->solids->get_width()*mini_tile_width) / 2;
778
779   int mini_tile_height;
780   if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 4)
781     mini_tile_height = 4;
782   else if((unsigned)screen->h > le_level->get_sector("main")->solids->get_height() * 2)
783     mini_tile_height = 2;
784   else
785     mini_tile_height = 1;
786
787   for (unsigned int y = 0; y < le_level->get_sector("main")->solids->get_height(); ++y)
788     for (unsigned int x = 0; x < le_level->get_sector("main")->solids->get_width(); ++x)
789     {
790
791       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
792           mini_tile_width , mini_tile_height, le_level->bg_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
793
794       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
795           mini_tile_width , mini_tile_height, le_level->ia_tiles[y * le_level->get_sector("main")->solids->get_width() + x]);
796
797       Tile::draw_stretched(left_offset + mini_tile_width*x, y * mini_tile_height,
798           mini_tile_width , mini_tile_height, le_level->fg_tiles[y + le_level->get_sector("main")->solids->get_width() + x]);
799
800     }
801
802   fillrect(left_offset, 0,
803              le_level->get_sector("main")->solids->get_width()*mini_tile_width, le_level->get_sector("main")->solids->get_height()*mini_tile_height,
804              200, 200, 200, 96);
805
806   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
807              (VISIBLE_TILES_X-3)*mini_tile_width, 2,
808              200, 200, 200, 200);
809   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height,
810              2, (VISIBLE_TILES_Y-1)*mini_tile_height,
811              200, 200, 200, 200);
812   fillrect(left_offset + (pos_x/32)*mini_tile_width + (VISIBLE_TILES_X-3)*mini_tile_width - 2, (pos_y/32)*mini_tile_height,
813              2, (VISIBLE_TILES_Y-1)*mini_tile_height,
814              200, 200, 200, 200);
815   fillrect(left_offset + (pos_x/32)*mini_tile_width, (pos_y/32)*mini_tile_height + (VISIBLE_TILES_Y-1)*mini_tile_height - 2,
816              (VISIBLE_TILES_X-3)*mini_tile_width, 2,
817              200, 200, 200, 200);
818 #endif
819 }
820
821 void le_drawinterface(DrawingContext &context)
822 {
823   int x,y;
824   char str[80];
825
826   if(le_level != NULL)
827   {
828     /* draw a grid (if selected) */
829     if(le_show_grid)
830     {
831       for(x = 0; x < VISIBLE_TILES_X; x++)
832         fillrect(x*32 - ((int)pos_x % 32), 0, 1, screen->h, 225, 225, 225,255);
833       for(y = 0; y < VISIBLE_TILES_Y; y++)
834         fillrect(0, y*32 - ((int)pos_y % 32), screen->w, 1, 225, 225, 225,255);
835     }
836   }
837
838   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
839     le_drawminimap();
840
841   if(show_selections && MouseCursor::current() != mouse_select_object)
842   {
843     if(le_selection_mode == CURSOR)
844     {
845       if(le_current.IsTile())
846         context.draw_surface(le_selection, Vector(cursor_x - pos_x, cursor_y - pos_y), LAYER_GUI);
847     }
848     else if(le_selection_mode == SQUARE)
849     {
850       int w, h;
851       le_highlight_selection();
852       /* draw current selection */
853       w = selection.x2 - selection.x1;
854       h = selection.y2 - selection.y1;
855       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
856       context.draw_filled_rect(Vector(selection.x1 - pos_x + w, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
857       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y + h), Vector(w, SELECT_W), Color(SELECT_CLR), LAYER_GUI);
858       context.draw_filled_rect(Vector(selection.x1 - pos_x, selection.y1 - pos_y), Vector(SELECT_W, h), Color(SELECT_CLR), LAYER_GUI);
859     }
860   }
861
862
863   /* draw button bar */
864   context.draw_filled_rect(Vector(screen->w - 64, 0), Vector(64, screen->h), Color(50, 50, 50,255), LAYER_GUI);
865
866   if(le_current.IsTile())
867   {
868 //    le_level->get_sector("main")->solids->draw(context);
869
870 /*screen->w - 32, screen->h - 32, le_current.tile);
871     if(TileManager::instance()->get(le_current.tile)->editor_images.size() > 0)
872       TileManager::instance()->get(le_current.tile)->editor_images[0]->draw( screen->w - 32, screen->h - 32);*/
873   }
874 #if 0 // XXX FIXME TODO: Do we have a new solution for draw_on_screen()?
875   if(le_current.IsObject() && MouseCursor::current() != mouse_select_object)
876   {
877     le_current.obj->draw_on_screen(screen->w - 32, screen->h - 32);
878     le_current.obj->draw_on_screen(cursor_x,cursor_y);
879   }
880 #endif
881
882   if(mouse_select_object && selected_game_object != NULL)
883   {
884     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);
885     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);
886     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);
887     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);
888   }
889
890   if(le_level != NULL)
891   {
892     le_save_level_bt->draw(context);
893     le_exit_bt->draw(context);
894     le_test_level_bt->draw(context);
895     le_next_level_bt->draw(context);
896     le_previous_level_bt->draw(context);
897     le_rubber_bt->draw(context);
898     if(le_selection_mode == SQUARE)
899       le_select_mode_one_bt->draw(context);
900     else if(le_selection_mode == CURSOR)
901       le_select_mode_two_bt->draw(context);
902     le_settings_bt->draw(context);
903     le_move_right_bt->draw(context);
904     le_move_left_bt->draw(context);
905     le_move_up_bt->draw(context);
906     le_move_down_bt->draw(context);
907     le_tilegroup_bt->draw(context);
908     le_objects_bt->draw(context);
909     if(!cur_tilegroup.empty())
910       tilegroups_map[cur_tilegroup]->draw(context);
911     else if(!cur_objects.empty())
912     {
913       objects_map[cur_objects]->draw(context);
914     }
915
916     le_tilemap_panel->draw(context);
917
918     if(!cur_objects.empty())
919     {
920       le_object_select_bt->draw(context);
921       le_object_properties_bt->draw(context);
922     }
923
924     sprintf(str, "%d/%d", le_levelnb,le_level_subset->levels);
925     context.draw_text(white_text, str, Vector((le_level_subset->levels < 10) ? -10 : 0, 16), LAYER_GUI);
926
927     if(!le_help_shown)
928       context.draw_text(white_small_text, "F1 for Help", Vector(10, 430), LAYER_GUI);
929
930     if(display_level_info.check())
931       context.draw_text_center(white_text, le_level->name.c_str(), Vector(0, 0), LAYER_GUI);
932   }
933   else
934   {
935     if(!Menu::current())
936       context.draw_text(white_small_text, "No Level Subset loaded - Press ESC and choose one in the menu", Vector(10, 430), LAYER_GUI);
937     else
938       context.draw_text(white_small_text, "No Level Subset loaded", Vector(10, 430), LAYER_GUI);
939   }
940
941 }
942
943 void le_drawlevel(DrawingContext& context)
944 {
945 //  unsigned int y,x;
946 //  Uint8 a;
947
948   /* Draw the real background */
949   le_level->get_sector("main")->background->draw(context);
950
951   if(le_current.IsTile())
952   {
953 le_level->get_sector("main")->solids->draw(context);
954 /*
955     Tile::draw(cursor_x-pos_x, cursor_y-pos_y,le_current.tile,128);
956     if(!TileManager::instance()->get(le_current.tile)->images.empty())
957       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);*/
958   }
959 #if 0 // XXX FIXME TODO: Do we have a new solution for move_to()?
960   if(le_current.IsObject())
961   {
962     le_current.obj->move_to(cursor_x, cursor_y);
963   }
964 #endif
965
966   /*       clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue); */
967
968
969 le_level->get_sector("main")->solids->draw(context);
970
971 // FIXME: make tiles to be drawn semi-transparent when not selected
972 #if 0
973   for (y = 0; y < VISIBLE_TILES_Y && y < (unsigned)le_level->get_section("main")->height; ++y)
974     for (x = 0; x < (unsigned)VISIBLE_TILES_X - 2; ++x)
975     {
976
977       if(active_tm == TM_BG)
978         a = 255;
979       else
980         a = 128;
981
982       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
983           le_level->bg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() + 
984           (x + (int)(pos_x / 32))],a);
985
986       if(active_tm == TM_IA)
987         a = 255;
988       else
989         a = 128;
990
991       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
992           le_level->ia_tiles[ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width +       
993           (x + (int)(pos_x / 32))],a);
994
995       
996       if(active_tm == TM_FG)
997         a = 255;
998       else
999         a = 128;
1000
1001       Tile::draw(32*x - fmodf(pos_x, 32), y*32 - fmodf(pos_y, 32),
1002           le_level->fg_tiles[ (y + (int)(pos_y / 32)) * le_level->get_sector("main")->solids->get_width() +       
1003           (x + (int)(pos_x / 32))],a);
1004
1005       /* draw whats inside stuff when cursor is selecting those */
1006       /* (draw them all the time - is this the right behaviour?) */
1007       Tile* edit_image = TileManager::instance()->get(
1008           le_level->ia_tiles
1009           [ (y + (int)(pos_y / 32)) * le_level->get_section("main")->width + (x + (int)(pos_x / 32))]);
1010       if(edit_image && !edit_image->editor_images.empty())
1011         edit_image->editor_images[0]->draw( x * 32 - ((int)pos_x % 32), y*32 - ((int)pos_y % 32));
1012
1013     }
1014 #endif
1015   /* Draw the Bad guys: */
1016   for (std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1017        it != le_level->get_sector("main")->gameobjects.end(); ++it)
1018   {
1019     BadGuy* badguy = dynamic_cast<BadGuy*> (*it);
1020     if(badguy == 0)
1021       continue;
1022     
1023     /* to support frames: img_bsod_left[(frame / 5) % 4] */
1024     badguy->draw(context);
1025   }
1026
1027   /* Draw the player: */
1028   /* for now, the position is fixed at (100, 240) */
1029   largetux.walk_right->draw(context, Vector(100 - pos_x, 240 - pos_y), LAYER_OBJECTS-1);
1030 }
1031
1032 void le_change_object_properties(GameObject *pobj)
1033 {
1034   DrawingContext context;
1035     
1036   Menu* object_properties_menu = new Menu();
1037   bool loop = true;
1038
1039   std::string type = typeid(pobj).name();
1040   object_properties_menu->additem(MN_LABEL, type + " Properties",0,0);
1041   object_properties_menu->additem(MN_HL,"",0,0);
1042
1043   BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1044   if(pobj != 0)
1045   {
1046     object_properties_menu->additem(MN_STRINGSELECT,"Kind",0,0,1);
1047     for(int i = 0; i < NUM_BadGuyKinds; ++i)
1048     {
1049       string_list_add_item(object_properties_menu->get_item_by_id(1).list,
1050           badguykind_to_string(static_cast<BadGuyKind>(i)).c_str());
1051       if(pbad->kind == i)
1052         object_properties_menu->get_item_by_id(1).list->active_item = i;
1053     }
1054     object_properties_menu->additem(MN_TOGGLE,"StayOnPlatform",pbad->stay_on_platform,0,2);
1055   }
1056
1057   object_properties_menu->additem(MN_HL,"",0,0);
1058   object_properties_menu->additem(MN_ACTION,"Ok",0,0,3);
1059
1060   Menu::set_current(object_properties_menu);
1061
1062   while(loop)
1063   {
1064     SDL_Event event;
1065
1066     while (SDL_PollEvent(&event))
1067     {
1068       object_properties_menu->event(event);
1069     }
1070
1071     //cap_screen->draw(0,0);
1072
1073     object_properties_menu->draw(context);
1074     object_properties_menu->action();
1075
1076     switch (object_properties_menu->check())
1077     {
1078     case 3:
1079       {
1080       BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1081       if(pbad != 0) {
1082         BadGuy* pbad = dynamic_cast<BadGuy*>(pobj);
1083         pbad->kind =  badguykind_from_string(string_list_active(object_properties_menu->get_item_by_id(1).list));
1084         pbad->stay_on_platform = object_properties_menu->get_item_by_id(2).toggled;
1085       }
1086       loop = false;
1087       break;
1088       }
1089     default:
1090       break;
1091     }
1092
1093     if(Menu::current() == NULL)
1094       loop = false;
1095
1096     mouse_cursor->draw(context);
1097 //    context.draw_filled_rect();
1098     SDL_Delay(25);
1099   }
1100
1101   //delete cap_screen;
1102   Menu::set_current(0);
1103   delete object_properties_menu;
1104 }
1105
1106
1107 void le_checkevents()
1108 {
1109   SDLKey key;
1110   SDLMod keymod;
1111   Button* pbutton;
1112   int x,y;
1113
1114   keymod = SDL_GetModState();
1115
1116   while(SDL_PollEvent(&event))
1117   {
1118     if (Menu::current())
1119     {
1120       Menu::current()->event(event);
1121       if(!le_level && !Menu::current())
1122         Menu::set_current(leveleditor_menu);
1123     }
1124     else
1125     {
1126       mouse_cursor->set_state(MC_NORMAL);
1127
1128       /* testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events*/
1129       if(event.type == SDL_KEYDOWN
1130           || ((event.type == SDL_MOUSEBUTTONDOWN || SDL_MOUSEMOTION)
1131               && (event.motion.x > 0
1132                   && event.motion.x < screen->w - 64 &&
1133                   event.motion.y > 0 && event.motion.y < screen->h)))
1134       {
1135         switch(event.type)
1136         {
1137         case SDL_KEYDOWN:       // key pressed
1138           key = event.key.keysym.sym;
1139           switch(key)
1140           {
1141           case SDLK_ESCAPE:
1142             Menu::set_current(leveleditor_menu);
1143             break;
1144           case SDLK_F1:
1145             if(le_level != NULL)
1146               le_showhelp();
1147             break;
1148           case SDLK_HOME:
1149             cursor_x = 0;
1150             pos_x = cursor_x;
1151             break;
1152           case SDLK_END:
1153             cursor_x = (le_level->get_sector("main")->solids->get_width() * 32) - 32;
1154             pos_x = cursor_x;
1155             break;
1156           case SDLK_F9:
1157             le_show_grid = !le_show_grid;
1158             break;
1159           default:
1160             break;
1161           }
1162           break;
1163         case SDL_MOUSEBUTTONDOWN:
1164           if(event.button.button == SDL_BUTTON_LEFT)
1165           {
1166             le_mouse_pressed[LEFT] = true;
1167
1168             selection.x1 = event.motion.x + pos_x;
1169             selection.y1 = event.motion.y + pos_y;
1170             selection.x2 = event.motion.x + pos_x;
1171             selection.y2 = event.motion.y + pos_y;
1172           }
1173           else if(event.button.button == SDL_BUTTON_RIGHT)
1174           {
1175             le_mouse_pressed[RIGHT] = true;
1176           }
1177           break;
1178         case SDL_MOUSEBUTTONUP:
1179           if(event.button.button == SDL_BUTTON_LEFT)
1180           {
1181             le_mouse_pressed[LEFT] = false;
1182             le_mouse_clicked[LEFT] = true;
1183           }
1184           else if(event.button.button == SDL_BUTTON_RIGHT)
1185           {
1186             le_mouse_pressed[RIGHT] = false;
1187             le_mouse_clicked[RIGHT] = true;
1188           }
1189           break;
1190         case SDL_MOUSEMOTION:
1191
1192           if(!Menu::current())
1193           {
1194             x = event.motion.x;
1195             y = event.motion.y;
1196
1197             if(le_current.IsTile())
1198             {
1199               cursor_x = ((int)(pos_x + x) / 32) * 32;
1200               cursor_y = ((int)(pos_y + y) / 32) * 32;
1201             }
1202             else
1203             {
1204               cursor_x = x;
1205               cursor_y = y;
1206             }
1207
1208             if(le_mouse_pressed[LEFT])
1209             {
1210               selection.x2 = x + pos_x;
1211               selection.y2 = y + pos_y;
1212             }
1213
1214             if(le_mouse_pressed[RIGHT])
1215             {
1216               pos_x += -1 * event.motion.xrel;
1217               pos_y += -1 * event.motion.yrel;
1218             }
1219           }
1220           break;
1221         default:
1222           break;
1223         }
1224       }
1225       else if(event.type == SDL_QUIT) /* window closing */
1226       {
1227       done = 1;
1228       }
1229     }
1230
1231     if(le_level != NULL)
1232     {
1233       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 &&
1234           event.motion.y > 0 && event.motion.y < screen->h)))
1235       {
1236         le_mouse_pressed[LEFT] = false;
1237         le_mouse_pressed[RIGHT] = false;
1238
1239         if(!Menu::current())
1240         {
1241           /* Check for button events */
1242           le_test_level_bt->event(event);
1243           if(le_test_level_bt->get_state() == BUTTON_CLICKED)
1244             le_testlevel();
1245           le_save_level_bt->event(event);
1246           if(le_save_level_bt->get_state() == BUTTON_CLICKED)
1247             le_level->save(le_level_subset->name.c_str());
1248           le_exit_bt->event(event);
1249           if(le_exit_bt->get_state() == BUTTON_CLICKED)
1250           {
1251             Menu::set_current(leveleditor_menu);
1252           }
1253           le_next_level_bt->event(event);
1254           if(le_next_level_bt->get_state() == BUTTON_CLICKED)
1255           {
1256             if(le_levelnb < le_level_subset->levels)
1257             {
1258               le_goto_level(le_levelnb+1);
1259             }
1260             else
1261             {
1262               Level new_lev;
1263               char str[1024];
1264               sprintf(str,"Level %d doesn't exist. Create it?",le_levelnb+1);
1265               Surface* surf = new Surface(le_level->get_sector("main")->background->get_image(), false);
1266               if(confirm_dialog(surf, str))
1267               {
1268                 new_lev.save(le_level_subset->name.c_str());
1269                 le_level_subset->levels = le_levelnb;
1270                 le_goto_level(le_levelnb);
1271               }
1272              if(surf != NULL)
1273               delete surf;
1274             }
1275           }
1276           le_previous_level_bt->event(event);
1277           if(le_previous_level_bt->get_state() == BUTTON_CLICKED)
1278           {
1279             if(le_levelnb > 1)
1280               le_goto_level(le_levelnb -1);
1281           }
1282           le_rubber_bt->event(event);
1283           if(le_rubber_bt->get_state() == BUTTON_CLICKED)
1284             le_current.Tile(0);
1285
1286           if(!cur_objects.empty())
1287           {
1288             le_object_select_bt->event(event);
1289             if(le_object_select_bt->get_state() == BUTTON_CLICKED)
1290             {
1291               MouseCursor::set_current(mouse_select_object);
1292             }
1293
1294             le_object_properties_bt->event(event);
1295             if(le_object_properties_bt->get_state() == BUTTON_CLICKED)
1296             {
1297               le_change_object_properties(selected_game_object);
1298             }
1299           }
1300
1301
1302           if(le_selection_mode == SQUARE)
1303           {
1304             le_select_mode_one_bt->event(event);
1305             if(le_select_mode_one_bt->get_state() == BUTTON_CLICKED)
1306               le_selection_mode = CURSOR;
1307           }
1308           else
1309           {
1310             le_select_mode_two_bt->event(event);
1311             if(le_select_mode_two_bt->get_state() == BUTTON_CLICKED)
1312               le_selection_mode = SQUARE;
1313           }
1314           ButtonPanelMap::iterator it;
1315           le_tilegroup_bt->event(event);
1316           switch (le_tilegroup_bt->get_state())
1317           {
1318           case BUTTON_CLICKED:
1319             Menu::set_current(select_tilegroup_menu);
1320             select_tilegroup_menu_effect.start(200);
1321             select_tilegroup_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1322             break;
1323           case BUTTON_WHEELUP:
1324             if(cur_tilegroup.empty())
1325             {
1326               cur_tilegroup = tilegroups_map.begin()->first;
1327             }
1328             else
1329             {
1330               it = tilegroups_map.find(cur_tilegroup);
1331               if((++it) == tilegroups_map.end())
1332               {
1333                 cur_tilegroup = tilegroups_map.begin()->first;
1334               }
1335               else
1336               {
1337                 cur_tilegroup = (*it).first;
1338               }
1339             }
1340
1341             cur_objects = "";
1342             break;
1343           case BUTTON_WHEELDOWN:
1344             it = tilegroups_map.find(cur_tilegroup);
1345             if(it == tilegroups_map.begin())
1346             {
1347               cur_tilegroup = tilegroups_map.rbegin()->first;
1348               cur_objects = "";
1349               break;
1350             }
1351             if(--it != --tilegroups_map.begin())
1352               cur_tilegroup = (*it).first;
1353             else
1354               cur_tilegroup = tilegroups_map.rbegin()->first;
1355
1356             cur_objects = "";
1357             break;
1358           default:
1359             break;
1360           }
1361
1362           le_objects_bt->event(event);
1363           switch (le_objects_bt->get_state())
1364           {
1365           case BUTTON_CLICKED:
1366             Menu::set_current(select_objects_menu);
1367             select_objects_menu_effect.start(200);
1368             select_objects_menu->set_pos(screen->w - 64,100,-0.5,0.5);
1369             break;
1370           case BUTTON_WHEELUP:
1371             it = objects_map.find(cur_objects);
1372             if(it == objects_map.end())
1373             {
1374               cur_objects = objects_map.begin()->first;
1375               cur_tilegroup = "";
1376               break;
1377             }
1378             if(++it != objects_map.end())
1379               cur_objects = (*it).first;
1380             else
1381               cur_objects = objects_map.begin()->first;
1382
1383             cur_tilegroup = "";
1384             break;
1385           case BUTTON_WHEELDOWN:
1386             it = objects_map.find(cur_objects);
1387             if(it == objects_map.begin())
1388             {
1389               cur_objects = objects_map.rbegin()->first;
1390               cur_tilegroup = "";
1391               break;
1392             }
1393             if(--it != --objects_map.begin())
1394               cur_objects = (*it).first;
1395             else
1396               cur_objects = objects_map.rbegin()->first;
1397
1398             cur_tilegroup = "";
1399             break;
1400             break;
1401           default:
1402             break;
1403           }
1404
1405           le_settings_bt->event(event);
1406           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1407           {
1408             update_level_settings_menu();
1409             Menu::set_current(level_settings_menu);
1410           }
1411           if(!cur_tilegroup.empty())
1412           {
1413             if((pbutton = tilegroups_map[cur_tilegroup]->event(event)) != NULL)
1414             {
1415               if(pbutton->get_state() == BUTTON_CLICKED)
1416               {
1417                 le_current.Tile(pbutton->get_tag());
1418               }
1419             }
1420           }
1421           else if(!cur_objects.empty())
1422           {
1423             if((pbutton = objects_map[cur_objects]->event(event)) != NULL)
1424             {
1425               if(pbutton->get_state() == BUTTON_CLICKED)
1426               {
1427 #if 0   // TODO FIXME XXX: New solution for this?
1428                 le_current.Object(pbutton->get_drawable());
1429 #endif
1430               }
1431             }
1432           }
1433
1434           if((pbutton = le_tilemap_panel->event(event)) != NULL)
1435           {
1436             if(pbutton->get_state() == BUTTON_CLICKED)
1437             {
1438               active_tm = pbutton->get_tag();
1439             }
1440           }
1441         }
1442         else
1443         {
1444           le_settings_bt->event(event);
1445           if(le_settings_bt->get_state() == BUTTON_CLICKED)
1446           {
1447             Menu::set_current(0);
1448           }
1449           le_tilegroup_bt->event(event);
1450           if(le_tilegroup_bt->get_state() == BUTTON_CLICKED)
1451           {
1452             Menu::set_current(0);
1453           }
1454           le_objects_bt->event(event);
1455           if(le_objects_bt->get_state() == BUTTON_CLICKED)
1456           {
1457             Menu::set_current(0);
1458           }
1459         }
1460       }
1461
1462       if(!Menu::current() && !show_minimap)
1463       {
1464         if(le_mouse_pressed[LEFT])
1465         {
1466           if(MouseCursor::current() != mouse_select_object)
1467           {
1468             if(le_current.IsTile())
1469               le_change(cursor_x, cursor_y, active_tm, le_current.tile);
1470           }
1471         }
1472         else if(le_mouse_clicked[LEFT])
1473         {
1474           if(MouseCursor::current() == mouse_select_object)
1475           {
1476             bool object_got_hit = false;
1477             base_type cursor_base;
1478             if(le_current.IsTile())
1479             {
1480             cursor_base.x = cursor_x;
1481             cursor_base.y = cursor_y;
1482             }
1483             else if(le_current.IsObject())
1484             {
1485             cursor_base.x = cursor_x + pos_x;
1486             cursor_base.y = cursor_y + pos_y;       
1487             }
1488             cursor_base.width = 32;
1489             cursor_base.height = 32;
1490
1491             for(std::vector<GameObject*>::iterator it =
1492                 le_level->get_sector("main")->gameobjects.begin();
1493                 it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1494               MovingObject* mobj = dynamic_cast<MovingObject*> (*it);
1495               if(!mobj)
1496                 continue;
1497
1498               if(rectcollision(cursor_base, mobj->base))
1499               {
1500                 selected_game_object = mobj;
1501                 object_got_hit = true;
1502                 break;
1503               }
1504             }
1505
1506             if(!object_got_hit)
1507             {
1508               selected_game_object = NULL;
1509               le_object_properties_bt->set_active(false);
1510             }
1511             else
1512               le_object_properties_bt->set_active(true);
1513
1514             MouseCursor::set_current(mouse_cursor);
1515
1516           }
1517           else
1518           {
1519             // FIXME TODO
1520 #if 0
1521 //FIXME: objects interactions with the level editor should have a major improvement
1522             if(le_current.IsObject())
1523             {
1524               le_level_changed  = true;
1525               BadGuy* pbadguy = dynamic_cast<BadGuy*>(le_current.obj);
1526
1527               if(pbadguy)
1528               {
1529                 Camera& camera = *le_level->get_sector("main")->camera;
1530
1531                 le_level->get_sector("main")->bad_guys.push_back(
1532                     new BadGuy(pbadguy->kind,
1533                       cursor_x + camera.get_translation().x,
1534                       cursor_y + camera.get_translation().y));
1535                 le_level->get_sector("main")->gameobjects.push_back(le_level->get_sector("main")->bad_guys.back());
1536               }
1537             }
1538 #endif
1539
1540           }
1541           
1542           le_mouse_clicked[LEFT] = false;
1543
1544         }
1545       }
1546     }
1547   }
1548   if(!Menu::current())
1549   {
1550     show_minimap = false;
1551
1552     if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB)
1553       show_minimap = true;
1554
1555     le_move_left_bt->event(event);
1556     le_move_right_bt->event(event);
1557     le_move_up_bt->event(event);
1558     le_move_down_bt->event(event);
1559     switch(le_move_left_bt->get_state())
1560     {
1561     case BUTTON_PRESSED:
1562       pos_x -= KEYBOARD_SPEED;
1563       show_minimap = true;
1564       break;
1565     case BUTTON_HOVER:
1566       pos_x -= MOUSE_SPEED;
1567       show_minimap = true;
1568       break;
1569     case BUTTON_CLICKED:
1570       show_minimap = true;
1571       break;
1572     default:
1573       break;
1574     }
1575
1576     switch(le_move_right_bt->get_state())
1577     {
1578     case BUTTON_PRESSED:
1579       pos_x += KEYBOARD_SPEED;
1580       show_minimap = true;
1581       break;
1582     case BUTTON_HOVER:
1583       pos_x += MOUSE_SPEED;
1584       show_minimap = true;
1585       break;
1586     case BUTTON_CLICKED:
1587       show_minimap = true;
1588       break;
1589     default:
1590       break;
1591     }
1592
1593     switch(le_move_up_bt->get_state())
1594     {
1595     case BUTTON_PRESSED:
1596       pos_y -= KEYBOARD_SPEED;
1597       show_minimap = true;
1598       break;
1599     case BUTTON_HOVER:
1600       pos_y -= MOUSE_SPEED;
1601       show_minimap = true;
1602       break;
1603     case BUTTON_CLICKED:
1604       show_minimap = true;
1605       break;
1606     default:
1607       break;
1608     }
1609
1610     switch(le_move_down_bt->get_state())
1611     {
1612     case BUTTON_PRESSED:
1613       pos_y += KEYBOARD_SPEED;
1614       show_minimap = true;
1615       break;
1616     case BUTTON_HOVER:
1617       pos_y += MOUSE_SPEED;
1618       show_minimap = true;
1619       break;
1620     case BUTTON_CLICKED:
1621       show_minimap = true;
1622       break;
1623     default:
1624       break;
1625     }
1626
1627     /* checking if pos_x and pos_y is within the limits... */
1628     if((unsigned)pos_x > (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w)
1629       pos_x = (le_level->get_sector("main")->solids->get_width() * 32 + 32*2) - screen->w;
1630     if(pos_x < 0)
1631       pos_x = 0;
1632
1633     if((unsigned)pos_y > (le_level->get_sector("main")->solids->get_height() * 32) - screen->h)
1634       pos_y = (le_level->get_sector("main")->solids->get_height() * 32) - screen->h;
1635     if(pos_y < 0)
1636       pos_y = 0;
1637   }
1638 }
1639
1640 void le_highlight_selection()
1641 {
1642   int x1, x2, y1, y2;
1643
1644   if(selection.x1 < selection.x2)
1645   {
1646     x1 = selection.x1;
1647     x2 = selection.x2;
1648   }
1649   else
1650   {
1651     x1 = selection.x2;
1652     x2 = selection.x1;
1653   }
1654   if(selection.y1 < selection.y2)
1655   {
1656     y1 = selection.y1;
1657     y2 = selection.y2;
1658   }
1659   else
1660   {
1661     y1 = selection.y2;
1662     y2 = selection.y1;
1663   }
1664
1665   x1 /= 32;
1666   x2 /= 32;
1667   y1 /= 32;
1668   y2 /= 32;
1669
1670   fillrect(x1*32-pos_x, y1*32-pos_y,32* (x2 - x1 + 1),32 * (y2 - y1 + 1),173,234,177,103);
1671 }
1672
1673 void le_change(float x, float y, int tm, unsigned int c)
1674 {
1675   if(le_level != NULL)
1676   {
1677     int xx,yy;
1678     int x1, x2, y1, y2;
1679
1680     le_level_changed = true;
1681
1682     switch(le_selection_mode)
1683     {
1684     case CURSOR:
1685       le_change(x,y,tm,c);
1686
1687       base_type cursor_base;
1688       cursor_base.x = x;
1689       cursor_base.y = y;
1690       cursor_base.width = 32;
1691       cursor_base.height = 32;
1692
1693       /* if there is a bad guy over there, remove it */
1694       // XXX TODO
1695       for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1696             it != le_level->get_sector("main")->gameobjects.end(); ++it) {
1697         BadGuy* badguy = dynamic_cast<BadGuy*>((*it));
1698         if (badguy)
1699         {
1700           if(rectcollision(cursor_base, badguy->base))
1701           {
1702             delete (*it);
1703             le_level->get_sector("main")->gameobjects.erase(std::remove(le_level->get_sector("main")->gameobjects.begin(),
1704                le_level->get_sector("main")->gameobjects.end(), *it),
1705                le_level->get_sector("main")->gameobjects.end());
1706             break;
1707           }
1708         }
1709       }
1710
1711       break;
1712     case SQUARE:
1713       if(selection.x1 < selection.x2)
1714       {
1715         x1 = selection.x1;
1716         x2 = selection.x2;
1717       }
1718       else
1719       {
1720         x1 = selection.x2;
1721         x2 = selection.x1;
1722       }
1723       if(selection.y1 < selection.y2)
1724       {
1725         y1 = selection.y1;
1726         y2 = selection.y2;
1727       }
1728       else
1729       {
1730         y1 = selection.y2;
1731         y2 = selection.y1;
1732       }
1733
1734       x1 /= 32;
1735       x2 /= 32;
1736       y1 /= 32;
1737       y2 /= 32;
1738
1739       /* if there is a bad guy over there, remove it */
1740       // TODO FIXME
1741       for(std::vector<GameObject*>::iterator it = le_level->get_sector("main")->gameobjects.begin();
1742           it != le_level->get_sector("main")->gameobjects.end(); ++it /* will be at end of loop */)
1743       {
1744         MovingObject* pmobject = dynamic_cast<MovingObject*> (*it);       
1745         if (pmobject)
1746         {
1747           if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2
1748               && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2)
1749           {
1750             delete (*it);
1751             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());
1752             continue;
1753           }
1754           else
1755           {
1756             ++it;
1757           }
1758         }
1759       }
1760
1761       for(xx = x1; xx <= x2; xx++)
1762         for(yy = y1; yy <= y2; yy++)
1763         {
1764           le_change(xx*32, yy*32, tm, c);
1765
1766         }
1767       break;
1768     default:
1769       break;
1770     }
1771   }
1772 }
1773
1774 void le_testlevel()
1775 {
1776   //Make sure a time value is set when testing the level
1777   if(le_level->time_left == 0)
1778     le_level->time_left = 250;
1779
1780   le_level->save("test.stl");
1781
1782   GameSession session("test.stl", ST_GL_TEST);
1783   session.run();
1784   player_status.reset();
1785
1786   sound_manager->halt_music();
1787
1788   Menu::set_current(NULL);
1789 }
1790
1791 void le_showhelp()
1792 {
1793   DrawingContext context;
1794
1795   bool tmp_show_grid = le_show_grid;
1796   SelectionMode temp_le_selection_mode = le_selection_mode;
1797   le_selection_mode = NONE;
1798   show_selections = true;
1799   le_show_grid = false;
1800   le_help_shown = true;
1801
1802   SDL_Event event;
1803   unsigned int done_;
1804   char str[1024];
1805   char *text1[] = {
1806
1807                    " - Supertux level editor tutorial - ",
1808                    "",
1809                    "To make your map, click the       ",
1810                    "tilegroup button and choose a     ",
1811                    "tilegroup.",
1812                    "Pick a tile and simply hold down  ",
1813                    "the left mouse button over the map",
1814                    "to \"paint\" your selection over",
1815                    "the screen.",
1816                    "",
1817                    "There are three layers for painting",
1818                    "tiles upon, Background layer,",
1819                    "the Interactive layer, and the",
1820                    "Foreground layer, which can be",
1821                    "toggled by the BkGrd, IntAct and",
1822                    "FrGrd buttons. The Foreground and",
1823                    "Background layers do not effect",
1824                    "Tux in the gameplay, but lie in",
1825                    "front of him or lie behind him in",
1826                    "his adventures.",
1827                  };
1828
1829   char *text2[] = {
1830
1831                     " - Supertux level editor tutorial - ",
1832                     "",
1833                     "The tiles placed on",
1834                     "the Interactive layer are those",
1835                     "which actually effect Tux in the",
1836                     "game.",
1837                     "",
1838                     "Click the objects menu to put ",
1839                     "bad guys and other objects in the",
1840                     "game. Unlike placing tiles, you",
1841                     "cannot \"paint\" enemies. Click",
1842                     "them onto the screen one at a time.",
1843                     "",
1844                     "To change the settings of your",
1845                     "level, click the button with the",
1846                     "screwdriver and wrench. From here",
1847                     "you can change the background,",
1848                     "music, length of the level,",
1849                     "and more."
1850                   };
1851
1852   char *text3[] = {
1853
1854                     " - Supertux level editor tutorial - ",
1855                     "",
1856                     "You may have more than one level.",
1857                     "Pressing the up and down buttons",
1858                     "above the button bar lets you",
1859                     "choose which one you are working on.",
1860                     "",
1861                     "If you would like to speed up your",
1862                     "level editing, a useful trick is",
1863                     "to learn the keyboard shortcuts.",
1864                     "They are easy to learn, just right-",
1865                     "click on the buttons.",
1866                     "",
1867                     "Have fun making levels! If you make",
1868                     "some good ones, send them to us on",
1869                     "the SuperTux mailing list!",
1870                     "- SuperTux team"
1871                   };
1872
1873   char **text[] = { text1, text2, text3 };
1874
1875
1876   for(int i = 0; i < 3; i++)
1877     {
1878     context.draw_gradient(Color(0,0,0), Color(255,255,255), LAYER_BACKGROUND0);
1879     le_drawinterface(context);
1880
1881     context.draw_text_center(blue_text, "- Help -", Vector(0, 30), LAYER_GUI);
1882
1883     for(unsigned int t = 0; t < sizeof(text[i])/sizeof(char *); t++)
1884       context.draw_text(white_text, text[i][t], Vector(5, 80+(t*white_text->get_height())), LAYER_GUI);
1885
1886     sprintf(str,"Press any key to continue - Page %d/%d?", i, sizeof(text));
1887     context.draw_text(gold_text, str, Vector(0, 0), LAYER_GUI);
1888
1889     context.do_drawing();
1890
1891     done_ = 0;
1892
1893     while(done_ == 0)
1894       {
1895       done_ = wait_for_event(event);
1896       SDL_Delay(50);
1897       }
1898     }
1899
1900   show_selections = true;
1901   le_show_grid = tmp_show_grid;
1902   le_selection_mode = temp_le_selection_mode;
1903   le_help_shown = false;
1904 }