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