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