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