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