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