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