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