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