rnd-19990110-2
[rocksndiamonds.git] / src / editor.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  editor.c                                                *
12 ***********************************************************/
13
14 #include "editor.h"
15 #include "screens.h"
16 #include "tools.h"
17 #include "misc.h"
18 #include "buttons.h"
19 #include "files.h"
20 #include "game.h"
21 #include "tape.h"
22
23 /* positions in the level editor */
24 #define ED_WIN_MB_LEFT_XPOS     7
25 #define ED_WIN_MB_LEFT_YPOS     6
26 #define ED_WIN_LEVELNR_XPOS     77
27 #define ED_WIN_LEVELNR_YPOS     7
28 #define ED_WIN_MB_MIDDLE_XPOS   7
29 #define ED_WIN_MB_MIDDLE_YPOS   258
30 #define ED_WIN_MB_RIGHT_XPOS    77
31 #define ED_WIN_MB_RIGHT_YPOS    258
32
33 /* other constants for the editor */
34 #define ED_SCROLL_NO            0
35 #define ED_SCROLL_LEFT          1
36 #define ED_SCROLL_RIGHT         2
37 #define ED_SCROLL_UP            4
38 #define ED_SCROLL_DOWN          8
39
40 /* screens in the level editor */
41 #define ED_MODE_DRAWING         0
42 #define ED_MODE_INFO            1
43 #define ED_MODE_PROPERTIES      2
44
45 /* how many steps can be cancelled */
46 #define NUM_UNDO_STEPS          (10 + 1)
47
48 /* values for random placement */
49 #define RANDOM_USE_PERCENTAGE   0
50 #define RANDOM_USE_NUM_OBJECTS  1
51
52 /* values for elements with content */
53 #define MAX_ELEMCONT            8
54
55 /* values for the control window */
56 #define ED_CTRL_BUTTONS_GFX_YPOS        236
57 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS    142
58
59 #define ED_CTRL1_BUTTONS_HORIZ  4
60 #define ED_CTRL1_BUTTONS_VERT   4
61 #define ED_CTRL1_BUTTON_XSIZE   22
62 #define ED_CTRL1_BUTTON_YSIZE   22
63 #define ED_CTRL1_BUTTONS_XPOS   6
64 #define ED_CTRL1_BUTTONS_YPOS   6
65 #define ED_CTRL2_BUTTONS_HORIZ  3
66 #define ED_CTRL2_BUTTONS_VERT   2
67 #define ED_CTRL2_BUTTON_XSIZE   30
68 #define ED_CTRL2_BUTTON_YSIZE   20
69 #define ED_CTRL2_BUTTONS_XPOS   5
70 #define ED_CTRL2_BUTTONS_YPOS   100
71 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
72 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
73 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
74
75 /* values for properties window */
76 #define ED_PROPERTIES_XPOS      (TILEX - MINI_TILEX/2)
77
78 /* values for counter gadgets */
79 #define ED_COUNT_VALUE_XOFFSET  5
80 #define ED_COUNT_VALUE_YOFFSET  3
81 #define ED_COUNT_SCORE_XPOS     ED_PROPERTIES_XPOS
82 #define ED_COUNT_SCORE_YPOS     (14 * MINI_TILEY)
83 #define ED_COUNT_ELEMCONT_XPOS  ED_PROPERTIES_XPOS
84 #define ED_COUNT_ELEMCONT_YPOS  (17 * MINI_TILEY)
85
86 /* values for element content drawing areas */
87 #define ED_AREA_ELEMCONT_XPOS   (TILEX)
88 #define ED_AREA_ELEMCONT_YPOS   (10 * TILEY)
89
90 /* values for scrolling gadgets */
91 #define ED_SCROLLBUTTON_XPOS    24
92 #define ED_SCROLLBUTTON_YPOS    0
93 #define ED_SCROLLBAR_XPOS       24
94 #define ED_SCROLLBAR_YPOS       64
95
96 #define ED_SCROLLBUTTON_XSIZE   16
97 #define ED_SCROLLBUTTON_YSIZE   16
98
99 #define ED_SCROLL_UP_XPOS       (SXSIZE - ED_SCROLLBUTTON_XSIZE)
100 #define ED_SCROLL_UP_YPOS       (0)
101 #define ED_SCROLL_DOWN_XPOS     ED_SCROLL_UP_XPOS
102 #define ED_SCROLL_DOWN_YPOS     (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
103 #define ED_SCROLL_LEFT_XPOS     (0)
104 #define ED_SCROLL_LEFT_YPOS     (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
105 #define ED_SCROLL_RIGHT_XPOS    (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
106 #define ED_SCROLL_RIGHT_YPOS    ED_SCROLL_LEFT_YPOS
107 #define ED_SCROLL_VERTICAL_XPOS ED_SCROLL_UP_XPOS
108 #define ED_SCROLL_VERTICAL_YPOS (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
109 #define ED_SCROLL_VERTICAL_XSIZE ED_SCROLLBUTTON_XSIZE
110 #define ED_SCROLL_VERTICAL_YSIZE (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
111 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
112 #define ED_SCROLL_HORIZONTAL_YPOS ED_SCROLL_LEFT_YPOS
113 #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
114 #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE
115
116 /* control button identifiers */
117 #define ED_CTRL_ID_SINGLE_ITEMS         0
118 #define ED_CTRL_ID_CONNECTED_ITEMS      1
119 #define ED_CTRL_ID_LINE                 2
120 #define ED_CTRL_ID_TEXT                 3
121 #define ED_CTRL_ID_RECTANGLE            4
122 #define ED_CTRL_ID_FILLED_BOX           5
123 #define ED_CTRL_ID_WRAP_UP              6
124 #define ED_CTRL_ID_PROPERTIES           7
125 #define ED_CTRL_ID_FLOOD_FILL           8
126 #define ED_CTRL_ID_WRAP_LEFT            9
127 #define ED_CTRL_ID_UNUSED1              10
128 #define ED_CTRL_ID_WRAP_RIGHT           11
129 #define ED_CTRL_ID_RANDOM_PLACEMENT     12
130 #define ED_CTRL_ID_BRUSH                13
131 #define ED_CTRL_ID_WRAP_DOWN            14
132 #define ED_CTRL_ID_PICK_ELEMENT         15
133 #define ED_CTRL_ID_UNDO                 16
134 #define ED_CTRL_ID_INFO                 17
135 #define ED_CTRL_ID_SAVE                 18
136 #define ED_CTRL_ID_CLEAR                19
137 #define ED_CTRL_ID_TEST                 20
138 #define ED_CTRL_ID_EXIT                 21
139
140 /* counter button identifiers */
141 #define ED_CTRL_ID_SCORE_DOWN           22
142 #define ED_CTRL_ID_SCORE_UP             23
143 #define ED_CTRL_ID_ELEMCONT_DOWN        24
144 #define ED_CTRL_ID_ELEMCONT_UP          25
145
146 /* drawing area identifiers */
147 #define ED_CTRL_ID_DRAWING_LEVEL        26
148 #define ED_CTRL_ID_ELEMCONT_0           27
149 #define ED_CTRL_ID_ELEMCONT_7           34
150 #define ED_CTRL_ID_AMOEBA_CONTENT       35
151
152 /* text input identifiers */
153 #define ED_CTRL_ID_LEVEL_NAME           36
154
155 /* gadgets for scrolling of drawing area */
156 #define ED_CTRL_ID_SCROLL_UP            37
157 #define ED_CTRL_ID_SCROLL_DOWN          38
158 #define ED_CTRL_ID_SCROLL_LEFT          39
159 #define ED_CTRL_ID_SCROLL_RIGHT         40
160 #define ED_CTRL_ID_SCROLL_VERTICAL      41
161 #define ED_CTRL_ID_SCROLL_HORIZONTAL    42
162
163 #define ED_NUM_GADGETS                  43
164
165 /* values for counter gadgets */
166 #define ED_COUNTER_SCORE                0
167 #define ED_COUNTER_ELEMCONT             1
168
169 #define ED_NUM_COUNTERBUTTONS           2
170 #define ED_NUM_SCROLLBUTTONS            4
171 #define ED_NUM_SCROLLBARS               2
172
173 /* values for CopyLevelToUndoBuffer() */
174 #define UNDO_IMMEDIATE                  0
175 #define UNDO_ACCUMULATE                 1
176
177 static char *control_infotext[ED_NUM_CTRL_BUTTONS] =
178 {
179   "draw single items",
180   "draw connected items",
181   "draw lines",
182   "enter text elements",
183   "draw outline rectangles",
184   "draw filled boxes",
185   "wrap (rotate) level up",
186   "properties of drawing element",
187   "flood fill",
188   "wrap (rotate) level left",
189   "",
190   "wrap (rotate) level right",
191   "random element placement",
192   "grab brush",
193   "wrap (rotate) level down",
194   "pick drawing element from editing area",
195   "undo last operation",
196   "level properties",
197   "save level",
198   "clear level",
199   "test level",
200   "exit level editor",
201 };
202
203 static struct
204 {
205   int x, y;
206   int gadget_id;
207 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
208 {
209   { ED_COUNT_SCORE_XPOS,    ED_COUNT_SCORE_YPOS,    ED_CTRL_ID_SCORE_DOWN },
210   { ED_COUNT_ELEMCONT_XPOS, ED_COUNT_ELEMCONT_YPOS, ED_CTRL_ID_ELEMCONT_DOWN }
211 };
212
213 static struct
214 {
215   int xpos, ypos;
216   int x, y;
217   int gadget_id;
218   char *text;
219 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
220 {
221   {
222     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
223     ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,      ED_CTRL_ID_SCROLL_UP,
224     "scroll level editing area up"
225   },
226   {
227     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
228     ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,    ED_CTRL_ID_SCROLL_DOWN,
229     "scroll level editing area down"
230   },
231   {
232     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
233     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,    ED_CTRL_ID_SCROLL_LEFT,
234     "scroll level editing area left"
235   },
236   {
237     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
238     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,   ED_CTRL_ID_SCROLL_RIGHT,
239     "scroll level editing area right"
240   }
241 };
242
243 static struct
244 {
245   int xpos, ypos;
246   int x, y;
247   int width, height;
248   int type;
249   int gadget_id;
250   char *text;
251 } scrollbar_info[ED_NUM_SCROLLBARS] =
252 {
253   {
254     ED_SCROLLBAR_XPOS,          ED_SCROLLBAR_YPOS,
255     ED_SCROLL_VERTICAL_XPOS,    ED_SCROLL_VERTICAL_YPOS,
256     ED_SCROLL_VERTICAL_XSIZE,   ED_SCROLL_VERTICAL_YSIZE,
257     GD_TYPE_SCROLLBAR_VERTICAL,
258     ED_CTRL_ID_SCROLL_VERTICAL,
259     "scroll level editing area vertically"
260   },
261   {
262     ED_SCROLLBAR_XPOS,          ED_SCROLLBAR_YPOS,
263     ED_SCROLL_HORIZONTAL_XPOS,  ED_SCROLL_HORIZONTAL_YPOS,
264     ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
265     GD_TYPE_SCROLLBAR_HORIZONTAL,
266     ED_CTRL_ID_SCROLL_HORIZONTAL,
267     "scroll level editing area horizontally"
268   },
269 };
270
271
272 /* forward declaration for internal use */
273 static void DrawDrawingWindow();
274 static void DrawPropertiesWindow();
275 static void CopyLevelToUndoBuffer(int);
276 static void HandleControlButtons(struct GadgetInfo *);
277 static void HandleCounterButtons(struct GadgetInfo *);
278 static void HandleDrawingAreas(struct GadgetInfo *);
279 static void HandleDrawingAreaInfo(struct GadgetInfo *);
280 static void HandleTextInputGadgets(struct GadgetInfo *);
281
282 static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS];
283 static boolean level_editor_gadgets_created = FALSE;
284
285 static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
286 static int last_drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
287 static boolean draw_with_brush = FALSE;
288 static int properties_element = 0;
289
290 static short ElementContent[MAX_ELEMCONT][3][3];
291 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
292 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
293 static int undo_buffer_position = 0;
294 static int undo_buffer_steps = 0;
295
296 static int random_placement_percentage = 10;
297 static int random_placement_num_objects = 10;
298 #if 0
299 static int random_placement_method = RANDOM_USE_PERCENTAGE;
300 #else
301 static int random_placement_method = RANDOM_USE_NUM_OBJECTS;
302 #endif
303
304 /* pointer to score value */
305 static int *gadget_score_value;
306 static int *gadget_areas_value;
307
308 static int level_xpos,level_ypos;
309 static int edit_mode;
310 static boolean name_typing;
311 static int new_element1 = EL_MAUERWERK;
312 static int new_element2 = EL_LEERRAUM;
313 static int new_element3 = EL_ERDREICH;
314
315 int element_shift = 0;
316
317 int editor_element[] =
318 {
319   EL_CHAR_A + ('B' - 'A'),
320   EL_CHAR_A + ('O' - 'A'),
321   EL_CHAR_A + ('U' - 'A'),
322   EL_CHAR_A + ('L' - 'A'),
323
324   EL_CHAR_MINUS,
325   EL_CHAR_A + ('D' - 'A'),
326   EL_CHAR_A + ('E' - 'A'),
327   EL_CHAR_A + ('R' - 'A'),
328
329   EL_CHAR_A + ('D' - 'A'),
330   EL_CHAR_A + ('A' - 'A'),
331   EL_CHAR_A + ('S' - 'A'),
332   EL_CHAR_A + ('H' - 'A'),
333
334   EL_SPIELFIGUR,
335   EL_LEERRAUM,
336   EL_ERDREICH,
337   EL_BETON,
338
339   EL_FELSBODEN,
340   EL_SIEB2_INAKTIV,
341   EL_AUSGANG_ZU,
342   EL_AUSGANG_AUF,
343
344   EL_EDELSTEIN_BD,
345   EL_BUTTERFLY_O,
346   EL_FIREFLY_O,
347   EL_FELSBROCKEN,
348
349   EL_BUTTERFLY_L,
350   EL_FIREFLY_L,
351   EL_BUTTERFLY_R,
352   EL_FIREFLY_R,
353
354   EL_AMOEBE_BD,
355   EL_BUTTERFLY_U,
356   EL_FIREFLY_U,
357   EL_LEERRAUM,
358
359   EL_CHAR_A + ('E' - 'A'),
360   EL_CHAR_A + ('M' - 'A'),
361   EL_CHAR_A + ('E' - 'A'),
362   EL_CHAR_MINUS,
363
364   EL_CHAR_A + ('R' - 'A'),
365   EL_CHAR_A + ('A' - 'A'),
366   EL_CHAR_A + ('L' - 'A'),
367   EL_CHAR_A + ('D' - 'A'),
368
369   EL_CHAR_A + ('M' - 'A'),
370   EL_CHAR_A + ('I' - 'A'),
371   EL_CHAR_A + ('N' - 'A'),
372   EL_CHAR_A + ('E' - 'A'),
373
374   EL_SPIELER1,
375   EL_SPIELER2,
376   EL_SPIELER3,
377   EL_SPIELER4,
378
379   EL_SPIELFIGUR,
380   EL_LEERRAUM,
381   EL_ERDREICH,
382   EL_FELSBROCKEN,
383
384   EL_BETON,
385   EL_MAUERWERK,
386   EL_FELSBODEN,
387   EL_SIEB_INAKTIV,
388
389   EL_EDELSTEIN,
390   EL_DIAMANT,
391   EL_KOKOSNUSS,
392   EL_BOMBE,
393
394   EL_ERZ_EDEL,
395   EL_ERZ_DIAM,
396   EL_MORAST_LEER,
397   EL_MORAST_VOLL,
398
399   EL_DYNAMIT_AUS,
400   EL_DYNAMIT,
401   EL_AUSGANG_ZU,
402   EL_AUSGANG_AUF,
403
404   EL_MAMPFER,
405   EL_KAEFER_O,
406   EL_FLIEGER_O,
407   EL_ROBOT,
408
409   EL_KAEFER_L,
410   EL_FLIEGER_L,
411   EL_KAEFER_R,
412   EL_FLIEGER_R,
413
414   EL_ABLENK_AUS,
415   EL_KAEFER_U,
416   EL_FLIEGER_U,
417   EL_UNSICHTBAR,
418
419   EL_BADEWANNE1,
420   EL_SALZSAEURE,
421   EL_BADEWANNE2,
422   EL_LEERRAUM,
423
424   EL_BADEWANNE3,
425   EL_BADEWANNE4,
426   EL_BADEWANNE5,
427   EL_LEERRAUM,
428
429   EL_TROPFEN,
430   EL_AMOEBE_TOT,
431   EL_AMOEBE_NASS,
432   EL_AMOEBE_NORM,
433
434   EL_SCHLUESSEL1,
435   EL_SCHLUESSEL2,
436   EL_SCHLUESSEL3,
437   EL_SCHLUESSEL4,
438
439   EL_PFORTE1,
440   EL_PFORTE2,
441   EL_PFORTE3,
442   EL_PFORTE4,
443
444   EL_PFORTE1X,
445   EL_PFORTE2X,
446   EL_PFORTE3X,
447   EL_PFORTE4X,
448
449   EL_CHAR_A + ('M' - 'A'),
450   EL_CHAR_A + ('O' - 'A'),
451   EL_CHAR_A + ('R' - 'A'),
452   EL_CHAR_A + ('E' - 'A'),
453
454   EL_PFEIL_L,
455   EL_PFEIL_R,
456   EL_PFEIL_O,
457   EL_PFEIL_U,
458
459   EL_AMOEBE_VOLL,
460   EL_EDELSTEIN_GELB,
461   EL_EDELSTEIN_ROT,
462   EL_EDELSTEIN_LILA,
463
464   EL_ERZ_EDEL_BD,
465   EL_ERZ_EDEL_GELB,
466   EL_ERZ_EDEL_ROT,
467   EL_ERZ_EDEL_LILA,
468
469   EL_LIFE,
470   EL_PACMAN_O,
471   EL_ZEIT_VOLL,
472   EL_ZEIT_LEER,
473
474   EL_PACMAN_L,
475   EL_MAMPFER2,
476   EL_PACMAN_R,
477   EL_MAUER_LEBT,
478
479   EL_LIFE_ASYNC,
480   EL_PACMAN_U,
481   EL_BIRNE_AUS,
482   EL_BIRNE_EIN,
483
484   EL_DYNABOMB_NR,
485   EL_DYNABOMB_SZ,
486   EL_DYNABOMB_XL,
487   EL_BADEWANNE,
488
489   EL_MAULWURF,
490   EL_PINGUIN,
491   EL_SCHWEIN,
492   EL_DRACHE,
493
494   EL_SONDE,
495   EL_MAUER_X,
496   EL_MAUER_Y,
497   EL_MAUER_XY,
498
499   EL_SPEED_PILL,
500   EL_LEERRAUM,
501   EL_LEERRAUM,
502   EL_LEERRAUM,
503
504   EL_CHAR_A + ('S' - 'A'),
505   EL_CHAR_A + ('O' - 'A'),
506   EL_CHAR_A + ('K' - 'A'),
507   EL_CHAR_A + ('O' - 'A'),
508
509   EL_CHAR_MINUS,
510   EL_CHAR_A + ('B' - 'A'),
511   EL_CHAR_A + ('A' - 'A'),
512   EL_CHAR_A + ('N' - 'A'),
513
514   EL_SOKOBAN_OBJEKT,
515   EL_SOKOBAN_FELD_LEER,
516   EL_SOKOBAN_FELD_VOLL,
517   EL_BETON,
518
519   EL_LEERRAUM,
520   EL_LEERRAUM,
521   EL_LEERRAUM,
522   EL_LEERRAUM,
523
524   EL_CHAR('S'),
525   EL_CHAR('U'),
526   EL_CHAR('P'),
527   EL_CHAR('A'),
528
529   EL_CHAR('P'),
530   EL_CHAR('L'),
531   EL_CHAR('E'),
532   EL_CHAR('X'),
533
534   EL_SP_EMPTY,
535   EL_SP_ZONK,
536   EL_SP_BASE,
537   EL_SP_MURPHY,
538
539   EL_SP_INFOTRON,
540   EL_SP_CHIP_SINGLE,
541   EL_SP_HARD_GRAY,
542   EL_SP_EXIT,
543
544   EL_SP_DISK_ORANGE,
545   EL_SP_PORT1_RIGHT,
546   EL_SP_PORT1_DOWN,
547   EL_SP_PORT1_LEFT,
548
549   EL_SP_PORT1_UP,
550   EL_SP_PORT2_RIGHT,
551   EL_SP_PORT2_DOWN,
552   EL_SP_PORT2_LEFT,
553
554   EL_SP_PORT2_UP,
555   EL_SP_SNIKSNAK,
556   EL_SP_DISK_YELLOW,
557   EL_SP_TERMINAL,
558
559   EL_SP_DISK_RED,
560   EL_SP_PORT_Y,
561   EL_SP_PORT_X,
562   EL_SP_PORT_XY,
563
564   EL_SP_ELECTRON,
565   EL_SP_BUG,
566   EL_SP_CHIP_LEFT,
567   EL_SP_CHIP_RIGHT,
568
569   EL_SP_HARD_BASE1,
570   EL_SP_HARD_GREEN,
571   EL_SP_HARD_BLUE,
572   EL_SP_HARD_RED,
573
574   EL_SP_HARD_YELLOW,
575   EL_SP_HARD_BASE2,
576   EL_SP_HARD_BASE3,
577   EL_SP_HARD_BASE4,
578
579   EL_SP_HARD_BASE5,
580   EL_SP_HARD_BASE6,
581   EL_SP_CHIP_UPPER,
582   EL_SP_CHIP_LOWER,
583
584 /*
585   EL_CHAR_A + ('D' - 'A'),
586   EL_CHAR_A + ('Y' - 'A'),
587   EL_CHAR_A + ('N' - 'A'),
588   EL_CHAR_A + ('A' - 'A'),
589
590   EL_CHAR_A + ('B' - 'A'),
591   EL_CHAR_A + ('L' - 'A'),
592   EL_CHAR_A + ('A' - 'A'),
593   EL_CHAR_A + ('S' - 'A'),
594
595   EL_CHAR_MINUS,
596   EL_CHAR_A + ('T' - 'A'),
597   EL_CHAR_A + ('E' - 'A'),
598   EL_CHAR_A + ('R' - 'A'),
599 */
600
601   EL_LEERRAUM,
602   EL_LEERRAUM,
603   EL_LEERRAUM,
604   EL_LEERRAUM,
605
606   EL_CHAR_AUSRUF,
607   EL_CHAR_ZOLL,
608   EL_CHAR_DOLLAR,
609   EL_CHAR_PROZ,
610
611   EL_CHAR_APOSTR,
612   EL_CHAR_KLAMM1,
613   EL_CHAR_KLAMM2,
614   EL_CHAR_PLUS,
615
616   EL_CHAR_KOMMA,
617   EL_CHAR_MINUS,
618   EL_CHAR_PUNKT,
619   EL_CHAR_SLASH,
620
621   EL_CHAR_0 + 0,
622   EL_CHAR_0 + 1,
623   EL_CHAR_0 + 2,
624   EL_CHAR_0 + 3,
625
626   EL_CHAR_0 + 4,
627   EL_CHAR_0 + 5,
628   EL_CHAR_0 + 6,
629   EL_CHAR_0 + 7,
630
631   EL_CHAR_0 + 8,
632   EL_CHAR_0 + 9,
633   EL_CHAR_DOPPEL,
634   EL_CHAR_SEMIKL,
635
636   EL_CHAR_LT,
637   EL_CHAR_GLEICH,
638   EL_CHAR_GT,
639   EL_CHAR_FRAGE,
640
641   EL_CHAR_AT,
642   EL_CHAR_A + 0,
643   EL_CHAR_A + 1,
644   EL_CHAR_A + 2,
645
646   EL_CHAR_A + 3,
647   EL_CHAR_A + 4,
648   EL_CHAR_A + 5,
649   EL_CHAR_A + 6,
650
651   EL_CHAR_A + 7,
652   EL_CHAR_A + 8,
653   EL_CHAR_A + 9,
654   EL_CHAR_A + 10,
655
656   EL_CHAR_A + 11,
657   EL_CHAR_A + 12,
658   EL_CHAR_A + 13,
659   EL_CHAR_A + 14,
660
661   EL_CHAR_A + 15,
662   EL_CHAR_A + 16,
663   EL_CHAR_A + 17,
664   EL_CHAR_A + 18,
665
666   EL_CHAR_A + 19,
667   EL_CHAR_A + 20,
668   EL_CHAR_A + 21,
669   EL_CHAR_A + 22,
670
671   EL_CHAR_A + 23,
672   EL_CHAR_A + 24,
673   EL_CHAR_A + 25,
674   EL_CHAR_AE,
675
676   EL_CHAR_OE,
677   EL_CHAR_UE,
678   EL_CHAR_COPY,
679   EL_LEERRAUM
680 };
681 int elements_in_list = sizeof(editor_element)/sizeof(int);
682
683 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
684 {
685   int x,y;
686   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
687   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
688
689   XCopyArea(display, drawto, drawto, gc,
690             SX + (dx == -1 ? MINI_TILEX : 0),
691             SY + (dy == -1 ? MINI_TILEY : 0),
692             (ED_FIELDX * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
693             (ED_FIELDY * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
694             SX + (dx == +1 ? MINI_TILEX : 0),
695             SY + (dy == +1 ? MINI_TILEY : 0));
696   if (dx)
697   {
698     x = (dx == 1 ? 0 : ED_FIELDX - 1);
699     for(y=0; y<ED_FIELDY; y++)
700       DrawMiniElementOrWall(x, y, from_x, from_y);
701   }
702   else if (dy)
703   {
704     y = (dy == 1 ? 0 : ED_FIELDY - 1);
705     for(x=0; x<ED_FIELDX; x++)
706       DrawMiniElementOrWall(x, y, from_x, from_y);
707   }
708
709   redraw_mask |= REDRAW_FIELD;
710   BackToFront();
711 }
712
713 void InitLevelEditorGadgets()
714 {
715   int i;
716
717   for (i=0; i<ED_NUM_GADGETS; i++)
718     level_editor_gadget[i] = NULL;
719 }
720
721 static void CreateControlButtons()
722 {
723   Pixmap gd_pixmap = pix[PIX_DOOR];
724   struct GadgetInfo *gi;
725   unsigned long event_mask;
726   int i;
727
728   /* create toolbox buttons */
729   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
730   {
731     int id = i;
732     int width, height;
733     int gd_xoffset, gd_yoffset;
734     int gd_x1, gd_x2, gd_y1, gd_y2;
735     int button_type;
736     int radio_button_nr;
737     boolean radio_button_pressed;
738
739     if (id == ED_CTRL_ID_SINGLE_ITEMS ||
740         id == ED_CTRL_ID_CONNECTED_ITEMS ||
741         id == ED_CTRL_ID_LINE ||
742         id == ED_CTRL_ID_TEXT ||
743         id == ED_CTRL_ID_RECTANGLE ||
744         id == ED_CTRL_ID_FILLED_BOX ||
745         id == ED_CTRL_ID_FLOOD_FILL ||
746         id == ED_CTRL_ID_BRUSH ||
747         id == ED_CTRL_ID_PICK_ELEMENT)
748     {
749       button_type = GD_TYPE_RADIO_BUTTON;
750       radio_button_nr = 1;
751       radio_button_pressed = (id == drawing_function ? TRUE : FALSE);
752       event_mask = GD_EVENT_PRESSED;
753     }
754     else
755     {
756       button_type = GD_TYPE_NORMAL_BUTTON;
757       radio_button_nr = 0;
758       radio_button_pressed = FALSE;
759
760       if (id == ED_CTRL_ID_WRAP_LEFT ||
761           id == ED_CTRL_ID_WRAP_RIGHT ||
762           id == ED_CTRL_ID_WRAP_UP ||
763           id == ED_CTRL_ID_WRAP_DOWN)
764         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
765       else
766         event_mask = GD_EVENT_RELEASED;
767     }
768
769     if (id < ED_NUM_CTRL1_BUTTONS)
770     {
771       int x = i % ED_CTRL1_BUTTONS_HORIZ;
772       int y = i / ED_CTRL1_BUTTONS_HORIZ;
773
774       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
775       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
776       width = ED_CTRL1_BUTTON_XSIZE;
777       height = ED_CTRL1_BUTTON_YSIZE;
778     }
779     else
780     {
781       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
782       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
783
784       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
785       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
786       width = ED_CTRL2_BUTTON_XSIZE;
787       height = ED_CTRL2_BUTTON_YSIZE;
788     }
789
790     gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
791     gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
792     gd_y1  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
793     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
794
795     gi = CreateGadget(GDI_CUSTOM_ID, id,
796                       GDI_DESCRIPTION_TEXT, control_infotext[i],
797                       GDI_X, EX + gd_xoffset,
798                       GDI_Y, EY + gd_yoffset,
799                       GDI_WIDTH, width,
800                       GDI_HEIGHT, height,
801                       GDI_TYPE, button_type,
802                       GDI_STATE, GD_BUTTON_UNPRESSED,
803                       GDI_RADIO_NR, radio_button_nr,
804                       GDI_RADIO_PRESSED, radio_button_pressed,
805                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
806                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
807                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
808                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
809                       GDI_EVENT_MASK, event_mask,
810                       GDI_CALLBACK_ACTION, HandleControlButtons,
811                       GDI_END);
812
813     if (gi == NULL)
814       Error(ERR_EXIT, "cannot create gadget");
815
816     level_editor_gadget[id] = gi;
817   }
818
819   /* create buttons for scrolling of drawing area */
820   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
821   {
822     int id = scrollbutton_info[i].gadget_id;
823     int gd_x1, gd_x2, gd_y;
824
825     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
826
827     gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
828     gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
829     gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
830
831     gi = CreateGadget(GDI_CUSTOM_ID, id,
832                       GDI_DESCRIPTION_TEXT, scrollbutton_info[i].text,
833                       GDI_X, SX + scrollbutton_info[i].x,
834                       GDI_Y, SY + scrollbutton_info[i].y,
835                       GDI_WIDTH, ED_SCROLLBUTTON_XSIZE,
836                       GDI_HEIGHT, ED_SCROLLBUTTON_YSIZE,
837                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
838                       GDI_STATE, GD_BUTTON_UNPRESSED,
839                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
840                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
841                       GDI_EVENT_MASK, event_mask,
842                       GDI_CALLBACK_ACTION, HandleControlButtons,
843                       GDI_END);
844
845     if (gi == NULL)
846       Error(ERR_EXIT, "cannot create gadget");
847
848     level_editor_gadget[id] = gi;
849   }
850 }
851
852 static void CreateCounterButtons()
853 {
854   int i, j;
855
856   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
857   {
858     for (j=0; j<2; j++)
859     {
860       Pixmap gd_pixmap = pix[PIX_DOOR];
861       struct GadgetInfo *gi;
862       int id = counterbutton_info[i].gadget_id + j;
863       int gd_xoffset;
864       int gd_x1, gd_x2, gd_y;
865       unsigned long event_mask;
866
867       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
868
869       gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
870       gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
871       gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
872       gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
873
874       gi = CreateGadget(GDI_CUSTOM_ID, id,
875                         GDI_X, SX + counterbutton_info[i].x + gd_xoffset,
876                         GDI_Y, SY + counterbutton_info[i].y,
877                         GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
878                         GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
879                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
880                         GDI_STATE, GD_BUTTON_UNPRESSED,
881                         GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
882                         GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
883                         GDI_EVENT_MASK, event_mask,
884                         GDI_CALLBACK_ACTION, HandleCounterButtons,
885                         GDI_END);
886
887       if (gi == NULL)
888         Error(ERR_EXIT, "cannot create gadget");
889
890       level_editor_gadget[id] = gi;
891     }
892   }
893 }
894
895 static void CreateDrawingAreas()
896 {
897   struct GadgetInfo *gi;
898   unsigned long event_mask;
899   int id;
900   int i;
901
902   event_mask =
903     GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
904     GD_EVENT_OFF_BORDERS;
905
906   /* one for the level drawing area ... */
907   id = ED_CTRL_ID_DRAWING_LEVEL;
908   gi = CreateGadget(GDI_CUSTOM_ID, id,
909                     GDI_X, SX,
910                     GDI_Y, SY,
911                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
912                     GDI_AREA_SIZE, ED_FIELDX, ED_FIELDY,
913                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
914                     GDI_EVENT_MASK, event_mask,
915                     GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
916                     GDI_CALLBACK_ACTION, HandleDrawingAreas,
917                     GDI_END);
918
919   if (gi == NULL)
920     Error(ERR_EXIT, "cannot create gadget");
921
922   level_editor_gadget[id] = gi;
923
924   /* ... up to eight areas for element content ... */
925   for (i=0; i<MAX_ELEMCONT; i++)
926   {
927     int gx = SX + ED_AREA_ELEMCONT_XPOS + 5 * (i % 4) * MINI_TILEX;
928     int gy = SX + ED_AREA_ELEMCONT_YPOS + 6 * (i / 4) * MINI_TILEY;
929
930     id = ED_CTRL_ID_ELEMCONT_0 + i;
931     gi = CreateGadget(GDI_CUSTOM_ID, id,
932                       GDI_X, gx,
933                       GDI_Y, gy,
934                       GDI_WIDTH, 3 * MINI_TILEX,
935                       GDI_HEIGHT, 3 * MINI_TILEY,
936                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
937                       GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
938                       GDI_EVENT_MASK, event_mask,
939                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
940                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
941                       GDI_END);
942
943     if (gi == NULL)
944       Error(ERR_EXIT, "cannot create gadget");
945
946     level_editor_gadget[id] = gi;
947   }
948
949   /* ... and one for the amoeba content */
950   id = ED_CTRL_ID_AMOEBA_CONTENT;
951   gi = CreateGadget(GDI_CUSTOM_ID, id,
952                     GDI_X, SX + ED_AREA_ELEMCONT_XPOS,
953                     GDI_Y, SY + ED_AREA_ELEMCONT_YPOS,
954                     GDI_WIDTH, MINI_TILEX,
955                     GDI_HEIGHT, MINI_TILEY,
956                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
957                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
958                     GDI_EVENT_MASK, event_mask,
959                     GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
960                     GDI_CALLBACK_ACTION, HandleDrawingAreas,
961                     GDI_END);
962
963   if (gi == NULL)
964     Error(ERR_EXIT, "cannot create gadget");
965
966   level_editor_gadget[id] = gi;
967 }
968
969 static void CreateTextInputGadgets()
970 {
971   Pixmap gd_pixmap = pix[PIX_DOOR];
972   int gd_x, gd_y;
973   struct GadgetInfo *gi;
974   unsigned long event_mask;
975   int id;
976
977   gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
978   gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
979   event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
980
981   /* text input gadget for the level name */
982   id = ED_CTRL_ID_LEVEL_NAME;
983   gi = CreateGadget(GDI_CUSTOM_ID, id,
984                     GDI_X, SX + ED_COUNT_ELEMCONT_XPOS,
985                     GDI_Y, SY + ED_AREA_ELEMCONT_YPOS + 3 * TILEX,
986                     GDI_TYPE, GD_TYPE_TEXTINPUT,
987                     GDI_TEXT_VALUE, level.name,
988                     GDI_TEXT_SIZE, 30,
989                     GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
990                     GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
991                     GDI_DESIGN_BORDER, 3,
992                     GDI_EVENT_MASK, event_mask,
993                     GDI_CALLBACK_ACTION, HandleTextInputGadgets,
994                     GDI_END);
995
996   if (gi == NULL)
997     Error(ERR_EXIT, "cannot create gadget");
998
999   level_editor_gadget[id] = gi;
1000 }
1001
1002 static void CreateScrollbarGadgets()
1003 {
1004   int i;
1005
1006   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1007   {
1008     int id = scrollbar_info[i].gadget_id;
1009     Pixmap gd_pixmap = pix[PIX_DOOR];
1010     int gd_x1, gd_x2, gd_y1, gd_y2;
1011     struct GadgetInfo *gi;
1012     int items_max, items_visible, item_position;
1013     unsigned long event_mask;
1014
1015     if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1016     {
1017       items_max = lev_fieldx + 2;
1018       items_visible = ED_FIELDX;
1019       item_position = 0;
1020     }
1021     else
1022     {
1023       items_max = lev_fieldy + 2;
1024       items_visible = ED_FIELDY;
1025       item_position = 0;
1026     }
1027
1028     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
1029
1030     gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
1031     gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1032     gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1033     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1034
1035     gi = CreateGadget(GDI_CUSTOM_ID, id,
1036                       GDI_DESCRIPTION_TEXT, scrollbar_info[i].text,
1037                       GDI_X, SX + scrollbar_info[i].x,
1038                       GDI_Y, SY + scrollbar_info[i].y,
1039                       GDI_WIDTH, scrollbar_info[i].width,
1040                       GDI_HEIGHT, scrollbar_info[i].height,
1041                       GDI_TYPE, scrollbar_info[i].type,
1042                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
1043                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1044                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
1045                       GDI_STATE, GD_BUTTON_UNPRESSED,
1046                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1047                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1048                       GDI_DESIGN_BORDER, 3,
1049                       GDI_EVENT_MASK, event_mask,
1050                       GDI_CALLBACK_ACTION, HandleControlButtons,
1051                       GDI_END);
1052
1053     if (gi == NULL)
1054       Error(ERR_EXIT, "cannot create gadget");
1055
1056     level_editor_gadget[id] = gi;
1057   }
1058 }
1059
1060 static void CreateLevelEditorGadgets()
1061 {
1062   if (level_editor_gadgets_created)
1063     return;
1064
1065   CreateControlButtons();
1066   CreateCounterButtons();
1067   CreateDrawingAreas();
1068   CreateTextInputGadgets();
1069   CreateScrollbarGadgets();
1070
1071   level_editor_gadgets_created = TRUE;
1072 }
1073
1074 static void MapControlButtons()
1075 {
1076   int i;
1077
1078   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1079     MapGadget(level_editor_gadget[i]);
1080 }
1081
1082 static void MapCounterButtons(int id)
1083 {
1084   int i;
1085
1086   for (i=0; i<2; i++)
1087     MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id + i]);
1088 }
1089
1090 static void MapDrawingArea(int id)
1091 {
1092   MapGadget(level_editor_gadget[id]);
1093 }
1094
1095 static void MapTextInputGadget(int id)
1096 {
1097   MapGadget(level_editor_gadget[id]);
1098 }
1099
1100 static void MapMainDrawingArea()
1101 {
1102   int i;
1103
1104   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1105     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1106
1107   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1108     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1109
1110   MapDrawingArea(ED_CTRL_ID_DRAWING_LEVEL);
1111 }
1112
1113 static void UnmapDrawingArea(int id)
1114 {
1115   UnmapGadget(level_editor_gadget[id]);
1116 }
1117
1118 void UnmapLevelEditorWindowGadgets()
1119 {
1120   int i;
1121
1122   for (i=ED_NUM_CTRL_BUTTONS; i<ED_NUM_GADGETS; i++)
1123     UnmapGadget(level_editor_gadget[i]);
1124 }
1125
1126 void UnmapLevelEditorGadgets()
1127 {
1128   int i;
1129
1130   for (i=0; i<ED_NUM_GADGETS; i++)
1131     UnmapGadget(level_editor_gadget[i]);
1132 }
1133
1134 void DrawLevelEd()
1135 {
1136   int i, x, y, graphic;
1137
1138   level_xpos = -1;
1139   level_ypos = -1;
1140   edit_mode = ED_MODE_DRAWING;
1141   name_typing = FALSE;
1142
1143   CloseDoor(DOOR_CLOSE_ALL);
1144
1145   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1146
1147   if (level_editor_test_game)
1148   {
1149     for(x=0; x<lev_fieldx; x++)
1150       for(y=0; y<lev_fieldy; y++)
1151         Feld[x][y] = Ur[x][y];
1152
1153     for(x=0; x<lev_fieldx; x++)
1154       for(y=0; y<lev_fieldy; y++)
1155         Ur[x][y] = FieldBackup[x][y];
1156
1157     level_editor_test_game = FALSE;
1158   }
1159   else
1160   {
1161     undo_buffer_position = -1;
1162     undo_buffer_steps = -1;
1163     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1164   }
1165
1166   /*
1167   DrawMiniLevel(level_xpos, level_ypos);
1168   FadeToFront();
1169   */
1170
1171   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1172             DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
1173             DXSIZE,DYSIZE,
1174             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1175   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1176             DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
1177             DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
1178             4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
1179             DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
1180             DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
1181
1182   for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1183   {
1184     if (i < elements_in_list)
1185       graphic = el2gfx(editor_element[i + element_shift]);
1186     else
1187       graphic = GFX_LEERRAUM;
1188
1189     DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1190                        DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 + 
1191                        (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
1192                        DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
1193                        (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
1194                        graphic);
1195   }
1196
1197   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1198                      DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
1199                      DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
1200                      el2gfx(new_element1));
1201   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1202                      DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
1203                      DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
1204                      el2gfx(new_element2));
1205   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1206                      DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
1207                      DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
1208                      el2gfx(new_element3));
1209   DrawTextExt(pix[PIX_DB_DOOR],gc,
1210               DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
1211               DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1212               int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
1213   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1214             DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
1215             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1216             7,FONT3_YSIZE,
1217             DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
1218             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1219   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1220             DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
1221             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1222             7,FONT3_YSIZE,
1223             DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
1224             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1225
1226   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1227             DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1228             VXSIZE,VYSIZE,
1229             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1230
1231   /* draw bigger door */
1232   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1233             DOOR_GFX_PAGEX7, 0,
1234             108, 64,
1235             EX - 4, EY - 12);
1236
1237   /* draw new control window */
1238   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1239             DOOR_GFX_PAGEX8, 236,
1240             EXSIZE, EYSIZE,
1241             EX, EY);
1242
1243   redraw_mask |= REDRAW_ALL;
1244
1245   OpenDoor(DOOR_OPEN_1);
1246
1247   if (!level_editor_gadgets_created)
1248     CreateLevelEditorGadgets();
1249
1250   MapControlButtons();
1251
1252   /*
1253   MapMainDrawingArea();
1254   */
1255
1256   DrawDrawingWindow();
1257   FadeToFront();
1258
1259   /*
1260   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1261   */
1262 }
1263
1264 void DrawControlWindow()
1265 {
1266   int i,x,y;
1267
1268   ClearWindow();
1269   UnmapLevelEditorWindowGadgets();
1270
1271   /* Inhalt der Mampfer */
1272   DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
1273            "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
1274   for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
1275   {
1276     DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
1277     XFillRectangle(display,drawto,gc,
1278                    SX+(1+5*i)*MINI_TILEX+MINI_TILEX/2-1,
1279                    SY+(2)*MINI_TILEY+MINI_TILEY/2-1,
1280                    3*MINI_TILEX+2,3*MINI_TILEY+2);
1281   }
1282   XCopyArea(display,drawto,drawto,gc,
1283             SX+1*MINI_TILEX,SY+2*MINI_TILEY,
1284             4*5*MINI_TILEX,5*MINI_TILEY,
1285             SX+1*MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
1286   for(i=0;i<4;i++)
1287   {
1288     for(y=0;y<3;y++) for(x=0;x<3;x++)
1289       DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
1290
1291     DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
1292              SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
1293              int2str(i+1,1),FS_SMALL,FC_YELLOW);
1294   }
1295
1296   /* Inhalt der Amöbe */
1297   for(y=0;y<2;y++) for(x=0;x<2;x++)
1298   {
1299     DrawMiniElement(29+x,26+y,EL_ERDREICH);
1300     XFillRectangle(display,drawto,gc,
1301                    SX+29*MINI_TILEX+MINI_TILEX/2-1,
1302                    SY+26*MINI_TILEY+MINI_TILEY/2-1,
1303                    MINI_TILEX+2,MINI_TILEY+2);
1304   }
1305   XCopyArea(display,drawto,drawto,gc,
1306             SX+29*MINI_TILEX,SY+26*MINI_TILEY,
1307             3*MINI_TILEX,3*MINI_TILEY,
1308             SX+29*MINI_TILEX-MINI_TILEX/2,SY+26*MINI_TILEY-MINI_TILEY/2);
1309   DrawMiniElement(29,26,level.amoebe_inhalt);
1310
1311   for(i=0;i<11+3+2;i++)
1312   {
1313     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1314               DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1315               DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1316               DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1317               ED_COUNT_GADGET_XPOS,
1318               ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
1319
1320     if (i<11)
1321       DrawText(ED_COUNT_VALUE_XPOS,
1322                ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
1323                int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
1324     else if (i==11)
1325       DrawText(ED_COUNT_VALUE_XPOS,
1326                ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1327                int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1328     else if (i==12)
1329       DrawText(ED_COUNT_VALUE_XPOS,
1330                ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1331                int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1332     else if (i==13)
1333       DrawText(ED_COUNT_VALUE_XPOS,
1334                ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1335                int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1336     else if (i==14)
1337       DrawText(ED_COUNT_VALUE_XPOS,
1338                ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1339                int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1340     else if (i==15)
1341       DrawText(ED_COUNT_VALUE_XPOS,
1342                ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1343                int2str(level.time,3),FS_SMALL,FC_YELLOW);
1344   }
1345
1346   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
1347            "Score for Emerald",FS_SMALL,FC_YELLOW);
1348   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
1349            "Score for Diamond",FS_SMALL,FC_YELLOW);
1350   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
1351            "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
1352   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
1353            "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
1354   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
1355            "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
1356   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
1357            "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
1358   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
1359            "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
1360   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
1361            "Score for cracking a nut",FS_SMALL,FC_YELLOW);
1362   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
1363            "Score for dynamite",FS_SMALL,FC_YELLOW);
1364   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
1365            "Score for key",FS_SMALL,FC_YELLOW);
1366   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
1367            "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
1368   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
1369            "Speed of the amoeba / Content",FS_SMALL,FC_YELLOW);
1370   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
1371            "Time for magic wall",FS_SMALL,FC_YELLOW);
1372   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
1373            "Time for wheel",FS_SMALL,FC_YELLOW);
1374   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
1375            "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
1376   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
1377            "Time available for this level",FS_SMALL,FC_YELLOW);
1378
1379   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1380             DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
1381             DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1382             ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
1383             ED_COUNT_GADGET_XPOS,
1384             ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1385   for(i=1;i<31;i++)
1386     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1387               DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
1388               DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1389               ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
1390               ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
1391               ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1392   DrawText(ED_COUNT_GADGET_XPOS+5,
1393            ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1394            level.name,FS_SMALL,FC_YELLOW);
1395   DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
1396            ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1397            "Title",FS_SMALL,FC_YELLOW);
1398
1399   DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
1400            "Playfield size:",FS_SMALL,FC_YELLOW);
1401   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1402             DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1403             DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1404             DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1405             ED_SIZE_GADGET_XPOS,
1406             ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
1407   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1408             DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1409             DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1410             DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1411             ED_SIZE_GADGET_XPOS,
1412             ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
1413   DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
1414            "Width",FS_SMALL,FC_YELLOW);
1415   DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
1416            "Height",FS_SMALL,FC_YELLOW);
1417   DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1418            int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1419   DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1420            int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1421 }
1422
1423 void AdjustLevelScrollPosition()
1424 {
1425   if (level_xpos < -1)
1426     level_xpos = -1;
1427   if (level_xpos > lev_fieldx - ED_FIELDX + 1)
1428     level_xpos = lev_fieldx - ED_FIELDX + 1;
1429   if (lev_fieldx < ED_FIELDX - 2)
1430     level_xpos = -1;
1431
1432   if (level_ypos < -1)
1433     level_ypos = -1;
1434   if (level_ypos > lev_fieldy - ED_FIELDY + 1)
1435     level_ypos = lev_fieldy - ED_FIELDY + 1;
1436   if (lev_fieldy < ED_FIELDY - 2)
1437     level_ypos = -1;
1438 }
1439
1440 void AdjustEditorScrollbar(int id)
1441 {
1442   struct GadgetInfo *gi = level_editor_gadget[id];
1443   struct GadgetScrollbar *gs = &gi->scrollbar;
1444   int items_max, items_visible, item_position = gs->item_position;
1445
1446   if (id == ED_CTRL_ID_SCROLL_HORIZONTAL)
1447   {
1448     items_max = lev_fieldx + 2;
1449     items_visible = ED_FIELDX;
1450   }
1451   else
1452   {
1453     items_max = lev_fieldy + 2;
1454     items_visible = ED_FIELDY;
1455   }
1456
1457   if (item_position > items_max - items_visible)
1458     item_position = items_max - items_visible;
1459
1460   AdjustScrollbar(gi, items_max, item_position);
1461 }
1462
1463 static void PickDrawingElement(int button, int element)
1464 {
1465   if (button < 1 || button > 3)
1466     return;
1467
1468   if (button == 1)
1469   {
1470     new_element1 = element;
1471     DrawMiniGraphicExt(drawto, gc,
1472                        DX + ED_WIN_MB_LEFT_XPOS,
1473                        DY + ED_WIN_MB_LEFT_YPOS,
1474                        el2gfx(new_element1));
1475   }
1476   else if (button == 2)
1477   {
1478     new_element2 = element;
1479     DrawMiniGraphicExt(drawto, gc,
1480                        DX + ED_WIN_MB_MIDDLE_XPOS,
1481                        DY + ED_WIN_MB_MIDDLE_YPOS,
1482                        el2gfx(new_element2));
1483   }
1484   else
1485   {
1486     new_element3 = element;
1487     DrawMiniGraphicExt(drawto, gc,
1488                        DX + ED_WIN_MB_RIGHT_XPOS,
1489                        DY + ED_WIN_MB_RIGHT_YPOS,
1490                        el2gfx(new_element3));
1491   }
1492
1493   redraw_mask |= REDRAW_DOOR_1;
1494 }
1495
1496 void LevelEd(int mx, int my, int button)
1497 {
1498   static int last_button = 0;
1499   static int in_field_pressed = FALSE;
1500   static boolean use_floodfill = FALSE;
1501
1502
1503   /*
1504   int x = (mx-SX)/MINI_TILEX; 
1505   int y = (my-SY)/MINI_TILEY; 
1506   */
1507
1508   /*
1509   HandlePressedControlButtons();
1510   HandleDrawingFunctions(mx, my, button);
1511   */
1512
1513   if (use_floodfill)            /********** FLOOD FILL **********/
1514   {
1515
1516
1517 #if 0
1518
1519     if (button)
1520     {
1521       if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1522       {
1523         int from_x, from_y;
1524         int fill_element;
1525
1526         if (x>lev_fieldx || y>lev_fieldy ||
1527             (x==0 && level_xpos<0) ||
1528             (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1529             (y==0 && level_ypos<0) ||
1530             (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY))
1531           return;
1532
1533         from_x = x+level_xpos;
1534         from_y = y+level_ypos;
1535         fill_element = (button==1 ? new_element1 :
1536                         button==2 ? new_element2 :
1537                         button==3 ? new_element3 : 0);
1538
1539         FloodFill(from_x,from_y,fill_element);
1540         DrawMiniLevel(level_xpos,level_ypos);
1541       }
1542
1543       use_floodfill = FALSE;
1544       CloseDoor(DOOR_CLOSE_1);
1545       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1546     }
1547     return;
1548
1549 #endif
1550
1551
1552
1553   }
1554   else                          /********** EDIT/CTRL-FENSTER **********/
1555   {
1556     static unsigned long choice_delay = 0;
1557     int choice = CheckElemButtons(mx,my,button);
1558     int elem_pos = choice-ED_BUTTON_ELEM;
1559
1560     if (((choice == ED_BUTTON_EUP && element_shift>0) ||
1561          (choice == ED_BUTTON_EDOWN &&
1562           element_shift<elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)) &&
1563         DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1564     {
1565       int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1566       int i;
1567
1568 #if 0
1569       step = (button==1 ? MAX_ELEM_X : button==2 ? 5*MAX_ELEM_X :
1570               elements_in_list);
1571       element_shift += (choice==ED_BUTTON_EUP ? -step : step);
1572 #else
1573       step = step * MAX_ELEM_X * (choice == ED_BUTTON_EUP ? -1 : +1);
1574       element_shift += step;
1575 #endif
1576
1577       if (element_shift<0)
1578         element_shift = 0;
1579       if (element_shift>elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)
1580         element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y;
1581       if (element_shift % MAX_ELEM_X)
1582         element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X);
1583
1584       for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1585         DrawElemButton(i+2,ED_BUTTON_RELEASED);
1586     }
1587     else if (elem_pos>=0 && elem_pos<MAX_ELEM_X*MAX_ELEM_Y)
1588     {
1589       int new_element;
1590
1591       if (elem_pos+element_shift < elements_in_list)
1592         new_element = editor_element[elem_pos+element_shift];
1593       else
1594         new_element = EL_LEERRAUM;
1595
1596       PickDrawingElement(last_button, new_element);
1597
1598       if (!HAS_CONTENT(properties_element))
1599       {
1600         properties_element = new_element;
1601         if (edit_mode == ED_MODE_PROPERTIES)
1602           DrawPropertiesWindow();
1603       }
1604     }
1605   
1606     if (edit_mode == ED_MODE_DRAWING)   /********** EDIT-FENSTER **********/
1607     {
1608
1609
1610
1611 #if 0
1612
1613       switch(CheckEditButtons(mx,my,button))
1614       {
1615         case ED_BUTTON_CTRL:
1616           CloseDoor(DOOR_CLOSE_2);
1617           DrawControlWindow();
1618           XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1619                     DOOR_GFX_PAGEX4,DOOR_GFX_PAGEY1+80,
1620                     VXSIZE,VYSIZE,
1621                     DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1622           OpenDoor(DOOR_OPEN_2);
1623           edit_mode = ED_MODE_INFO;
1624           break;
1625         case ED_BUTTON_FILL:
1626           Request("Caution ! Flood fill mode ! Choose area !",REQ_OPEN);
1627           use_floodfill = TRUE;
1628           return;
1629           break;
1630         case ED_BUTTON_LEFT:
1631           if (level_xpos>=0)
1632           {
1633             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1634               break;
1635             if (lev_fieldx<ED_FIELDX-2)
1636               break;
1637
1638             level_xpos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1639             if (level_xpos<-1)
1640               level_xpos = -1;
1641             if (button==1)
1642               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT);
1643             else
1644               DrawMiniLevel(level_xpos,level_ypos);
1645           }
1646           break;
1647         case ED_BUTTON_RIGHT:
1648           if (level_xpos<=lev_fieldx-ED_FIELDX)
1649           {
1650             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1651               break;
1652             if (lev_fieldx<ED_FIELDX-2)
1653               break;
1654
1655             level_xpos += (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1656             if (level_xpos>lev_fieldx-ED_FIELDX+1)
1657               level_xpos = lev_fieldx-ED_FIELDX+1;
1658             if (button==1)
1659               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT);
1660             else
1661               DrawMiniLevel(level_xpos,level_ypos);
1662           }
1663           break;
1664         case ED_BUTTON_UP:
1665           if (level_ypos>=0)
1666           {
1667             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1668               break;
1669             if (lev_fieldy<ED_FIELDY-2)
1670               break;
1671
1672             level_ypos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1673             if (level_ypos<-1)
1674               level_ypos = -1;
1675             if (button==1)
1676               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN);
1677             else
1678               DrawMiniLevel(level_xpos,level_ypos);
1679           }
1680           break;
1681         case ED_BUTTON_DOWN:
1682           if (level_ypos<=lev_fieldy-ED_FIELDY)
1683           {
1684             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1685               break;
1686             if (lev_fieldy<ED_FIELDY-2)
1687               break;
1688
1689             level_ypos += (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1690             if (level_ypos>lev_fieldy-ED_FIELDY+1)
1691               level_ypos = lev_fieldy-ED_FIELDY+1;
1692             if (button==1)
1693               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP);
1694             else
1695               DrawMiniLevel(level_xpos,level_ypos);
1696           }
1697           break;
1698         default:
1699           break;
1700       }
1701
1702 #endif
1703
1704
1705
1706 #if 0
1707
1708       if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1709       {
1710         int new_element;
1711
1712         if (button && !motion_status)
1713           in_field_pressed = TRUE;
1714
1715         if (!button || !in_field_pressed || button<1 || button>3 ||
1716             (y==0 && level_ypos<0) ||
1717             (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY) ||
1718             (x==0 && level_xpos<0) ||
1719             (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1720             x>lev_fieldx || y>lev_fieldy)
1721           return;
1722
1723         new_element = (button==1 ? new_element1 :
1724                        button==2 ? new_element2 :
1725                        button==3 ? new_element3 : 0);
1726
1727         if (new_element != Feld[x+level_xpos][y+level_ypos])
1728         {
1729           if (new_element==EL_SPIELFIGUR) /* Jeder nur EINE Figur bitte... */
1730           {
1731             int x,y;
1732
1733             for(x=0;x<lev_fieldx;x++) for(y=0;y<lev_fieldy;y++)
1734             {
1735               if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1)
1736               {
1737                 Feld[x][y] = EL_LEERRAUM;
1738                 if (x-level_xpos>=0 && x-level_xpos<ED_FIELDX &&
1739                     y-level_ypos>=0 && y-level_ypos<ED_FIELDY)
1740                   DrawMiniElement(x-level_xpos,y-level_ypos,EL_LEERRAUM);
1741               }
1742             }
1743           }
1744
1745           Feld[x+level_xpos][y+level_ypos] = new_element;
1746           DrawMiniElement(x,y,new_element);
1747         }
1748       }
1749       else if (!motion_status)  /* Mauszeiger nicht im Level-Feld */
1750         in_field_pressed = FALSE;
1751
1752 #endif
1753
1754
1755
1756     }
1757     else if (edit_mode == ED_MODE_INFO)/********** KONTROLL-FENSTER **********/
1758     {
1759       int choice = CheckCountButtons(mx,my,button);
1760       int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0);
1761
1762       if (choice >= 0 && choice < 36 &&
1763           DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1764       {
1765         if (!(choice % 2))
1766           step = -step;
1767
1768         choice /= 2;
1769
1770         if (choice<11)
1771         {
1772           level.score[choice] += step;
1773           if (level.score[choice]<0)
1774             level.score[choice] = 0;
1775           else if (level.score[choice]>255)
1776             level.score[choice] = 255;
1777         }
1778         else if (choice==11)
1779         {
1780           level.tempo_amoebe += step;
1781           if (level.tempo_amoebe<0)
1782             level.tempo_amoebe = 0;
1783           else if (level.tempo_amoebe>255)
1784             level.tempo_amoebe = 255;
1785         }
1786         else if (choice==12)
1787         {
1788           level.dauer_sieb += step;
1789           if (level.dauer_sieb<0)
1790             level.dauer_sieb = 0;
1791           else if (level.dauer_sieb>255)
1792             level.dauer_sieb = 255;
1793         }
1794         else if (choice==13)
1795         {
1796           level.dauer_ablenk += step;
1797           if (level.dauer_ablenk<0)
1798             level.dauer_ablenk = 0;
1799           else if (level.dauer_ablenk>255)
1800             level.dauer_ablenk = 255;
1801         }
1802         else if (choice==14)
1803         {
1804           level.edelsteine += step;
1805           if (level.edelsteine<0)
1806             level.edelsteine = 0;
1807           else if (level.edelsteine>999)
1808             level.edelsteine = 999;
1809         }
1810         else if (choice==15)
1811         {
1812           level.time += step;
1813           if (level.time<0)
1814             level.time = 0;
1815           else if (level.time>999)
1816             level.time = 999;
1817         }
1818         else if (choice==16)
1819         {
1820           lev_fieldx += step;
1821           if (lev_fieldx<MIN_LEV_FIELDX)
1822             lev_fieldx = MIN_LEV_FIELDX;
1823           else if (lev_fieldx>MAX_LEV_FIELDX)
1824             lev_fieldx = MAX_LEV_FIELDX;
1825           level.fieldx = lev_fieldx;
1826         }
1827         else if (choice==17)
1828         {
1829           lev_fieldy += step;
1830           if (lev_fieldy<MIN_LEV_FIELDY)
1831             lev_fieldy = MIN_LEV_FIELDY;
1832           else if (lev_fieldy>MAX_LEV_FIELDY)
1833             lev_fieldy = MAX_LEV_FIELDY;
1834           level.fieldy = lev_fieldy;
1835         }
1836
1837         if (choice<11)
1838           DrawText(ED_COUNT_VALUE_XPOS,
1839                    ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1840                    int2str(level.score[choice],3),FS_SMALL,FC_YELLOW);
1841         else if (choice==11)
1842           DrawText(ED_COUNT_VALUE_XPOS,
1843                    ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1844                    int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1845         else if (choice==12)
1846           DrawText(ED_COUNT_VALUE_XPOS,
1847                    ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1848                    int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1849         else if (choice==13)
1850           DrawText(ED_COUNT_VALUE_XPOS,
1851                    ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1852                    int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1853         else if (choice==14)
1854           DrawText(ED_COUNT_VALUE_XPOS,
1855                    ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1856                    int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1857         else if (choice==15)
1858           DrawText(ED_COUNT_VALUE_XPOS,
1859                    ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1860                    int2str(level.time,3),FS_SMALL,FC_YELLOW);
1861         else if (choice==16)
1862           DrawText(ED_SIZE_VALUE_XPOS,
1863                    ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1864                    int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1865         else if (choice==17)
1866           DrawText(ED_SIZE_VALUE_XPOS,
1867                    ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1868                    int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1869
1870         redraw_mask &= ~REDRAW_FIELD;
1871         if (choice<16)
1872           XCopyArea(display,drawto,window,gc,
1873                     ED_COUNT_VALUE_XPOS,
1874                     ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1875                     3*FONT2_XSIZE,FONT2_YSIZE,
1876                     ED_COUNT_VALUE_XPOS,
1877                     ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE);
1878         else
1879           XCopyArea(display,drawto,window,gc,
1880                     ED_SIZE_VALUE_XPOS,
1881                     ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE,
1882                     3*FONT2_XSIZE,FONT2_YSIZE,
1883                     ED_SIZE_VALUE_XPOS,
1884                     ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE);
1885         XFlush(display);
1886       }
1887
1888
1889
1890 #if 0
1891
1892       switch(CheckCtrlButtons(mx,my,button))
1893       {
1894         case ED_BUTTON_EDIT:
1895           CloseDoor(DOOR_CLOSE_2);
1896           AdjustLevelScrollPosition();
1897           DrawMiniLevel(level_xpos,level_ypos);
1898           XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1899                     DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1900                     VXSIZE,VYSIZE,
1901                     DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1902           OpenDoor(DOOR_OPEN_2);
1903           edit_mode = ED_MODE_DRAWING;
1904           break;
1905         case ED_BUTTON_CLEAR:
1906           if (Request("Are you sure to clear this level ?",REQ_ASK))
1907           {
1908             for(x=0;x<MAX_LEV_FIELDX;x++) 
1909               for(y=0;y<MAX_LEV_FIELDY;y++) 
1910                 Feld[x][y] = EL_ERDREICH;
1911             DrawMiniLevel(level_xpos,level_ypos);
1912           }
1913           break;
1914         case ED_BUTTON_UNDO:
1915           if (leveldir[leveldir_nr].readonly ||
1916               Request("Exit without saving ?",REQ_ASK | REQ_STAY_OPEN))
1917           {
1918             CloseDoor(DOOR_CLOSE_ALL);
1919             game_status=MAINMENU;
1920             DrawMainMenu();
1921           }
1922           else
1923           {
1924             CloseDoor(DOOR_CLOSE_1);
1925             OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1926           }
1927           break;
1928         case ED_BUTTON_EXIT:
1929           {
1930             int figur_vorhanden = FALSE;
1931
1932             if (leveldir[leveldir_nr].readonly)
1933             {
1934               Request("This level is read only !",REQ_CONFIRM);
1935               break;
1936             }
1937
1938             for(y=0;y<lev_fieldy;y++) 
1939               for(x=0;x<lev_fieldx;x++)
1940                 if (Feld[x][y] == EL_SPIELFIGUR ||
1941                     Feld[x][y] == EL_SPIELER1 ||
1942                     Feld[x][y] == EL_SP_MURPHY) 
1943                   figur_vorhanden = TRUE;
1944
1945             if (!figur_vorhanden)
1946               Request("No Level without Gregor Mc Duffin please !",
1947                          REQ_CONFIRM);
1948             else
1949             {
1950               if (Request("Save this level and kill the old ?",
1951                              REQ_ASK | REQ_STAY_OPEN))
1952               {
1953                 for(x=0;x<lev_fieldx;x++)
1954                   for(y=0;y<lev_fieldy;y++) 
1955                     Ur[x][y]=Feld[x][y];
1956                 SaveLevel(level_nr);
1957               }
1958               CloseDoor(DOOR_CLOSE_ALL);
1959               game_status=MAINMENU;
1960               DrawMainMenu();
1961             }
1962           }
1963           break;
1964         default:
1965           break;
1966       }
1967
1968 #endif
1969
1970
1971
1972       if (mx>=ED_COUNT_GADGET_XPOS &&
1973           mx<ED_COUNT_GADGET_XPOS+31*FONT2_XSIZE+10 &&
1974           my>=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE &&
1975           my<ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE+ED_WIN_COUNT_YSIZE)
1976       {
1977         if (!name_typing)
1978         {
1979           name_typing = TRUE;
1980           DrawText(ED_COUNT_GADGET_XPOS+5,
1981                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1982                    level.name,FS_SMALL,FC_GREEN);
1983           DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1984                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1985                    "<",FS_SMALL,FC_RED);
1986         }
1987       }
1988       else
1989       {
1990         if (name_typing)
1991         {
1992           name_typing = FALSE;
1993           DrawText(ED_COUNT_GADGET_XPOS+5,
1994                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1995                    level.name,FS_SMALL,FC_YELLOW);
1996           DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1997                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1998                    " ",FS_SMALL,FC_RED);
1999         }
2000       }
2001
2002       if (mx>=SX+29*MINI_TILEX && mx<SX+30*MINI_TILEX &&
2003           my>=SY+26*MINI_TILEY && my<SY+27*MINI_TILEY)
2004       {
2005         int new_element;
2006
2007         if (!button || button<1 || button>3)
2008           return;
2009
2010         new_element = (button==1 ? new_element1 :
2011                        button==2 ? new_element2 :
2012                        button==3 ? new_element3 : 0);
2013
2014         if (new_element != level.amoebe_inhalt)
2015         {
2016           level.amoebe_inhalt = new_element;
2017           DrawMiniElement(29,26,new_element);
2018         }
2019       }
2020
2021       if (mx>=SX+1*MINI_TILEX && mx<SX+(1+4*5)*MINI_TILEX &&
2022           my>=SY+2*MINI_TILEY && my<SY+(2+3)*MINI_TILEY)
2023       {
2024         int x = (mx-SX-1*MINI_TILEX)/MINI_TILEX;
2025         int y = (my-SY-2*MINI_TILEY)/MINI_TILEY;
2026         int i = x/5;
2027         int new_element;
2028
2029         x = x-i*5;
2030         if (i>=0 && i<43 && x>=0 && x<3 && y>=0 && y<3)
2031         {
2032           if (button && !motion_status)
2033             in_field_pressed = TRUE;
2034
2035           if (!button || !in_field_pressed || button<1 || button>3)
2036             return;
2037
2038           new_element = (button==1 ? new_element1 :
2039                          button==2 ? new_element2 :
2040                          button==3 ? new_element3 : 0);
2041
2042           if (new_element != level.mampfer_inhalt[i][x][y])
2043           {
2044             level.mampfer_inhalt[i][x][y] = new_element;
2045             DrawMiniElement(1+5*i+x,2+y,new_element);
2046           }
2047         }
2048         else if (!motion_status)/* Mauszeiger nicht im Cruncher-Feld */
2049           in_field_pressed = FALSE;
2050       }
2051       else if (!motion_status)  /* Mauszeiger nicht im Cruncher-Feld */
2052         in_field_pressed = FALSE;
2053     }
2054   }
2055
2056   last_button = button;
2057
2058   BackToFront();
2059 }
2060
2061 void LevelNameTyping(KeySym key)
2062 {
2063   unsigned char ascii = 0;
2064   int len = strlen(level.name);
2065
2066   if (!name_typing)
2067     return;
2068
2069   if (key>=XK_A && key<=XK_Z)
2070     ascii = 'A'+(char)(key-XK_A);
2071   else if (key>=XK_a && key<=XK_z)
2072     ascii = 'a'+(char)(key-XK_a);
2073   else if (key>=XK_0 && key<=XK_9)
2074     ascii = '0'+(char)(key-XK_0);
2075 #ifdef XK_LATIN1
2076   else if (key>=XK_space && key<=XK_at)
2077     ascii = ' '+(char)(key-XK_space);
2078   else if (key==XK_Adiaeresis)
2079     ascii = 'Ä';
2080   else if (key==XK_Odiaeresis)
2081     ascii = 'Ö';
2082   else if (key==XK_Udiaeresis)
2083     ascii = 'Ãœ';
2084   else if (key==XK_adiaeresis)
2085     ascii = 'ä';
2086   else if (key==XK_odiaeresis)
2087     ascii = 'ö';
2088   else if (key==XK_udiaeresis)
2089     ascii = 'ü';
2090   else if (key==XK_underscore)
2091     ascii = '_';
2092 #endif
2093
2094   if (ascii && len<MAX_LEVNAMLEN-2)
2095   {
2096     level.name[len] = ascii;
2097     level.name[len+1] = 0;
2098     len++;
2099
2100     DrawTextExt(drawto,gc,
2101                 ED_COUNT_GADGET_XPOS+5,
2102                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2103                 level.name,FS_SMALL,FC_GREEN);
2104     DrawTextExt(window,gc,
2105                 ED_COUNT_GADGET_XPOS+5,
2106                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2107                 level.name,FS_SMALL,FC_GREEN);
2108     DrawTextExt(drawto,gc,
2109                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2110                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2111                 "<",FS_SMALL,FC_RED);
2112     DrawTextExt(window,gc,
2113                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2114                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2115                 "<",FS_SMALL,FC_RED);
2116   }
2117   else if ((key==XK_Delete || key==XK_BackSpace) && len>0)
2118   {
2119     level.name[len-1] = 0;
2120     len--;
2121
2122     DrawTextExt(drawto,gc,
2123                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2124                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2125                 "< ",FS_SMALL,FC_GREEN);
2126     DrawTextExt(window,gc,
2127                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2128                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2129                 "< ",FS_SMALL,FC_GREEN);
2130   }
2131   else if (key==XK_Return)
2132   {
2133     DrawTextExt(drawto,gc,
2134                 ED_COUNT_GADGET_XPOS+5,
2135                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2136                 level.name,FS_SMALL,FC_YELLOW);
2137     DrawTextExt(window,gc,
2138                 ED_COUNT_GADGET_XPOS+5,
2139                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2140                 level.name,FS_SMALL,FC_YELLOW);
2141     DrawTextExt(drawto,gc,
2142                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2143                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2144                 " ",FS_SMALL,FC_YELLOW);
2145     DrawTextExt(window,gc,
2146                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2147                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2148                 " ",FS_SMALL,FC_YELLOW);
2149
2150     name_typing = FALSE;
2151   }
2152 }
2153
2154 static void DrawCounterValueField(int counter_id, int value)
2155 {
2156   int x = SX + counterbutton_info[counter_id].x + ED_WIN_COUNT_XPOS;
2157   int y = SY + counterbutton_info[counter_id].y;
2158
2159   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2160             DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS,
2161             DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS,
2162             ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE,
2163             x, y);
2164
2165   DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2166            int2str(value, 3), FS_SMALL, FC_YELLOW);
2167 }
2168
2169 static void DrawDrawingWindow()
2170 {
2171   ClearWindow();
2172   UnmapLevelEditorWindowGadgets();
2173   AdjustLevelScrollPosition();
2174   AdjustEditorScrollbar(ED_CTRL_ID_SCROLL_HORIZONTAL);
2175   AdjustEditorScrollbar(ED_CTRL_ID_SCROLL_VERTICAL);
2176   DrawMiniLevel(level_xpos, level_ypos);
2177   MapMainDrawingArea();
2178 }
2179
2180 static void DrawElementContentAreas()
2181 {
2182   int *num_areas = &MampferMax;
2183   int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2184   int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2185   int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2186   int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2187   int i, x, y;
2188
2189   for (i=0; i<MAX_ELEMCONT; i++)
2190     for (y=0; y<3; y++)
2191       for (x=0; x<3; x++)
2192         ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
2193
2194   for (i=0; i<MAX_ELEMCONT; i++)
2195     UnmapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2196
2197   /* display counter to choose number of element content areas */
2198   gadget_areas_value = num_areas;
2199   DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
2200   x = counterbutton_info[ED_COUNTER_ELEMCONT].x + DXSIZE;
2201   y = counterbutton_info[ED_COUNTER_ELEMCONT].y;
2202   DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2203             FC_YELLOW, "number of content areas");
2204   MapCounterButtons(ED_COUNTER_ELEMCONT);
2205
2206   /* delete content areas in case of reducing number of them */
2207   XFillRectangle(display, backbuffer, gc,
2208                  SX, area_sy - MINI_TILEX,
2209                  SXSIZE, 12 * MINI_TILEY);
2210
2211   /* draw some decorative border for the objects */
2212   for (i=0; i<*num_areas; i++)
2213   {
2214     for (y=0; y<4; y++)
2215       for (x=0; x<4; x++)
2216         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2217                         EL_ERDREICH);
2218
2219     XFillRectangle(display, drawto, gc,
2220                    area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2221                    area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2222                    3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2223   }
2224
2225   /* copy border to the right location */
2226   XCopyArea(display, drawto, drawto, gc,
2227             area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 12 * MINI_TILEY,
2228             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2229
2230   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2231            "Content", FS_SMALL, FC_YELLOW);
2232   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2233            "when", FS_SMALL, FC_YELLOW);
2234   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2235            "smashed", FS_SMALL, FC_YELLOW);
2236
2237   for (i=0; i<*num_areas; i++)
2238   {
2239     for (y=0; y<3; y++)
2240       for (x=0; x<3; x++)
2241         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2242                         ElementContent[i][x][y]);
2243
2244     DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2245               area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2246               FC_YELLOW, "%d", i + 1);
2247   }
2248
2249   for (i=0; i<*num_areas; i++)
2250     MapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2251 }
2252
2253 static void DrawAmoebaContentArea()
2254 {
2255   int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2256   int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2257   int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2258   int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2259   int x, y;
2260
2261   ElementContent[0][0][0] = level.amoebe_inhalt;
2262
2263   /* draw decorative border for the object */
2264   for (y=0; y<2; y++)
2265     for (x=0; x<2; x++)
2266       DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2267
2268   XFillRectangle(display, drawto, gc,
2269                  area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2270                  MINI_TILEX + 2, MINI_TILEY + 2);
2271
2272   /* copy border to the right location */
2273   XCopyArea(display, drawto, drawto, gc,
2274             area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2275             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2276
2277   DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2278            FS_SMALL, FC_YELLOW);
2279
2280   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2281
2282   MapDrawingArea(ED_CTRL_ID_AMOEBA_CONTENT);
2283 }
2284
2285 #define TEXT_COLLECTING         "Score for collecting"
2286 #define TEXT_SMASHING           "Score for smashing"
2287 #define TEXT_CRACKING           "Score for cracking"
2288 #define TEXT_SPEED              "Speed of amoeba growth"
2289 #define TEXT_DURATION           "Duration when activated"
2290
2291 static void DrawPropertiesWindow()
2292 {
2293   int i, x, y;
2294   int num_elements_in_level;
2295   static struct
2296   {
2297     int element;
2298     int *counter_value;
2299     char *text;
2300   } elements_with_counter[] =
2301   {
2302     { EL_EDELSTEIN,     &level.score[0],        TEXT_COLLECTING },
2303     { EL_EDELSTEIN_BD,  &level.score[0],        TEXT_COLLECTING },
2304     { EL_EDELSTEIN_GELB,&level.score[0],        TEXT_COLLECTING },
2305     { EL_EDELSTEIN_ROT, &level.score[0],        TEXT_COLLECTING },
2306     { EL_EDELSTEIN_LILA,&level.score[0],        TEXT_COLLECTING },
2307     { EL_DIAMANT,       &level.score[1],        TEXT_COLLECTING },
2308     { EL_KAEFER_R,      &level.score[2],        TEXT_SMASHING },
2309     { EL_KAEFER_O,      &level.score[2],        TEXT_SMASHING },
2310     { EL_KAEFER_L,      &level.score[2],        TEXT_SMASHING },
2311     { EL_KAEFER_U,      &level.score[2],        TEXT_SMASHING },
2312     { EL_BUTTERFLY_R,   &level.score[2],        TEXT_SMASHING },
2313     { EL_BUTTERFLY_O,   &level.score[2],        TEXT_SMASHING },
2314     { EL_BUTTERFLY_L,   &level.score[2],        TEXT_SMASHING },
2315     { EL_BUTTERFLY_U,   &level.score[2],        TEXT_SMASHING },
2316     { EL_FLIEGER_R,     &level.score[3],        TEXT_SMASHING },
2317     { EL_FLIEGER_O,     &level.score[3],        TEXT_SMASHING },
2318     { EL_FLIEGER_L,     &level.score[3],        TEXT_SMASHING },
2319     { EL_FLIEGER_U,     &level.score[3],        TEXT_SMASHING },
2320     { EL_FIREFLY_R,     &level.score[3],        TEXT_SMASHING },
2321     { EL_FIREFLY_O,     &level.score[3],        TEXT_SMASHING },
2322     { EL_FIREFLY_L,     &level.score[3],        TEXT_SMASHING },
2323     { EL_FIREFLY_U,     &level.score[3],        TEXT_SMASHING },
2324     { EL_MAMPFER,       &level.score[4],        TEXT_SMASHING },
2325     { EL_MAMPFER2,      &level.score[4],        TEXT_SMASHING },
2326     { EL_ROBOT,         &level.score[5],        TEXT_SMASHING },
2327     { EL_PACMAN_R,      &level.score[6],        TEXT_SMASHING },
2328     { EL_PACMAN_O,      &level.score[6],        TEXT_SMASHING },
2329     { EL_PACMAN_L,      &level.score[6],        TEXT_SMASHING },
2330     { EL_PACMAN_U,      &level.score[6],        TEXT_SMASHING },
2331     { EL_KOKOSNUSS,     &level.score[7],        TEXT_CRACKING },
2332     { EL_DYNAMIT_AUS,   &level.score[8],        TEXT_COLLECTING },
2333     { EL_SCHLUESSEL1,   &level.score[9],        TEXT_COLLECTING },
2334     { EL_SCHLUESSEL2,   &level.score[9],        TEXT_COLLECTING },
2335     { EL_SCHLUESSEL3,   &level.score[9],        TEXT_COLLECTING },
2336     { EL_SCHLUESSEL4,   &level.score[9],        TEXT_COLLECTING },
2337     { EL_AMOEBE_NASS,   &level.tempo_amoebe,    TEXT_SPEED },
2338     { EL_AMOEBE_NORM,   &level.tempo_amoebe,    TEXT_SPEED },
2339     { EL_AMOEBE_VOLL,   &level.tempo_amoebe,    TEXT_SPEED },
2340     { EL_AMOEBE_BD,     &level.tempo_amoebe,    TEXT_SPEED },
2341     { EL_SIEB_INAKTIV,  &level.dauer_sieb,      TEXT_DURATION },
2342     { EL_ABLENK_AUS,    &level.dauer_ablenk,    TEXT_DURATION },
2343     { -1, NULL, NULL }
2344   };
2345
2346   ClearWindow();
2347   UnmapLevelEditorWindowGadgets();
2348
2349   /* draw some decorative border for the object */
2350   for (y=0; y<3; y++)
2351     for (x=0; x<3; x++)
2352       DrawMiniElement(2 + x , 2 + y, EL_ERDREICH);
2353
2354   XFillRectangle(display, drawto, gc,
2355                  SX + TILEX + MINI_TILEX/2 - 1,
2356                  SY + TILEY + MINI_TILEY/2 - 1,
2357                  TILEX + 2, TILEY + 2);
2358
2359   /* copy border to the right location */
2360   XCopyArea(display, drawto, drawto, gc,
2361             SX + TILEX, SY + TILEY,
2362             2 * TILEX, 2 * TILEY,
2363             SX + TILEX - MINI_TILEX/2, SY + TILEY - MINI_TILEY/2);
2364
2365   DrawGraphic(1, 1, el2gfx(properties_element));
2366   DrawText(SX + 3*TILEX, SY + 5*TILEY/4, "Element Properties",
2367            FS_SMALL, FC_YELLOW);
2368
2369   num_elements_in_level = 0;
2370   for (y=0; y<lev_fieldy; y++) 
2371     for (x=0; x<lev_fieldx; x++)
2372       if (Feld[x][y] == properties_element)
2373         num_elements_in_level++;
2374
2375   DrawTextF(ED_PROPERTIES_XPOS, 5*TILEY, FC_YELLOW, "%d x contained in level",
2376             num_elements_in_level);
2377
2378   /* check if there are elements where a score can be chosen for */
2379   for (i=0; elements_with_counter[i].element != -1; i++)
2380   {
2381     if (elements_with_counter[i].element == properties_element)
2382     {
2383       int x = counterbutton_info[ED_COUNTER_SCORE].x + DXSIZE;
2384       int y = counterbutton_info[ED_COUNTER_SCORE].y;
2385
2386       gadget_score_value = elements_with_counter[i].counter_value;
2387       DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
2388       DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2389                 FC_YELLOW, elements_with_counter[i].text);
2390       MapCounterButtons(ED_COUNTER_SCORE);
2391       break;
2392     }
2393   }
2394
2395   if (HAS_CONTENT(properties_element))
2396   {
2397     if (IS_AMOEBOID(properties_element))
2398       DrawAmoebaContentArea();
2399     else
2400       DrawElementContentAreas();
2401   }
2402
2403   /* TEST ONLY: level name text input gadget */
2404   MapTextInputGadget(ED_CTRL_ID_LEVEL_NAME);
2405 }
2406
2407 static void swap_numbers(int *i1, int *i2)
2408 {
2409   int help = *i1;
2410
2411   *i1 = *i2;
2412   *i2 = help;
2413 }
2414
2415 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2416 {
2417   int help_x = *x1;
2418   int help_y = *y1;
2419
2420   *x1 = *x2;
2421   *x2 = help_x;
2422
2423   *y1 = *y2;
2424   *y2 = help_y;
2425 }
2426
2427 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2428 {
2429   int lx = sx + level_xpos;
2430   int ly = sy + level_ypos;
2431
2432   DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2433
2434   if (change_level)
2435     Feld[lx][ly] = element;
2436 }
2437
2438 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2439                      int element, boolean change_level)
2440 {
2441   if (from_y == to_y)                   /* horizontal line */
2442   {
2443     int x;
2444     int y = from_y;
2445
2446     if (from_x > to_x)
2447       swap_numbers(&from_x, &to_x);
2448
2449     for (x=from_x; x<=to_x; x++)
2450       DrawLineElement(x, y, element, change_level);
2451   }
2452   else if (from_x == to_x)              /* vertical line */
2453   {
2454     int x = from_x;
2455     int y;
2456
2457     if (from_y > to_y)
2458       swap_numbers(&from_y, &to_y);
2459
2460     for (y=from_y; y<=to_y; y++)
2461       DrawLineElement(x, y, element, change_level);
2462   }
2463   else                                  /* diagonal line */
2464   {
2465     int len_x = ABS(to_x - from_x);
2466     int len_y = ABS(to_y - from_y);
2467     int x, y;
2468
2469     if (len_y < len_x)                  /* a < 1 */
2470     {
2471       float a = (float)len_y / (float)len_x;
2472
2473       if (from_x > to_x)
2474         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2475
2476       for (x=0; x<=len_x; x++)
2477       {
2478         int y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2479
2480         DrawLineElement(from_x + x, from_y + y, element, change_level);
2481       }
2482     }
2483     else                                /* a >= 1 */
2484     {
2485       float a = (float)len_x / (float)len_y;
2486
2487       if (from_y > to_y)
2488         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2489
2490       for (y=0; y<=len_y; y++)
2491       {
2492         int x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2493
2494         DrawLineElement(from_x + x, from_y + y, element, change_level);
2495       }
2496     }
2497   }
2498 }
2499
2500 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2501                           int element, boolean change_level)
2502 {
2503   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2504   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2505   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2506   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2507 }
2508
2509 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2510                           int element, boolean change_level)
2511 {
2512   int y;
2513
2514   if (from_y > to_y)
2515     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2516
2517   for (y=from_y; y<=to_y; y++)
2518     DrawLine(from_x, y, to_x, y, element, change_level);
2519 }
2520
2521 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2522 {
2523   int from_sx, from_sy;
2524   int to_sx, to_sy;
2525
2526   if (from_x > to_x)
2527     swap_numbers(&from_x, &to_x);
2528
2529   if (from_y > to_y)
2530     swap_numbers(&from_y, &to_y);
2531
2532   from_sx = SX + from_x * MINI_TILEX;
2533   from_sy = SY + from_y * MINI_TILEY;
2534   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2535   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2536
2537   XSetForeground(display, gc, WhitePixel(display, screen));
2538
2539   XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2540   XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2541   XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2542   XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2543
2544   XSetForeground(display, gc, BlackPixel(display, screen));
2545
2546   if (from_x == to_x && from_y == to_y)
2547     MarkTileDirty(from_x/2, from_y/2);
2548   else
2549     redraw_mask |= REDRAW_FIELD;
2550 }
2551
2552 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2553                        int element, boolean change_level)
2554 {
2555   if (element == -1 || change_level)
2556     DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2557   else
2558     DrawAreaBorder(from_x, from_y, to_x, to_y);
2559 }
2560
2561 /* values for CopyBrushExt() */
2562 #define CB_AREA_TO_BRUSH        0
2563 #define CB_BRUSH_TO_CURSOR      1
2564 #define CB_BRUSH_TO_LEVEL       2
2565 #define CB_DELETE_OLD_CURSOR    3
2566
2567 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int mode)
2568 {
2569   static short brush_buffer[ED_FIELDX][ED_FIELDY];
2570   static int brush_width, brush_height;
2571   static int last_cursor_x = -1, last_cursor_y = -1;
2572   static boolean delete_old_brush;
2573   int x, y;
2574
2575   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
2576     return;
2577
2578   if (mode == CB_AREA_TO_BRUSH)
2579   {
2580     int from_lx, from_ly;
2581
2582     if (from_x > to_x)
2583       swap_numbers(&from_x, &to_x);
2584
2585     if (from_y > to_y)
2586       swap_numbers(&from_y, &to_y);
2587
2588     brush_width = to_x - from_x + 1;
2589     brush_height = to_y - from_y + 1;
2590
2591     from_lx = from_x + level_xpos;
2592     from_ly = from_y + level_ypos;
2593
2594     for (y=0; y<brush_height; y++)
2595       for (x=0; x<brush_width; x++)
2596         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
2597
2598     delete_old_brush = FALSE;
2599   }
2600   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
2601            mode == CB_BRUSH_TO_LEVEL)
2602   {
2603     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
2604     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
2605     int cursor_from_x = cursor_x - brush_width / 2;
2606     int cursor_from_y = cursor_y - brush_height / 2;
2607     int border_from_x = cursor_x, border_from_y = cursor_y;
2608     int border_to_x = cursor_x, border_to_y = cursor_y;
2609
2610     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
2611       CopyBrushExt(0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2612
2613     if (!IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
2614     {
2615       delete_old_brush = FALSE;
2616       return;
2617     }
2618
2619     for (y=0; y<brush_height; y++)
2620     {
2621       for (x=0; x<brush_width; x++)
2622       {
2623         int sx = cursor_from_x + x;
2624         int sy = cursor_from_y + y;
2625         int lx = sx + level_xpos;
2626         int ly = sy + level_ypos;
2627         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 : brush_buffer[x][y]);
2628         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
2629
2630         if (IN_LEV_FIELD(lx, ly) &&
2631             sx >=0 && sx < ED_FIELDX && sy >=0 && sy < ED_FIELDY)
2632         {
2633           if (sx < border_from_x)
2634             border_from_x = sx;
2635           else if (sx > border_to_x)
2636             border_to_x = sx;
2637           if (sy < border_from_y)
2638             border_from_y = sy;
2639           else if (sy > border_to_y)
2640             border_to_y = sy;
2641
2642           DrawLineElement(sx, sy, element, change_level);
2643         }
2644       }
2645     }
2646
2647     /*
2648     printf("%d, %d - %d, %d in level and screen\n",
2649            border_from_x, border_from_y, border_to_x, border_to_y);
2650     */
2651
2652     if (mode != CB_DELETE_OLD_CURSOR)
2653       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
2654
2655     if (mode == CB_BRUSH_TO_LEVEL)
2656       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2657
2658     last_cursor_x = cursor_x;
2659     last_cursor_y = cursor_y;
2660     delete_old_brush = TRUE;
2661   }
2662 }
2663
2664 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y)
2665 {
2666   CopyBrushExt(from_x, from_y, to_x, to_y, CB_AREA_TO_BRUSH);
2667 }
2668
2669 static void CopyBrushToLevel(int x, int y)
2670 {
2671   CopyBrushExt(x, y, 0, 0, CB_BRUSH_TO_LEVEL);
2672 }
2673
2674 static void CopyBrushToCursor(int x, int y)
2675 {
2676   CopyBrushExt(x, y, 0, 0, CB_BRUSH_TO_CURSOR);
2677 }
2678
2679 static void DeleteBrushFromCursor()
2680 {
2681   CopyBrushExt(0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2682 }
2683
2684 static void FloodFill(int from_x, int from_y, int fill_element)
2685 {
2686   int i,x,y;
2687   int old_element;
2688   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2689   static int safety = 0;
2690
2691   /* check if starting field still has the desired content */
2692   if (Feld[from_x][from_y] == fill_element)
2693     return;
2694
2695   safety++;
2696
2697   if (safety > lev_fieldx*lev_fieldy)
2698     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2699
2700   old_element = Feld[from_x][from_y];
2701   Feld[from_x][from_y] = fill_element;
2702
2703   for(i=0;i<4;i++)
2704   {
2705     x = from_x + check[i][0];
2706     y = from_y + check[i][1];
2707
2708     if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2709       FloodFill(x, y, fill_element);
2710   }
2711
2712   safety--;
2713 }
2714
2715 /* values for DrawLevelText() modes */
2716 #define TEXT_INIT       0
2717 #define TEXT_SETCURSOR  1
2718 #define TEXT_WRITECHAR  2
2719 #define TEXT_BACKSPACE  3
2720 #define TEXT_NEWLINE    4
2721 #define TEXT_END        5
2722
2723 static void DrawLevelText(int sx, int sy, char letter, int mode)
2724 {
2725   static short delete_buffer[MAX_LEV_FIELDX];
2726   static int start_sx, start_sy;
2727   static int last_sx, last_sy;
2728   static boolean typing = FALSE;
2729   int letter_element = EL_CHAR_ASCII0 + letter;
2730   int lx, ly;
2731
2732   /* map lower case letters to upper case and convert special characters */
2733   if (letter >= 'a' && letter <= 'z')
2734     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
2735   else if (letter == 'ä' || letter == 'Ä')
2736     letter_element = EL_CHAR_AE;
2737   else if (letter == 'ö' || letter == 'Ö')
2738     letter_element = EL_CHAR_OE;
2739   else if (letter == 'ü' || letter == 'Ãœ')
2740     letter_element = EL_CHAR_UE;
2741   else if (letter == '^')
2742     letter_element = EL_CHAR_COPY;
2743   else
2744     letter_element = EL_CHAR_ASCII0 + letter;
2745
2746   if (mode != TEXT_INIT)
2747   {
2748     if (!typing)
2749       return;
2750
2751     if (mode != TEXT_SETCURSOR)
2752     {
2753       sx = last_sx;
2754       sy = last_sy;
2755     }
2756
2757     lx = last_sx + level_xpos;
2758     ly = last_sy + level_ypos;
2759   }
2760
2761   switch (mode)
2762   {
2763     case TEXT_INIT:
2764       if (typing)
2765         DrawLevelText(0, 0, 0, TEXT_END);
2766
2767       typing = TRUE;
2768       start_sx = last_sx = sx;
2769       start_sy = last_sy = sy;
2770       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2771       break;
2772
2773     case TEXT_SETCURSOR:
2774       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2775       DrawAreaBorder(sx, sy, sx, sy);
2776       last_sx = sx;
2777       last_sy = sy;
2778       break;
2779
2780     case TEXT_WRITECHAR:
2781       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2782       {
2783         delete_buffer[sx - start_sx] = Feld[lx][ly];
2784         Feld[lx][ly] = letter_element;
2785
2786         if (sx + 1 < ED_FIELDX && lx + 1 < lev_fieldx)
2787           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2788         else if (sy + 1 < ED_FIELDY && ly + 1 < lev_fieldy)
2789           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2790         else
2791           DrawLevelText(0, 0, 0, TEXT_END);
2792       }
2793       break;
2794
2795     case TEXT_BACKSPACE:
2796       if (sx > start_sx)
2797       {
2798         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2799         DrawMiniElement(sx - 1, sy, new_element3);
2800         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2801       }
2802       break;
2803
2804     case TEXT_NEWLINE:
2805       if (sy + 1 < ED_FIELDY - 1 && ly + 1 < lev_fieldy - 1)
2806         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2807       else
2808         DrawLevelText(0, 0, 0, TEXT_END);
2809       break;
2810
2811     case TEXT_END:
2812       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2813       DrawMiniElement(sx, sy, Feld[lx][ly]);
2814       typing = FALSE;
2815       break;
2816
2817     default:
2818       break;
2819   }
2820 }
2821
2822 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
2823                           int element, boolean change_level)
2824 {
2825   int lx = sx + level_xpos;
2826   int ly = sy + level_ypos;
2827
2828   if (element == -1)
2829     DrawMiniElement(sx, sy, Feld[lx][ly]);
2830   else
2831     DrawAreaBorder(sx, sy, sx, sy);
2832 }
2833
2834 static void CopyLevelToUndoBuffer(int mode)
2835 {
2836   static boolean accumulated_undo = FALSE;
2837   boolean new_undo_buffer_position = TRUE;
2838   int x, y;
2839
2840   switch (mode)
2841   {
2842     case UNDO_IMMEDIATE:
2843       accumulated_undo = FALSE;
2844       break;
2845
2846     case UNDO_ACCUMULATE:
2847       if (accumulated_undo)
2848         new_undo_buffer_position = FALSE;
2849       accumulated_undo = TRUE;
2850       break;
2851
2852     default:
2853       break;
2854   }
2855
2856   if (new_undo_buffer_position)
2857   {
2858     /* new position in undo buffer ring */
2859     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2860
2861     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2862       undo_buffer_steps++;
2863   }
2864
2865   for(x=0; x<lev_fieldx; x++)
2866     for(y=0; y<lev_fieldy; y++)
2867       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2868 #if 0
2869 #ifdef DEBUG
2870   printf("level saved to undo buffer\n");
2871 #endif
2872 #endif
2873 }
2874
2875 static void RandomPlacement(int button)
2876 {
2877   int new_element;
2878   int x, y;
2879
2880   new_element = (button == 1 ? new_element1 :
2881                  button == 2 ? new_element2 :
2882                  button == 3 ? new_element3 : 0);
2883
2884   if (random_placement_method == RANDOM_USE_PERCENTAGE)
2885   {
2886     for(x=0; x<lev_fieldx; x++)
2887       for(y=0; y<lev_fieldy; y++)
2888         if (RND(100) < random_placement_percentage)
2889           Feld[x][y] = new_element;
2890   }
2891   else
2892   {
2893     int elements_left = random_placement_num_objects;
2894
2895     while (elements_left > 0)
2896     {
2897       x = RND(lev_fieldx);
2898       y = RND(lev_fieldy);
2899
2900       if (Feld[x][y] != new_element)
2901       {
2902         Feld[x][y] = new_element;
2903         elements_left--;
2904       }
2905     }
2906   }
2907
2908   DrawMiniLevel(level_xpos, level_ypos);
2909   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2910 }
2911
2912 void WrapLevel(int dx, int dy)
2913 {
2914   int wrap_dx = lev_fieldx - dx;
2915   int wrap_dy = lev_fieldy - dy;
2916   int x, y;
2917
2918   for(x=0; x<lev_fieldx; x++)
2919     for(y=0; y<lev_fieldy; y++)
2920       FieldBackup[x][y] = Feld[x][y];
2921
2922   for(x=0; x<lev_fieldx; x++)
2923     for(y=0; y<lev_fieldy; y++)
2924       Feld[x][y] =
2925         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
2926
2927   DrawMiniLevel(level_xpos, level_ypos);
2928   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
2929 }
2930
2931 static void HandleDrawingAreas(struct GadgetInfo *gi)
2932 {
2933   static boolean started_inside_drawing_area = FALSE;
2934   int id = gi->custom_id;
2935   boolean inside_drawing_area = !gi->event.off_borders;
2936   boolean button_press_event;
2937   boolean button_release_event;
2938   boolean draw_level = (id == ED_CTRL_ID_DRAWING_LEVEL);
2939   int new_element;
2940   int button = gi->event.button;
2941   int sx = gi->event.x, sy = gi->event.y;
2942   int min_sx = 0, min_sy = 0;
2943   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
2944   int lx, ly;
2945   int min_lx = 0, min_ly = 0;
2946   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2947   int x, y;
2948
2949   /*
2950   if (edit_mode != ED_MODE_DRAWING)
2951     return;
2952   */
2953
2954   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
2955   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
2956
2957   /* make sure to stay inside drawing area boundaries */
2958   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2959   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2960
2961   if (draw_level)
2962   {
2963     /* get positions inside level field */
2964     lx = sx + level_xpos;
2965     ly = sy + level_ypos;
2966
2967     /* make sure to stay inside level field boundaries */
2968     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2969     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2970
2971     /* correct drawing area positions accordingly */
2972     sx = lx - level_xpos;
2973     sy = ly - level_ypos;
2974   }
2975
2976   if (button_press_event)
2977     started_inside_drawing_area = inside_drawing_area;
2978
2979   if (!started_inside_drawing_area)
2980     return;
2981
2982   if (!button && !button_release_event)
2983     return;
2984
2985   new_element = (button == 1 ? new_element1 :
2986                  button == 2 ? new_element2 :
2987                  button == 3 ? new_element3 : 0);
2988
2989   if (!draw_level && drawing_function != ED_CTRL_ID_SINGLE_ITEMS)
2990     return;
2991
2992   switch (drawing_function)
2993   {
2994     case ED_CTRL_ID_SINGLE_ITEMS:
2995       if (draw_level)
2996       {
2997         if (button_release_event)
2998           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2999
3000         if (!button)
3001           break;
3002
3003         if (new_element != Feld[lx][ly])
3004         {
3005           if (new_element == EL_SPIELFIGUR)
3006           {
3007             /* remove player at old position */
3008             for(y=0; y<lev_fieldy; y++)
3009             {
3010               for(x=0; x<lev_fieldx; x++)
3011               {
3012                 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
3013                 {
3014                   Feld[x][y] = EL_LEERRAUM;
3015                   if (x - level_xpos >= 0 && x - level_xpos < ED_FIELDX &&
3016                       y - level_ypos >= 0 && y - level_ypos < ED_FIELDY)
3017                     DrawMiniElement(x - level_xpos, y - level_ypos,
3018                                     EL_LEERRAUM);
3019                 }
3020               }
3021             }
3022           }
3023
3024           Feld[lx][ly] = new_element;
3025           DrawMiniElement(sx, sy, new_element);
3026         }
3027       }
3028       else
3029       {
3030         DrawMiniGraphicExt(drawto, gc,
3031                            gi->x + sx * MINI_TILEX,
3032                            gi->y + sy * MINI_TILEY,
3033                            el2gfx(new_element));
3034         DrawMiniGraphicExt(window, gc,
3035                            gi->x + sx * MINI_TILEX,
3036                            gi->y + sy * MINI_TILEY,
3037                            el2gfx(new_element));
3038
3039         if (id == ED_CTRL_ID_AMOEBA_CONTENT)
3040           level.amoebe_inhalt = new_element;
3041         else if (id >= ED_CTRL_ID_ELEMCONT_0 && id <= ED_CTRL_ID_ELEMCONT_7)
3042           level.mampfer_inhalt[id - ED_CTRL_ID_ELEMCONT_0][sx][sy] =
3043             new_element;
3044       }
3045       break;
3046
3047     case ED_CTRL_ID_CONNECTED_ITEMS:
3048       {
3049         static int last_sx = -1;
3050         static int last_sy = -1;
3051
3052         if (button_release_event)
3053           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3054
3055         if (button)
3056         {
3057           if (!button_press_event)
3058             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
3059
3060           last_sx = sx;
3061           last_sy = sy;
3062         }
3063       }
3064       break;
3065
3066     case ED_CTRL_ID_LINE:
3067     case ED_CTRL_ID_RECTANGLE:
3068     case ED_CTRL_ID_FILLED_BOX:
3069     case ED_CTRL_ID_BRUSH:
3070     case ED_CTRL_ID_TEXT:
3071       {
3072         static int last_sx = -1;
3073         static int last_sy = -1;
3074         static int start_sx = -1;
3075         static int start_sy = -1;
3076         void (*draw_func)(int, int, int, int, int, boolean);
3077
3078         if (drawing_function == ED_CTRL_ID_LINE)
3079           draw_func = DrawLine;
3080         else if (drawing_function == ED_CTRL_ID_RECTANGLE)
3081           draw_func = DrawRectangle;
3082         else if (drawing_function == ED_CTRL_ID_FILLED_BOX)
3083           draw_func = DrawFilledBox;
3084         else if (drawing_function == ED_CTRL_ID_BRUSH)
3085           draw_func = SelectArea;
3086         else /* (drawing_function == ED_CTRL_ID_TEXT) */
3087           draw_func = SetTextCursor;
3088
3089         if (button_press_event)
3090         {
3091           draw_func(sx, sy, sx, sy, new_element, FALSE);
3092           start_sx = last_sx = sx;
3093           start_sy = last_sy = sy;
3094
3095           if (drawing_function == ED_CTRL_ID_TEXT)
3096             DrawLevelText(0, 0, 0, TEXT_END);
3097         }
3098         else if (button_release_event)
3099         {
3100           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
3101           if (drawing_function == ED_CTRL_ID_BRUSH)
3102           {
3103             CopyAreaToBrush(start_sx, start_sy, sx, sy);
3104             draw_with_brush = TRUE;
3105           }
3106           else if (drawing_function == ED_CTRL_ID_TEXT)
3107             DrawLevelText(sx, sy, 0, TEXT_INIT);
3108           else
3109             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3110         }
3111         else if (last_sx != sx || last_sy != sy)
3112         {
3113           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
3114           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
3115           last_sx = sx;
3116           last_sy = sy;
3117         }
3118       }
3119       break;
3120
3121
3122
3123 #if 0
3124     case ED_CTRL_ID_TEXT:
3125       /*
3126       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
3127       DrawAreaBorder(sx, sy, sx, sy);
3128       last_sx = sx;
3129       last_sy = sy;
3130       */
3131
3132       if (button_press_event)
3133         DrawLevelText(sx, sy, 0, TEXT_INIT);
3134       break;
3135 #endif
3136
3137
3138
3139     case ED_CTRL_ID_FLOOD_FILL:
3140       if (button_press_event && Feld[lx][ly] != new_element)
3141       {
3142         FloodFill(lx, ly, new_element);
3143         DrawMiniLevel(level_xpos, level_ypos);
3144         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3145       }
3146       break;
3147
3148     case ED_CTRL_ID_PICK_ELEMENT:
3149       if (button_press_event)
3150         PickDrawingElement(button, Feld[lx][ly]);
3151       if (button_release_event)
3152         ClickOnGadget(level_editor_gadget[last_drawing_function]);
3153       break;
3154
3155     default:
3156       break;
3157   }
3158 }
3159
3160 static void HandleCounterButtons(struct GadgetInfo *gi)
3161 {
3162   int id = gi->custom_id;
3163   int button = gi->event.button;
3164   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3165
3166   switch (id)
3167   {
3168     case ED_CTRL_ID_SCORE_DOWN:
3169     case ED_CTRL_ID_SCORE_UP:
3170       *gadget_score_value += (id == ED_CTRL_ID_SCORE_DOWN ? -step : step);
3171       if (*gadget_score_value < 0)
3172         *gadget_score_value = 0;
3173       else if (*gadget_score_value > 255)
3174         *gadget_score_value = 255;
3175
3176       DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
3177       break;
3178
3179     case ED_CTRL_ID_ELEMCONT_DOWN:
3180     case ED_CTRL_ID_ELEMCONT_UP:
3181       *gadget_areas_value += (id == ED_CTRL_ID_ELEMCONT_DOWN ? -step : step);
3182       if (*gadget_areas_value < 1)
3183         *gadget_areas_value = 1;
3184       else if (*gadget_areas_value > MAX_ELEMCONT)
3185         *gadget_areas_value = MAX_ELEMCONT;
3186
3187       DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
3188       DrawElementContentAreas();
3189       break;
3190
3191     default:
3192       break;
3193   }
3194 }
3195
3196 static void HandleControlButtons(struct GadgetInfo *gi)
3197 {
3198   int id = gi->custom_id;
3199   int button = gi->event.button;
3200   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3201   int new_element;
3202   int player_present = FALSE;
3203   int level_changed = FALSE;
3204   int x, y;
3205
3206   new_element = (button == 1 ? new_element1 :
3207                  button == 2 ? new_element2 :
3208                  button == 3 ? new_element3 : 0);
3209
3210   if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3211     DrawLevelText(0, 0, 0, TEXT_END);
3212
3213   if (id < ED_NUM_CTRL1_BUTTONS && id != ED_CTRL_ID_PROPERTIES &&
3214       edit_mode != ED_MODE_DRAWING)
3215   {
3216     DrawDrawingWindow();
3217     edit_mode = ED_MODE_DRAWING;
3218   }
3219
3220   switch (id)
3221   {
3222     case ED_CTRL_ID_SCROLL_LEFT:
3223       if (level_xpos >= 0)
3224       {
3225         int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3226         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3227         struct GadgetScrollbar *gs = &gi->scrollbar;
3228
3229         if (lev_fieldx < ED_FIELDX - 2)
3230           break;
3231
3232         level_xpos -= step;
3233         if (level_xpos < -1)
3234           level_xpos = -1;
3235         if (button == 1)
3236           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3237         else
3238           DrawMiniLevel(level_xpos, level_ypos);
3239
3240         AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3241       }
3242       break;
3243
3244     case ED_CTRL_ID_SCROLL_RIGHT:
3245       if (level_xpos <= lev_fieldx - ED_FIELDX)
3246       {
3247         int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3248         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3249         struct GadgetScrollbar *gs = &gi->scrollbar;
3250
3251         if (lev_fieldx < ED_FIELDX - 2)
3252           break;
3253
3254         level_xpos += step;
3255         if (level_xpos > lev_fieldx - ED_FIELDX + 1)
3256           level_xpos = lev_fieldx - ED_FIELDX + 1;
3257         if (button == 1)
3258           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3259         else
3260           DrawMiniLevel(level_xpos, level_ypos);
3261
3262         AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3263       }
3264       break;
3265
3266     case ED_CTRL_ID_SCROLL_UP:
3267       if (level_ypos >= 0)
3268       {
3269         int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3270         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3271         struct GadgetScrollbar *gs = &gi->scrollbar;
3272
3273         if (lev_fieldy < ED_FIELDY - 2)
3274           break;
3275
3276         level_ypos -= step;
3277         if (level_ypos < -1)
3278           level_ypos = -1;
3279         if (button == 1)
3280           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3281         else
3282           DrawMiniLevel(level_xpos, level_ypos);
3283
3284         AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3285       }
3286       break;
3287
3288     case ED_CTRL_ID_SCROLL_DOWN:
3289       if (level_ypos <= lev_fieldy - ED_FIELDY)
3290       {
3291         int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3292         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3293         struct GadgetScrollbar *gs = &gi->scrollbar;
3294
3295         if (lev_fieldy < ED_FIELDY - 2)
3296           break;
3297
3298         level_ypos += step;
3299         if (level_ypos > lev_fieldy - ED_FIELDY + 1)
3300           level_ypos = lev_fieldy - ED_FIELDY + 1;
3301         if (button == 1)
3302           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3303         else
3304           DrawMiniLevel(level_xpos, level_ypos);
3305
3306         AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3307       }
3308       break;
3309
3310     case ED_CTRL_ID_SCROLL_HORIZONTAL:
3311       level_xpos = gi->event.item_position - 1;
3312       DrawMiniLevel(level_xpos, level_ypos);
3313       break;
3314
3315     case ED_CTRL_ID_SCROLL_VERTICAL:
3316       level_ypos = gi->event.item_position - 1;
3317       DrawMiniLevel(level_xpos, level_ypos);
3318       break;
3319
3320     case ED_CTRL_ID_WRAP_LEFT:
3321       WrapLevel(-step, 0);
3322       break;
3323
3324     case ED_CTRL_ID_WRAP_RIGHT:
3325       WrapLevel(step, 0);
3326       break;
3327
3328     case ED_CTRL_ID_WRAP_UP:
3329       WrapLevel(0, -step);
3330       break;
3331
3332     case ED_CTRL_ID_WRAP_DOWN:
3333       WrapLevel(0, step);
3334       break;
3335
3336     case ED_CTRL_ID_SINGLE_ITEMS:
3337     case ED_CTRL_ID_CONNECTED_ITEMS:
3338     case ED_CTRL_ID_LINE:
3339     case ED_CTRL_ID_TEXT:
3340     case ED_CTRL_ID_RECTANGLE:
3341     case ED_CTRL_ID_FILLED_BOX:
3342     case ED_CTRL_ID_FLOOD_FILL:
3343     case ED_CTRL_ID_BRUSH:
3344     case ED_CTRL_ID_PICK_ELEMENT:
3345       last_drawing_function = drawing_function;
3346       drawing_function = id;
3347       break;
3348
3349     case ED_CTRL_ID_RANDOM_PLACEMENT:
3350       RandomPlacement(button);
3351       break;
3352
3353     case ED_CTRL_ID_PROPERTIES:
3354       if (edit_mode != ED_MODE_PROPERTIES)
3355       {
3356         properties_element = new_element;
3357         DrawPropertiesWindow();
3358         edit_mode = ED_MODE_PROPERTIES;
3359       }
3360       else
3361       {
3362         DrawDrawingWindow();
3363         edit_mode = ED_MODE_DRAWING;
3364       }
3365       break;
3366
3367     case ED_CTRL_ID_UNDO:
3368       if (undo_buffer_steps == 0)
3369       {
3370         Request("Undo buffer empty !", REQ_CONFIRM);
3371         break;
3372       }
3373
3374       undo_buffer_position =
3375         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3376       undo_buffer_steps--;
3377
3378       for(x=0; x<lev_fieldx; x++)
3379         for(y=0; y<lev_fieldy; y++)
3380           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3381       DrawMiniLevel(level_xpos,level_ypos);
3382       break;
3383
3384     case ED_CTRL_ID_INFO:
3385       if (edit_mode != ED_MODE_INFO)
3386       {
3387         DrawControlWindow();
3388         edit_mode = ED_MODE_INFO;
3389       }
3390       else
3391       {
3392         DrawDrawingWindow();
3393         edit_mode = ED_MODE_DRAWING;
3394       }
3395       break;
3396
3397     case ED_CTRL_ID_CLEAR:
3398       for(x=0; x<MAX_LEV_FIELDX; x++) 
3399         for(y=0; y<MAX_LEV_FIELDY; y++) 
3400           Feld[x][y] = new_element3;
3401       CopyLevelToUndoBuffer(ED_CTRL_ID_CLEAR);
3402
3403       DrawMiniLevel(level_xpos, level_ypos);
3404       break;
3405
3406     case ED_CTRL_ID_SAVE:
3407       if (leveldir[leveldir_nr].readonly)
3408       {
3409         Request("This level is read only !", REQ_CONFIRM);
3410         break;
3411       }
3412
3413       for(y=0; y<lev_fieldy; y++) 
3414         for(x=0; x<lev_fieldx; x++)
3415           if (Feld[x][y] != Ur[x][y])
3416             level_changed = TRUE;
3417
3418       if (0 && !level_changed)
3419       {
3420         Request("Level has not changed !", REQ_CONFIRM);
3421         break;
3422       }
3423
3424       for(y=0; y<lev_fieldy; y++) 
3425         for(x=0; x<lev_fieldx; x++)
3426           if (Feld[x][y] == EL_SPIELFIGUR ||
3427               Feld[x][y] == EL_SPIELER1 ||
3428               Feld[x][y] == EL_SP_MURPHY) 
3429             player_present = TRUE;
3430
3431       if (!player_present)
3432         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3433       else
3434       {
3435         if (Request("Save this level and kill the old ?", REQ_ASK))
3436         {
3437           for(x=0; x<lev_fieldx; x++)
3438             for(y=0; y<lev_fieldy; y++) 
3439               Ur[x][y] = Feld[x][y];
3440           SaveLevel(level_nr);
3441         }
3442       }
3443       break;
3444
3445     case ED_CTRL_ID_TEST:
3446       for(y=0; y<lev_fieldy; y++) 
3447         for(x=0; x<lev_fieldx; x++)
3448           if (Feld[x][y] == EL_SPIELFIGUR ||
3449               Feld[x][y] == EL_SPIELER1 ||
3450               Feld[x][y] == EL_SP_MURPHY) 
3451             player_present = TRUE;
3452
3453       if (!player_present)
3454         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3455       else
3456       {
3457         for(x=0; x<lev_fieldx; x++)
3458           for(y=0; y<lev_fieldy; y++)
3459             FieldBackup[x][y] = Ur[x][y];
3460
3461         for(x=0; x<lev_fieldx; x++)
3462           for(y=0; y<lev_fieldy; y++)
3463             Ur[x][y] = Feld[x][y];
3464
3465         UnmapLevelEditorGadgets();
3466
3467         /* draw smaller door */
3468         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3469                   DOOR_GFX_PAGEX7, 64,
3470                   108, 64,
3471                   EX - 4, EY - 12);
3472         redraw_mask |= REDRAW_ALL;
3473
3474         CloseDoor(DOOR_CLOSE_ALL);
3475
3476         DrawCompleteVideoDisplay();
3477
3478         if (setup.autorecord)
3479           TapeStartRecording();
3480
3481         level_editor_test_game = TRUE;
3482         game_status = PLAYING;
3483
3484         InitGame();
3485       }
3486       break;
3487
3488     case ED_CTRL_ID_EXIT:
3489       for(y=0; y<lev_fieldy; y++) 
3490         for(x=0; x<lev_fieldx; x++)
3491           if (Feld[x][y] != Ur[x][y])
3492             level_changed = TRUE;
3493
3494       if (!level_changed ||
3495           Request("Level has changed! Exit without saving ?",
3496                   REQ_ASK | REQ_STAY_OPEN))
3497       {
3498         CloseDoor(DOOR_CLOSE_1);
3499
3500         /*
3501         CloseDoor(DOOR_CLOSE_ALL);
3502         */
3503
3504         /* draw smaller door */
3505         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3506                   DOOR_GFX_PAGEX7, 64,
3507                   108, 64,
3508                   EX - 4, EY - 12);
3509         redraw_mask |= REDRAW_ALL;
3510
3511         game_status = MAINMENU;
3512         DrawMainMenu();
3513       }
3514       else
3515       {
3516         CloseDoor(DOOR_CLOSE_1);
3517         XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3518                   DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3519                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3520         OpenDoor(DOOR_OPEN_1);
3521       }
3522       break;
3523
3524     default:
3525 #ifdef DEBUG
3526       if (gi->event.type == GD_EVENT_PRESSED)
3527         printf("default: HandleControlButtons: GD_EVENT_PRESSED\n");
3528       else if (gi->event.type == GD_EVENT_RELEASED)
3529         printf("default: HandleControlButtons: GD_EVENT_RELEASED\n");
3530       else if (gi->event.type == GD_EVENT_MOVING)
3531         printf("default: HandleControlButtons: GD_EVENT_MOVING\n");
3532       else
3533         printf("default: HandleControlButtons: ?\n");
3534 #endif
3535       break;
3536   }
3537 }
3538
3539 void HandleLevelEditorKeyInput(KeySym key)
3540 {
3541   if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3542   {
3543     char letter = getCharFromKeySym(key);
3544
3545     if (letter)
3546       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3547     else if (key == XK_Delete || key == XK_BackSpace)
3548       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3549     else if (key == XK_Return)
3550       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3551   }
3552 }
3553
3554 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3555 {
3556   int id = gi->custom_id;
3557
3558   switch (id)
3559   {
3560     case ED_CTRL_ID_LEVEL_NAME:
3561       strcpy(level.name, gi->text_value);
3562       break;
3563
3564     default:
3565       break;
3566   }
3567 }
3568
3569 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
3570 #define INFOTEXT_XPOS           SX
3571 #define INFOTEXT_YPOS           (SY + SYSIZE - MINI_TILEX + 2)
3572 #define INFOTEXT_XSIZE          SXSIZE
3573 #define INFOTEXT_YSIZE          MINI_TILEX
3574 #define MAX_INFOTEXT_LEN        (SXSIZE / FONT2_XSIZE)
3575
3576 void ClearEditorGadgetInfoText()
3577 {
3578   XFillRectangle(display, drawto, gc,
3579                  INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
3580   redraw_mask |= REDRAW_FIELD;
3581 }
3582
3583 void HandleEditorGadgetInfoText(void *ptr)
3584 {
3585   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
3586   char infotext[MAX_INFOTEXT_LEN + 1];
3587
3588   ClearEditorGadgetInfoText();
3589
3590   /* misuse this function to delete brush cursor, if needed */
3591   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
3592     DeleteBrushFromCursor();
3593
3594   if (gi == NULL || gi->description_text == NULL)
3595     return;
3596
3597   strncpy(infotext, gi->description_text, MAX_INFOTEXT_LEN);
3598   infotext[MAX_INFOTEXT_LEN] = '\0';
3599
3600   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
3601 }
3602
3603 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
3604 {
3605   int id = gi->custom_id;
3606   int sx = gi->event.x;
3607   int sy = gi->event.y;
3608   int lx = sx + level_xpos;
3609   int ly = sy + level_ypos;
3610
3611   ClearEditorGadgetInfoText();
3612
3613   if (id == ED_CTRL_ID_DRAWING_LEVEL)
3614   {
3615     if (IN_LEV_FIELD(lx, ly))
3616       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3617                 "Level: %d, %d (Screen: %d, %d)", lx, ly, sx, sy);
3618
3619     /* misuse this function to draw brush cursor, if needed */
3620     if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
3621       CopyBrushToCursor(sx, sy);
3622   }
3623   else if (id == ED_CTRL_ID_AMOEBA_CONTENT)
3624     DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3625               "Amoeba content");
3626   else
3627     DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3628               "Cruncher %d content: %d, %d", id - ED_CTRL_ID_ELEMCONT_0 + 1,
3629               sx, sy);
3630 }