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