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