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