5fb4dd93b4444f26017086e13c78fbcd145dee6c
[rocksndiamonds.git] / src / editor.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * editor.c                                                 *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "libgame/libgame.h"
17
18 #include "editor.h"
19 #include "screens.h"
20 #include "tools.h"
21 #include "files.h"
22 #include "game.h"
23 #include "init.h"
24 #include "tape.h"
25
26
27 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
28
29
30 /*
31   -----------------------------------------------------------------------------
32   screen and artwork graphic pixel position definitions
33   -----------------------------------------------------------------------------
34 */
35
36 /* positions in the level editor */
37 #define ED_WIN_MB_LEFT_XPOS             6
38 #define ED_WIN_MB_LEFT_YPOS             258
39 #define ED_WIN_MB_MIDDLE_XPOS           42
40 #define ED_WIN_MB_MIDDLE_YPOS           ED_WIN_MB_LEFT_YPOS
41 #define ED_WIN_MB_RIGHT_XPOS            78
42 #define ED_WIN_MB_RIGHT_YPOS            ED_WIN_MB_LEFT_YPOS
43
44 /* values for the control window */
45 #define ED_CTRL_NO_BUTTONS_GFX_XPOS     6
46 #define ED_CTRL_NO_BUTTONS_GFX_YPOS     286
47 #define ED_CTRL1_BUTTONS_GFX_YPOS       236
48 #define ED_CTRL2_BUTTONS_GFX_YPOS       236
49 #define ED_CTRL3_BUTTONS_GFX_YPOS       324
50 #define ED_CTRL4_BUTTONS_GFX_XPOS       44
51 #define ED_CTRL4_BUTTONS_GFX_YPOS       214
52 #define ED_CTRL1_BUTTONS_ALT_GFX_YPOS   142
53 #define ED_CTRL3_BUTTONS_ALT_GFX_YPOS   302
54
55 #define ED_CTRL1_BUTTON_XSIZE           22
56 #define ED_CTRL1_BUTTON_YSIZE           22
57 #define ED_CTRL1_BUTTONS_XPOS           6
58 #define ED_CTRL1_BUTTONS_YPOS           6
59 #define ED_CTRL2_BUTTON_XSIZE           30
60 #define ED_CTRL2_BUTTON_YSIZE           20
61 #define ED_CTRL2_BUTTONS_XPOS           5
62 #define ED_CTRL2_BUTTONS_YPOS           99
63 #define ED_CTRL3_BUTTON_XSIZE           22
64 #define ED_CTRL3_BUTTON_YSIZE           22
65 #define ED_CTRL3_BUTTONS_XPOS           6
66 #define ED_CTRL3_BUTTONS_YPOS           6
67 #define ED_CTRL4_BUTTON_XSIZE           22
68 #define ED_CTRL4_BUTTON_YSIZE           22
69 #define ED_CTRL4_BUTTONS_XPOS           6
70 #define ED_CTRL4_BUTTONS_YPOS           6
71
72 #define ED_CTRL1_BUTTONS_HORIZ          4
73 #define ED_CTRL1_BUTTONS_VERT           4
74 #define ED_CTRL2_BUTTONS_HORIZ          3
75 #define ED_CTRL2_BUTTONS_VERT           2
76 #define ED_CTRL3_BUTTONS_HORIZ          3
77 #define ED_CTRL3_BUTTONS_VERT           1
78 #define ED_CTRL4_BUTTONS_HORIZ          2
79 #define ED_CTRL4_BUTTONS_VERT           1
80
81 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
82 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
83 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
84 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
85 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
86 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
87 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS +  \
88                                 ED_NUM_CTRL2_BUTTONS +  \
89                                 ED_NUM_CTRL3_BUTTONS +  \
90                                 ED_NUM_CTRL4_BUTTONS)
91
92 /* values for the element list */
93 #define ED_ELEMENTLIST_XPOS             5
94 #define ED_ELEMENTLIST_YPOS             30
95 #define ED_ELEMENTLIST_XSIZE            20
96 #define ED_ELEMENTLIST_YSIZE            20
97 #define ED_ELEMENTLIST_BUTTONS_HORIZ    4
98 #define ED_ELEMENTLIST_BUTTONS_VERT     11
99 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
100                                          ED_ELEMENTLIST_BUTTONS_VERT)
101
102 /* standard distances */
103 #define ED_BORDER_SIZE                  3
104 #define ED_BORDER_TEXT_XSIZE            5
105 #define ED_BORDER_AREA_YSIZE            1
106
107 #define ED_GADGET_DISTANCE              2
108 #define ED_GADGET_TEXT_DISTANCE         (2 * ED_GADGET_DISTANCE)
109 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
110                                          MINI_TILEX / 2)
111
112 /* values for the settings windows */
113 #define ED_LEVEL_SETTINGS_XSTART        (3 * MINI_TILEX / 2)
114 #define ED_LEVEL_SETTINGS_YSTART        (7 * MINI_TILEY)
115
116 #define ED_ELEMENT_SETTINGS_XSTART      (3 * MINI_TILEX / 2)
117 #define ED_ELEMENT_SETTINGS_YSTART      (10 * MINI_TILEY)
118
119 #define ED_XOFFSET_CHECKBOX             (ED_CHECKBUTTON_XSIZE +         \
120                                          2 * ED_GADGET_DISTANCE)
121
122 #define ED_SETTINGS_XOFFSET             ED_XOFFSET_CHECKBOX
123 #define ED_SETTINGS_YOFFSET             (3 * MINI_TILEY / 2)
124 #define ED_SETTINGS_TAB_XOFFSET         124
125
126 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_LEVEL_SETTINGS_XSTART +     \
127                                          (n) * ED_SETTINGS_XOFFSET)
128 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_LEVEL_SETTINGS_YSTART +     \
129                                          (n) * ED_SETTINGS_YOFFSET)
130
131 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_ELEMENT_SETTINGS_XSTART +   \
132                                          (n) * ED_SETTINGS_XOFFSET)
133 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_ELEMENT_SETTINGS_YSTART +   \
134                                          (n) * ED_SETTINGS_YOFFSET)
135
136 #define ED_LEVEL_SETTINGS_TABS_XPOS(n)  (ED_LEVEL_SETTINGS_XPOS(0) +    \
137                                         (n) * ED_SETTINGS_TAB_XOFFSET)
138 #define ED_LEVEL_SETTINGS_TABS_YPOS(n)  (ED_LEVEL_SETTINGS_YSTART -     \
139                                          3 * MINI_TILEY)
140
141 #define ED_ELEMENT_SETTINGS_TABS_XPOS(n) (ED_ELEMENT_SETTINGS_XPOS(0) + \
142                                          (n) * ED_SETTINGS_TAB_XOFFSET)
143 #define ED_ELEMENT_SETTINGS_TABS_YPOS(n) (ED_ELEMENT_SETTINGS_YSTART -  \
144                                          2 * MINI_TILEY)
145
146 #define ED_SETTINGS1_YPOS               MINI_TILEY
147 #define ED_SETTINGS2_XPOS               MINI_TILEX
148 #define ED_SETTINGS2_YPOS               (ED_SETTINGS1_YPOS + 12 * TILEY - 2)
149
150 /* values for counter gadgets */
151 #define ED_COUNTER_YSTART               (ED_SETTINGS1_YPOS + 2 * TILEY)
152 #define ED_COUNTER_YDISTANCE            (3 * MINI_TILEY)
153 #define ED_COUNTER_YPOS(n)              (ED_COUNTER_YSTART +            \
154                                          (n) * ED_COUNTER_YDISTANCE)
155 #define ED_COUNTER2_YPOS(n)             (ED_COUNTER_YSTART +            \
156                                          (n) * ED_COUNTER_YDISTANCE - 2)
157
158 /* values for element content drawing areas */
159 #define ED_AREA_1X1_SETTINGS_XPOS(n)    (ED_ELEMENT_SETTINGS_XPOS(n))
160 #define ED_AREA_1X1_SETTINGS_YPOS(n)    (ED_ELEMENT_SETTINGS_YPOS(n) +  \
161                                          ED_GADGET_DISTANCE)
162
163 #define ED_AREA_3X3_SETTINGS_XPOS(n)    (ED_ELEMENT_SETTINGS_XPOS(n))
164 #define ED_AREA_3X3_SETTINGS_YPOS(n)    (ED_ELEMENT_SETTINGS_YPOS(n) +  \
165                                          ED_GADGET_DISTANCE - MINI_TILEY)
166
167 /* yamyam content */
168 #define ED_AREA_YAMYAM_CONTENT_XPOS(n)  (2 * MINI_TILEX +               \
169                                          5 * ((n) % 4) * MINI_TILEX)
170 #define ED_AREA_YAMYAM_CONTENT_YPOS(n)  (11 * ED_SETTINGS_YOFFSET +     \
171                                          6 * ((n) / 4) * MINI_TILEY)
172
173 /* magic ball content */
174 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS(n) (2 * MINI_TILEX +            \
175                                             5 * ((n) % 4) * MINI_TILEX)
176 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS(n) (12 * ED_SETTINGS_YOFFSET +  \
177                                             6 * ((n) / 4) * MINI_TILEY)
178
179 /* values for scrolling gadgets for drawing area */
180 #define ED_SCROLLBUTTON_XPOS            24
181 #define ED_SCROLLBUTTON_YPOS            0
182 #define ED_SCROLLBAR_XPOS               24
183 #define ED_SCROLLBAR_YPOS               64
184
185 #define ED_SCROLLBUTTON_XSIZE           16
186 #define ED_SCROLLBUTTON_YSIZE           16
187
188 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
189 #define ED_SCROLL_UP_YPOS               (0)
190 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
191 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
192 #define ED_SCROLL_LEFT_XPOS             (0)
193 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
194 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
195 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
196 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
197                                          ED_SCROLLBUTTON_XSIZE)
198 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
199 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
200 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
201 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
202 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
203                                          ED_SCROLLBUTTON_YSIZE)
204 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
205 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
206
207 /* values for scrolling gadgets for element list */
208 #define ED_SCROLLBUTTON2_XPOS           50
209 #define ED_SCROLLBUTTON2_YPOS           0
210 #define ED_SCROLLBAR2_XPOS              50
211 #define ED_SCROLLBAR2_YPOS              20
212
213 #define ED_SCROLLBUTTON2_XSIZE          10
214 #define ED_SCROLLBUTTON2_YSIZE          10
215
216 #define ED_SCROLL2_UP_XPOS              85
217 #define ED_SCROLL2_UP_YPOS              30
218 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
219 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
220                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
221                                          ED_ELEMENTLIST_YSIZE -         \
222                                          ED_SCROLLBUTTON2_YSIZE)
223 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
224 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
225                                          ED_SCROLLBUTTON2_YSIZE)
226 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
227 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
228                                          ED_ELEMENTLIST_YSIZE -         \
229                                          2 * ED_SCROLLBUTTON2_YSIZE)
230
231 /* values for checkbutton gadgets */
232 #define ED_CHECKBUTTON_XSIZE            ED_BUTTON_COUNT_XSIZE
233 #define ED_CHECKBUTTON_YSIZE            ED_BUTTON_COUNT_YSIZE
234 #define ED_CHECKBUTTON_UNCHECKED_XPOS   ED_BUTTON_MINUS_XPOS
235 #define ED_CHECKBUTTON_CHECKED_XPOS     ED_BUTTON_PLUS_XPOS
236 #define ED_CHECKBUTTON_YPOS             (ED_BUTTON_MINUS_YPOS + 22)
237 #define ED_RADIOBUTTON_YPOS             (ED_BUTTON_MINUS_YPOS + 44)
238 #define ED_STICKYBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 66)
239
240 /* values for some special graphic buttons */
241 #define ED_COPY_CHANGE_PAGE_XPOS        25
242 #define ED_COPY_CHANGE_PAGE_YPOS        50
243 #define ED_PASTE_CHANGE_PAGE_XPOS       25
244 #define ED_PASTE_CHANGE_PAGE_YPOS       70
245
246 /* some values for text input, selectbox and counter gadgets */
247 #define ED_BUTTON_COUNT_YPOS            60
248 #define ED_BUTTON_COUNT_XSIZE           20
249 #define ED_BUTTON_COUNT_YSIZE           20
250 #define ED_WIN_COUNT_XPOS               (2 + ED_BUTTON_COUNT_XSIZE + 2)
251 #define ED_WIN_COUNT_YPOS               ED_BUTTON_COUNT_YPOS
252 #define ED_WIN_COUNT_XSIZE              52
253 #define ED_WIN_COUNT_YSIZE              ED_BUTTON_COUNT_YSIZE
254 #define ED_WIN_COUNT2_XPOS              27
255 #define ED_WIN_COUNT2_YPOS              3
256 #define ED_WIN_COUNT2_XSIZE             46
257 #define ED_WIN_COUNT2_YSIZE             ED_BUTTON_COUNT_YSIZE
258
259 #define ED_BUTTON_MINUS_XPOS            2
260 #define ED_BUTTON_MINUS_YPOS            ED_BUTTON_COUNT_YPOS
261 #define ED_BUTTON_MINUS_XSIZE           ED_BUTTON_COUNT_XSIZE
262 #define ED_BUTTON_MINUS_YSIZE           ED_BUTTON_COUNT_YSIZE
263 #define ED_BUTTON_PLUS_XPOS             (ED_WIN_COUNT_XPOS +            \
264                                          ED_WIN_COUNT_XSIZE + 2)
265 #define ED_BUTTON_PLUS_YPOS             ED_BUTTON_COUNT_YPOS
266 #define ED_BUTTON_PLUS_XSIZE            ED_BUTTON_COUNT_XSIZE
267 #define ED_BUTTON_PLUS_YSIZE            ED_BUTTON_COUNT_YSIZE
268
269 #define ED_SELECTBOX_XPOS               ED_WIN_COUNT_XPOS
270 #define ED_SELECTBOX_YPOS               (ED_WIN_COUNT_YPOS +            \
271                                          2 + ED_WIN_COUNT_YSIZE)
272 #define ED_SELECTBOX_XSIZE              ED_WIN_COUNT_XSIZE
273 #define ED_SELECTBOX_YSIZE              ED_WIN_COUNT_YSIZE
274
275 #define ED_SELECTBOX_BUTTON_XSIZE       14
276
277 #define ED_TEXTBUTTON_XPOS              ED_WIN_COUNT_XPOS
278 #define ED_TEXTBUTTON_YPOS              (ED_WIN_COUNT_YPOS +            \
279                                          4 * (2 + ED_WIN_COUNT_YSIZE))
280 #define ED_TEXTBUTTON_INACTIVE_YPOS     ED_TEXTBUTTON_YPOS
281
282 #define ED_TEXTBUTTON_TAB_XPOS          ED_WIN_COUNT_XPOS
283 #define ED_TEXTBUTTON_TAB_YPOS          (ED_WIN_COUNT_YPOS +            \
284                                          2 * (2 + ED_WIN_COUNT_YSIZE))
285 #define ED_TEXTBUTTON_TAB_INACTIVE_YPOS (ED_WIN_COUNT_YPOS +            \
286                                          3 * (2 + ED_WIN_COUNT_YSIZE))
287
288 #define ED_TEXTBUTTON_XSIZE             ED_WIN_COUNT_XSIZE
289 #define ED_TEXTBUTTON_YSIZE             ED_WIN_COUNT_YSIZE
290
291 /* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */
292 #define INFOTEXT_XPOS                   SX
293 #define INFOTEXT_YPOS                   (SY + SYSIZE - MINI_TILEX + 2)
294 #define INFOTEXT_XSIZE                  SXSIZE
295 #define INFOTEXT_YSIZE                  MINI_TILEX
296
297
298 /*
299   -----------------------------------------------------------------------------
300   editor gadget definitions
301   -----------------------------------------------------------------------------
302 */
303
304 /* drawing toolbox buttons */
305 #define GADGET_ID_NONE                  -1
306 #define GADGET_ID_TOOLBOX_FIRST         0
307
308 #define GADGET_ID_SINGLE_ITEMS          (GADGET_ID_TOOLBOX_FIRST + 0)
309 #define GADGET_ID_CONNECTED_ITEMS       (GADGET_ID_TOOLBOX_FIRST + 1)
310 #define GADGET_ID_LINE                  (GADGET_ID_TOOLBOX_FIRST + 2)
311 #define GADGET_ID_ARC                   (GADGET_ID_TOOLBOX_FIRST + 3)
312 #define GADGET_ID_RECTANGLE             (GADGET_ID_TOOLBOX_FIRST + 4)
313 #define GADGET_ID_FILLED_BOX            (GADGET_ID_TOOLBOX_FIRST + 5)
314 #define GADGET_ID_WRAP_UP               (GADGET_ID_TOOLBOX_FIRST + 6)
315 #define GADGET_ID_TEXT                  (GADGET_ID_TOOLBOX_FIRST + 7)
316 #define GADGET_ID_FLOOD_FILL            (GADGET_ID_TOOLBOX_FIRST + 8)
317 #define GADGET_ID_WRAP_LEFT             (GADGET_ID_TOOLBOX_FIRST + 9)
318 #define GADGET_ID_PROPERTIES            (GADGET_ID_TOOLBOX_FIRST + 10)
319 #define GADGET_ID_WRAP_RIGHT            (GADGET_ID_TOOLBOX_FIRST + 11)
320 #define GADGET_ID_RANDOM_PLACEMENT      (GADGET_ID_TOOLBOX_FIRST + 12)
321 #define GADGET_ID_GRAB_BRUSH            (GADGET_ID_TOOLBOX_FIRST + 13)
322 #define GADGET_ID_WRAP_DOWN             (GADGET_ID_TOOLBOX_FIRST + 14)
323 #define GADGET_ID_PICK_ELEMENT          (GADGET_ID_TOOLBOX_FIRST + 15)
324
325 #define GADGET_ID_UNDO                  (GADGET_ID_TOOLBOX_FIRST + 16)
326 #define GADGET_ID_INFO                  (GADGET_ID_TOOLBOX_FIRST + 17)
327 #define GADGET_ID_SAVE                  (GADGET_ID_TOOLBOX_FIRST + 18)
328 #define GADGET_ID_CLEAR                 (GADGET_ID_TOOLBOX_FIRST + 19)
329 #define GADGET_ID_TEST                  (GADGET_ID_TOOLBOX_FIRST + 20)
330 #define GADGET_ID_EXIT                  (GADGET_ID_TOOLBOX_FIRST + 21)
331
332 #define GADGET_ID_CUSTOM_COPY_FROM      (GADGET_ID_TOOLBOX_FIRST + 22)
333 #define GADGET_ID_CUSTOM_COPY_TO        (GADGET_ID_TOOLBOX_FIRST + 23)
334 #define GADGET_ID_CUSTOM_EXCHANGE       (GADGET_ID_TOOLBOX_FIRST + 24)
335 #define GADGET_ID_CUSTOM_COPY           (GADGET_ID_TOOLBOX_FIRST + 25)
336 #define GADGET_ID_CUSTOM_PASTE          (GADGET_ID_TOOLBOX_FIRST + 26)
337
338 /* counter gadget identifiers */
339 #define GADGET_ID_COUNTER_FIRST         (GADGET_ID_TOOLBOX_FIRST + 27)
340
341 #define GADGET_ID_SELECT_LEVEL_DOWN     (GADGET_ID_COUNTER_FIRST + 0)
342 #define GADGET_ID_SELECT_LEVEL_TEXT     (GADGET_ID_COUNTER_FIRST + 1)
343 #define GADGET_ID_SELECT_LEVEL_UP       (GADGET_ID_COUNTER_FIRST + 2)
344 #define GADGET_ID_LEVEL_XSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 3)
345 #define GADGET_ID_LEVEL_XSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 4)
346 #define GADGET_ID_LEVEL_XSIZE_UP        (GADGET_ID_COUNTER_FIRST + 5)
347 #define GADGET_ID_LEVEL_YSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 6)
348 #define GADGET_ID_LEVEL_YSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 7)
349 #define GADGET_ID_LEVEL_YSIZE_UP        (GADGET_ID_COUNTER_FIRST + 8)
350 #define GADGET_ID_LEVEL_RANDOM_DOWN     (GADGET_ID_COUNTER_FIRST + 9)
351 #define GADGET_ID_LEVEL_RANDOM_TEXT     (GADGET_ID_COUNTER_FIRST + 10)
352 #define GADGET_ID_LEVEL_RANDOM_UP       (GADGET_ID_COUNTER_FIRST + 11)
353 #define GADGET_ID_LEVEL_GEMSLIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 12)
354 #define GADGET_ID_LEVEL_GEMSLIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 13)
355 #define GADGET_ID_LEVEL_GEMSLIMIT_UP    (GADGET_ID_COUNTER_FIRST + 14)
356 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 15)
357 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 16)
358 #define GADGET_ID_LEVEL_TIMELIMIT_UP    (GADGET_ID_COUNTER_FIRST + 17)
359 #define GADGET_ID_LEVEL_TIMESCORE_DOWN  (GADGET_ID_COUNTER_FIRST + 18)
360 #define GADGET_ID_LEVEL_TIMESCORE_TEXT  (GADGET_ID_COUNTER_FIRST + 19)
361 #define GADGET_ID_LEVEL_TIMESCORE_UP    (GADGET_ID_COUNTER_FIRST + 20)
362 #define GADGET_ID_LEVEL_RANDOM_SEED_DOWN (GADGET_ID_COUNTER_FIRST + 21)
363 #define GADGET_ID_LEVEL_RANDOM_SEED_TEXT (GADGET_ID_COUNTER_FIRST + 22)
364 #define GADGET_ID_LEVEL_RANDOM_SEED_UP  (GADGET_ID_COUNTER_FIRST + 23)
365 #define GADGET_ID_ELEMENT_VALUE1_DOWN   (GADGET_ID_COUNTER_FIRST + 24)
366 #define GADGET_ID_ELEMENT_VALUE1_TEXT   (GADGET_ID_COUNTER_FIRST + 25)
367 #define GADGET_ID_ELEMENT_VALUE1_UP     (GADGET_ID_COUNTER_FIRST + 26)
368 #define GADGET_ID_ELEMENT_VALUE2_DOWN   (GADGET_ID_COUNTER_FIRST + 27)
369 #define GADGET_ID_ELEMENT_VALUE2_TEXT   (GADGET_ID_COUNTER_FIRST + 28)
370 #define GADGET_ID_ELEMENT_VALUE2_UP     (GADGET_ID_COUNTER_FIRST + 29)
371 #define GADGET_ID_ELEMENT_VALUE3_DOWN   (GADGET_ID_COUNTER_FIRST + 30)
372 #define GADGET_ID_ELEMENT_VALUE3_TEXT   (GADGET_ID_COUNTER_FIRST + 31)
373 #define GADGET_ID_ELEMENT_VALUE3_UP     (GADGET_ID_COUNTER_FIRST + 32)
374 #define GADGET_ID_ELEMENT_VALUE4_DOWN   (GADGET_ID_COUNTER_FIRST + 33)
375 #define GADGET_ID_ELEMENT_VALUE4_TEXT   (GADGET_ID_COUNTER_FIRST + 34)
376 #define GADGET_ID_ELEMENT_VALUE4_UP     (GADGET_ID_COUNTER_FIRST + 35)
377 #define GADGET_ID_YAMYAM_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 36)
378 #define GADGET_ID_YAMYAM_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 37)
379 #define GADGET_ID_YAMYAM_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 38)
380 #define GADGET_ID_BALL_CONTENT_DOWN     (GADGET_ID_COUNTER_FIRST + 39)
381 #define GADGET_ID_BALL_CONTENT_TEXT     (GADGET_ID_COUNTER_FIRST + 40)
382 #define GADGET_ID_BALL_CONTENT_UP       (GADGET_ID_COUNTER_FIRST + 41)
383 #define GADGET_ID_ANDROID_CONTENT_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
384 #define GADGET_ID_ANDROID_CONTENT_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
385 #define GADGET_ID_ANDROID_CONTENT_UP    (GADGET_ID_COUNTER_FIRST + 44)
386 #define GADGET_ID_ENVELOPE_XSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 45)
387 #define GADGET_ID_ENVELOPE_XSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 46)
388 #define GADGET_ID_ENVELOPE_XSIZE_UP     (GADGET_ID_COUNTER_FIRST + 47)
389 #define GADGET_ID_ENVELOPE_YSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 48)
390 #define GADGET_ID_ENVELOPE_YSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 49)
391 #define GADGET_ID_ENVELOPE_YSIZE_UP     (GADGET_ID_COUNTER_FIRST + 50)
392 #define GADGET_ID_INVENTORY_SIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 51)
393 #define GADGET_ID_INVENTORY_SIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 52)
394 #define GADGET_ID_INVENTORY_SIZE_UP     (GADGET_ID_COUNTER_FIRST + 53)
395 #define GADGET_ID_CUSTOM_SCORE_DOWN     (GADGET_ID_COUNTER_FIRST + 54)
396 #define GADGET_ID_CUSTOM_SCORE_TEXT     (GADGET_ID_COUNTER_FIRST + 55)
397 #define GADGET_ID_CUSTOM_SCORE_UP       (GADGET_ID_COUNTER_FIRST + 56)
398 #define GADGET_ID_CUSTOM_GEMCOUNT_DOWN  (GADGET_ID_COUNTER_FIRST + 57)
399 #define GADGET_ID_CUSTOM_GEMCOUNT_TEXT  (GADGET_ID_COUNTER_FIRST + 58)
400 #define GADGET_ID_CUSTOM_GEMCOUNT_UP    (GADGET_ID_COUNTER_FIRST + 59)
401 #define GADGET_ID_CUSTOM_VALUE_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 60)
402 #define GADGET_ID_CUSTOM_VALUE_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 61)
403 #define GADGET_ID_CUSTOM_VALUE_FIX_UP   (GADGET_ID_COUNTER_FIRST + 62)
404 #define GADGET_ID_CUSTOM_VALUE_RND_DOWN (GADGET_ID_COUNTER_FIRST + 63)
405 #define GADGET_ID_CUSTOM_VALUE_RND_TEXT (GADGET_ID_COUNTER_FIRST + 64)
406 #define GADGET_ID_CUSTOM_VALUE_RND_UP   (GADGET_ID_COUNTER_FIRST + 65)
407 #define GADGET_ID_PUSH_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 66)
408 #define GADGET_ID_PUSH_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 67)
409 #define GADGET_ID_PUSH_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 68)
410 #define GADGET_ID_PUSH_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 69)
411 #define GADGET_ID_PUSH_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 70)
412 #define GADGET_ID_PUSH_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 71)
413 #define GADGET_ID_DROP_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 72)
414 #define GADGET_ID_DROP_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 73)
415 #define GADGET_ID_DROP_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 74)
416 #define GADGET_ID_DROP_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 75)
417 #define GADGET_ID_DROP_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 76)
418 #define GADGET_ID_DROP_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 77)
419 #define GADGET_ID_MOVE_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 78)
420 #define GADGET_ID_MOVE_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 79)
421 #define GADGET_ID_MOVE_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 80)
422 #define GADGET_ID_MOVE_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 81)
423 #define GADGET_ID_MOVE_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 82)
424 #define GADGET_ID_MOVE_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 83)
425 #define GADGET_ID_EXPLOSION_DELAY_DOWN  (GADGET_ID_COUNTER_FIRST + 84)
426 #define GADGET_ID_EXPLOSION_DELAY_TEXT  (GADGET_ID_COUNTER_FIRST + 85)
427 #define GADGET_ID_EXPLOSION_DELAY_UP    (GADGET_ID_COUNTER_FIRST + 86)
428 #define GADGET_ID_IGNITION_DELAY_DOWN   (GADGET_ID_COUNTER_FIRST + 87)
429 #define GADGET_ID_IGNITION_DELAY_TEXT   (GADGET_ID_COUNTER_FIRST + 88)
430 #define GADGET_ID_IGNITION_DELAY_UP     (GADGET_ID_COUNTER_FIRST + 89)
431 #define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 90)
432 #define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 91)
433 #define GADGET_ID_CHANGE_DELAY_FIX_UP   (GADGET_ID_COUNTER_FIRST + 92)
434 #define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 93)
435 #define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 94)
436 #define GADGET_ID_CHANGE_DELAY_RND_UP   (GADGET_ID_COUNTER_FIRST + 95)
437 #define GADGET_ID_CHANGE_CONT_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 96)
438 #define GADGET_ID_CHANGE_CONT_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 97)
439 #define GADGET_ID_CHANGE_CONT_RND_UP    (GADGET_ID_COUNTER_FIRST + 98)
440 #define GADGET_ID_GROUP_CONTENT_DOWN    (GADGET_ID_COUNTER_FIRST + 99)
441 #define GADGET_ID_GROUP_CONTENT_TEXT    (GADGET_ID_COUNTER_FIRST + 100)
442 #define GADGET_ID_GROUP_CONTENT_UP      (GADGET_ID_COUNTER_FIRST + 101)
443
444 /* drawing area identifiers */
445 #define GADGET_ID_DRAWING_AREA_FIRST    (GADGET_ID_COUNTER_FIRST + 102)
446
447 #define GADGET_ID_DRAWING_LEVEL         (GADGET_ID_DRAWING_AREA_FIRST + 0)
448 #define GADGET_ID_YAMYAM_CONTENT_0      (GADGET_ID_DRAWING_AREA_FIRST + 1)
449 #define GADGET_ID_YAMYAM_CONTENT_1      (GADGET_ID_DRAWING_AREA_FIRST + 2)
450 #define GADGET_ID_YAMYAM_CONTENT_2      (GADGET_ID_DRAWING_AREA_FIRST + 3)
451 #define GADGET_ID_YAMYAM_CONTENT_3      (GADGET_ID_DRAWING_AREA_FIRST + 4)
452 #define GADGET_ID_YAMYAM_CONTENT_4      (GADGET_ID_DRAWING_AREA_FIRST + 5)
453 #define GADGET_ID_YAMYAM_CONTENT_5      (GADGET_ID_DRAWING_AREA_FIRST + 6)
454 #define GADGET_ID_YAMYAM_CONTENT_6      (GADGET_ID_DRAWING_AREA_FIRST + 7)
455 #define GADGET_ID_YAMYAM_CONTENT_7      (GADGET_ID_DRAWING_AREA_FIRST + 8)
456 #define GADGET_ID_MAGIC_BALL_CONTENT_0  (GADGET_ID_DRAWING_AREA_FIRST + 9)
457 #define GADGET_ID_MAGIC_BALL_CONTENT_1  (GADGET_ID_DRAWING_AREA_FIRST + 10)
458 #define GADGET_ID_MAGIC_BALL_CONTENT_2  (GADGET_ID_DRAWING_AREA_FIRST + 11)
459 #define GADGET_ID_MAGIC_BALL_CONTENT_3  (GADGET_ID_DRAWING_AREA_FIRST + 12)
460 #define GADGET_ID_MAGIC_BALL_CONTENT_4  (GADGET_ID_DRAWING_AREA_FIRST + 13)
461 #define GADGET_ID_MAGIC_BALL_CONTENT_5  (GADGET_ID_DRAWING_AREA_FIRST + 14)
462 #define GADGET_ID_MAGIC_BALL_CONTENT_6  (GADGET_ID_DRAWING_AREA_FIRST + 15)
463 #define GADGET_ID_MAGIC_BALL_CONTENT_7  (GADGET_ID_DRAWING_AREA_FIRST + 16)
464 #define GADGET_ID_ANDROID_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 17)
465 #define GADGET_ID_AMOEBA_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 18)
466 #define GADGET_ID_START_ELEMENT         (GADGET_ID_DRAWING_AREA_FIRST + 19)
467 #define GADGET_ID_ARTWORK_ELEMENT       (GADGET_ID_DRAWING_AREA_FIRST + 20)
468 #define GADGET_ID_EXPLOSION_ELEMENT     (GADGET_ID_DRAWING_AREA_FIRST + 21)
469 #define GADGET_ID_INVENTORY_CONTENT     (GADGET_ID_DRAWING_AREA_FIRST + 22)
470 #define GADGET_ID_CUSTOM_GRAPHIC        (GADGET_ID_DRAWING_AREA_FIRST + 23)
471 #define GADGET_ID_CUSTOM_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 24)
472 #define GADGET_ID_CUSTOM_MOVE_ENTER     (GADGET_ID_DRAWING_AREA_FIRST + 25)
473 #define GADGET_ID_CUSTOM_MOVE_LEAVE     (GADGET_ID_DRAWING_AREA_FIRST + 26)
474 #define GADGET_ID_CUSTOM_CHANGE_TARGET  (GADGET_ID_DRAWING_AREA_FIRST + 27)
475 #define GADGET_ID_CUSTOM_CHANGE_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 28)
476 #define GADGET_ID_CUSTOM_CHANGE_TRIGGER (GADGET_ID_DRAWING_AREA_FIRST + 29)
477 #define GADGET_ID_CUSTOM_CHANGE_ACTION  (GADGET_ID_DRAWING_AREA_FIRST + 30)
478 #define GADGET_ID_GROUP_CONTENT         (GADGET_ID_DRAWING_AREA_FIRST + 31)
479 #define GADGET_ID_RANDOM_BACKGROUND     (GADGET_ID_DRAWING_AREA_FIRST + 32)
480
481 /* text input identifiers */
482 #define GADGET_ID_TEXT_INPUT_FIRST      (GADGET_ID_DRAWING_AREA_FIRST + 33)
483
484 #define GADGET_ID_LEVEL_NAME            (GADGET_ID_TEXT_INPUT_FIRST + 0)
485 #define GADGET_ID_LEVEL_AUTHOR          (GADGET_ID_TEXT_INPUT_FIRST + 1)
486 #define GADGET_ID_ELEMENT_NAME          (GADGET_ID_TEXT_INPUT_FIRST + 2)
487
488 /* text area identifiers */
489 #define GADGET_ID_TEXT_AREA_FIRST       (GADGET_ID_TEXT_INPUT_FIRST + 3)
490
491 #define GADGET_ID_ENVELOPE_INFO         (GADGET_ID_TEXT_AREA_FIRST + 0)
492
493 /* selectbox identifiers */
494 #define GADGET_ID_SELECTBOX_FIRST       (GADGET_ID_TEXT_AREA_FIRST + 1)
495
496 #define GADGET_ID_TIME_OR_STEPS         (GADGET_ID_SELECTBOX_FIRST + 0)
497 #define GADGET_ID_GAME_ENGINE_TYPE      (GADGET_ID_SELECTBOX_FIRST + 1)
498 #define GADGET_ID_WIND_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 2)
499 #define GADGET_ID_PLAYER_SPEED          (GADGET_ID_SELECTBOX_FIRST + 3)
500 #define GADGET_ID_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 4)
501 #define GADGET_ID_CUSTOM_EXPLOSION_TYPE (GADGET_ID_SELECTBOX_FIRST + 5)
502 #define GADGET_ID_CUSTOM_DEADLINESS     (GADGET_ID_SELECTBOX_FIRST + 6)
503 #define GADGET_ID_CUSTOM_MOVE_PATTERN   (GADGET_ID_SELECTBOX_FIRST + 7)
504 #define GADGET_ID_CUSTOM_MOVE_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 8)
505 #define GADGET_ID_CUSTOM_MOVE_STEPSIZE  (GADGET_ID_SELECTBOX_FIRST + 9)
506 #define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 10)
507 #define GADGET_ID_CUSTOM_SMASH_TARGETS  (GADGET_ID_SELECTBOX_FIRST + 11)
508 #define GADGET_ID_CUSTOM_SLIPPERY_TYPE  (GADGET_ID_SELECTBOX_FIRST + 12)
509 #define GADGET_ID_CUSTOM_ACCESS_TYPE    (GADGET_ID_SELECTBOX_FIRST + 13)
510 #define GADGET_ID_CUSTOM_ACCESS_LAYER   (GADGET_ID_SELECTBOX_FIRST + 14)
511 #define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 15)
512 #define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 16)
513 #define GADGET_ID_CHANGE_TIME_UNITS     (GADGET_ID_SELECTBOX_FIRST + 17)
514 #define GADGET_ID_CHANGE_DIRECT_ACTION  (GADGET_ID_SELECTBOX_FIRST + 18)
515 #define GADGET_ID_CHANGE_OTHER_ACTION   (GADGET_ID_SELECTBOX_FIRST + 19)
516 #define GADGET_ID_CHANGE_SIDE           (GADGET_ID_SELECTBOX_FIRST + 20)
517 #define GADGET_ID_CHANGE_PLAYER         (GADGET_ID_SELECTBOX_FIRST + 21)
518 #define GADGET_ID_CHANGE_PAGE           (GADGET_ID_SELECTBOX_FIRST + 22)
519 #define GADGET_ID_CHANGE_REPLACE_WHEN   (GADGET_ID_SELECTBOX_FIRST + 23)
520 #define GADGET_ID_ACTION_TYPE           (GADGET_ID_SELECTBOX_FIRST + 24)
521 #define GADGET_ID_ACTION_MODE           (GADGET_ID_SELECTBOX_FIRST + 25)
522 #define GADGET_ID_ACTION_ARG            (GADGET_ID_SELECTBOX_FIRST + 26)
523 #define GADGET_ID_SELECT_CHANGE_PAGE    (GADGET_ID_SELECTBOX_FIRST + 27)
524 #define GADGET_ID_GROUP_CHOICE_MODE     (GADGET_ID_SELECTBOX_FIRST + 28)
525
526 /* textbutton identifiers */
527 #define GADGET_ID_TEXTBUTTON_FIRST      (GADGET_ID_SELECTBOX_FIRST + 29)
528
529 #define GADGET_ID_LEVELINFO_LEVEL       (GADGET_ID_TEXTBUTTON_FIRST + 0)
530 #define GADGET_ID_LEVELINFO_EDITOR      (GADGET_ID_TEXTBUTTON_FIRST + 1)
531 #define GADGET_ID_PROPERTIES_INFO       (GADGET_ID_TEXTBUTTON_FIRST + 2)
532 #define GADGET_ID_PROPERTIES_CONFIG     (GADGET_ID_TEXTBUTTON_FIRST + 3)
533 #define GADGET_ID_PROPERTIES_CONFIG_1   (GADGET_ID_TEXTBUTTON_FIRST + 4)
534 #define GADGET_ID_PROPERTIES_CONFIG_2   (GADGET_ID_TEXTBUTTON_FIRST + 5)
535 #define GADGET_ID_PROPERTIES_CHANGE     (GADGET_ID_TEXTBUTTON_FIRST + 6)
536 #define GADGET_ID_SAVE_AS_TEMPLATE      (GADGET_ID_TEXTBUTTON_FIRST + 7)
537 #define GADGET_ID_ADD_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 8)
538 #define GADGET_ID_DEL_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 9)
539
540 /* graphicbutton identifiers */
541 #define GADGET_ID_GRAPHICBUTTON_FIRST   (GADGET_ID_TEXTBUTTON_FIRST + 10)
542
543 #define GADGET_ID_PREV_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 0)
544 #define GADGET_ID_NEXT_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 1)
545 #define GADGET_ID_COPY_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 2)
546 #define GADGET_ID_PASTE_CHANGE_PAGE     (GADGET_ID_GRAPHICBUTTON_FIRST + 3)
547
548 /* gadgets for scrolling of drawing area */
549 #define GADGET_ID_SCROLLING_FIRST       (GADGET_ID_GRAPHICBUTTON_FIRST + 4)
550
551 #define GADGET_ID_SCROLL_UP             (GADGET_ID_SCROLLING_FIRST + 0)
552 #define GADGET_ID_SCROLL_DOWN           (GADGET_ID_SCROLLING_FIRST + 1)
553 #define GADGET_ID_SCROLL_LEFT           (GADGET_ID_SCROLLING_FIRST + 2)
554 #define GADGET_ID_SCROLL_RIGHT          (GADGET_ID_SCROLLING_FIRST + 3)
555 #define GADGET_ID_SCROLL_HORIZONTAL     (GADGET_ID_SCROLLING_FIRST + 4)
556 #define GADGET_ID_SCROLL_VERTICAL       (GADGET_ID_SCROLLING_FIRST + 5)
557
558 /* gadgets for scrolling element list */
559 #define GADGET_ID_SCROLLING_LIST_FIRST  (GADGET_ID_SCROLLING_FIRST + 6)
560
561 #define GADGET_ID_SCROLL_LIST_UP        (GADGET_ID_SCROLLING_LIST_FIRST + 0)
562 #define GADGET_ID_SCROLL_LIST_DOWN      (GADGET_ID_SCROLLING_LIST_FIRST + 1)
563 #define GADGET_ID_SCROLL_LIST_VERTICAL  (GADGET_ID_SCROLLING_LIST_FIRST + 2)
564
565 /* checkbuttons/radiobuttons for level/element properties */
566 #define GADGET_ID_CHECKBUTTON_FIRST     (GADGET_ID_SCROLLING_LIST_FIRST + 3)
567
568 #define GADGET_ID_RANDOM_PERCENTAGE     (GADGET_ID_CHECKBUTTON_FIRST + 0)
569 #define GADGET_ID_RANDOM_QUANTITY       (GADGET_ID_CHECKBUTTON_FIRST + 1)
570 #define GADGET_ID_RANDOM_RESTRICTED     (GADGET_ID_CHECKBUTTON_FIRST + 2)
571 #define GADGET_ID_STICK_ELEMENT         (GADGET_ID_CHECKBUTTON_FIRST + 3)
572 #define GADGET_ID_EM_SLIPPERY_GEMS      (GADGET_ID_CHECKBUTTON_FIRST + 4)
573 #define GADGET_ID_EM_EXPLODES_BY_FIRE   (GADGET_ID_CHECKBUTTON_FIRST + 5)
574 #define GADGET_ID_USE_SPRING_BUG        (GADGET_ID_CHECKBUTTON_FIRST + 6)
575 #define GADGET_ID_USE_TIME_ORB_BUG      (GADGET_ID_CHECKBUTTON_FIRST + 7)
576 #define GADGET_ID_RANDOM_BALL_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 8)
577 #define GADGET_ID_INITIAL_BALL_STATE    (GADGET_ID_CHECKBUTTON_FIRST + 9)
578 #define GADGET_ID_GROW_INTO_DIGGABLE    (GADGET_ID_CHECKBUTTON_FIRST + 10)
579 #define GADGET_ID_CONTINUOUS_SNAPPING   (GADGET_ID_CHECKBUTTON_FIRST + 11)
580 #define GADGET_ID_BLOCK_SNAP_FIELD      (GADGET_ID_CHECKBUTTON_FIRST + 12)
581 #define GADGET_ID_BLOCK_LAST_FIELD      (GADGET_ID_CHECKBUTTON_FIRST + 13)
582 #define GADGET_ID_SP_BLOCK_LAST_FIELD   (GADGET_ID_CHECKBUTTON_FIRST + 14)
583 #define GADGET_ID_INSTANT_RELOCATION    (GADGET_ID_CHECKBUTTON_FIRST + 15)
584 #define GADGET_ID_SHIFTED_RELOCATION    (GADGET_ID_CHECKBUTTON_FIRST + 16)
585 #define GADGET_ID_USE_START_ELEMENT     (GADGET_ID_CHECKBUTTON_FIRST + 17)
586 #define GADGET_ID_USE_ARTWORK_ELEMENT   (GADGET_ID_CHECKBUTTON_FIRST + 18)
587 #define GADGET_ID_USE_EXPLOSION_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 19)
588 #define GADGET_ID_INITIAL_GRAVITY       (GADGET_ID_CHECKBUTTON_FIRST + 20)
589 #define GADGET_ID_USE_INITIAL_INVENTORY (GADGET_ID_CHECKBUTTON_FIRST + 21)
590 #define GADGET_ID_CAN_PASS_TO_WALKABLE  (GADGET_ID_CHECKBUTTON_FIRST + 22)
591 #define GADGET_ID_CAN_FALL_INTO_ACID    (GADGET_ID_CHECKBUTTON_FIRST + 23)
592 #define GADGET_ID_CAN_MOVE_INTO_ACID    (GADGET_ID_CHECKBUTTON_FIRST + 24)
593 #define GADGET_ID_DONT_COLLIDE_WITH     (GADGET_ID_CHECKBUTTON_FIRST + 25)
594 #define GADGET_ID_ENVELOPE_AUTOWRAP     (GADGET_ID_CHECKBUTTON_FIRST + 26)
595 #define GADGET_ID_ENVELOPE_CENTERED     (GADGET_ID_CHECKBUTTON_FIRST + 27)
596 #define GADGET_ID_CUSTOM_INDESTRUCTIBLE (GADGET_ID_CHECKBUTTON_FIRST + 28)
597 #define GADGET_ID_CUSTOM_CAN_EXPLODE    (GADGET_ID_CHECKBUTTON_FIRST + 29)
598 #define GADGET_ID_CUSTOM_EXPLODE_FIRE   (GADGET_ID_CHECKBUTTON_FIRST + 30)
599 #define GADGET_ID_CUSTOM_EXPLODE_SMASH  (GADGET_ID_CHECKBUTTON_FIRST + 31)
600 #define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 32)
601 #define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 33)
602 #define GADGET_ID_CUSTOM_DEADLY         (GADGET_ID_CHECKBUTTON_FIRST + 34)
603 #define GADGET_ID_CUSTOM_CAN_MOVE       (GADGET_ID_CHECKBUTTON_FIRST + 35)
604 #define GADGET_ID_CUSTOM_CAN_FALL       (GADGET_ID_CHECKBUTTON_FIRST + 36)
605 #define GADGET_ID_CUSTOM_CAN_SMASH      (GADGET_ID_CHECKBUTTON_FIRST + 37)
606 #define GADGET_ID_CUSTOM_SLIPPERY       (GADGET_ID_CHECKBUTTON_FIRST + 38)
607 #define GADGET_ID_CUSTOM_ACCESSIBLE     (GADGET_ID_CHECKBUTTON_FIRST + 39)
608 #define GADGET_ID_CUSTOM_GRAV_REACHABLE (GADGET_ID_CHECKBUTTON_FIRST + 40)
609 #define GADGET_ID_CUSTOM_USE_LAST_VALUE (GADGET_ID_CHECKBUTTON_FIRST + 41)
610 #define GADGET_ID_CUSTOM_USE_GRAPHIC    (GADGET_ID_CHECKBUTTON_FIRST + 42)
611 #define GADGET_ID_CUSTOM_USE_TEMPLATE   (GADGET_ID_CHECKBUTTON_FIRST + 43)
612 #define GADGET_ID_CUSTOM_CAN_CHANGE     (GADGET_ID_CHECKBUTTON_FIRST + 44)
613 #define GADGET_ID_CHANGE_USE_CONTENT    (GADGET_ID_CHECKBUTTON_FIRST + 45)
614 #define GADGET_ID_CHANGE_USE_EXPLOSION  (GADGET_ID_CHECKBUTTON_FIRST + 46)
615 #define GADGET_ID_CHANGE_ONLY_COMPLETE  (GADGET_ID_CHECKBUTTON_FIRST + 47)
616 #define GADGET_ID_CHANGE_USE_RANDOM     (GADGET_ID_CHECKBUTTON_FIRST + 48)
617 #define GADGET_ID_CHANGE_HAS_ACTION     (GADGET_ID_CHECKBUTTON_FIRST + 49)
618 #define GADGET_ID_CHANGE_DELAY          (GADGET_ID_CHECKBUTTON_FIRST + 50)
619 #define GADGET_ID_CHANGE_BY_DIRECT_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 51)
620 #define GADGET_ID_CHANGE_BY_OTHER_ACT   (GADGET_ID_CHECKBUTTON_FIRST + 52)
621
622 /* gadgets for buttons in element list */
623 #define GADGET_ID_ELEMENTLIST_FIRST     (GADGET_ID_CHECKBUTTON_FIRST + 53)
624 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
625                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
626
627 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
628
629 /* radio button numbers */
630 #define RADIO_NR_NONE                   0
631 #define RADIO_NR_DRAWING_TOOLBOX        1
632 #define RADIO_NR_RANDOM_ELEMENTS        2
633
634 /* values for counter gadgets */
635 #define ED_COUNTER_ID_SELECT_LEVEL      0
636 #define ED_COUNTER_ID_LEVEL_XSIZE       1
637 #define ED_COUNTER_ID_LEVEL_YSIZE       2
638 #define ED_COUNTER_ID_LEVEL_GEMSLIMIT   3
639 #define ED_COUNTER_ID_LEVEL_TIMELIMIT   4
640 #define ED_COUNTER_ID_LEVEL_TIMESCORE   5
641 #define ED_COUNTER_ID_LEVEL_RANDOM_SEED 6
642 #define ED_COUNTER_ID_LEVEL_RANDOM      7
643 #define ED_COUNTER_ID_ELEMENT_VALUE1    8
644 #define ED_COUNTER_ID_ELEMENT_VALUE2    9
645 #define ED_COUNTER_ID_ELEMENT_VALUE3    10
646 #define ED_COUNTER_ID_ELEMENT_VALUE4    11
647 #define ED_COUNTER_ID_YAMYAM_CONTENT    12
648 #define ED_COUNTER_ID_BALL_CONTENT      13
649 #define ED_COUNTER_ID_ANDROID_CONTENT   14
650 #define ED_COUNTER_ID_ENVELOPE_XSIZE    15
651 #define ED_COUNTER_ID_ENVELOPE_YSIZE    16
652 #define ED_COUNTER_ID_INVENTORY_SIZE    17
653 #define ED_COUNTER_ID_CUSTOM_SCORE      18
654 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT   19
655 #define ED_COUNTER_ID_CUSTOM_VALUE_FIX  20
656 #define ED_COUNTER_ID_CUSTOM_VALUE_RND  21
657 #define ED_COUNTER_ID_PUSH_DELAY_FIX    22
658 #define ED_COUNTER_ID_PUSH_DELAY_RND    23
659 #define ED_COUNTER_ID_DROP_DELAY_FIX    24
660 #define ED_COUNTER_ID_DROP_DELAY_RND    25
661 #define ED_COUNTER_ID_MOVE_DELAY_FIX    26
662 #define ED_COUNTER_ID_MOVE_DELAY_RND    27
663 #define ED_COUNTER_ID_EXPLOSION_DELAY   28
664 #define ED_COUNTER_ID_IGNITION_DELAY    29
665 #define ED_COUNTER_ID_GROUP_CONTENT     30
666 #define ED_COUNTER_ID_CHANGE_DELAY_FIX  31
667 #define ED_COUNTER_ID_CHANGE_DELAY_RND  32
668 #define ED_COUNTER_ID_CHANGE_CONT_RND   33
669
670 #define ED_NUM_COUNTERBUTTONS           34
671
672 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
673 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
674 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
675 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
676
677 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
678 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
679 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
680 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
681 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
682 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
683
684 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
685 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
686
687 /* values for scrollbutton gadgets */
688 #define ED_SCROLLBUTTON_ID_AREA_UP      0
689 #define ED_SCROLLBUTTON_ID_AREA_DOWN    1
690 #define ED_SCROLLBUTTON_ID_AREA_LEFT    2
691 #define ED_SCROLLBUTTON_ID_AREA_RIGHT   3
692 #define ED_SCROLLBUTTON_ID_LIST_UP      4
693 #define ED_SCROLLBUTTON_ID_LIST_DOWN    5
694
695 #define ED_NUM_SCROLLBUTTONS            6
696
697 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
698 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
699
700 /* values for scrollbar gadgets */
701 #define ED_SCROLLBAR_ID_AREA_HORIZONTAL 0
702 #define ED_SCROLLBAR_ID_AREA_VERTICAL   1
703 #define ED_SCROLLBAR_ID_LIST_VERTICAL   2
704
705 #define ED_NUM_SCROLLBARS               3
706
707 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
708 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
709
710 /* values for text input gadgets */
711 #define ED_TEXTINPUT_ID_LEVEL_NAME      0
712 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR    1
713 #define ED_TEXTINPUT_ID_ELEMENT_NAME    2
714
715 #define ED_NUM_TEXTINPUT                3
716
717 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
718 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
719
720 /* values for text area gadgets */
721 #define ED_TEXTAREA_ID_ENVELOPE_INFO    0
722
723 #define ED_NUM_TEXTAREAS                        1
724
725 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
726 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
727
728 /* values for selectbox gadgets */
729 #define ED_SELECTBOX_ID_TIME_OR_STEPS           0
730 #define ED_SELECTBOX_ID_GAME_ENGINE_TYPE        1
731 #define ED_SELECTBOX_ID_WIND_DIRECTION          2
732 #define ED_SELECTBOX_ID_PLAYER_SPEED            3
733 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE      4
734 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER     5
735 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED 6
736 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION 7
737 #define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION   8
738 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN     9
739 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION   10      
740 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE    11
741 #define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE  12
742 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS    13
743 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE    14
744 #define ED_SELECTBOX_ID_CUSTOM_DEADLINESS       15
745 #define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE   16
746 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS       17
747 #define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION    18
748 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION     19
749 #define ED_SELECTBOX_ID_CHANGE_SIDE             20
750 #define ED_SELECTBOX_ID_CHANGE_PLAYER           21
751 #define ED_SELECTBOX_ID_CHANGE_PAGE             22
752 #define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN     23
753 #define ED_SELECTBOX_ID_ACTION_TYPE             24
754 #define ED_SELECTBOX_ID_ACTION_MODE             25
755 #define ED_SELECTBOX_ID_ACTION_ARG              26
756 #define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE      27
757 #define ED_SELECTBOX_ID_GROUP_CHOICE_MODE       28
758
759 #define ED_NUM_SELECTBOX                        29
760
761 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
762 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_WIND_DIRECTION
763
764 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
765 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
766 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
767 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
768 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
769 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
770
771 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
772 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
773
774 /* values for textbutton gadgets */
775 #define ED_TEXTBUTTON_ID_LEVELINFO_LEVEL        0
776 #define ED_TEXTBUTTON_ID_LEVELINFO_EDITOR       1
777 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO        2
778 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG      3
779 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1    4
780 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2    5
781 #define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE      6
782 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE       7
783 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE        8
784 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE        9
785
786 #define ED_NUM_TEXTBUTTONS                      10
787
788 #define ED_TEXTBUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
789 #define ED_TEXTBUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
790
791 #define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
792 #define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
793
794 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
795 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
796
797 /* values for graphicbutton gadgets */
798 #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE    0
799 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE    1
800 #define ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE    2
801 #define ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE   3
802
803 #define ED_NUM_GRAPHICBUTTONS                   4
804
805 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
806 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
807
808 /* values for checkbutton gadgets */
809 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED     0
810 #define ED_CHECKBUTTON_ID_STICK_ELEMENT         1
811 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS      2
812 #define ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE   3
813 #define ED_CHECKBUTTON_ID_USE_SPRING_BUG        4
814 #define ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG      5
815 #define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT   6
816 #define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE    7
817 #define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE    8
818 #define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING   9
819 #define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD      10
820 #define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD      11
821 #define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD   12
822 #define ED_CHECKBUTTON_ID_INSTANT_RELOCATION    13
823 #define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION    14
824 #define ED_CHECKBUTTON_ID_USE_START_ELEMENT     15
825 #define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT   16
826 #define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT 17
827 #define ED_CHECKBUTTON_ID_INITIAL_GRAVITY       18
828 #define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY 19
829 #define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE  20
830 #define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID    21
831 #define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID    22
832 #define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH     23
833 #define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP     24
834 #define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED     25
835 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC    26
836 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE   27
837 #define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE     28
838 #define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE 29
839 #define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE 30
840 #define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 31
841 #define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE 32
842 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE       33
843 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL       34
844 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH      35
845 #define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY       36
846 #define ED_CHECKBUTTON_ID_CUSTOM_DEADLY         37
847 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE    38
848 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE   39
849 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH  40
850 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 41
851 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE     42
852 #define ED_CHECKBUTTON_ID_CHANGE_DELAY          43
853 #define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT  44
854 #define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT   45
855 #define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION  46
856 #define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT    47
857 #define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE  48
858 #define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM     49
859 #define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION     50
860
861 #define ED_NUM_CHECKBUTTONS                     51
862
863 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
864 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
865
866 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
867 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
868 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
869 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
870 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
871 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
872
873 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
874 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
875
876 /* values for radiobutton gadgets */
877 #define ED_RADIOBUTTON_ID_PERCENTAGE    0
878 #define ED_RADIOBUTTON_ID_QUANTITY      1
879
880 #define ED_NUM_RADIOBUTTONS             2
881
882 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
883 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
884
885 /* values for drawing area gadgets */
886 #define ED_DRAWING_ID_DRAWING_LEVEL             0
887 #define ED_DRAWING_ID_YAMYAM_CONTENT_0          1
888 #define ED_DRAWING_ID_YAMYAM_CONTENT_1          2
889 #define ED_DRAWING_ID_YAMYAM_CONTENT_2          3
890 #define ED_DRAWING_ID_YAMYAM_CONTENT_3          4
891 #define ED_DRAWING_ID_YAMYAM_CONTENT_4          5
892 #define ED_DRAWING_ID_YAMYAM_CONTENT_5          6
893 #define ED_DRAWING_ID_YAMYAM_CONTENT_6          7
894 #define ED_DRAWING_ID_YAMYAM_CONTENT_7          8
895 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_0      9
896 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_1      10
897 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_2      11
898 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_3      12
899 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_4      13
900 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_5      14
901 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_6      15
902 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_7      16
903 #define ED_DRAWING_ID_ANDROID_CONTENT           17
904 #define ED_DRAWING_ID_AMOEBA_CONTENT            18
905 #define ED_DRAWING_ID_START_ELEMENT             19
906 #define ED_DRAWING_ID_ARTWORK_ELEMENT           20
907 #define ED_DRAWING_ID_EXPLOSION_ELEMENT         21
908 #define ED_DRAWING_ID_INVENTORY_CONTENT         22
909 #define ED_DRAWING_ID_CUSTOM_GRAPHIC            23
910 #define ED_DRAWING_ID_CUSTOM_CONTENT            24
911 #define ED_DRAWING_ID_CUSTOM_MOVE_ENTER         25
912 #define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE         26
913 #define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET      27
914 #define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT     28
915 #define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER     29
916 #define ED_DRAWING_ID_CUSTOM_CHANGE_ACTION      30
917 #define ED_DRAWING_ID_GROUP_CONTENT             31
918 #define ED_DRAWING_ID_RANDOM_BACKGROUND         32
919
920 #define ED_NUM_DRAWING_AREAS                    33
921
922
923 /*
924   -----------------------------------------------------------------------------
925   some internally used definitions
926   -----------------------------------------------------------------------------
927 */
928
929 /* values for CopyLevelToUndoBuffer() */
930 #define UNDO_IMMEDIATE                  0
931 #define UNDO_ACCUMULATE                 1
932
933 /* values for scrollbars */
934 #define ED_SCROLL_NO                    0
935 #define ED_SCROLL_LEFT                  1
936 #define ED_SCROLL_RIGHT                 2
937 #define ED_SCROLL_UP                    4
938 #define ED_SCROLL_DOWN                  8
939
940 /* screens in the level editor */
941 #define ED_MODE_DRAWING                 0
942 #define ED_MODE_INFO                    1
943 #define ED_MODE_PROPERTIES              2
944
945 /* sub-screens in the global settings section */
946 #define ED_MODE_LEVELINFO_LEVEL         ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
947 #define ED_MODE_LEVELINFO_EDITOR        ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
948
949 /* sub-screens in the element properties section */
950 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
951 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
952 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
953 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
954 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
955
956 /* how many steps can be cancelled */
957 #define NUM_UNDO_STEPS                  (10 + 1)
958
959 /* values for elements with score for certain actions */
960 #define MIN_SCORE                       0
961 #define MAX_SCORE                       999
962
963 /* values for elements with count for collecting */
964 #define MIN_COLLECT_COUNT               0
965 #define MAX_COLLECT_COUNT               999
966
967 /* values for random placement */
968 #define RANDOM_USE_PERCENTAGE           0
969 #define RANDOM_USE_QUANTITY             1
970
971 /* maximal size of level editor drawing area */
972 #define MAX_ED_FIELDX           (2 * SCR_FIELDX)
973 #define MAX_ED_FIELDY           (2 * SCR_FIELDY - 1)
974
975
976 /*
977   -----------------------------------------------------------------------------
978   some internally used data structure definitions
979   -----------------------------------------------------------------------------
980 */
981
982 static struct
983 {
984   char shortcut;
985   char *text;
986 } control_info[ED_NUM_CTRL_BUTTONS] =
987 {
988   /* note: some additional characters are already reserved for "cheat mode"
989      shortcuts (":XYZ" style) -- for details, see "events.c" */
990
991   { 's',        "draw single items"                     },
992   { 'd',        "draw connected items"                  },
993   { 'l',        "draw lines"                            },
994   { 'a',        "draw arcs"                             },
995   { 'r',        "draw outline rectangles"               },
996   { 'R',        "draw filled rectangles"                },
997   { '\0',       "wrap (rotate) level up"                },
998   { 't',        "enter text elements"                   },
999   { 'f',        "flood fill"                            },
1000   { '\0',       "wrap (rotate) level left"              },
1001   { '?',        "properties of drawing element"         },
1002   { '\0',       "wrap (rotate) level right"             },
1003   { '\0',       "random element placement"              },
1004   { 'b',        "grab brush"                            },
1005   { '\0',       "wrap (rotate) level down"              },
1006   { ',',        "pick drawing element"                  },
1007
1008   { 'U',        "undo last operation"                   },
1009   { 'I',        "properties of level"                   },
1010   { 'S',        "save level"                            },
1011   { 'C',        "clear level"                           },
1012   { 'T',        "test level"                            },
1013   { 'E',        "exit level editor"                     },
1014
1015   { '\0',       "copy settings from other element"      },
1016   { '\0',       "copy settings to other element"        },
1017   { '\0',       "exchange element with other element"   },
1018
1019   { '\0',       "copy settings from this element"       },
1020   { '\0',       "paste settings to this element"        },
1021 };
1022
1023 static int random_placement_value = 10;
1024 static int random_placement_method = RANDOM_USE_QUANTITY;
1025 static int random_placement_background_element = EL_SAND;
1026 static boolean random_placement_background_restricted = FALSE;
1027 static boolean stick_element_properties_window = FALSE;
1028 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1029 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1030 static struct ElementChangeInfo custom_element_change;
1031 static struct ElementGroupInfo group_element_info;
1032 static struct ElementInfo custom_element;
1033
1034 static struct
1035 {
1036   int x, y;
1037   int min_value, max_value;
1038   int gadget_id_down, gadget_id_up;
1039   int gadget_id_text;
1040   int gadget_id_align;
1041   int *value;
1042   char *text_above, *text_left, *text_right;
1043 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1044 {
1045   /* ---------- current level number --------------------------------------- */
1046
1047   {
1048     DX + 5 - SX,                        DY + 3 - SY,
1049     1,                                  100,
1050     GADGET_ID_SELECT_LEVEL_DOWN,        GADGET_ID_SELECT_LEVEL_UP,
1051     GADGET_ID_SELECT_LEVEL_TEXT,        GADGET_ID_NONE,
1052     &level_nr,
1053     NULL,                               NULL, NULL
1054   },
1055
1056   /* ---------- level and editor settings ---------------------------------- */
1057
1058   {
1059     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1060     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
1061     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
1062     GADGET_ID_LEVEL_XSIZE_TEXT,         GADGET_ID_NONE,
1063     &level.fieldx,
1064     "playfield size:",                  NULL, "width",
1065   },
1066   {
1067     -1,                                 ED_LEVEL_SETTINGS_YPOS(4),
1068     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
1069     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
1070     GADGET_ID_LEVEL_YSIZE_TEXT,         GADGET_ID_LEVEL_XSIZE_UP,
1071     &level.fieldy,
1072     NULL,                               " ", "height",
1073   },
1074   {
1075     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
1076     0,                                  999,
1077     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,     GADGET_ID_LEVEL_GEMSLIMIT_UP,
1078     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,     GADGET_ID_NONE,
1079     &level.gems_needed,
1080     NULL,                               "number of gems to collect:", NULL
1081   },
1082   {
1083     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(7),
1084     0,                                  9999,
1085     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
1086     GADGET_ID_LEVEL_TIMELIMIT_TEXT,     GADGET_ID_NONE,
1087     &level.time,
1088     "time or step limit to solve level:", NULL, NULL
1089   },
1090   {
1091     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(9),
1092     0,                                  999,
1093     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
1094     GADGET_ID_LEVEL_TIMESCORE_TEXT,     GADGET_ID_NONE,
1095     &level.score[SC_TIME_BONUS],
1096     "score for each second/step left:", NULL, NULL
1097   },
1098   {
1099     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(12),
1100     0,                                  9999,
1101     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,   GADGET_ID_LEVEL_RANDOM_SEED_UP,
1102     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,   GADGET_ID_NONE,
1103     &level.random_seed,
1104     NULL,                               "random seed:", "(0 => random)"
1105   },
1106   {
1107     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1108     1,                                  100,
1109     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
1110     GADGET_ID_LEVEL_RANDOM_TEXT,        GADGET_ID_NONE,
1111     &random_placement_value,
1112     "random element placement:",        NULL, "in"
1113   },
1114
1115   /* ---------- element settings: configure (various elements) ------------- */
1116
1117   {
1118     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1119     MIN_SCORE,                          MAX_SCORE,
1120     GADGET_ID_ELEMENT_VALUE1_DOWN,      GADGET_ID_ELEMENT_VALUE1_UP,
1121     GADGET_ID_ELEMENT_VALUE1_TEXT,      GADGET_ID_NONE,
1122     NULL,                               /* will be set when used */
1123     NULL,                               NULL, NULL
1124   },
1125   {
1126     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
1127     MIN_SCORE,                          MAX_SCORE,
1128     GADGET_ID_ELEMENT_VALUE2_DOWN,      GADGET_ID_ELEMENT_VALUE2_UP,
1129     GADGET_ID_ELEMENT_VALUE2_TEXT,      GADGET_ID_NONE,
1130     NULL,                               /* will be set when used */
1131     NULL,                               NULL, NULL
1132   },
1133   {
1134     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1135     MIN_SCORE,                          MAX_SCORE,
1136     GADGET_ID_ELEMENT_VALUE3_DOWN,      GADGET_ID_ELEMENT_VALUE3_UP,
1137     GADGET_ID_ELEMENT_VALUE3_TEXT,      GADGET_ID_NONE,
1138     NULL,                               /* will be set when used */
1139     NULL,                               NULL, NULL
1140   },
1141   {
1142     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1143     MIN_SCORE,                          MAX_SCORE,
1144     GADGET_ID_ELEMENT_VALUE4_DOWN,      GADGET_ID_ELEMENT_VALUE4_UP,
1145     GADGET_ID_ELEMENT_VALUE4_TEXT,      GADGET_ID_NONE,
1146     NULL,                               /* will be set when used */
1147     NULL,                               NULL, NULL
1148   },
1149   {
1150     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1151     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1152     GADGET_ID_YAMYAM_CONTENT_DOWN,      GADGET_ID_YAMYAM_CONTENT_UP,
1153     GADGET_ID_YAMYAM_CONTENT_TEXT,      GADGET_ID_NONE,
1154     &level.num_yamyam_contents,
1155     NULL,                               NULL, "number of content areas"
1156   },
1157   {
1158     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1159     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1160     GADGET_ID_BALL_CONTENT_DOWN,        GADGET_ID_BALL_CONTENT_UP,
1161     GADGET_ID_BALL_CONTENT_TEXT,        GADGET_ID_NONE,
1162     &level.num_ball_contents,
1163     NULL,                               NULL, "number of content areas"
1164   },
1165   {
1166     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1167     MIN_ANDROID_ELEMENTS,               MAX_ANDROID_ELEMENTS,
1168     GADGET_ID_ANDROID_CONTENT_DOWN,     GADGET_ID_ANDROID_CONTENT_UP,
1169     GADGET_ID_ANDROID_CONTENT_TEXT,     GADGET_ID_NONE,
1170     &level.num_android_clone_elements,
1171     NULL,                               NULL, "number of clonable elements"
1172   },
1173   {
1174     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1175     MIN_ENVELOPE_XSIZE,                 MAX_ENVELOPE_XSIZE,
1176     GADGET_ID_ENVELOPE_XSIZE_DOWN,      GADGET_ID_ENVELOPE_XSIZE_UP,
1177     GADGET_ID_ENVELOPE_XSIZE_TEXT,      GADGET_ID_NONE,
1178     NULL,                               /* will be set when used */
1179     NULL,                               NULL, "width",
1180   },
1181   {
1182     -1,                                 ED_ELEMENT_SETTINGS_YPOS(0),
1183     MIN_ENVELOPE_YSIZE,                 MAX_ENVELOPE_YSIZE,
1184     GADGET_ID_ENVELOPE_YSIZE_DOWN,      GADGET_ID_ENVELOPE_YSIZE_UP,
1185     GADGET_ID_ENVELOPE_YSIZE_TEXT,      GADGET_ID_ENVELOPE_XSIZE_UP,
1186     NULL,                               /* will be set when used */
1187     NULL,                               " ", "height",
1188   },
1189   {
1190     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1191     MIN_INITIAL_INVENTORY_SIZE,         MAX_INITIAL_INVENTORY_SIZE,
1192     GADGET_ID_INVENTORY_SIZE_DOWN,      GADGET_ID_INVENTORY_SIZE_UP,
1193     GADGET_ID_INVENTORY_SIZE_TEXT,      GADGET_ID_NONE,
1194     &level.initial_inventory_size[0],
1195     NULL,                               NULL, "number of inventory elements"
1196   },
1197
1198   /* ---------- element settings: configure 1 (custom elements) ------------ */
1199
1200   {
1201     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1202     MIN_SCORE,                          MAX_SCORE,
1203     GADGET_ID_CUSTOM_SCORE_DOWN,        GADGET_ID_CUSTOM_SCORE_UP,
1204     GADGET_ID_CUSTOM_SCORE_TEXT,        GADGET_ID_NONE,
1205     &custom_element.collect_score_initial,
1206     NULL,                               "CE score", " "
1207   },
1208   {
1209     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1210     MIN_COLLECT_COUNT,                  MAX_COLLECT_COUNT,
1211     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,     GADGET_ID_CUSTOM_GEMCOUNT_UP,
1212     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,     GADGET_ID_CUSTOM_SCORE_UP,
1213     &custom_element.collect_count_initial,
1214     NULL,                               "CE count", NULL
1215   },
1216   {
1217     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
1218     0,                                  9999,
1219     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1220     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,    GADGET_ID_NONE,
1221     &custom_element.ce_value_fixed_initial,
1222     NULL,                               "CE value", NULL
1223   },
1224   {
1225     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
1226     0,                                  9999,
1227     GADGET_ID_CUSTOM_VALUE_RND_DOWN,    GADGET_ID_CUSTOM_VALUE_RND_UP,
1228     GADGET_ID_CUSTOM_VALUE_RND_TEXT,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1229     &custom_element.ce_value_random_initial,
1230     NULL,                               "+random", NULL
1231   },
1232   {
1233     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(7),
1234     0,                                  999,
1235     GADGET_ID_PUSH_DELAY_FIX_DOWN,      GADGET_ID_PUSH_DELAY_FIX_UP,
1236     GADGET_ID_PUSH_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1237     &custom_element.push_delay_fixed,
1238     NULL,                               "push delay", NULL
1239   },
1240   {
1241     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
1242     0,                                  999,
1243     GADGET_ID_PUSH_DELAY_RND_DOWN,      GADGET_ID_PUSH_DELAY_RND_UP,
1244     GADGET_ID_PUSH_DELAY_RND_TEXT,      GADGET_ID_PUSH_DELAY_FIX_UP,
1245     &custom_element.push_delay_random,
1246     NULL,                               "+random", NULL
1247   },
1248   {
1249     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
1250     0,                                  999,
1251     GADGET_ID_DROP_DELAY_FIX_DOWN,      GADGET_ID_DROP_DELAY_FIX_UP,
1252     GADGET_ID_DROP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1253     &custom_element.drop_delay_fixed,
1254     NULL,                               "drop delay", NULL
1255   },
1256   {
1257     -1,                                 ED_ELEMENT_SETTINGS_YPOS(8),
1258     0,                                  999,
1259     GADGET_ID_DROP_DELAY_RND_DOWN,      GADGET_ID_DROP_DELAY_RND_UP,
1260     GADGET_ID_DROP_DELAY_RND_TEXT,      GADGET_ID_DROP_DELAY_FIX_UP,
1261     &custom_element.drop_delay_random,
1262     NULL,                               "+random", NULL
1263   },
1264
1265   /* ---------- element settings: configure 2 (custom elements) ------------ */
1266
1267   {
1268     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1269     0,                                  999,
1270     GADGET_ID_MOVE_DELAY_FIX_DOWN,      GADGET_ID_MOVE_DELAY_FIX_UP,
1271     GADGET_ID_MOVE_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1272     &custom_element.move_delay_fixed,
1273     NULL,                               "move delay", NULL
1274   },
1275   {
1276     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1277     0,                                  999,
1278     GADGET_ID_MOVE_DELAY_RND_DOWN,      GADGET_ID_MOVE_DELAY_RND_UP,
1279     GADGET_ID_MOVE_DELAY_RND_TEXT,      GADGET_ID_MOVE_DELAY_FIX_UP,
1280     &custom_element.move_delay_random,
1281     NULL,                               "+random", NULL
1282   },
1283   {
1284     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(12),
1285     0,                                  999,
1286     GADGET_ID_EXPLOSION_DELAY_DOWN,     GADGET_ID_EXPLOSION_DELAY_UP,
1287     GADGET_ID_EXPLOSION_DELAY_TEXT,     GADGET_ID_NONE,
1288     &custom_element.explosion_delay,
1289     NULL,                               "explosion delay", NULL
1290   },
1291   {
1292     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
1293     0,                                  999,
1294     GADGET_ID_IGNITION_DELAY_DOWN,      GADGET_ID_IGNITION_DELAY_UP,
1295     GADGET_ID_IGNITION_DELAY_TEXT,      GADGET_ID_NONE,
1296     &custom_element.ignition_delay,
1297     NULL,                               "ignition delay", "(by fire)"
1298   },
1299
1300   /* ---------- element settings: configure (group elements) --------------- */
1301
1302   {
1303     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
1304     MIN_ELEMENTS_IN_GROUP,              MAX_ELEMENTS_IN_GROUP,
1305     GADGET_ID_GROUP_CONTENT_DOWN,       GADGET_ID_GROUP_CONTENT_UP,
1306     GADGET_ID_GROUP_CONTENT_TEXT,       GADGET_ID_NONE,
1307     &group_element_info.num_elements,
1308     NULL,                               NULL, "number of elements in group"
1309   },
1310
1311   /* ---------- element settings: advanced (custom elements) --------------- */
1312
1313   {
1314     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(2),
1315     0,                                  999,
1316     GADGET_ID_CHANGE_DELAY_FIX_DOWN,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1317     GADGET_ID_CHANGE_DELAY_FIX_TEXT,    GADGET_ID_NONE,
1318     &custom_element_change.delay_fixed,
1319     NULL,                               "CE delay", NULL,
1320   },
1321   {
1322     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
1323     0,                                  999,
1324     GADGET_ID_CHANGE_DELAY_RND_DOWN,    GADGET_ID_CHANGE_DELAY_RND_UP,
1325     GADGET_ID_CHANGE_DELAY_RND_TEXT,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1326     &custom_element_change.delay_random,
1327     NULL,                               "+random", NULL
1328   },
1329   {
1330     ED_ELEMENT_SETTINGS_XPOS(3),        ED_ELEMENT_SETTINGS_YPOS(12),
1331     0,                                  100,
1332     GADGET_ID_CHANGE_CONT_RND_DOWN,     GADGET_ID_CHANGE_CONT_RND_UP,
1333     GADGET_ID_CHANGE_CONT_RND_TEXT,     GADGET_ID_NONE,
1334     &custom_element_change.random_percentage,
1335     NULL,                               "use random replace:", "%"
1336   },
1337 };
1338
1339 static struct
1340 {
1341   int x, y;
1342   int gadget_id;
1343   int size;
1344   char *value;
1345   char *text_above, *infotext;
1346 } textinput_info[ED_NUM_TEXTINPUT] =
1347 {
1348   {
1349     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1350     GADGET_ID_LEVEL_NAME,
1351     MAX_LEVEL_NAME_LEN,
1352     level.name,
1353     "Title:", "Title"
1354   },
1355   {
1356     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1357     GADGET_ID_LEVEL_AUTHOR,
1358     MAX_LEVEL_AUTHOR_LEN,
1359     level.author,
1360     "Author:", "Author"
1361   },
1362   {
1363     5 * MINI_TILEX - 2,                 5 * MINI_TILEY - ED_BORDER_SIZE + 1,
1364     GADGET_ID_ELEMENT_NAME,
1365     MAX_ELEMENT_NAME_LEN - 2,           /* currently 2 chars less editable */
1366     custom_element.description,
1367     NULL, "Element name"
1368   }
1369 };
1370
1371 static struct
1372 {
1373   int x, y;
1374   int gadget_id;
1375   int xsize, ysize;
1376   char *value;
1377   char *text_above, *infotext;
1378 } textarea_info[ED_NUM_TEXTAREAS] =
1379 {
1380   {
1381     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1382     GADGET_ID_ENVELOPE_INFO,
1383     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
1384     NULL,
1385     "Envelope Content:", "Envelope Content"
1386   }
1387 };
1388
1389 static struct ValueTextInfo options_time_or_steps[] =
1390 {
1391   { 0,                          "seconds"                       },
1392   { 1,                          "steps"                         },
1393
1394   { -1,                         NULL                            }
1395 };
1396
1397 static struct ValueTextInfo options_game_engine_type[] =
1398 {
1399   { GAME_ENGINE_TYPE_RND,       "Rocks'n'Diamonds"              },
1400   { GAME_ENGINE_TYPE_EM,        "Emerald Mine"                  },
1401
1402   { -1,                         NULL                            }
1403 };
1404
1405 static struct ValueTextInfo options_wind_direction[] =
1406 {
1407   { MV_START_NONE,              "none"                          },
1408   { MV_START_LEFT,              "left"                          },
1409   { MV_START_RIGHT,             "right"                         },
1410   { MV_START_UP,                "up"                            },
1411   { MV_START_DOWN,              "down"                          },
1412
1413   { -1,                         NULL                            }
1414 };
1415
1416 static struct ValueTextInfo options_player_speed[] =
1417 {
1418   { 0,                          "frozen"                        },
1419   { 1,                          "very slow"                     },
1420   { 2,                          "slow"                          },
1421   { 4,                          "normal"                        },
1422   { 8,                          "fast"                          },
1423   { 16,                         "very fast"                     },
1424   { 32,                         "ultrafast"                     },
1425
1426   { -1,                         NULL                            }
1427 };
1428
1429 static struct ValueTextInfo options_access_type[] =
1430 {
1431   { EP_WALKABLE,                "walkable"                      },
1432   { EP_PASSABLE,                "passable"                      },
1433
1434   { -1,                         NULL                            }
1435 };
1436
1437 static struct ValueTextInfo options_access_layer[] =
1438 {
1439   { EP_ACCESSIBLE_OVER,         "over"                          },
1440   { EP_ACCESSIBLE_INSIDE,       "inside"                        },
1441   { EP_ACCESSIBLE_UNDER,        "under"                         },
1442
1443   { -1,                         NULL                            }
1444 };
1445
1446 static struct ValueTextInfo options_access_protected[] =
1447 {
1448   { 0,                          "unprotected"                   },
1449   { 1,                          "protected"                     },
1450
1451   { -1,                         NULL                            }
1452 };
1453
1454 static struct ValueTextInfo options_access_direction[] =
1455 {
1456   { MV_NO_DIRECTION,            "no direction"                  },
1457   { MV_LEFT,                    "left"                          },
1458   { MV_RIGHT,                   "right"                         },
1459   { MV_UP,                      "up"                            },
1460   { MV_DOWN,                    "down"                          },
1461   { MV_LEFT  | MV_UP,           "left + up"                     },
1462   { MV_LEFT  | MV_DOWN,         "left + down"                   },
1463   { MV_RIGHT | MV_UP,           "right + up"                    },
1464   { MV_RIGHT | MV_DOWN,         "right + down"                  },
1465   { MV_HORIZONTAL,              "horizontal"                    },
1466   { MV_VERTICAL,                "vertical"                      },
1467   { MV_HORIZONTAL | MV_UP,      "horizontal + up"               },
1468   { MV_HORIZONTAL | MV_DOWN,    "horizontal + down"             },
1469   { MV_VERTICAL   | MV_LEFT,    "vertical + left"               },
1470   { MV_VERTICAL   | MV_RIGHT,   "vertical + right"              },
1471   { MV_ALL_DIRECTIONS,          "all directions"                },
1472
1473   { -1,                         NULL                            }
1474 };
1475
1476 static struct ValueTextInfo options_walk_to_action[] =
1477 {
1478   { EP_DIGGABLE,                "diggable"                      },
1479   { EP_COLLECTIBLE_ONLY,        "collectible"                   },
1480   { EP_DROPPABLE,               "collectible & droppable"       },
1481   { EP_THROWABLE,               "collectible & throwable"       },
1482   { EP_PUSHABLE,                "pushable"                      },
1483
1484   { -1,                         NULL                            }
1485 };
1486
1487 static struct ValueTextInfo options_move_pattern[] =
1488 {
1489   { MV_LEFT,                    "left"                          },
1490   { MV_RIGHT,                   "right"                         },
1491   { MV_UP,                      "up"                            },
1492   { MV_DOWN,                    "down"                          },
1493   { MV_HORIZONTAL,              "horizontal"                    },
1494   { MV_VERTICAL,                "vertical"                      },
1495   { MV_ALL_DIRECTIONS,          "all directions"                },
1496   { MV_WIND_DIRECTION,          "wind direction"                },
1497   { MV_TOWARDS_PLAYER,          "towards player"                },
1498   { MV_AWAY_FROM_PLAYER,        "away from player"              },
1499   { MV_ALONG_LEFT_SIDE,         "along left side"               },
1500   { MV_ALONG_RIGHT_SIDE,        "along right side"              },
1501   { MV_TURNING_LEFT,            "turning left"                  },
1502   { MV_TURNING_RIGHT,           "turning right"                 },
1503   { MV_TURNING_LEFT_RIGHT,      "turning left, right"           },
1504   { MV_TURNING_RIGHT_LEFT,      "turning right, left"           },
1505   { MV_TURNING_RANDOM,          "turning random"                },
1506   { MV_MAZE_RUNNER,             "maze runner style"             },
1507   { MV_MAZE_HUNTER,             "maze hunter style"             },
1508   { MV_WHEN_PUSHED,             "when pushed"                   },
1509   { MV_WHEN_DROPPED,            "when dropped/thrown"           },
1510
1511   { -1,                         NULL                            }
1512 };
1513
1514 static struct ValueTextInfo options_move_direction[] =
1515 {
1516   { MV_START_AUTOMATIC,         "automatic"                     },
1517   { MV_START_LEFT,              "left"                          },
1518   { MV_START_RIGHT,             "right"                         },
1519   { MV_START_UP,                "up"                            },
1520   { MV_START_DOWN,              "down"                          },
1521   { MV_START_RANDOM,            "random"                        },
1522   { MV_START_PREVIOUS,          "previous"                      },
1523
1524   { -1,                         NULL                            }
1525 };
1526
1527 static struct ValueTextInfo options_move_stepsize[] =
1528 {
1529   { 0,                          "not moving"                    },
1530   { 1,                          "very slow"                     },
1531   { 2,                          "slow"                          },
1532   { 4,                          "normal"                        },
1533   { 8,                          "fast"                          },
1534   { 16,                         "very fast"                     },
1535   { 32,                         "even faster"                   },
1536
1537   { -1,                         NULL                            }
1538 };
1539
1540 static struct ValueTextInfo options_move_leave_type[] =
1541 {
1542   { LEAVE_TYPE_UNLIMITED,       "leave behind"                  },
1543   { LEAVE_TYPE_LIMITED,         "change it to"                  },
1544
1545   { -1,                         NULL                            }
1546 };
1547
1548 static struct ValueTextInfo options_smash_targets[] =
1549 {
1550   { EP_CAN_SMASH_PLAYER,        "player"                        },
1551 #if 0
1552   { EP_CAN_SMASH_ENEMIES,       "enemies"                       },
1553 #endif
1554   { EP_CAN_SMASH_EVERYTHING,    "everything"                    },
1555
1556   { -1,                         NULL                            }
1557 };
1558
1559 static struct ValueTextInfo options_slippery_type[] =
1560 {
1561   { SLIPPERY_ANY_RANDOM,        "random"                        },
1562   { SLIPPERY_ANY_LEFT_RIGHT,    "left, right"                   },
1563   { SLIPPERY_ANY_RIGHT_LEFT,    "right, left"                   },
1564   { SLIPPERY_ONLY_LEFT,         "only left"                     },
1565   { SLIPPERY_ONLY_RIGHT,        "only right"                    },
1566
1567   { -1,                         NULL                            }
1568 };
1569
1570 static struct ValueTextInfo options_deadliness[] =
1571 {
1572   { EP_DONT_RUN_INTO,           "running into"                  },
1573   { EP_DONT_COLLIDE_WITH,       "colliding with"                },
1574   { EP_DONT_GET_HIT_BY,         "getting hit by"                },
1575   { EP_DONT_TOUCH,              "touching"                      },
1576
1577   { -1,                         NULL                            }
1578 };
1579
1580 static struct ValueTextInfo options_explosion_type[] =
1581 {
1582   { EXPLODES_3X3,               "3x3"                           },
1583   { EXPLODES_CROSS,             "3+3"                           },
1584   { EXPLODES_1X1,               "1x1"                           },
1585
1586   { -1,                         NULL                            }
1587 };
1588
1589 static struct ValueTextInfo options_time_units[] =
1590 {
1591   { 1,                          "frames"                        },
1592   { FRAMES_PER_SECOND,          "seconds"                       },
1593
1594   { -1,                         NULL                            }
1595 };
1596
1597 static struct ValueTextInfo options_change_direct_action[] =
1598 {
1599   { CE_TOUCHED_BY_PLAYER,       "touched by player"             },
1600   { CE_PRESSED_BY_PLAYER,       "pressed by player"             },
1601   { CE_SWITCHED_BY_PLAYER,      "switched by player"            },
1602   { CE_SNAPPED_BY_PLAYER,       "snapped by player"             },
1603   { CE_PUSHED_BY_PLAYER,        "pushed by player"              },
1604   { CE_ENTERED_BY_PLAYER,       "entered by player"             },
1605   { CE_LEFT_BY_PLAYER,          "left by player"                },
1606   { CE_DROPPED_BY_PLAYER,       "dropped/thrown by player"      },
1607   { CE_SWITCHED,                "switched"                      },
1608   { CE_HITTING_SOMETHING,       "hitting something"             },
1609   { CE_HIT_BY_SOMETHING,        "hit by something"              },
1610 #if 0
1611   { CE_BLOCKED,                 "blocked"                       },
1612 #endif
1613   { CE_IMPACT,                  "impact (on something)"         },
1614   { CE_SMASHED,                 "smashed (from above)"          },
1615 #if 0
1616   { CE_VALUE_CHANGES,           "CE value changes"              },
1617   { CE_SCORE_CHANGES,           "CE score changes"              },
1618 #endif
1619   { CE_VALUE_GETS_ZERO,         "CE value gets 0"               },
1620   { CE_SCORE_GETS_ZERO,         "CE score gets 0"               },
1621
1622   { -1,                         NULL                            }
1623 };
1624
1625 static struct ValueTextInfo options_change_other_action[] =
1626 {
1627   { CE_PLAYER_TOUCHES_X,        "player touches"                },
1628   { CE_PLAYER_PRESSES_X,        "player presses"                },
1629   { CE_PLAYER_SWITCHES_X,       "player switches"               },
1630   { CE_PLAYER_SNAPS_X,          "player snaps"                  },
1631   { CE_PLAYER_PUSHES_X,         "player pushes"                 },
1632   { CE_PLAYER_ENTERS_X,         "player enters"                 },
1633   { CE_PLAYER_LEAVES_X,         "player leaves"                 },
1634   { CE_PLAYER_DIGS_X,           "player digs"                   },
1635   { CE_PLAYER_COLLECTS_X,       "player collects"               },
1636   { CE_PLAYER_DROPS_X,          "player drops/throws"           },
1637   { CE_TOUCHING_X,              "touching"                      },
1638   { CE_HITTING_X,               "hitting"                       },
1639   { CE_DIGGING_X,               "digging"                       },
1640   { CE_HIT_BY_X,                "hit by"                        },
1641   { CE_SWITCH_OF_X,             "switch of"                     },
1642   { CE_CHANGE_OF_X,             "change by page of"             },
1643   { CE_EXPLOSION_OF_X,          "explosion of"                  },
1644   { CE_MOVE_OF_X,               "move of"                       },
1645   { CE_CREATION_OF_X,           "creation of"                   },
1646   { CE_VALUE_CHANGES_OF_X,      "CE value changes of"           },
1647   { CE_SCORE_CHANGES_OF_X,      "CE score changes of"           },
1648   { CE_VALUE_GETS_ZERO_OF_X,    "CE value gets 0 of"            },
1649   { CE_SCORE_GETS_ZERO_OF_X,    "CE score gets 0 of"            },
1650
1651   { -1,                         NULL                            }
1652 };
1653
1654 static struct ValueTextInfo options_change_trigger_side[] =
1655 {
1656   { CH_SIDE_LEFT,               "left"                          },
1657   { CH_SIDE_RIGHT,              "right"                         },
1658   { CH_SIDE_TOP,                "top"                           },
1659   { CH_SIDE_BOTTOM,             "bottom"                        },
1660   { CH_SIDE_LEFT_RIGHT,         "left/right"                    },
1661   { CH_SIDE_TOP_BOTTOM,         "top/bottom"                    },
1662   { CH_SIDE_ANY,                "any"                           },
1663
1664   { -1,                         NULL                            }
1665 };
1666
1667 static struct ValueTextInfo options_change_trigger_player[] =
1668 {
1669   { CH_PLAYER_1,                "1"                             },
1670   { CH_PLAYER_2,                "2"                             },
1671   { CH_PLAYER_3,                "3"                             },
1672   { CH_PLAYER_4,                "4"                             },
1673   { CH_PLAYER_ANY,              "any"                           },
1674
1675   { -1,                         NULL                            }
1676 };
1677
1678 static struct ValueTextInfo options_change_trigger_page[] =
1679 {
1680   { (1 << 0),                   "1"                             },
1681   { (1 << 1),                   "2"                             },
1682   { (1 << 2),                   "3"                             },
1683   { (1 << 3),                   "4"                             },
1684   { (1 << 4),                   "5"                             },
1685   { (1 << 5),                   "6"                             },
1686   { (1 << 6),                   "7"                             },
1687   { (1 << 7),                   "8"                             },
1688   { (1 << 8),                   "9"                             },
1689   { (1 << 9),                   "10"                            },
1690   { (1 << 10),                  "11"                            },
1691   { (1 << 11),                  "12"                            },
1692   { (1 << 12),                  "13"                            },
1693   { (1 << 13),                  "14"                            },
1694   { (1 << 14),                  "15"                            },
1695   { (1 << 15),                  "16"                            },
1696   { (1 << 16),                  "17"                            },
1697   { (1 << 17),                  "18"                            },
1698   { (1 << 18),                  "19"                            },
1699   { (1 << 19),                  "20"                            },
1700   { (1 << 20),                  "21"                            },
1701   { (1 << 21),                  "22"                            },
1702   { (1 << 22),                  "23"                            },
1703   { (1 << 23),                  "24"                            },
1704   { (1 << 24),                  "25"                            },
1705   { (1 << 25),                  "26"                            },
1706   { (1 << 26),                  "27"                            },
1707   { (1 << 27),                  "28"                            },
1708   { (1 << 28),                  "29"                            },
1709   { (1 << 29),                  "30"                            },
1710   { (1 << 30),                  "31"                            },
1711   { (1 << 31),                  "32"                            },
1712   { CH_PAGE_ANY,                "any"                           },
1713
1714   { -1,                         NULL                            }
1715 };
1716
1717 static struct ValueTextInfo options_change_replace_when[] =
1718 {
1719   { CP_WHEN_EMPTY,              "empty"                         },
1720   { CP_WHEN_WALKABLE,           "walkable"                      },
1721   { CP_WHEN_DIGGABLE,           "diggable"                      },
1722   { CP_WHEN_COLLECTIBLE,        "collectible"                   },
1723   { CP_WHEN_REMOVABLE,          "removable"                     },
1724   { CP_WHEN_DESTRUCTIBLE,       "destructible"                  },
1725
1726   { -1,                         NULL                            }
1727 };
1728
1729 static struct ValueTextInfo options_action_type[] =
1730 {
1731   { CA_NO_ACTION,               "no action"                     },
1732   { CA_UNDEFINED,               " "                             },
1733   { CA_HEADLINE_LEVEL_ACTIONS,  "[level]"                       },
1734   { CA_RESTART_LEVEL,           "restart level"                 },
1735   { CA_SHOW_ENVELOPE,           "show envelope"                 },
1736   { CA_SET_LEVEL_TIME,          "set time"                      },
1737   { CA_SET_LEVEL_SCORE,         "set score"                     },
1738   { CA_SET_LEVEL_GEMS,          "set gems"                      },
1739   { CA_SET_LEVEL_WIND,          "set wind dir."                 },
1740   { CA_SET_LEVEL_RANDOM_SEED,   "set rand. seed"                },
1741   { CA_UNDEFINED,               " "                             },
1742   { CA_HEADLINE_PLAYER_ACTIONS, "[player]"                      },
1743   { CA_MOVE_PLAYER,             "move player"                   },
1744   { CA_EXIT_PLAYER,             "exit player"                   },
1745   { CA_KILL_PLAYER,             "kill player"                   },
1746   { CA_SET_PLAYER_KEYS,         "set keys"                      },
1747   { CA_SET_PLAYER_SPEED,        "set speed"                     },
1748   { CA_SET_PLAYER_SHIELD,       "set shield"                    },
1749   { CA_SET_PLAYER_GRAVITY,      "set gravity"                   },
1750   { CA_SET_PLAYER_ARTWORK,      "set artwork"                   },
1751   { CA_SET_PLAYER_INVENTORY,    "set inventory"                 },
1752   { CA_UNDEFINED,               " "                             },
1753   { CA_HEADLINE_CE_ACTIONS,     "[CE]"                          },
1754   { CA_SET_CE_VALUE,            "set CE value"                  },
1755   { CA_SET_CE_SCORE,            "set CE score"                  },
1756   { CA_SET_CE_ARTWORK,          "set CE artwork"                },
1757   { CA_UNDEFINED,               " "                             },
1758   { CA_HEADLINE_ENGINE_ACTIONS, "[engine]"                      },
1759   { CA_SET_ENGINE_SCAN_MODE,    "set scan mode"                 },
1760
1761   { -1,                         NULL                            }
1762 };
1763
1764 static struct ValueTextInfo options_action_mode_none[] =
1765 {
1766   { CA_MODE_UNDEFINED,          " "                             },
1767
1768   { -1,                         NULL                            }
1769 };
1770
1771 static struct ValueTextInfo options_action_mode_assign[] =
1772 {
1773   { CA_MODE_SET,                "="                             },
1774
1775   { -1,                         NULL                            }
1776 };
1777
1778 static struct ValueTextInfo options_action_mode_add_remove[] =
1779 {
1780   { CA_MODE_ADD,                "+"                             },
1781   { CA_MODE_SUBTRACT,           "-"                             },
1782
1783   { -1,                         NULL                            }
1784 };
1785
1786 static struct ValueTextInfo options_action_mode_calculate[] =
1787 {
1788   { CA_MODE_SET,                "="                             },
1789   { CA_MODE_ADD,                "+"                             },
1790   { CA_MODE_SUBTRACT,           "-"                             },
1791   { CA_MODE_MULTIPLY,           "*"                             },
1792   { CA_MODE_DIVIDE,             "/"                             },
1793   { CA_MODE_MODULO,             "%"                             },
1794
1795   { -1,                         NULL                            }
1796 };
1797
1798 static struct ValueTextInfo options_action_arg_none[] =
1799 {
1800   { CA_ARG_UNDEFINED,           "         "                     },
1801
1802   { -1,                         NULL                            }
1803 };
1804
1805 static struct ValueTextInfo options_action_arg_player[] =
1806 {
1807   { CA_ARG_PLAYER_HEADLINE,     "[player]"                      },
1808   { CA_ARG_PLAYER_1,            "1"                             },
1809   { CA_ARG_PLAYER_2,            "2"                             },
1810   { CA_ARG_PLAYER_3,            "3"                             },
1811   { CA_ARG_PLAYER_4,            "4"                             },
1812   { CA_ARG_PLAYER_ANY,          "any"                           },
1813   { CA_ARG_PLAYER_TRIGGER,      "trigger"                       },
1814   { CA_ARG_PLAYER_ACTION,       "action ->"                     },
1815
1816   { -1,                         NULL                            }
1817 };
1818
1819 static struct ValueTextInfo options_action_arg_number[] =
1820 {
1821   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
1822   { CA_ARG_0,                   "0"                             },
1823   { CA_ARG_1,                   "1"                             },
1824   { CA_ARG_2,                   "2"                             },
1825   { CA_ARG_3,                   "3"                             },
1826   { CA_ARG_4,                   "4"                             },
1827   { CA_ARG_5,                   "5"                             },
1828   { CA_ARG_10,                  "10"                            },
1829   { CA_ARG_100,                 "100"                           },
1830   { CA_ARG_1000,                "1000"                          },
1831   { CA_ARG_UNDEFINED,           " "                             },
1832   { CA_ARG_NUMBER_MIN,          "min"                           },
1833   { CA_ARG_NUMBER_MAX,          "max"                           },
1834   { CA_ARG_UNDEFINED,           " "                             },
1835   { CA_ARG_NUMBER_RESET,        "reset"                         },
1836   { CA_ARG_UNDEFINED,           " "                             },
1837   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
1838   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
1839   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
1840   { CA_ARG_UNDEFINED,           " "                             },
1841   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
1842   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
1843   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
1844   { CA_ARG_UNDEFINED,           " "                             },
1845   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
1846   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
1847   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
1848   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
1849   { CA_ARG_UNDEFINED,           " "                             },
1850   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
1851   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
1852   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
1853   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
1854
1855   { -1,                         NULL                            }
1856 };
1857
1858 static struct ValueTextInfo options_action_arg_value[] =
1859 {
1860   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
1861   { CA_ARG_0,                   "0"                             },
1862   { CA_ARG_1,                   "1"                             },
1863   { CA_ARG_2,                   "2"                             },
1864   { CA_ARG_3,                   "3"                             },
1865   { CA_ARG_4,                   "4"                             },
1866   { CA_ARG_5,                   "5"                             },
1867   { CA_ARG_10,                  "10"                            },
1868   { CA_ARG_100,                 "100"                           },
1869   { CA_ARG_1000,                "1000"                          },
1870   { CA_ARG_UNDEFINED,           " "                             },
1871   { CA_ARG_NUMBER_MIN,          "min"                           },
1872   { CA_ARG_NUMBER_MAX,          "max"                           },
1873   { CA_ARG_UNDEFINED,           " "                             },
1874   { CA_ARG_NUMBER_RESET,        "reset"                         },
1875   { CA_ARG_UNDEFINED,           " "                             },
1876   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
1877   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
1878   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
1879   { CA_ARG_UNDEFINED,           " "                             },
1880   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
1881   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
1882   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
1883   { CA_ARG_UNDEFINED,           " "                             },
1884   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
1885   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
1886   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
1887   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
1888   { CA_ARG_UNDEFINED,           " "                             },
1889   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
1890   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
1891   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
1892   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
1893   { CA_ARG_UNDEFINED,           " "                             },
1894   { CA_ARG_ELEMENT_NR_HEADLINE, "[element]"                     },
1895   { CA_ARG_ELEMENT_NR_TARGET,   "target"                        },
1896   { CA_ARG_ELEMENT_NR_TRIGGER,  "trigger"                       },
1897   { CA_ARG_ELEMENT_NR_ACTION,   "action ->"                     },
1898
1899   { -1,                         NULL                            }
1900 };
1901
1902 static struct ValueTextInfo options_action_arg_envelope[] =
1903 {
1904   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
1905   { CA_ARG_1,                   "1"                             },
1906   { CA_ARG_2,                   "2"                             },
1907   { CA_ARG_3,                   "3"                             },
1908   { CA_ARG_4,                   "4"                             },
1909   { CA_ARG_UNDEFINED,           " "                             },
1910   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
1911   { CA_ARG_ELEMENT_TARGET,      "target"                        },
1912   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
1913   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
1914
1915   { -1,                         NULL                            }
1916 };
1917
1918 static struct ValueTextInfo options_action_arg_key[] =
1919 {
1920   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
1921   { CA_ARG_1,                   "1"                             },
1922   { CA_ARG_2,                   "2"                             },
1923   { CA_ARG_3,                   "3"                             },
1924   { CA_ARG_4,                   "4"                             },
1925   { CA_ARG_5,                   "5"                             },
1926   { CA_ARG_6,                   "6"                             },
1927   { CA_ARG_7,                   "7"                             },
1928   { CA_ARG_8,                   "8"                             },
1929   { CA_ARG_UNDEFINED,           " "                             },
1930   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
1931   { CA_ARG_ELEMENT_TARGET,      "target"                        },
1932   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
1933   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
1934
1935   { -1,                         NULL                            }
1936 };
1937
1938 static struct ValueTextInfo options_action_arg_speed[] =
1939 {
1940   { CA_ARG_SPEED_HEADLINE,      "[speed]"                       },
1941   { CA_ARG_SPEED_NOT_MOVING,    "frozen"                        },
1942   { CA_ARG_SPEED_VERY_SLOW,     "very slow"                     },
1943   { CA_ARG_SPEED_SLOW,          "slow"                          },
1944   { CA_ARG_SPEED_NORMAL,        "normal"                        },
1945   { CA_ARG_SPEED_FAST,          "fast"                          },
1946   { CA_ARG_SPEED_VERY_FAST,     "very fast"                     },
1947   { CA_ARG_SPEED_EVEN_FASTER,   "ultrafast"                     },
1948   { CA_ARG_UNDEFINED,           " "                             },
1949   { CA_ARG_SPEED_SLOWER,        "slower"                        },
1950   { CA_ARG_SPEED_FASTER,        "faster"                        },
1951   { CA_ARG_UNDEFINED,           " "                             },
1952   { CA_ARG_SPEED_RESET,         "reset"                         },
1953
1954   { -1,                         NULL                            }
1955 };
1956
1957 static struct ValueTextInfo options_action_arg_shield[] =
1958 {
1959   { CA_ARG_SHIELD_HEADLINE,     "[shield]"                      },
1960   { CA_ARG_SHIELD_OFF,          "off"                           },
1961   { CA_ARG_SHIELD_NORMAL,       "normal"                        },
1962   { CA_ARG_SHIELD_DEADLY,       "deadly"                        },
1963
1964   { -1,                         NULL                            }
1965 };
1966
1967 static struct ValueTextInfo options_action_arg_artwork[] =
1968 {
1969   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
1970   { CA_ARG_ELEMENT_TARGET,      "target"                        },
1971   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
1972   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
1973   { CA_ARG_UNDEFINED,           " "                             },
1974   { CA_ARG_ELEMENT_RESET,       "reset"                         },
1975
1976   { -1,                         NULL                            }
1977 };
1978
1979 static struct ValueTextInfo options_action_arg_gravity[] =
1980 {
1981   { CA_ARG_GRAVITY_HEADLINE,    "[gravity]"                     },
1982   { CA_ARG_GRAVITY_ON,          "on"                            },
1983   { CA_ARG_GRAVITY_OFF,         "off"                           },
1984   { CA_ARG_GRAVITY_TOGGLE,      "toggle"                        },
1985
1986   { -1,                         NULL                            }
1987 };
1988
1989 static struct ValueTextInfo options_action_arg_direction[] =
1990 {
1991   { CA_ARG_DIRECTION_HEADLINE,  "[dir.]"                        },
1992   { CA_ARG_DIRECTION_NONE,      "none"                          },
1993   { CA_ARG_DIRECTION_LEFT,      "left"                          },
1994   { CA_ARG_DIRECTION_RIGHT,     "right"                         },
1995   { CA_ARG_DIRECTION_UP,        "up"                            },
1996   { CA_ARG_DIRECTION_DOWN,      "down"                          },
1997   { CA_ARG_DIRECTION_TRIGGER,   "trigger"                       },
1998   { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                   },
1999
2000   { -1,                         NULL                            }
2001 };
2002
2003 static struct ValueTextInfo options_action_arg_scan_mode[] =
2004 {
2005   { CA_ARG_SCAN_MODE_HEADLINE,  "[mode]"                        },
2006   { CA_ARG_SCAN_MODE_NORMAL,    "normal"                        },
2007   { CA_ARG_SCAN_MODE_REVERSE,   "reverse"                       },
2008
2009   { -1,                         NULL                            }
2010 };
2011
2012 static struct ValueTextInfo options_action_arg_inventory[] =
2013 {
2014   { CA_ARG_INVENTORY_HEADLINE,  "[add]"                         },
2015   { CA_ARG_ELEMENT_TARGET,      "+ target"                      },
2016   { CA_ARG_ELEMENT_TRIGGER,     "+ trigger"                     },
2017   { CA_ARG_ELEMENT_ACTION,      "+ action"                      },
2018   { CA_ARG_UNDEFINED,           " "                             },
2019   { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]"                     },
2020   { CA_ARG_INVENTORY_RM_TARGET, "- target"                      },
2021   { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger"                     },
2022   { CA_ARG_INVENTORY_RM_ACTION, "- action"                      },
2023   { CA_ARG_INVENTORY_RM_FIRST,  "- first"                       },
2024   { CA_ARG_INVENTORY_RM_LAST,   "- last"                        },
2025   { CA_ARG_INVENTORY_RM_ALL,    "- all"                         },
2026   { CA_ARG_UNDEFINED,           " "                             },
2027   { CA_ARG_INVENTORY_RESET,     "reset"                         },
2028
2029   { -1,                         NULL                            }
2030 };
2031
2032 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2033 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2034 {
2035   { -1,                         NULL                            }
2036 };
2037
2038 static struct ValueTextInfo options_group_choice_mode[] =
2039 {
2040   { ANIM_RANDOM,                "random"                        },
2041   { ANIM_LOOP,                  "loop"                          },
2042   { ANIM_LINEAR,                "linear"                        },
2043   { ANIM_PINGPONG,              "pingpong"                      },
2044   { ANIM_PINGPONG2,             "pingpong 2"                    },
2045
2046   { -1,                         NULL                            }
2047 };
2048
2049 static struct ValueTextInfo *action_arg_modes[] =
2050 {
2051   options_action_mode_none,
2052   options_action_mode_assign,
2053   options_action_mode_add_remove,
2054   options_action_mode_calculate,
2055 };
2056
2057 static struct
2058 {
2059   int value;
2060   int mode;
2061   struct ValueTextInfo *options;
2062 }
2063 action_arg_options[] =
2064 {
2065   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2066   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2067   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2068   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2069   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2070   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2071   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2072   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2073   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2074   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2075   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2076   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2077   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2078   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2079   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2080   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2081   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2082   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2083   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2084   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2085   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2086
2087   { -1,                         FALSE,  NULL                            }
2088 };
2089
2090 static struct
2091 {
2092   int x, y;
2093   int gadget_id;
2094   int gadget_id_align;
2095   int size;     /* char size of selectbox or '-1' (dynamically determined) */
2096   struct ValueTextInfo *options;
2097   int *value;
2098   char *text_left, *text_right, *infotext;
2099 } selectbox_info[ED_NUM_SELECTBOX] =
2100 {
2101   /* ---------- level and editor settings ---------------------------------- */
2102
2103   {
2104     -1,                                 ED_LEVEL_SETTINGS_YPOS(7),
2105     GADGET_ID_TIME_OR_STEPS,            GADGET_ID_LEVEL_TIMELIMIT_UP,
2106     -1,
2107     options_time_or_steps,
2108     &level.use_step_counter,
2109     NULL, "(0 => no limit)",            "time or step limit"
2110   },
2111   {
2112     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(11),
2113     GADGET_ID_GAME_ENGINE_TYPE,         GADGET_ID_NONE,
2114     -1,
2115     options_game_engine_type,
2116     &level.game_engine_type,
2117     "game engine:", NULL,               "game engine"
2118   },
2119   {
2120     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
2121     GADGET_ID_WIND_DIRECTION,           GADGET_ID_NONE,
2122     -1,
2123     options_wind_direction,
2124     &level.wind_direction_initial,
2125     "initial wind direction:", NULL,    "initial wind direction"
2126   },
2127
2128   /* ---------- element settings: configure (several elements) ------------- */
2129
2130   {
2131     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
2132     GADGET_ID_PLAYER_SPEED,             GADGET_ID_NONE,
2133     -1,
2134     options_player_speed,
2135     &level.initial_player_stepsize[0],
2136     "initial player speed:", NULL,      "initial player speed"
2137   },
2138
2139   /* ---------- element settings: configure 1 (custom elements) ------------ */
2140
2141   {
2142     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2143     GADGET_ID_CUSTOM_ACCESS_TYPE,       GADGET_ID_NONE,
2144     -1,
2145     options_access_type,
2146     &custom_element.access_type,
2147     NULL, NULL,                         "type of access to this field"
2148   },
2149   {
2150     -1,                                 ED_ELEMENT_SETTINGS_YPOS(3),
2151     GADGET_ID_CUSTOM_ACCESS_LAYER,      GADGET_ID_CUSTOM_ACCESS_TYPE,
2152     -1,
2153     options_access_layer,
2154     &custom_element.access_layer,
2155     NULL, NULL,                         "layer of access for this field"
2156   },
2157   {
2158     -1,                                 ED_ELEMENT_SETTINGS_YPOS(3),
2159     GADGET_ID_CUSTOM_ACCESS_PROTECTED,  GADGET_ID_CUSTOM_ACCESS_LAYER,
2160     -1,
2161     options_access_protected,
2162     &custom_element.access_protected,
2163     NULL, NULL,                         "protected access for this field"
2164   },
2165   {
2166     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2167     GADGET_ID_CUSTOM_ACCESS_DIRECTION,  GADGET_ID_NONE,
2168     -1,
2169     options_access_direction,
2170     &custom_element.access_direction,
2171     "from", NULL,                       "access direction for this field"
2172   },
2173   {
2174     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
2175     GADGET_ID_CUSTOM_WALK_TO_ACTION,    GADGET_ID_NONE,
2176     -1,
2177     options_walk_to_action,
2178     &custom_element.walk_to_action,
2179     NULL, NULL,                         "diggable/collectible/pushable"
2180   },
2181
2182   /* ---------- element settings: configure 2 (custom elements) ------------ */
2183
2184   {
2185     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(1),
2186     GADGET_ID_CUSTOM_MOVE_PATTERN,      GADGET_ID_NONE,
2187     -1,
2188     options_move_pattern,
2189     &custom_element.move_pattern,
2190     "can move", NULL,                   "element move pattern"
2191   },
2192   {
2193     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2194     GADGET_ID_CUSTOM_MOVE_DIRECTION,    GADGET_ID_NONE,
2195     -1,
2196     options_move_direction,
2197     &custom_element.move_direction_initial,
2198     "starts moving", NULL,              "initial element move direction"
2199   },
2200   {
2201     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2202     GADGET_ID_CUSTOM_MOVE_STEPSIZE,     GADGET_ID_NONE,
2203     -1,
2204     options_move_stepsize,
2205     &custom_element.move_stepsize,
2206     "move/fall speed", NULL,            "speed of element movement"
2207   },
2208   {
2209     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2210     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,   GADGET_ID_NONE,
2211     -1,
2212     options_move_leave_type,
2213     &custom_element.move_leave_type,
2214     "can dig:    can", ":",             "leave behind or change element"
2215   },
2216   {
2217     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
2218     GADGET_ID_CUSTOM_SMASH_TARGETS,     GADGET_ID_CUSTOM_CAN_SMASH,
2219     -1,
2220     options_smash_targets,
2221     &custom_element.smash_targets,
2222     "can smash", NULL,                  "elements that can be smashed"
2223   },
2224   {
2225     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
2226     GADGET_ID_CUSTOM_SLIPPERY_TYPE,     GADGET_ID_NONE,
2227     -1,
2228     options_slippery_type,
2229     &custom_element.slippery_type,
2230     "slippery", NULL,                   "where other elements fall down"
2231   },
2232   {
2233     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
2234     GADGET_ID_CUSTOM_DEADLINESS,        GADGET_ID_NONE,
2235     -1,
2236     options_deadliness,
2237     &custom_element.deadliness,
2238     "deadly when", NULL,                "deadliness of element"
2239   },
2240   {
2241     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(10),
2242     GADGET_ID_CUSTOM_EXPLOSION_TYPE,    GADGET_ID_NONE,
2243     -1,
2244     options_explosion_type,
2245     &custom_element.explosion_type,
2246     "can explode", NULL,                "explosion type"
2247   },
2248
2249   /* ---------- element settings: advanced (custom elements) --------------- */
2250
2251   {
2252     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(3),
2253     GADGET_ID_CHANGE_TIME_UNITS,        GADGET_ID_NONE,
2254     -1,
2255     options_time_units,
2256     &custom_element_change.delay_frames,
2257     "delay time given in", NULL,        "delay time units for change"
2258   },
2259   {
2260     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(4),
2261     GADGET_ID_CHANGE_DIRECT_ACTION,     GADGET_ID_NONE,
2262     -1,
2263     options_change_direct_action,
2264     &custom_element_change.direct_action,
2265     NULL, NULL,                         "type of direct action"
2266   },
2267   {
2268     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(5),
2269     GADGET_ID_CHANGE_OTHER_ACTION,      GADGET_ID_NONE,
2270     -1,
2271     options_change_other_action,
2272     &custom_element_change.other_action,
2273     NULL, "element:",                   "type of other element action"
2274   },
2275   {
2276     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(6),
2277     GADGET_ID_CHANGE_SIDE,              GADGET_ID_NONE,
2278     -1,
2279     options_change_trigger_side,
2280     &custom_element_change.trigger_side,
2281     "at", "side",                       "element side triggering change"
2282   },
2283   {
2284     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2285     GADGET_ID_CHANGE_PLAYER,            GADGET_ID_NONE,
2286     -1,
2287     options_change_trigger_player,
2288     &custom_element_change.trigger_player,
2289     "player:", " ",                     "player that causes change"
2290   },
2291   {
2292     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2293     GADGET_ID_CHANGE_PAGE,              GADGET_ID_CHANGE_PLAYER,
2294     -1,
2295     options_change_trigger_page,
2296     &custom_element_change.trigger_page,
2297     "page:", NULL,                      "change page that causes change"
2298   },
2299   {
2300     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(10),
2301     GADGET_ID_CHANGE_REPLACE_WHEN,      GADGET_ID_NONE,
2302     -1,
2303     options_change_replace_when,
2304     &custom_element_change.replace_when,
2305     "replace when", NULL,               "which elements can be replaced"
2306   },
2307   {
2308     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
2309     GADGET_ID_ACTION_TYPE,              GADGET_ID_NONE,
2310     -1,
2311     options_action_type,
2312     &custom_element_change.action_type,
2313     NULL, NULL,                         "action on specified condition"
2314   },
2315   {
2316     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2317     GADGET_ID_ACTION_MODE,              GADGET_ID_ACTION_TYPE,
2318     -1,
2319     options_action_mode_none,
2320     &custom_element_change.action_mode,
2321     NULL, NULL,                         "action operator"
2322   },
2323   {
2324     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2325     GADGET_ID_ACTION_ARG,               GADGET_ID_ACTION_MODE,
2326     -1,
2327     options_action_arg_none,
2328     &custom_element_change.action_arg,
2329     NULL, NULL,                         "action parameter"
2330   },
2331   {
2332     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
2333     GADGET_ID_SELECT_CHANGE_PAGE,       GADGET_ID_NONE,
2334     3,
2335     options_change_page,
2336     &custom_element.current_change_page,
2337     NULL, NULL,                         "element change page"
2338   },
2339
2340   /* ---------- element settings: configure (group elements) --------------- */
2341
2342   {
2343     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
2344     GADGET_ID_GROUP_CHOICE_MODE,        GADGET_ID_NONE,
2345     -1,
2346     options_group_choice_mode,
2347     &group_element_info.choice_mode,
2348     "choice type:", NULL,               "type of group element choice"
2349   },
2350 };
2351
2352 static struct
2353 {
2354   int x, y;
2355   int gadget_id;
2356   int gadget_id_align;
2357   int size;
2358   char *text;
2359   char *text_left, *text_right, *infotext;
2360 } textbutton_info[ED_NUM_TEXTBUTTONS] =
2361 {
2362   {
2363     ED_LEVEL_SETTINGS_TABS_XPOS(0),     ED_LEVEL_SETTINGS_TABS_YPOS(0),
2364     GADGET_ID_LEVELINFO_LEVEL,          GADGET_ID_NONE,
2365     8,                                  "Level",                        
2366     NULL, NULL,                         "Configure level properties"
2367   },
2368   {
2369     ED_LEVEL_SETTINGS_TABS_XPOS(1),     ED_LEVEL_SETTINGS_TABS_YPOS(0),
2370     GADGET_ID_LEVELINFO_EDITOR,         GADGET_ID_NONE,
2371     8,                                  "Editor",                       
2372     NULL, NULL,                         "Configure editor properties"
2373   },
2374   {
2375     ED_ELEMENT_SETTINGS_TABS_XPOS(0),   ED_ELEMENT_SETTINGS_TABS_YPOS(0),
2376     GADGET_ID_PROPERTIES_INFO,          GADGET_ID_NONE,
2377     8,                                  "Info",                 
2378     NULL, NULL,                         "Show information about element"
2379   },
2380   {
2381     ED_ELEMENT_SETTINGS_TABS_XPOS(1),   ED_ELEMENT_SETTINGS_TABS_YPOS(0),
2382     GADGET_ID_PROPERTIES_CONFIG,        GADGET_ID_NONE,
2383     8,                                  "Config",
2384     NULL, NULL,                         "Configure element properties"
2385   },
2386   {
2387     ED_ELEMENT_SETTINGS_TABS_XPOS(1),   ED_ELEMENT_SETTINGS_TABS_YPOS(0),
2388     GADGET_ID_PROPERTIES_CONFIG_1,      GADGET_ID_NONE,
2389     8,                                  "Config 1",
2390     NULL, NULL,                         "Configure element properties, part 1"
2391   },
2392   {
2393     ED_ELEMENT_SETTINGS_TABS_XPOS(2),   ED_ELEMENT_SETTINGS_TABS_YPOS(0),
2394     GADGET_ID_PROPERTIES_CONFIG_2,      GADGET_ID_NONE,
2395     8,                                  "Config 2",
2396     NULL, NULL,                         "Configure element properties, part 2"
2397   },
2398   {
2399     ED_ELEMENT_SETTINGS_TABS_XPOS(3),   ED_ELEMENT_SETTINGS_TABS_YPOS(0),
2400     GADGET_ID_PROPERTIES_CHANGE,        GADGET_ID_NONE,
2401     8,                                  "Change",
2402     NULL, NULL,                         "Configure custom element change pages"
2403   },
2404   {
2405     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2406     GADGET_ID_SAVE_AS_TEMPLATE,         GADGET_ID_CUSTOM_USE_TEMPLATE,
2407     -1,                                 "Save",
2408     " ", "As Template",                 "Save current settings as new template"
2409   },
2410   {
2411     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2412     GADGET_ID_ADD_CHANGE_PAGE,          GADGET_ID_PASTE_CHANGE_PAGE,
2413     -1,                                 "New",
2414     NULL, NULL,                         "Add new change page"
2415   },
2416   {
2417     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2418     GADGET_ID_DEL_CHANGE_PAGE,          GADGET_ID_ADD_CHANGE_PAGE,
2419     -1,                                 "Delete",
2420     NULL, NULL,                         "Delete current change page"
2421   },
2422 };
2423
2424 static struct
2425 {
2426   int gd_x, gd_y;
2427   int x, y;
2428   int width, height;
2429   int gadget_id;
2430   int gadget_id_align;
2431   char *text_left, *text_right, *infotext;
2432 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
2433 {
2434   {
2435     ED_BUTTON_MINUS_XPOS,               ED_BUTTON_COUNT_YPOS,
2436     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
2437     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
2438     GADGET_ID_PREV_CHANGE_PAGE,         GADGET_ID_NONE,
2439     NULL, NULL,                         "select previous change page"
2440   },
2441   {
2442     ED_BUTTON_PLUS_XPOS,                ED_BUTTON_COUNT_YPOS,
2443     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2444     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
2445     GADGET_ID_NEXT_CHANGE_PAGE,         GADGET_ID_SELECT_CHANGE_PAGE,
2446     NULL, "change page",                "select next change page"
2447   },
2448   {
2449     ED_COPY_CHANGE_PAGE_XPOS,           ED_COPY_CHANGE_PAGE_YPOS,
2450     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2451     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
2452     GADGET_ID_COPY_CHANGE_PAGE,         GADGET_ID_NEXT_CHANGE_PAGE,
2453     " ", NULL,                          "copy settings from this change page"
2454   },
2455   {
2456     ED_PASTE_CHANGE_PAGE_XPOS,          ED_PASTE_CHANGE_PAGE_YPOS,
2457     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2458     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
2459     GADGET_ID_PASTE_CHANGE_PAGE,        GADGET_ID_COPY_CHANGE_PAGE,
2460     NULL, NULL,                         "paste settings to this change page"
2461   },
2462 };
2463
2464 static struct
2465 {
2466   int gd_x, gd_y;
2467   int x, y;
2468   int gadget_id;
2469   char *infotext;
2470 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
2471 {
2472   {
2473     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
2474     ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,
2475     GADGET_ID_SCROLL_UP,
2476     "scroll level editing area up"
2477   },
2478   {
2479     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
2480     ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,
2481     GADGET_ID_SCROLL_DOWN,
2482     "scroll level editing area down"
2483   },
2484   {
2485     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
2486     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
2487     GADGET_ID_SCROLL_LEFT,
2488     "scroll level editing area left"
2489   },
2490   {
2491     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
2492     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
2493     GADGET_ID_SCROLL_RIGHT,
2494     "scroll level editing area right"
2495   },
2496   {
2497     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 0 * ED_SCROLLBUTTON2_YSIZE,
2498     ED_SCROLL2_UP_XPOS,     ED_SCROLL2_UP_YPOS,
2499     GADGET_ID_SCROLL_LIST_UP,
2500     "scroll element list up ('Page Up')"
2501   },
2502   {
2503     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE,
2504     ED_SCROLL2_DOWN_XPOS,   ED_SCROLL2_DOWN_YPOS,
2505     GADGET_ID_SCROLL_LIST_DOWN,
2506     "scroll element list down ('Page Down')"
2507   },
2508 };
2509
2510 static struct
2511 {
2512   int gd_x, gd_y;
2513   int x, y;
2514   int width, height;
2515   int wheel_x, wheel_y;
2516   int wheel_width, wheel_height;
2517   int type;
2518   int gadget_id;
2519   char *infotext;
2520 } scrollbar_info[ED_NUM_SCROLLBARS] =
2521 {
2522   {
2523     ED_SCROLLBAR_XPOS,                  ED_SCROLLBAR_YPOS,
2524     SX + ED_SCROLL_HORIZONTAL_XPOS,     SY + ED_SCROLL_HORIZONTAL_YPOS,
2525     ED_SCROLL_HORIZONTAL_XSIZE,         ED_SCROLL_HORIZONTAL_YSIZE,
2526 #if 1
2527     SX,                                 SY,
2528     SXSIZE,                             SYSIZE,
2529 #else
2530     0,                                  0,
2531     SX + SXSIZE + SX,                   WIN_YSIZE,
2532 #endif
2533     GD_TYPE_SCROLLBAR_HORIZONTAL,
2534     GADGET_ID_SCROLL_HORIZONTAL,
2535     "scroll level editing area horizontally"
2536   },
2537   {
2538     ED_SCROLLBAR_XPOS,                  ED_SCROLLBAR_YPOS,
2539     SX + ED_SCROLL_VERTICAL_XPOS,       SY + ED_SCROLL_VERTICAL_YPOS,
2540     ED_SCROLL_VERTICAL_XSIZE,           ED_SCROLL_VERTICAL_YSIZE,
2541 #if 1
2542     SX,                                 SY,
2543     SXSIZE,                             SYSIZE,
2544 #else
2545     0,                                  0,
2546     SX + SXSIZE + SX,                   WIN_YSIZE,
2547 #endif
2548     GD_TYPE_SCROLLBAR_VERTICAL,
2549     GADGET_ID_SCROLL_VERTICAL,
2550     "scroll level editing area vertically"
2551   },
2552   {
2553     ED_SCROLLBAR2_XPOS,                 ED_SCROLLBAR2_YPOS,
2554     DX + ED_SCROLL2_VERTICAL_XPOS,      DY + ED_SCROLL2_VERTICAL_YPOS,
2555     ED_SCROLL2_VERTICAL_XSIZE,          ED_SCROLL2_VERTICAL_YSIZE,
2556 #if 1
2557     DX,                                 DY,
2558     DXSIZE,                             DYSIZE,
2559 #else
2560     SX + SXSIZE + SX,                   0,
2561     WIN_XSIZE - (SX + SXSIZE + SX),     WIN_YSIZE,
2562 #endif
2563     GD_TYPE_SCROLLBAR_VERTICAL,
2564     GADGET_ID_SCROLL_LIST_VERTICAL,
2565     "scroll element list vertically"
2566   }
2567 };
2568
2569 static struct
2570 {
2571   int x, y;
2572   int gadget_id;
2573   int gadget_id_align;
2574   int radio_button_nr;
2575   int *value;
2576   int checked_value;
2577   char *text_left, *text_right, *infotext;
2578 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
2579 {
2580   {
2581     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
2582     GADGET_ID_RANDOM_PERCENTAGE,        GADGET_ID_LEVEL_RANDOM_UP,
2583     RADIO_NR_RANDOM_ELEMENTS,
2584     &random_placement_method,           RANDOM_USE_PERCENTAGE,
2585     " ", "percentage",                  "use percentage for random elements"
2586   },
2587   {
2588     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
2589     GADGET_ID_RANDOM_QUANTITY,          GADGET_ID_RANDOM_PERCENTAGE,
2590     RADIO_NR_RANDOM_ELEMENTS,
2591     &random_placement_method,           RANDOM_USE_QUANTITY,
2592     " ", "quantity",                    "use quantity for random elements"
2593   }
2594 };
2595
2596 static struct
2597 {
2598   int x, y;
2599   int gadget_id;
2600   int gadget_id_align;
2601   boolean *value;
2602   char *text_left, *text_right, *infotext;
2603 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
2604 {
2605   /* ---------- level and editor settings ---------------------------------- */
2606
2607   {
2608     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(1),
2609     GADGET_ID_RANDOM_RESTRICTED,        GADGET_ID_NONE,
2610     &random_placement_background_restricted,
2611     NULL,
2612     "restrict random placement to:",    "set random placement restriction"
2613   },
2614
2615   /* ---------- element settings: configure (various elements) ------------- */
2616
2617   {
2618     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2619     GADGET_ID_STICK_ELEMENT,            GADGET_ID_NONE,
2620     &stick_element_properties_window,
2621     NULL,
2622     "stick this screen to edit content","stick this screen to edit content"
2623   },
2624   {
2625     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2626     GADGET_ID_EM_SLIPPERY_GEMS,         GADGET_ID_NONE,
2627     &level.em_slippery_gems,
2628     NULL,
2629     "slip down from certain flat walls","use EM/DC style slipping behaviour"
2630   },
2631   {
2632     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2633     GADGET_ID_EM_EXPLODES_BY_FIRE,      GADGET_ID_NONE,
2634     &level.em_explodes_by_fire,
2635     NULL,
2636     "explodes with chain reaction",     "use R'n'D style explosion behaviour"
2637   },
2638   {
2639     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2640     GADGET_ID_USE_SPRING_BUG,           GADGET_ID_NONE,
2641     &level.use_spring_bug,
2642     NULL,
2643     "use spring pushing bug",           "use odd spring pushing behaviour"
2644   },
2645   {
2646     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2647     GADGET_ID_USE_TIME_ORB_BUG,         GADGET_ID_NONE,
2648     &level.use_time_orb_bug,
2649     NULL,
2650     "use time orb bug",                 "use odd time orb behaviour"
2651   },
2652   {
2653     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2654     GADGET_ID_RANDOM_BALL_CONTENT,      GADGET_ID_NONE,
2655     &level.ball_random,
2656     NULL,
2657     "create single random element",     "only create one element from content"
2658   },
2659   {
2660     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2661     GADGET_ID_INITIAL_BALL_STATE,       GADGET_ID_NONE,
2662     &level.ball_state_initial,
2663     NULL,
2664     "magic ball initially activated",   "activate magic ball after level start"
2665   },
2666   {
2667     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2668     GADGET_ID_GROW_INTO_DIGGABLE,       GADGET_ID_NONE,
2669     &level.grow_into_diggable,
2670     NULL,
2671     "can grow into anything diggable",  "grow into more than just sand"
2672   },
2673   {
2674     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
2675     GADGET_ID_CONTINUOUS_SNAPPING,      GADGET_ID_NONE,
2676     &level.continuous_snapping,
2677     NULL,
2678     "continuos snapping",               "use snapping without releasing key"
2679   },
2680   {
2681     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
2682     GADGET_ID_BLOCK_SNAP_FIELD,         GADGET_ID_NONE,
2683     &level.block_snap_field,
2684     NULL,
2685     "block snapped field when snapping", "use snapping delay to show animation"
2686   },
2687   {
2688     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2689     GADGET_ID_BLOCK_LAST_FIELD,         GADGET_ID_NONE,
2690     &level.block_last_field,
2691     NULL,
2692     "block last field when moving",     "player blocks last field when moving"
2693   },
2694   {
2695     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2696     GADGET_ID_SP_BLOCK_LAST_FIELD,      GADGET_ID_NONE,
2697     &level.sp_block_last_field,
2698     NULL,
2699     "block last field when moving",     "player blocks last field when moving"
2700   },
2701   {
2702     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
2703     GADGET_ID_INSTANT_RELOCATION,       GADGET_ID_NONE,
2704     &level.instant_relocation,
2705     NULL,
2706     "no scrolling when relocating",     "player gets relocated without delay"
2707   },
2708   {
2709     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2710     GADGET_ID_SHIFTED_RELOCATION,       GADGET_ID_NONE,
2711     &level.shifted_relocation,
2712     NULL,
2713     "no centering when relocating",     "level not centered after relocation"
2714   },
2715   {
2716     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
2717     GADGET_ID_USE_START_ELEMENT,        GADGET_ID_NONE,
2718     &level.use_start_element[0],
2719     NULL,
2720     "use level start element:",        "start level at this element's position"
2721   },
2722   {
2723     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
2724     GADGET_ID_USE_ARTWORK_ELEMENT,      GADGET_ID_NONE,
2725     &level.use_artwork_element[0],
2726     NULL,
2727     "use artwork from element:",        "use player artwork from other element"
2728   },
2729   {
2730     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
2731     GADGET_ID_USE_EXPLOSION_ELEMENT,    GADGET_ID_NONE,
2732     &level.use_explosion_element[0],
2733     NULL,
2734     "use explosion from element:",      "use explosion properties from element"
2735   },
2736   {
2737     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
2738     GADGET_ID_INITIAL_GRAVITY,          GADGET_ID_NONE,
2739     &level.initial_player_gravity[0],
2740     NULL,
2741     "use initial gravity",              "set initial player gravity"
2742   },
2743   {
2744     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2745     GADGET_ID_USE_INITIAL_INVENTORY,    GADGET_ID_NONE,
2746     &level.use_initial_inventory[0],
2747     NULL,
2748     "use initial inventory:",           "use collected elements on level start"
2749   },
2750   {
2751     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
2752     GADGET_ID_CAN_PASS_TO_WALKABLE,     GADGET_ID_NONE,
2753     &level.can_pass_to_walkable,
2754     NULL,
2755     "can pass to walkable element",     "player can pass to empty or walkable"
2756   },
2757   {
2758     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2759     GADGET_ID_CAN_FALL_INTO_ACID,       GADGET_ID_NONE,
2760     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
2761     NULL,
2762     "can fall into acid (with gravity)","player can fall into acid pool"
2763   },
2764   {
2765     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2766     GADGET_ID_CAN_MOVE_INTO_ACID,       GADGET_ID_NONE,
2767     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
2768     NULL,
2769     "can move into acid",               "element can move into acid pool"
2770   },
2771   {
2772     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2773     GADGET_ID_DONT_COLLIDE_WITH,        GADGET_ID_NONE,
2774     &custom_element_properties[EP_DONT_COLLIDE_WITH],
2775     NULL,
2776     "deadly when colliding with",       "element is deadly when hitting player"
2777   },
2778   {
2779     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2780     GADGET_ID_ENVELOPE_AUTOWRAP,        GADGET_ID_NONE,
2781     &level.envelope[0].autowrap,
2782     NULL,
2783     "auto-wrap",                        "automatically wrap envelope text"
2784   },
2785   {
2786     -1,                                 ED_ELEMENT_SETTINGS_YPOS(1),
2787     GADGET_ID_ENVELOPE_CENTERED,        GADGET_ID_ENVELOPE_AUTOWRAP,
2788     &level.envelope[0].centered,
2789     " ",
2790     "centered",                         "automatically center envelope text"
2791   },
2792
2793   /* ---------- element settings: configure 1 (custom elements) ----------- */
2794
2795   {
2796     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2797     GADGET_ID_CUSTOM_USE_GRAPHIC,       GADGET_ID_NONE,
2798     &custom_element.use_gfx_element,
2799
2800     /* !!! add separate "use existing element sound" !!! */
2801 #if 0
2802     NULL,
2803     "use graphic/sound of element:",    "use existing graphic and sound"
2804 #else
2805     NULL,
2806     "use graphic of element:",          "use existing element graphic"
2807 #endif
2808   },
2809   {
2810     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2811     GADGET_ID_CUSTOM_USE_TEMPLATE,      GADGET_ID_NONE,
2812     &level.use_custom_template,
2813     NULL,
2814     "use template",                     "use template for custom properties"
2815   },
2816   {
2817     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
2818     GADGET_ID_CUSTOM_ACCESSIBLE,        GADGET_ID_NONE,
2819     &custom_element_properties[EP_ACCESSIBLE],
2820     NULL,
2821     NULL,                               "player can walk to or pass this field"
2822   },
2823   {
2824     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
2825     GADGET_ID_CUSTOM_GRAV_REACHABLE,    GADGET_ID_NONE,
2826     &custom_element_properties[EP_GRAVITY_REACHABLE],
2827     NULL,
2828     "reachable despite gravity",        "player can walk/dig despite gravity"
2829   },
2830   {
2831     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
2832     GADGET_ID_CUSTOM_USE_LAST_VALUE,    GADGET_ID_NONE,
2833     &custom_element.use_last_ce_value,
2834     NULL,
2835     "use last CE value after change",   "use last CE value after change"
2836   },
2837   {
2838     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
2839     GADGET_ID_CUSTOM_WALK_TO_OBJECT,    GADGET_ID_NONE,
2840     &custom_element_properties[EP_WALK_TO_OBJECT],
2841     NULL,
2842     NULL,                               "player can dig/collect/push element"
2843   },
2844   {
2845     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
2846     GADGET_ID_CUSTOM_INDESTRUCTIBLE,    GADGET_ID_NONE,
2847     &custom_element_properties[EP_INDESTRUCTIBLE],
2848     NULL,
2849     "indestructible",                   "element is indestructible"
2850   },
2851
2852   /* ---------- element settings: configure 2 (custom elements) ----------- */
2853
2854   {
2855     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2856     GADGET_ID_CUSTOM_CAN_MOVE,          GADGET_ID_NONE,
2857     &custom_element_properties[EP_CAN_MOVE],
2858     NULL,
2859     NULL,                               "element can move with some pattern"
2860   },
2861   {
2862     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
2863     GADGET_ID_CUSTOM_CAN_FALL,          GADGET_ID_NONE,
2864     &custom_element_properties[EP_CAN_FALL],
2865     NULL,
2866     "can fall",                         "element can fall down"
2867   },
2868   {
2869     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
2870     GADGET_ID_CUSTOM_CAN_SMASH,         GADGET_ID_CUSTOM_CAN_FALL,
2871     &custom_element_properties[EP_CAN_SMASH],
2872     " ",
2873     NULL,                               "element can smash other elements"
2874   },
2875   {
2876     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
2877     GADGET_ID_CUSTOM_SLIPPERY,          GADGET_ID_NONE,
2878     &custom_element_properties[EP_SLIPPERY],
2879     NULL,
2880     NULL,                               "other elements can fall down from it"
2881   },
2882   {
2883     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
2884     GADGET_ID_CUSTOM_DEADLY,            GADGET_ID_NONE,
2885     &custom_element_properties[EP_DEADLY],
2886     NULL,
2887     NULL,                               "element can kill the player"
2888   },
2889   {
2890     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
2891     GADGET_ID_CUSTOM_CAN_EXPLODE,       GADGET_ID_NONE,
2892     &custom_element_properties[EP_CAN_EXPLODE],
2893     NULL,
2894     NULL,                               "element can explode"
2895   },
2896   {
2897     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(11),
2898     GADGET_ID_CUSTOM_EXPLODE_FIRE,      GADGET_ID_NONE,
2899     &custom_element_properties[EP_EXPLODES_BY_FIRE],
2900     NULL,
2901     "by fire",                          "element can explode by fire/explosion"
2902   },
2903   {
2904     -1,                                 ED_ELEMENT_SETTINGS_YPOS(11),
2905     GADGET_ID_CUSTOM_EXPLODE_SMASH,     GADGET_ID_CUSTOM_EXPLODE_FIRE,
2906     &custom_element_properties[EP_EXPLODES_SMASHED],
2907     " ",
2908     "smashed",                          "element can explode when smashed"
2909   },
2910   {
2911     -1,                                 ED_ELEMENT_SETTINGS_YPOS(11),
2912     GADGET_ID_CUSTOM_EXPLODE_IMPACT,    GADGET_ID_CUSTOM_EXPLODE_SMASH,
2913     &custom_element_properties[EP_EXPLODES_IMPACT],
2914     " ",
2915     "impact",                           "element can explode on impact"
2916   },
2917
2918   /* ---------- element settings: advanced (custom elements) --------------- */
2919
2920   {
2921     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2922     GADGET_ID_CUSTOM_CAN_CHANGE,        GADGET_ID_NONE,
2923     &custom_element_change.can_change,
2924     NULL,
2925     "element changes to:",              "change element on specified condition"
2926   },
2927   {
2928     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2929     GADGET_ID_CHANGE_DELAY,             GADGET_ID_NONE,
2930     &custom_element_change_events[CE_DELAY],
2931     NULL,
2932     NULL,                               "element changes after delay"
2933   },
2934   {
2935     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2936     GADGET_ID_CHANGE_BY_DIRECT_ACT,     GADGET_ID_NONE,
2937     &custom_element_change_events[CE_BY_DIRECT_ACTION],
2938     NULL,
2939     NULL,                               "element changes by direct action"
2940   },
2941   {
2942     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
2943     GADGET_ID_CHANGE_BY_OTHER_ACT,      GADGET_ID_NONE,
2944     &custom_element_change_events[CE_BY_OTHER_ACTION],
2945     NULL,
2946     NULL,                               "element changes by other element"
2947   },
2948   {
2949     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
2950     GADGET_ID_CHANGE_USE_EXPLOSION,     GADGET_ID_NONE,
2951     &custom_element_change.explode,
2952     NULL,
2953     "explode instead of change",        "element explodes instead of change"
2954   },
2955   {
2956     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
2957     GADGET_ID_CHANGE_USE_CONTENT,       GADGET_ID_NONE,
2958     &custom_element_change.use_target_content,
2959     NULL,
2960     "use extended change target:",      "element changes to more elements"
2961   },
2962   {
2963     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(11),
2964     GADGET_ID_CHANGE_ONLY_COMPLETE,     GADGET_ID_NONE,
2965     &custom_element_change.only_if_complete,
2966     NULL,
2967     "replace all or nothing",           "only replace when all can be changed"
2968   },
2969   {
2970     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(12),
2971     GADGET_ID_CHANGE_USE_RANDOM,        GADGET_ID_NONE,
2972     &custom_element_change.use_random_replace,
2973     NULL,
2974     NULL,                               "use percentage for random replace"
2975   },
2976   {
2977     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
2978     GADGET_ID_CHANGE_HAS_ACTION,        GADGET_ID_NONE,
2979     &custom_element_change.has_action,
2980     NULL,
2981     NULL,                               "execute action on specified condition"
2982   },
2983 };
2984
2985 static struct
2986 {
2987   int x, y;
2988   int gadget_id;
2989   int gadget_id_align;
2990   int *value;
2991   int area_xsize, area_ysize;
2992   char *text_left, *text_right, *text_below, *infotext;
2993 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
2994 {
2995   /* ---------- level playfield content ------------------------------------ */
2996
2997   {
2998     0,                                  0,
2999     GADGET_ID_DRAWING_LEVEL,            GADGET_ID_NONE,
3000     NULL,                               MAX_ED_FIELDX, MAX_ED_FIELDY,
3001     NULL, NULL, NULL,                   NULL
3002   },
3003
3004   /* ---------- yam yam content -------------------------------------------- */
3005
3006   {
3007     ED_AREA_YAMYAM_CONTENT_XPOS(0),     ED_AREA_YAMYAM_CONTENT_YPOS(0),
3008     GADGET_ID_YAMYAM_CONTENT_0,         GADGET_ID_NONE,
3009     &level.yamyam_content[0].e[0][0],   3, 3,
3010     NULL, NULL, "1",                    NULL
3011   },
3012   {
3013     ED_AREA_YAMYAM_CONTENT_XPOS(1),     ED_AREA_YAMYAM_CONTENT_YPOS(1),
3014     GADGET_ID_YAMYAM_CONTENT_1,         GADGET_ID_NONE,
3015     &level.yamyam_content[1].e[0][0],   3, 3,
3016     NULL, NULL, "2",                    NULL
3017   },
3018   {
3019     ED_AREA_YAMYAM_CONTENT_XPOS(2),     ED_AREA_YAMYAM_CONTENT_YPOS(2),
3020     GADGET_ID_YAMYAM_CONTENT_2,         GADGET_ID_NONE,
3021     &level.yamyam_content[2].e[0][0],   3, 3,
3022     NULL, NULL, "3",                    NULL
3023   },
3024   {
3025     ED_AREA_YAMYAM_CONTENT_XPOS(3),     ED_AREA_YAMYAM_CONTENT_YPOS(3),
3026     GADGET_ID_YAMYAM_CONTENT_3,         GADGET_ID_NONE,
3027     &level.yamyam_content[3].e[0][0],   3, 3,
3028     NULL, NULL, "4",                    NULL
3029   },
3030   {
3031     ED_AREA_YAMYAM_CONTENT_XPOS(4),     ED_AREA_YAMYAM_CONTENT_YPOS(4),
3032     GADGET_ID_YAMYAM_CONTENT_4,         GADGET_ID_NONE,
3033     &level.yamyam_content[4].e[0][0],   3, 3,
3034     NULL, NULL, "5",                    NULL
3035   },
3036   {
3037     ED_AREA_YAMYAM_CONTENT_XPOS(5),     ED_AREA_YAMYAM_CONTENT_YPOS(5),
3038     GADGET_ID_YAMYAM_CONTENT_5,         GADGET_ID_NONE,
3039     &level.yamyam_content[5].e[0][0],   3, 3,
3040     NULL, NULL, "6",                    NULL
3041   },
3042   {
3043     ED_AREA_YAMYAM_CONTENT_XPOS(6),     ED_AREA_YAMYAM_CONTENT_YPOS(6),
3044     GADGET_ID_YAMYAM_CONTENT_6,         GADGET_ID_NONE,
3045     &level.yamyam_content[6].e[0][0],   3, 3,
3046     NULL, NULL, "7",                    NULL
3047   },
3048   {
3049     ED_AREA_YAMYAM_CONTENT_XPOS(7),     ED_AREA_YAMYAM_CONTENT_YPOS(7),
3050     GADGET_ID_YAMYAM_CONTENT_7,         GADGET_ID_NONE,
3051     &level.yamyam_content[7].e[0][0],   3, 3,
3052     NULL, NULL, "8",                    NULL
3053   },
3054
3055   /* ---------- magic ball content ----------------------------------------- */
3056
3057   {
3058     ED_AREA_MAGIC_BALL_CONTENT_XPOS(0), ED_AREA_MAGIC_BALL_CONTENT_YPOS(0),
3059     GADGET_ID_MAGIC_BALL_CONTENT_0,     GADGET_ID_NONE,
3060     &level.ball_content[0].e[0][0],     3, 3,
3061     NULL, NULL, "1",                    NULL
3062   },
3063   {
3064     ED_AREA_MAGIC_BALL_CONTENT_XPOS(1), ED_AREA_MAGIC_BALL_CONTENT_YPOS(1),
3065     GADGET_ID_MAGIC_BALL_CONTENT_1,     GADGET_ID_NONE,
3066     &level.ball_content[1].e[0][0],     3, 3,
3067     NULL, NULL, "2",                    NULL
3068   },
3069   {
3070     ED_AREA_MAGIC_BALL_CONTENT_XPOS(2), ED_AREA_MAGIC_BALL_CONTENT_YPOS(2),
3071     GADGET_ID_MAGIC_BALL_CONTENT_2,     GADGET_ID_NONE,
3072     &level.ball_content[2].e[0][0],     3, 3,
3073     NULL, NULL, "3",                    NULL
3074   },
3075   {
3076     ED_AREA_MAGIC_BALL_CONTENT_XPOS(3), ED_AREA_MAGIC_BALL_CONTENT_YPOS(3),
3077     GADGET_ID_MAGIC_BALL_CONTENT_3,     GADGET_ID_NONE,
3078     &level.ball_content[3].e[0][0],     3, 3,
3079     NULL, NULL, "4",                    NULL
3080   },
3081   {
3082     ED_AREA_MAGIC_BALL_CONTENT_XPOS(4), ED_AREA_MAGIC_BALL_CONTENT_YPOS(4),
3083     GADGET_ID_MAGIC_BALL_CONTENT_4,     GADGET_ID_NONE,
3084     &level.ball_content[4].e[0][0],     3, 3,
3085     NULL, NULL, "5",                    NULL
3086   },
3087   {
3088     ED_AREA_MAGIC_BALL_CONTENT_XPOS(5), ED_AREA_MAGIC_BALL_CONTENT_YPOS(5),
3089     GADGET_ID_MAGIC_BALL_CONTENT_5,     GADGET_ID_NONE,
3090     &level.ball_content[5].e[0][0],     3, 3,
3091     NULL, NULL, "6",                    NULL
3092   },
3093   {
3094     ED_AREA_MAGIC_BALL_CONTENT_XPOS(6), ED_AREA_MAGIC_BALL_CONTENT_YPOS(6),
3095     GADGET_ID_MAGIC_BALL_CONTENT_6,     GADGET_ID_NONE,
3096     &level.ball_content[6].e[0][0],     3, 3,
3097     NULL, NULL, "7",                    NULL
3098   },
3099   {
3100     ED_AREA_MAGIC_BALL_CONTENT_XPOS(7), ED_AREA_MAGIC_BALL_CONTENT_YPOS(7),
3101     GADGET_ID_MAGIC_BALL_CONTENT_7,     GADGET_ID_NONE,
3102     &level.ball_content[7].e[0][0],     3, 3,
3103     NULL, NULL, "8",                    NULL
3104   },
3105
3106   /* ---------- android content -------------------------------------------- */
3107
3108   {
3109     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
3110     GADGET_ID_ANDROID_CONTENT,          GADGET_ID_NONE,
3111     &level.android_clone_element[0],    MAX_ANDROID_ELEMENTS, 1,
3112     "elements:", NULL, NULL,            "elements android can clone"
3113   },
3114
3115   /* ---------- amoeba content --------------------------------------------- */
3116
3117   {
3118     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(3),
3119     GADGET_ID_AMOEBA_CONTENT,           GADGET_ID_NONE,
3120     &level.amoeba_content,              1, 1,
3121     "content:", NULL, NULL,             "amoeba content"
3122   },
3123
3124   /* ---------- level start element ---------------------------------------- */
3125
3126   {
3127     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(9),
3128     GADGET_ID_START_ELEMENT,            GADGET_ID_USE_START_ELEMENT,
3129     &level.start_element[0],            1, 1,
3130     NULL, NULL, NULL,                   "level start element"
3131   },
3132
3133   /* ---------- player artwork element ------------------------------------- */
3134
3135   {
3136     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(10),
3137     GADGET_ID_ARTWORK_ELEMENT,          GADGET_ID_USE_ARTWORK_ELEMENT,
3138     &level.artwork_element[0],          1, 1,
3139     NULL, NULL, NULL,                   "element for player artwork"
3140   },
3141
3142   /* ---------- player explosion element ----------------------------------- */
3143
3144   {
3145     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(11),
3146     GADGET_ID_EXPLOSION_ELEMENT,        GADGET_ID_USE_EXPLOSION_ELEMENT,
3147     &level.explosion_element[0],        1, 1,
3148     NULL, NULL, NULL,                   "element for player explosion"
3149   },
3150
3151   /* ---------- player initial inventory ----------------------------------- */
3152
3153   {
3154     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3155     GADGET_ID_INVENTORY_CONTENT,        GADGET_ID_USE_INITIAL_INVENTORY,
3156     &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
3157     NULL, NULL, NULL,                   "content for initial inventory"
3158   },
3159
3160   /* ---------- element settings: configure 1 (custom elements) ----------- */
3161
3162   /* ---------- custom graphic --------------------------------------------- */
3163
3164   {
3165     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3166     GADGET_ID_CUSTOM_GRAPHIC,           GADGET_ID_CUSTOM_USE_GRAPHIC,
3167     &custom_element.gfx_element_initial,1, 1,
3168     NULL, NULL, NULL,                   "custom graphic element"
3169   },
3170
3171   /* ---------- element settings: configure 2 (custom elements) ----------- */
3172
3173   /* ---------- custom content (when exploding) ---------------------------- */
3174
3175   {
3176     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(10),
3177     GADGET_ID_CUSTOM_CONTENT,           GADGET_ID_NONE, /* align three rows */
3178     &custom_element.content.e[0][0],    3, 3,
3179     "content:", NULL, NULL,             NULL
3180   },
3181
3182   /* ---------- custom enter and leave element (when moving) --------------- */
3183
3184   {
3185     ED_AREA_1X1_SETTINGS_XPOS(1),       ED_AREA_1X1_SETTINGS_YPOS(3),
3186     GADGET_ID_CUSTOM_MOVE_ENTER,        GADGET_ID_NONE,
3187     &custom_element.move_enter_element, 1, 1,
3188     "can dig:", " ", NULL,              "element that can be digged/collected"
3189   },
3190   {
3191     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(3),
3192     GADGET_ID_CUSTOM_MOVE_LEAVE,        GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
3193     &custom_element.move_leave_element, 1, 1,
3194     NULL, NULL, NULL,                   "element that will be left behind"
3195   },
3196
3197   /* ---------- element settings: advanced (custom elements) --------------- */
3198
3199   /* ---------- custom change target --------------------------------------- */
3200
3201   {
3202     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3203     GADGET_ID_CUSTOM_CHANGE_TARGET,     GADGET_ID_CUSTOM_CAN_CHANGE,
3204     &custom_element_change.target_element, 1, 1,
3205     NULL, "after/when:", NULL,          "new target element after change"
3206   },
3207
3208   /* ---------- custom change content (extended change target) ------------- */
3209
3210   {
3211     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(9),
3212     GADGET_ID_CUSTOM_CHANGE_CONTENT,    GADGET_ID_NONE, /* align three rows */
3213     &custom_element_change.target_content.e[0][0], 3, 3,
3214     NULL, NULL, NULL,                   "new extended elements after change"
3215   },
3216
3217   /* ---------- custom change trigger (element causing change) ------------- */
3218
3219   {
3220     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(5),
3221     GADGET_ID_CUSTOM_CHANGE_TRIGGER,    GADGET_ID_CHANGE_OTHER_ACTION,
3222     &custom_element_change.initial_trigger_element, 1, 1,
3223     NULL, NULL, NULL,                   "other element triggering change"
3224   },
3225
3226   /* ---------- custom change action (element used for action) ------------- */
3227
3228   {
3229     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(13),
3230     GADGET_ID_CUSTOM_CHANGE_ACTION,     GADGET_ID_ACTION_ARG,
3231     &custom_element_change.action_element, 1, 1,
3232     NULL, NULL, NULL,                   "element used as action parameter"
3233   },
3234
3235   /* ---------- group element content -------------------------------------- */
3236
3237   {
3238     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(4),
3239     GADGET_ID_GROUP_CONTENT,            GADGET_ID_NONE,
3240     &group_element_info.element[0],     MAX_ELEMENTS_IN_GROUP, 1,
3241     "content:", NULL, NULL,             NULL
3242   },
3243
3244   /* ---------- random background (for random painting) -------------------- */
3245
3246   {
3247     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(-1),
3248     GADGET_ID_RANDOM_BACKGROUND,        GADGET_ID_RANDOM_RESTRICTED,
3249     &random_placement_background_element, 1, 1,
3250     NULL, NULL, NULL,                   "random placement background"
3251   },
3252 };
3253
3254
3255 /*
3256   -----------------------------------------------------------------------------
3257   some internally used variables
3258   -----------------------------------------------------------------------------
3259 */
3260
3261 /* actual size of level editor drawing area */
3262 static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
3263
3264 /* actual position of level editor drawing area in level playfield */
3265 static int level_xpos = -1, level_ypos = -1;
3266
3267 #if 1
3268 #define IN_ED_FIELD(x,y)        IN_FIELD(x, y, ed_fieldx, ed_fieldy)
3269 #else
3270 #define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldy)
3271 #endif
3272
3273 /* drawing elements on the three mouse buttons */
3274 static int new_element1 = EL_WALL;
3275 static int new_element2 = EL_EMPTY;
3276 static int new_element3 = EL_SAND;
3277
3278 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
3279 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
3280                                 (button) == 2 ? new_element2 : \
3281                                 (button) == 3 ? new_element3 : EL_EMPTY)
3282 #define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10)
3283
3284 /* forward declaration for internal use */
3285 static void ModifyEditorCounterValue(int, int);
3286 static void ModifyEditorCounterLimits(int, int, int);
3287 static void ModifyEditorSelectboxValue(int, int);
3288 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
3289 static void ModifyEditorDrawingArea(int, int, int);
3290 static void ModifyEditorElementList();
3291 static void AdjustElementListScrollbar();
3292 static void RedrawDrawingElements();
3293 static void DrawDrawingWindow();
3294 static void DrawLevelInfoWindow();
3295 static void DrawPropertiesWindow();
3296 static void UpdateCustomElementGraphicGadgets();
3297 static boolean checkPropertiesConfig(int);
3298 static void CopyLevelToUndoBuffer(int);
3299 static void HandleDrawingAreas(struct GadgetInfo *);
3300 static void HandleCounterButtons(struct GadgetInfo *);
3301 static void HandleTextInputGadgets(struct GadgetInfo *);
3302 static void HandleTextAreaGadgets(struct GadgetInfo *);
3303 static void HandleSelectboxGadgets(struct GadgetInfo *);
3304 static void HandleTextbuttonGadgets(struct GadgetInfo *);
3305 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
3306 static void HandleRadiobuttons(struct GadgetInfo *);
3307 static void HandleCheckbuttons(struct GadgetInfo *);
3308 static void HandleControlButtons(struct GadgetInfo *);
3309 static void HandleDrawingAreaInfo(struct GadgetInfo *);
3310 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
3311
3312 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
3313 static int right_gadget_border[NUM_EDITOR_GADGETS];
3314
3315 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
3316 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
3317 static boolean draw_with_brush = FALSE;
3318 static int properties_element = 0;
3319
3320 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3321 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3322 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3323 static int undo_buffer_position = 0;
3324 static int undo_buffer_steps = 0;
3325
3326 static int edit_mode;
3327 static int edit_mode_levelinfo;
3328 static int edit_mode_properties;
3329
3330 static int element_shift = 0;
3331
3332 static int editor_el_players[] =
3333 {
3334   EL_PLAYER_1,
3335   EL_PLAYER_2,
3336   EL_PLAYER_3,
3337   EL_PLAYER_4
3338 };
3339 static int *editor_el_players_ptr = editor_el_players;
3340 static int num_editor_el_players = SIZEOF_ARRAY_INT(editor_el_players);
3341
3342 static int editor_hl_boulderdash[] =
3343 {
3344   EL_INTERNAL_CASCADE_BD_ACTIVE,
3345   EL_CHAR('B'),
3346   EL_CHAR('D'),
3347   EL_EMPTY,
3348 };
3349
3350 static int editor_el_boulderdash[] =
3351 {
3352   EL_EMPTY,
3353   EL_SAND,
3354   EL_BD_ROCK,
3355   EL_BD_DIAMOND,
3356
3357   EL_STEELWALL,
3358   EL_BD_WALL,
3359   EL_BD_EXPANDABLE_WALL,
3360   EL_BD_MAGIC_WALL,
3361
3362   EL_BD_AMOEBA,
3363   EL_BD_BUTTERFLY_UP,
3364   EL_BD_FIREFLY_UP,
3365   EL_EXIT_CLOSED,
3366
3367   EL_BD_BUTTERFLY_LEFT,
3368   EL_BD_FIREFLY_LEFT,
3369   EL_BD_BUTTERFLY_RIGHT,
3370   EL_BD_FIREFLY_RIGHT,
3371
3372   EL_EMPTY,
3373   EL_BD_BUTTERFLY_DOWN,
3374   EL_BD_FIREFLY_DOWN,
3375   EL_EXIT_OPEN,
3376 };
3377 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
3378 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
3379 static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash);
3380 static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash);
3381
3382 static int editor_hl_emerald_mine[] =
3383 {
3384   EL_INTERNAL_CASCADE_EM_ACTIVE,
3385   EL_CHAR('E'),
3386   EL_CHAR('M'),
3387   EL_EMPTY,
3388 };
3389
3390 static int editor_el_emerald_mine[] =
3391 {
3392   EL_SAND,
3393   EL_ROCK,
3394   EL_QUICKSAND_EMPTY,
3395   EL_QUICKSAND_FULL,
3396
3397   EL_STEELWALL,
3398   EL_WALL,
3399   EL_WALL_SLIPPERY,
3400   EL_MAGIC_WALL,
3401
3402   EL_EMERALD,
3403   EL_DIAMOND,
3404   EL_NUT,
3405   EL_BOMB,
3406
3407   EL_WALL_EMERALD,
3408   EL_WALL_DIAMOND,
3409   EL_DYNAMITE,
3410   EL_DYNAMITE_ACTIVE,
3411
3412   EL_YAMYAM,
3413   EL_BUG_UP,
3414   EL_SPACESHIP_UP,
3415   EL_ROBOT,
3416
3417   EL_BUG_LEFT,
3418   EL_SPACESHIP_LEFT,
3419   EL_BUG_RIGHT,
3420   EL_SPACESHIP_RIGHT,
3421
3422   EL_ROBOT_WHEEL,
3423   EL_BUG_DOWN,
3424   EL_SPACESHIP_DOWN,
3425   EL_INVISIBLE_WALL,
3426
3427   EL_ACID_POOL_TOPLEFT,
3428   EL_ACID,
3429   EL_ACID_POOL_TOPRIGHT,
3430   EL_AMOEBA_DROP,
3431
3432   EL_ACID_POOL_BOTTOMLEFT,
3433   EL_ACID_POOL_BOTTOM,
3434   EL_ACID_POOL_BOTTOMRIGHT,
3435   EL_AMOEBA_WET,
3436
3437   EL_EM_KEY_1,
3438   EL_EM_KEY_2,
3439   EL_EM_KEY_3,
3440   EL_EM_KEY_4,
3441
3442   EL_EM_GATE_1,
3443   EL_EM_GATE_2,
3444   EL_EM_GATE_3,
3445   EL_EM_GATE_4,
3446
3447   EL_EM_GATE_1_GRAY,
3448   EL_EM_GATE_2_GRAY,
3449   EL_EM_GATE_3_GRAY,
3450   EL_EM_GATE_4_GRAY,
3451
3452   EL_EM_EXIT_CLOSED,
3453   EL_EM_EXIT_OPEN,
3454   EL_EM_STEEL_EXIT_CLOSED,
3455   EL_EM_STEEL_EXIT_OPEN,
3456 };
3457 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
3458 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
3459 static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine);
3460 static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine);
3461
3462 static int editor_hl_emerald_mine_club[] =
3463 {
3464   EL_INTERNAL_CASCADE_EMC_ACTIVE,
3465   EL_CHAR('E'),
3466   EL_CHAR('M'),
3467   EL_CHAR('C'),
3468 };
3469
3470 static int editor_el_emerald_mine_club[] =
3471 {
3472   EL_EMC_KEY_5,
3473   EL_EMC_KEY_6,
3474   EL_EMC_KEY_7,
3475   EL_EMC_KEY_8,
3476
3477   EL_EMC_GATE_5,
3478   EL_EMC_GATE_6,
3479   EL_EMC_GATE_7,
3480   EL_EMC_GATE_8,
3481
3482   EL_EMC_GATE_5_GRAY,
3483   EL_EMC_GATE_6_GRAY,
3484   EL_EMC_GATE_7_GRAY,
3485   EL_EMC_GATE_8_GRAY,
3486
3487   EL_EMC_STEELWALL_1,
3488   EL_EMC_STEELWALL_2,
3489   EL_EMC_STEELWALL_3,
3490   EL_EMC_STEELWALL_4,
3491
3492   EL_EMC_WALL_13,
3493   EL_EMC_WALL_14,
3494   EL_EMC_WALL_15,
3495   EL_EMC_WALL_16,
3496
3497   EL_EMC_WALL_SLIPPERY_1,
3498   EL_EMC_WALL_SLIPPERY_2,
3499   EL_EMC_WALL_SLIPPERY_3,
3500   EL_EMC_WALL_SLIPPERY_4,
3501
3502   EL_EMC_WALL_1,
3503   EL_EMC_WALL_2,
3504   EL_EMC_WALL_3,
3505   EL_EMC_WALL_4,
3506
3507   EL_EMC_WALL_5,
3508   EL_EMC_WALL_6,
3509   EL_EMC_WALL_7,
3510   EL_EMC_WALL_8,
3511
3512   EL_EMC_WALL_9,
3513   EL_EMC_WALL_10,
3514   EL_EMC_WALL_11,
3515   EL_EMC_WALL_12,
3516
3517   EL_EMC_GRASS,
3518   EL_EMC_FAKE_GRASS,
3519   EL_EMC_PLANT,
3520   EL_EMC_DRIPPER,
3521
3522   EL_EMC_MAGIC_BALL,
3523   EL_EMC_MAGIC_BALL_SWITCH,
3524   EL_SPRING,
3525   EL_EMC_SPRING_BUMPER,
3526
3527   EL_EMC_LENSES,
3528   EL_EMC_MAGNIFIER,
3529   EL_EM_DYNAMITE,
3530   EL_EM_DYNAMITE_ACTIVE,
3531
3532   EL_BALLOON,
3533   EL_YAMYAM_UP,
3534   EL_BALLOON_SWITCH_UP,
3535   EL_BALLOON_SWITCH_ANY,
3536
3537   EL_YAMYAM_LEFT,
3538   EL_BALLOON_SWITCH_LEFT,
3539   EL_YAMYAM_RIGHT,
3540   EL_BALLOON_SWITCH_RIGHT,
3541
3542   EL_EMC_ANDROID,
3543   EL_YAMYAM_DOWN,
3544   EL_BALLOON_SWITCH_DOWN,
3545   EL_BALLOON_SWITCH_NONE,
3546 };
3547 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
3548 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
3549 static int num_editor_hl_emerald_mine_club=SIZEOF_ARRAY_INT(editor_hl_emerald_mine_club);
3550 static int num_editor_el_emerald_mine_club=SIZEOF_ARRAY_INT(editor_el_emerald_mine_club);
3551
3552 static int editor_hl_rnd[] =
3553 {
3554   EL_INTERNAL_CASCADE_RND_ACTIVE,
3555   EL_CHAR('R'),
3556   EL_CHAR('N'),
3557   EL_CHAR('D'),
3558 };
3559
3560 static int editor_el_rnd[] =
3561 {
3562   EL_KEY_1,
3563   EL_KEY_2,
3564   EL_KEY_3,
3565   EL_KEY_4,
3566
3567   EL_GATE_1,
3568   EL_GATE_2,
3569   EL_GATE_3,
3570   EL_GATE_4,
3571
3572   EL_GATE_1_GRAY,
3573   EL_GATE_2_GRAY,
3574   EL_GATE_3_GRAY,
3575   EL_GATE_4_GRAY,
3576
3577   EL_ARROW_LEFT,
3578   EL_ARROW_RIGHT,
3579   EL_ARROW_UP,
3580   EL_ARROW_DOWN,
3581
3582   EL_AMOEBA_DEAD,
3583   EL_AMOEBA_DRY,
3584   EL_AMOEBA_FULL,
3585   EL_GAME_OF_LIFE,
3586
3587   EL_EMERALD_YELLOW,
3588   EL_EMERALD_RED,
3589   EL_EMERALD_PURPLE,
3590   EL_BIOMAZE,
3591
3592   EL_WALL_EMERALD_YELLOW,
3593   EL_WALL_EMERALD_RED,
3594   EL_WALL_EMERALD_PURPLE,
3595   EL_WALL_BD_DIAMOND,
3596
3597   EL_SPEED_PILL,
3598   EL_PACMAN_UP,
3599   EL_TIME_ORB_FULL,
3600   EL_TIME_ORB_EMPTY,
3601
3602   EL_PACMAN_LEFT,
3603   EL_DARK_YAMYAM,
3604   EL_PACMAN_RIGHT,
3605   EL_EMPTY,
3606
3607   EL_BLACK_ORB,
3608   EL_PACMAN_DOWN,
3609   EL_LAMP,
3610   EL_LAMP_ACTIVE,
3611
3612   EL_DYNABOMB_INCREASE_NUMBER,
3613   EL_DYNABOMB_INCREASE_SIZE,
3614   EL_DYNABOMB_INCREASE_POWER,
3615   EL_STONEBLOCK,
3616
3617   EL_MOLE,
3618   EL_PENGUIN,
3619   EL_PIG,
3620   EL_DRAGON,
3621
3622   EL_BUG,
3623   EL_MOLE_UP,
3624   EL_BD_BUTTERFLY,
3625   EL_BD_FIREFLY,
3626
3627   EL_MOLE_LEFT,
3628   EL_SATELLITE,
3629   EL_MOLE_RIGHT,
3630   EL_PACMAN,
3631
3632   EL_SPACESHIP,
3633   EL_MOLE_DOWN,
3634   EL_INVISIBLE_STEELWALL,
3635   EL_INVISIBLE_WALL,
3636
3637   EL_EXPANDABLE_WALL,
3638   EL_EXPANDABLE_WALL_HORIZONTAL,
3639   EL_EXPANDABLE_WALL_VERTICAL,
3640   EL_EXPANDABLE_WALL_ANY,
3641 };
3642 static int *editor_hl_rnd_ptr = editor_hl_rnd;
3643 static int *editor_el_rnd_ptr = editor_el_rnd;
3644 static int num_editor_hl_rnd = SIZEOF_ARRAY_INT(editor_hl_rnd);
3645 static int num_editor_el_rnd = SIZEOF_ARRAY_INT(editor_el_rnd);
3646
3647 static int editor_hl_sokoban[] =
3648 {
3649   EL_INTERNAL_CASCADE_SB_ACTIVE,
3650   EL_CHAR('S'),
3651   EL_CHAR('B'),
3652   EL_EMPTY,
3653 };
3654
3655 static int editor_el_sokoban[] =
3656 {
3657   EL_SOKOBAN_OBJECT,
3658   EL_SOKOBAN_FIELD_EMPTY,
3659   EL_SOKOBAN_FIELD_FULL,
3660   EL_SOKOBAN_FIELD_PLAYER,
3661 };
3662 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
3663 static int *editor_el_sokoban_ptr = editor_el_sokoban;
3664 static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban);
3665 static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban);
3666
3667 static int editor_hl_supaplex[] =
3668 {
3669   EL_INTERNAL_CASCADE_SP_ACTIVE,
3670   EL_CHAR('S'),
3671   EL_CHAR('P'),
3672   EL_EMPTY,
3673 };
3674
3675 static int editor_el_supaplex[] =
3676 {
3677   EL_SP_MURPHY,
3678   EL_EMPTY,
3679   EL_SP_BASE,
3680   EL_SP_BUGGY_BASE,
3681
3682   EL_SP_INFOTRON,
3683   EL_SP_ZONK,
3684   EL_SP_SNIKSNAK,
3685   EL_SP_ELECTRON,
3686
3687   EL_SP_DISK_RED,
3688   EL_SP_DISK_ORANGE,
3689   EL_SP_DISK_YELLOW,
3690   EL_SP_TERMINAL,
3691
3692   EL_SP_EXIT_CLOSED,
3693   EL_SP_PORT_HORIZONTAL,
3694   EL_SP_PORT_VERTICAL,
3695   EL_SP_PORT_ANY,
3696
3697   EL_SP_PORT_LEFT,
3698   EL_SP_PORT_RIGHT,
3699   EL_SP_PORT_UP,
3700   EL_SP_PORT_DOWN,
3701
3702   EL_SP_GRAVITY_PORT_LEFT,
3703   EL_SP_GRAVITY_PORT_RIGHT,
3704   EL_SP_GRAVITY_PORT_UP,
3705   EL_SP_GRAVITY_PORT_DOWN,
3706
3707   EL_SP_HARDWARE_GRAY,
3708   EL_SP_HARDWARE_GREEN,
3709   EL_SP_HARDWARE_BLUE,
3710   EL_SP_HARDWARE_RED,
3711
3712   EL_SP_HARDWARE_BASE_1,
3713   EL_SP_HARDWARE_BASE_2,
3714   EL_SP_HARDWARE_BASE_3,
3715   EL_SP_HARDWARE_BASE_4,
3716
3717   EL_SP_HARDWARE_BASE_5,
3718   EL_SP_HARDWARE_BASE_6,
3719   EL_SP_HARDWARE_YELLOW,
3720   EL_SP_CHIP_TOP,
3721
3722   EL_SP_CHIP_SINGLE,
3723   EL_SP_CHIP_LEFT,
3724   EL_SP_CHIP_RIGHT,
3725   EL_SP_CHIP_BOTTOM,
3726 };
3727 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
3728 static int *editor_el_supaplex_ptr = editor_el_supaplex;
3729 static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex);
3730 static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex);
3731
3732 static int editor_hl_diamond_caves[] =
3733 {
3734   EL_INTERNAL_CASCADE_DC_ACTIVE,
3735   EL_CHAR('D'),
3736   EL_CHAR('C'),
3737   EL_CHAR('2'),
3738 };
3739
3740 static int editor_el_diamond_caves[] =
3741 {
3742   EL_PEARL,
3743   EL_CRYSTAL,
3744   EL_WALL_PEARL,
3745   EL_WALL_CRYSTAL,
3746
3747   EL_CONVEYOR_BELT_1_LEFT,
3748   EL_CONVEYOR_BELT_1_MIDDLE,
3749   EL_CONVEYOR_BELT_1_RIGHT,
3750   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3751
3752   EL_CONVEYOR_BELT_2_LEFT,
3753   EL_CONVEYOR_BELT_2_MIDDLE,
3754   EL_CONVEYOR_BELT_2_RIGHT,
3755   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3756
3757   EL_CONVEYOR_BELT_3_LEFT,
3758   EL_CONVEYOR_BELT_3_MIDDLE,
3759   EL_CONVEYOR_BELT_3_RIGHT,
3760   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3761
3762   EL_CONVEYOR_BELT_4_LEFT,
3763   EL_CONVEYOR_BELT_4_MIDDLE,
3764   EL_CONVEYOR_BELT_4_RIGHT,
3765   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3766
3767   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3768   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3769   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3770   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3771
3772   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3773   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3774   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3775   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3776
3777   EL_TIMEGATE_CLOSED,
3778   EL_TIMEGATE_OPEN,
3779   EL_TIMEGATE_SWITCH,
3780   EL_DC_TIMEGATE_SWITCH,
3781
3782   EL_SWITCHGATE_CLOSED,
3783   EL_SWITCHGATE_OPEN,
3784   EL_SWITCHGATE_SWITCH_UP,
3785   EL_SWITCHGATE_SWITCH_DOWN,
3786
3787   EL_LIGHT_SWITCH,
3788   EL_LIGHT_SWITCH_ACTIVE,
3789   EL_DC_SWITCHGATE_SWITCH_UP,
3790   EL_DC_SWITCHGATE_SWITCH_DOWN,
3791
3792   EL_STEEL_EXIT_CLOSED,
3793   EL_STEEL_EXIT_OPEN,
3794   EL_STEELWALL_SLIPPERY,
3795   EL_INVISIBLE_SAND,
3796
3797   EL_QUICKSAND_FAST_EMPTY,
3798   EL_QUICKSAND_FAST_FULL,
3799   EL_LANDMINE,
3800   EL_DC_LANDMINE,
3801
3802   EL_SHIELD_NORMAL,
3803   EL_SHIELD_DEADLY,
3804   EL_EXTRA_TIME,
3805   EL_DC_MAGIC_WALL,
3806
3807   EL_ENVELOPE_1,
3808   EL_ENVELOPE_2,
3809   EL_ENVELOPE_3,
3810   EL_ENVELOPE_4,
3811
3812   EL_SIGN_RADIOACTIVITY,
3813   EL_SIGN_WHEELCHAIR,
3814   EL_SIGN_PARKING,
3815   EL_SIGN_NO_ENTRY,
3816
3817   EL_SIGN_GIVE_WAY,
3818   EL_SIGN_ENTRY_FORBIDDEN,
3819   EL_SIGN_EMERGENCY_EXIT,
3820   EL_SIGN_YIN_YANG,
3821
3822 #if 0
3823   EL_SIGN_SPERMS,
3824   EL_SIGN_BULLET,
3825   EL_SIGN_HEART,
3826   EL_SIGN_CROSS,
3827
3828   EL_SIGN_FRANKIE,
3829   EL_EMPTY,
3830   EL_EMPTY,
3831   EL_EMPTY,
3832
3833   EL_SPERMS,
3834   EL_BULLET,
3835   EL_HEART,
3836   EL_CROSS,
3837
3838   EL_FRANKIE,
3839   EL_EMPTY,
3840   EL_EMPTY,
3841   EL_EMPTY,
3842 #endif
3843
3844   EL_DC_STEELWALL_2_SINGLE,
3845   EL_DC_STEELWALL_2_TOP,
3846   EL_SIGN_EXCLAMATION,
3847   EL_SIGN_STOP,
3848
3849   EL_DC_STEELWALL_2_LEFT,
3850   EL_DC_STEELWALL_2_MIDDLE,
3851   EL_DC_STEELWALL_2_HORIZONTAL,
3852   EL_DC_STEELWALL_2_RIGHT,
3853
3854   EL_DC_STEELWALL_1_TOPLEFT,
3855   EL_DC_STEELWALL_2_VERTICAL,
3856   EL_DC_STEELWALL_1_TOPRIGHT,
3857   EL_DC_GATE_WHITE,
3858
3859   EL_DC_STEELWALL_1_VERTICAL,
3860   EL_DC_STEELWALL_2_BOTTOM,
3861   EL_DC_KEY_WHITE,
3862   EL_DC_GATE_WHITE_GRAY,
3863
3864   EL_DC_STEELWALL_1_BOTTOMLEFT,
3865   EL_DC_STEELWALL_1_HORIZONTAL,
3866   EL_DC_STEELWALL_1_BOTTOMRIGHT,
3867   EL_DC_GATE_FAKE_GRAY,
3868
3869   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3870   EL_DC_STEELWALL_1_BOTTOM,
3871   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3872   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3873
3874   EL_DC_STEELWALL_1_RIGHT,
3875   EL_EMPTY,
3876   EL_DC_STEELWALL_1_LEFT,
3877   EL_EXPANDABLE_STEELWALL_VERTICAL,
3878
3879   EL_DC_STEELWALL_1_TOPRIGHT_2,
3880   EL_DC_STEELWALL_1_TOP,
3881   EL_DC_STEELWALL_1_TOPLEFT_2,
3882   EL_EXPANDABLE_STEELWALL_ANY,
3883 };
3884 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
3885 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
3886 static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves);
3887 static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves);
3888
3889 static int editor_hl_dx_boulderdash[] =
3890 {
3891   EL_INTERNAL_CASCADE_DX_ACTIVE,
3892   EL_CHAR('D'),
3893   EL_CHAR('X'),
3894   EL_EMPTY,
3895 };
3896
3897 static int editor_el_dx_boulderdash[] =
3898 {
3899   EL_EMPTY,
3900   EL_TUBE_RIGHT_DOWN,
3901   EL_TUBE_HORIZONTAL_DOWN,
3902   EL_TUBE_LEFT_DOWN,
3903
3904   EL_TUBE_HORIZONTAL,
3905   EL_TUBE_VERTICAL_RIGHT,
3906   EL_TUBE_ANY,
3907   EL_TUBE_VERTICAL_LEFT,
3908
3909   EL_TUBE_VERTICAL,
3910   EL_TUBE_RIGHT_UP,
3911   EL_TUBE_HORIZONTAL_UP,
3912   EL_TUBE_LEFT_UP,
3913
3914   EL_TRAP,
3915   EL_DX_SUPABOMB,
3916   EL_EMPTY,
3917   EL_EMPTY
3918 };
3919 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
3920 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
3921 static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash);
3922 static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash);
3923
3924 static int editor_hl_chars[] =
3925 {
3926   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3927   EL_CHAR('T'),
3928   EL_CHAR('X'),
3929   EL_CHAR('T'),
3930 };
3931
3932 static int editor_el_chars[] =
3933 {
3934   EL_CHAR(' '),
3935   EL_CHAR('!'),
3936   EL_CHAR('"'),
3937   EL_CHAR('#'),
3938
3939   EL_CHAR('$'),
3940   EL_CHAR('%'),
3941   EL_CHAR('&'),
3942   EL_CHAR('\''),
3943
3944   EL_CHAR('('),
3945   EL_CHAR(')'),
3946   EL_CHAR('*'),
3947   EL_CHAR('+'),
3948
3949   EL_CHAR(','),
3950   EL_CHAR('-'),
3951   EL_CHAR('.'),
3952   EL_CHAR('/'),
3953
3954   EL_CHAR('0'),
3955   EL_CHAR('1'),
3956   EL_CHAR('2'),
3957   EL_CHAR('3'),
3958
3959   EL_CHAR('4'),
3960   EL_CHAR('5'),
3961   EL_CHAR('6'),
3962   EL_CHAR('7'),
3963
3964   EL_CHAR('8'),
3965   EL_CHAR('9'),
3966   EL_CHAR(':'),
3967   EL_CHAR(';'),
3968
3969   EL_CHAR('<'),
3970   EL_CHAR('='),
3971   EL_CHAR('>'),
3972   EL_CHAR('?'),
3973
3974   EL_CHAR('@'),
3975   EL_CHAR('A'),
3976   EL_CHAR('B'),
3977   EL_CHAR('C'),
3978
3979   EL_CHAR('D'),
3980   EL_CHAR('E'),
3981   EL_CHAR('F'),
3982   EL_CHAR('G'),
3983
3984   EL_CHAR('H'),
3985   EL_CHAR('I'),
3986   EL_CHAR('J'),
3987   EL_CHAR('K'),
3988
3989   EL_CHAR('L'),
3990   EL_CHAR('M'),
3991   EL_CHAR('N'),
3992   EL_CHAR('O'),
3993
3994   EL_CHAR('P'),
3995   EL_CHAR('Q'),
3996   EL_CHAR('R'),
3997   EL_CHAR('S'),
3998
3999   EL_CHAR('T'),
4000   EL_CHAR('U'),
4001   EL_CHAR('V'),
4002   EL_CHAR('W'),
4003
4004   EL_CHAR('X'),
4005   EL_CHAR('Y'),
4006   EL_CHAR('Z'),
4007   EL_CHAR('['),
4008
4009   EL_CHAR('\\'),
4010   EL_CHAR(']'),
4011   EL_CHAR('^'),
4012   EL_CHAR('_'),
4013
4014   EL_CHAR('©'),
4015   EL_CHAR('Ä'),
4016   EL_CHAR('Ö'),
4017   EL_CHAR('Ãœ'),
4018
4019   EL_CHAR('°'),
4020   EL_CHAR('®'),
4021   EL_CHAR(FONT_ASCII_CURSOR),
4022   EL_CHAR(FONT_ASCII_BUTTON),
4023
4024   EL_CHAR(FONT_ASCII_UP),
4025   EL_CHAR(FONT_ASCII_DOWN),
4026   EL_CHAR(' '),
4027   EL_CHAR(' ')
4028 };
4029 static int *editor_hl_chars_ptr = editor_hl_chars;
4030 static int *editor_el_chars_ptr = editor_el_chars;
4031 static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars);
4032 static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars);
4033
4034 static int editor_hl_steel_chars[] =
4035 {
4036   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4037   EL_STEEL_CHAR('T'),
4038   EL_STEEL_CHAR('X'),
4039   EL_STEEL_CHAR('T'),
4040 };
4041
4042 static int editor_el_steel_chars[] =
4043 {
4044   EL_STEEL_CHAR(' '),
4045   EL_STEEL_CHAR('!'),
4046   EL_STEEL_CHAR('"'),
4047   EL_STEEL_CHAR('#'),
4048
4049   EL_STEEL_CHAR('$'),
4050   EL_STEEL_CHAR('%'),
4051   EL_STEEL_CHAR('&'),
4052   EL_STEEL_CHAR('\''),
4053
4054   EL_STEEL_CHAR('('),
4055   EL_STEEL_CHAR(')'),
4056   EL_STEEL_CHAR('*'),
4057   EL_STEEL_CHAR('+'),
4058
4059   EL_STEEL_CHAR(','),
4060   EL_STEEL_CHAR('-'),
4061   EL_STEEL_CHAR('.'),
4062   EL_STEEL_CHAR('/'),
4063
4064   EL_STEEL_CHAR('0'),
4065   EL_STEEL_CHAR('1'),
4066   EL_STEEL_CHAR('2'),
4067   EL_STEEL_CHAR('3'),
4068
4069   EL_STEEL_CHAR('4'),
4070   EL_STEEL_CHAR('5'),
4071   EL_STEEL_CHAR('6'),
4072   EL_STEEL_CHAR('7'),
4073
4074   EL_STEEL_CHAR('8'),
4075   EL_STEEL_CHAR('9'),
4076   EL_STEEL_CHAR(':'),
4077   EL_STEEL_CHAR(';'),
4078
4079   EL_STEEL_CHAR('<'),
4080   EL_STEEL_CHAR('='),
4081   EL_STEEL_CHAR('>'),
4082   EL_STEEL_CHAR('?'),
4083
4084   EL_STEEL_CHAR('@'),
4085   EL_STEEL_CHAR('A'),
4086   EL_STEEL_CHAR('B'),
4087   EL_STEEL_CHAR('C'),
4088
4089   EL_STEEL_CHAR('D'),
4090   EL_STEEL_CHAR('E'),
4091   EL_STEEL_CHAR('F'),
4092   EL_STEEL_CHAR('G'),
4093
4094   EL_STEEL_CHAR('H'),
4095   EL_STEEL_CHAR('I'),
4096   EL_STEEL_CHAR('J'),
4097   EL_STEEL_CHAR('K'),
4098
4099   EL_STEEL_CHAR('L'),
4100   EL_STEEL_CHAR('M'),
4101   EL_STEEL_CHAR('N'),
4102   EL_STEEL_CHAR('O'),
4103
4104   EL_STEEL_CHAR('P'),
4105   EL_STEEL_CHAR('Q'),
4106   EL_STEEL_CHAR('R'),
4107   EL_STEEL_CHAR('S'),
4108
4109   EL_STEEL_CHAR('T'),
4110   EL_STEEL_CHAR('U'),
4111   EL_STEEL_CHAR('V'),
4112   EL_STEEL_CHAR('W'),
4113
4114   EL_STEEL_CHAR('X'),
4115   EL_STEEL_CHAR('Y'),
4116   EL_STEEL_CHAR('Z'),
4117   EL_STEEL_CHAR('['),
4118
4119   EL_STEEL_CHAR('\\'),
4120   EL_STEEL_CHAR(']'),
4121   EL_STEEL_CHAR('^'),
4122   EL_STEEL_CHAR('_'),
4123
4124   EL_STEEL_CHAR('©'),
4125   EL_STEEL_CHAR('Ä'),
4126   EL_STEEL_CHAR('Ö'),
4127   EL_STEEL_CHAR('Ãœ'),
4128
4129   EL_STEEL_CHAR('°'),
4130   EL_STEEL_CHAR('®'),
4131   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
4132   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
4133
4134   EL_STEEL_CHAR(FONT_ASCII_UP),
4135   EL_STEEL_CHAR(FONT_ASCII_DOWN),
4136   EL_STEEL_CHAR(' '),
4137   EL_STEEL_CHAR(' ')
4138 };
4139 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
4140 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
4141 static int num_editor_hl_steel_chars = SIZEOF_ARRAY_INT(editor_hl_steel_chars);
4142 static int num_editor_el_steel_chars = SIZEOF_ARRAY_INT(editor_el_steel_chars);
4143
4144 static int editor_hl_custom[] =
4145 {
4146   EL_INTERNAL_CASCADE_CE_ACTIVE,
4147   EL_CHAR('C'),
4148   EL_CHAR('E'),
4149   EL_EMPTY,
4150 };
4151
4152 static int editor_el_custom[] =
4153 {
4154   EL_CUSTOM_START + 0,
4155   EL_CUSTOM_START + 1,
4156   EL_CUSTOM_START + 2,
4157   EL_CUSTOM_START + 3,
4158
4159   EL_CUSTOM_START + 4,
4160   EL_CUSTOM_START + 5,
4161   EL_CUSTOM_START + 6,
4162   EL_CUSTOM_START + 7,
4163
4164   EL_CUSTOM_START + 8,
4165   EL_CUSTOM_START + 9,
4166   EL_CUSTOM_START + 10,
4167   EL_CUSTOM_START + 11,
4168
4169   EL_CUSTOM_START + 12,
4170   EL_CUSTOM_START + 13,
4171   EL_CUSTOM_START + 14,
4172   EL_CUSTOM_START + 15,
4173
4174   EL_CUSTOM_START + 16,
4175   EL_CUSTOM_START + 17,
4176   EL_CUSTOM_START + 18,
4177   EL_CUSTOM_START + 19,
4178
4179   EL_CUSTOM_START + 20,
4180   EL_CUSTOM_START + 21,
4181   EL_CUSTOM_START + 22,
4182   EL_CUSTOM_START + 23,
4183
4184   EL_CUSTOM_START + 24,
4185   EL_CUSTOM_START + 25,
4186   EL_CUSTOM_START + 26,
4187   EL_CUSTOM_START + 27,
4188
4189   EL_CUSTOM_START + 28,
4190   EL_CUSTOM_START + 29,
4191   EL_CUSTOM_START + 30,
4192   EL_CUSTOM_START + 31,
4193
4194   EL_CUSTOM_START + 32,
4195   EL_CUSTOM_START + 33,
4196   EL_CUSTOM_START + 34,
4197   EL_CUSTOM_START + 35,
4198
4199   EL_CUSTOM_START + 36,
4200   EL_CUSTOM_START + 37,
4201   EL_CUSTOM_START + 38,
4202   EL_CUSTOM_START + 39,
4203
4204   EL_CUSTOM_START + 40,
4205   EL_CUSTOM_START + 41,
4206   EL_CUSTOM_START + 42,
4207   EL_CUSTOM_START + 43,
4208
4209   EL_CUSTOM_START + 44,
4210   EL_CUSTOM_START + 45,
4211   EL_CUSTOM_START + 46,
4212   EL_CUSTOM_START + 47,
4213
4214   EL_CUSTOM_START + 48,
4215   EL_CUSTOM_START + 49,
4216   EL_CUSTOM_START + 50,
4217   EL_CUSTOM_START + 51,
4218
4219   EL_CUSTOM_START + 52,
4220   EL_CUSTOM_START + 53,
4221   EL_CUSTOM_START + 54,
4222   EL_CUSTOM_START + 55,
4223
4224   EL_CUSTOM_START + 56,
4225   EL_CUSTOM_START + 57,
4226   EL_CUSTOM_START + 58,
4227   EL_CUSTOM_START + 59,
4228
4229   EL_CUSTOM_START + 60,
4230   EL_CUSTOM_START + 61,
4231   EL_CUSTOM_START + 62,
4232   EL_CUSTOM_START + 63,
4233
4234   EL_CUSTOM_START + 64,
4235   EL_CUSTOM_START + 65,
4236   EL_CUSTOM_START + 66,
4237   EL_CUSTOM_START + 67,
4238
4239   EL_CUSTOM_START + 68,
4240   EL_CUSTOM_START + 69,
4241   EL_CUSTOM_START + 70,
4242   EL_CUSTOM_START + 71,
4243
4244   EL_CUSTOM_START + 72,
4245   EL_CUSTOM_START + 73,
4246   EL_CUSTOM_START + 74,
4247   EL_CUSTOM_START + 75,
4248
4249   EL_CUSTOM_START + 76,
4250   EL_CUSTOM_START + 77,
4251   EL_CUSTOM_START + 78,
4252   EL_CUSTOM_START + 79,
4253
4254   EL_CUSTOM_START + 80,
4255   EL_CUSTOM_START + 81,
4256   EL_CUSTOM_START + 82,
4257   EL_CUSTOM_START + 83,
4258
4259   EL_CUSTOM_START + 84,
4260   EL_CUSTOM_START + 85,
4261   EL_CUSTOM_START + 86,
4262   EL_CUSTOM_START + 87,
4263
4264   EL_CUSTOM_START + 88,
4265   EL_CUSTOM_START + 89,
4266   EL_CUSTOM_START + 90,
4267   EL_CUSTOM_START + 91,
4268
4269   EL_CUSTOM_START + 92,
4270   EL_CUSTOM_START + 93,
4271   EL_CUSTOM_START + 94,
4272   EL_CUSTOM_START + 95,
4273
4274   EL_CUSTOM_START + 96,
4275   EL_CUSTOM_START + 97,
4276   EL_CUSTOM_START + 98,
4277   EL_CUSTOM_START + 99,
4278
4279   EL_CUSTOM_START + 100,
4280   EL_CUSTOM_START + 101,
4281   EL_CUSTOM_START + 102,
4282   EL_CUSTOM_START + 103,
4283
4284   EL_CUSTOM_START + 104,
4285   EL_CUSTOM_START + 105,
4286   EL_CUSTOM_START + 106,
4287   EL_CUSTOM_START + 107,
4288
4289   EL_CUSTOM_START + 108,
4290   EL_CUSTOM_START + 109,
4291   EL_CUSTOM_START + 110,
4292   EL_CUSTOM_START + 111,
4293
4294   EL_CUSTOM_START + 112,
4295   EL_CUSTOM_START + 113,
4296   EL_CUSTOM_START + 114,
4297   EL_CUSTOM_START + 115,
4298
4299   EL_CUSTOM_START + 116,
4300   EL_CUSTOM_START + 117,
4301   EL_CUSTOM_START + 118,
4302   EL_CUSTOM_START + 119,
4303
4304   EL_CUSTOM_START + 120,
4305   EL_CUSTOM_START + 121,
4306   EL_CUSTOM_START + 122,
4307   EL_CUSTOM_START + 123,
4308
4309   EL_CUSTOM_START + 124,
4310   EL_CUSTOM_START + 125,
4311   EL_CUSTOM_START + 126,
4312   EL_CUSTOM_START + 127,
4313
4314   EL_CUSTOM_START + 128,
4315   EL_CUSTOM_START + 129,
4316   EL_CUSTOM_START + 130,
4317   EL_CUSTOM_START + 131,
4318
4319   EL_CUSTOM_START + 132,
4320   EL_CUSTOM_START + 133,
4321   EL_CUSTOM_START + 134,
4322   EL_CUSTOM_START + 135,
4323
4324   EL_CUSTOM_START + 136,
4325   EL_CUSTOM_START + 137,
4326   EL_CUSTOM_START + 138,
4327   EL_CUSTOM_START + 139,
4328
4329   EL_CUSTOM_START + 140,
4330   EL_CUSTOM_START + 141,
4331   EL_CUSTOM_START + 142,
4332   EL_CUSTOM_START + 143,
4333
4334   EL_CUSTOM_START + 144,
4335   EL_CUSTOM_START + 145,
4336   EL_CUSTOM_START + 146,
4337   EL_CUSTOM_START + 147,
4338
4339   EL_CUSTOM_START + 148,
4340   EL_CUSTOM_START + 149,
4341   EL_CUSTOM_START + 150,
4342   EL_CUSTOM_START + 151,
4343
4344   EL_CUSTOM_START + 152,
4345   EL_CUSTOM_START + 153,
4346   EL_CUSTOM_START + 154,
4347   EL_CUSTOM_START + 155,
4348
4349   EL_CUSTOM_START + 156,
4350   EL_CUSTOM_START + 157,
4351   EL_CUSTOM_START + 158,
4352   EL_CUSTOM_START + 159,
4353
4354   EL_CUSTOM_START + 160,
4355   EL_CUSTOM_START + 161,
4356   EL_CUSTOM_START + 162,
4357   EL_CUSTOM_START + 163,
4358
4359   EL_CUSTOM_START + 164,
4360   EL_CUSTOM_START + 165,
4361   EL_CUSTOM_START + 166,
4362   EL_CUSTOM_START + 167,
4363
4364   EL_CUSTOM_START + 168,
4365   EL_CUSTOM_START + 169,
4366   EL_CUSTOM_START + 170,
4367   EL_CUSTOM_START + 171,
4368
4369   EL_CUSTOM_START + 172,
4370   EL_CUSTOM_START + 173,
4371   EL_CUSTOM_START + 174,
4372   EL_CUSTOM_START + 175,
4373
4374   EL_CUSTOM_START + 176,
4375   EL_CUSTOM_START + 177,
4376   EL_CUSTOM_START + 178,
4377   EL_CUSTOM_START + 179,
4378
4379   EL_CUSTOM_START + 180,
4380   EL_CUSTOM_START + 181,
4381   EL_CUSTOM_START + 182,
4382   EL_CUSTOM_START + 183,
4383
4384   EL_CUSTOM_START + 184,
4385   EL_CUSTOM_START + 185,
4386   EL_CUSTOM_START + 186,
4387   EL_CUSTOM_START + 187,
4388
4389   EL_CUSTOM_START + 188,
4390   EL_CUSTOM_START + 189,
4391   EL_CUSTOM_START + 190,
4392   EL_CUSTOM_START + 191,
4393
4394   EL_CUSTOM_START + 192,
4395   EL_CUSTOM_START + 193,
4396   EL_CUSTOM_START + 194,
4397   EL_CUSTOM_START + 195,
4398
4399   EL_CUSTOM_START + 196,
4400   EL_CUSTOM_START + 197,
4401   EL_CUSTOM_START + 198,
4402   EL_CUSTOM_START + 199,
4403
4404   EL_CUSTOM_START + 200,
4405   EL_CUSTOM_START + 201,
4406   EL_CUSTOM_START + 202,
4407   EL_CUSTOM_START + 203,
4408
4409   EL_CUSTOM_START + 204,
4410   EL_CUSTOM_START + 205,
4411   EL_CUSTOM_START + 206,
4412   EL_CUSTOM_START + 207,
4413
4414   EL_CUSTOM_START + 208,
4415   EL_CUSTOM_START + 209,
4416   EL_CUSTOM_START + 210,
4417   EL_CUSTOM_START + 211,
4418
4419   EL_CUSTOM_START + 212,
4420   EL_CUSTOM_START + 213,
4421   EL_CUSTOM_START + 214,
4422   EL_CUSTOM_START + 215,
4423
4424   EL_CUSTOM_START + 216,
4425   EL_CUSTOM_START + 217,
4426   EL_CUSTOM_START + 218,
4427   EL_CUSTOM_START + 219,
4428
4429   EL_CUSTOM_START + 220,
4430   EL_CUSTOM_START + 221,
4431   EL_CUSTOM_START + 222,
4432   EL_CUSTOM_START + 223,
4433
4434   EL_CUSTOM_START + 224,
4435   EL_CUSTOM_START + 225,
4436   EL_CUSTOM_START + 226,
4437   EL_CUSTOM_START + 227,
4438
4439   EL_CUSTOM_START + 228,
4440   EL_CUSTOM_START + 229,
4441   EL_CUSTOM_START + 230,
4442   EL_CUSTOM_START + 231,
4443
4444   EL_CUSTOM_START + 232,
4445   EL_CUSTOM_START + 233,
4446   EL_CUSTOM_START + 234,
4447   EL_CUSTOM_START + 235,
4448
4449   EL_CUSTOM_START + 236,
4450   EL_CUSTOM_START + 237,
4451   EL_CUSTOM_START + 238,
4452   EL_CUSTOM_START + 239,
4453
4454   EL_CUSTOM_START + 240,
4455   EL_CUSTOM_START + 241,
4456   EL_CUSTOM_START + 242,
4457   EL_CUSTOM_START + 243,
4458
4459   EL_CUSTOM_START + 244,
4460   EL_CUSTOM_START + 245,
4461   EL_CUSTOM_START + 246,
4462   EL_CUSTOM_START + 247,
4463
4464   EL_CUSTOM_START + 248,
4465   EL_CUSTOM_START + 249,
4466   EL_CUSTOM_START + 250,
4467   EL_CUSTOM_START + 251,
4468
4469   EL_CUSTOM_START + 252,
4470   EL_CUSTOM_START + 253,
4471   EL_CUSTOM_START + 254,
4472   EL_CUSTOM_START + 255
4473 };
4474 static int *editor_hl_custom_ptr = editor_hl_custom;
4475 static int *editor_el_custom_ptr = editor_el_custom;
4476 static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom);
4477 static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
4478
4479 static int editor_hl_group[] =
4480 {
4481   EL_INTERNAL_CASCADE_GE_ACTIVE,
4482   EL_CHAR('G'),
4483   EL_CHAR('E'),
4484   EL_EMPTY,
4485 };
4486
4487 static int editor_el_group[] =
4488 {
4489   EL_GROUP_START + 0,
4490   EL_GROUP_START + 1,
4491   EL_GROUP_START + 2,
4492   EL_GROUP_START + 3,
4493
4494   EL_GROUP_START + 4,
4495   EL_GROUP_START + 5,
4496   EL_GROUP_START + 6,
4497   EL_GROUP_START + 7,
4498
4499   EL_GROUP_START + 8,
4500   EL_GROUP_START + 9,
4501   EL_GROUP_START + 10,
4502   EL_GROUP_START + 11,
4503
4504   EL_GROUP_START + 12,
4505   EL_GROUP_START + 13,
4506   EL_GROUP_START + 14,
4507   EL_GROUP_START + 15,
4508
4509   EL_GROUP_START + 16,
4510   EL_GROUP_START + 17,
4511   EL_GROUP_START + 18,
4512   EL_GROUP_START + 19,
4513
4514   EL_GROUP_START + 20,
4515   EL_GROUP_START + 21,
4516   EL_GROUP_START + 22,
4517   EL_GROUP_START + 23,
4518
4519   EL_GROUP_START + 24,
4520   EL_GROUP_START + 25,
4521   EL_GROUP_START + 26,
4522   EL_GROUP_START + 27,
4523
4524   EL_GROUP_START + 28,
4525   EL_GROUP_START + 29,
4526   EL_GROUP_START + 30,
4527   EL_GROUP_START + 31
4528 };
4529 static int *editor_hl_group_ptr = editor_hl_group;
4530 static int *editor_el_group_ptr = editor_el_group;
4531 static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
4532 static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
4533
4534 static int editor_hl_reference[] =
4535 {
4536   EL_INTERNAL_CASCADE_REF_ACTIVE,
4537   EL_CHAR('R'),
4538   EL_CHAR('E'),
4539   EL_CHAR('F')
4540 };
4541
4542 static int editor_el_reference[] =
4543 {
4544   EL_TRIGGER_PLAYER,
4545   EL_TRIGGER_ELEMENT,
4546   EL_TRIGGER_CE_VALUE,
4547   EL_TRIGGER_CE_SCORE,
4548
4549   EL_SELF,
4550   EL_ANY_ELEMENT,
4551   EL_CURRENT_CE_VALUE,
4552   EL_CURRENT_CE_SCORE,
4553
4554   EL_PREV_CE_8,
4555   EL_PREV_CE_7,
4556   EL_PREV_CE_6,
4557   EL_PREV_CE_5,
4558
4559   EL_PREV_CE_4,
4560   EL_PREV_CE_3,
4561   EL_PREV_CE_2,
4562   EL_PREV_CE_1,
4563
4564   EL_NEXT_CE_1,
4565   EL_NEXT_CE_2,
4566   EL_NEXT_CE_3,
4567   EL_NEXT_CE_4,
4568
4569   EL_NEXT_CE_5,
4570   EL_NEXT_CE_6,
4571   EL_NEXT_CE_7,
4572   EL_NEXT_CE_8,
4573 };
4574 static int *editor_hl_reference_ptr = editor_hl_reference;
4575 static int *editor_el_reference_ptr = editor_el_reference;
4576 static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference);
4577 static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference);
4578
4579 static int editor_hl_user_defined[] =
4580 {
4581   EL_INTERNAL_CASCADE_USER_ACTIVE,
4582   EL_CHAR('M'),
4583   EL_CHAR('Y'),
4584   EL_EMPTY,
4585 };
4586
4587 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
4588 static int *editor_el_user_defined_ptr = NULL;
4589 static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined);
4590 static int num_editor_el_user_defined = 0;
4591
4592 static int editor_hl_dynamic[] =
4593 {
4594   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4595   EL_CHAR('U'),
4596   EL_CHAR('S'),
4597   EL_CHAR('E'),
4598 };
4599
4600 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
4601 static int *editor_el_dynamic_ptr = NULL;
4602 static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic);
4603 static int num_editor_el_dynamic = 0;
4604
4605 static int editor_hl_empty[] = { };
4606 static int editor_el_empty[ED_NUM_ELEMENTLIST_BUTTONS];
4607
4608 static int *editor_hl_empty_ptr = editor_hl_empty;
4609 static int *editor_el_empty_ptr = editor_el_empty;
4610 static int num_editor_hl_empty = 0;
4611 static int num_editor_el_empty = 0;     /* dynamically determined, if needed */
4612
4613 static boolean use_el_empty = FALSE;
4614
4615 static int *editor_elements = NULL;     /* dynamically allocated */
4616 static int num_editor_elements = 0;     /* dynamically determined */
4617
4618 static boolean setup_editor_show_always = TRUE;
4619 static boolean setup_editor_cascade_never = FALSE;
4620
4621 static int editor_hl_unused[] = { EL_EMPTY };
4622 static int *editor_hl_unused_ptr = editor_hl_unused;
4623 static int num_editor_hl_unused = 0;
4624
4625 static struct
4626 {
4627   boolean *setup_value;
4628   boolean *setup_cascade_value;
4629
4630   int **headline_list;
4631   int *headline_list_size;
4632
4633   int **element_list;
4634   int *element_list_size;
4635
4636   boolean last_setup_value;
4637 }
4638 editor_elements_info[] =
4639 {
4640   {
4641     &setup_editor_show_always,
4642     &setup_editor_cascade_never,
4643     &editor_hl_unused_ptr,              &num_editor_hl_unused,
4644     &editor_el_players_ptr,             &num_editor_el_players
4645   },
4646   {
4647     &setup.editor.el_boulderdash,
4648     &setup.editor_cascade.el_bd,
4649     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
4650     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
4651   },
4652   {
4653     &setup.editor.el_emerald_mine,
4654     &setup.editor_cascade.el_em,
4655     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
4656     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
4657   },
4658   {
4659     &setup.editor.el_emerald_mine_club,
4660     &setup.editor_cascade.el_emc,
4661     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
4662     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
4663   },
4664   {
4665     &setup.editor.el_more,
4666     &setup.editor_cascade.el_rnd,
4667     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
4668     &editor_el_rnd_ptr,                 &num_editor_el_rnd
4669   },
4670   {
4671     &setup.editor.el_sokoban,
4672     &setup.editor_cascade.el_sb,
4673     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
4674     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
4675   },
4676   {
4677     &setup.editor.el_supaplex,
4678     &setup.editor_cascade.el_sp,
4679     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
4680     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
4681   },
4682   {
4683     &setup.editor.el_diamond_caves,
4684     &setup.editor_cascade.el_dc,
4685     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
4686     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
4687   },
4688   {
4689     &setup.editor.el_dx_boulderdash,
4690     &setup.editor_cascade.el_dx,
4691     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
4692     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
4693   },
4694   {
4695     &setup.editor.el_chars,
4696     &setup.editor_cascade.el_chars,
4697     &editor_hl_chars_ptr,               &num_editor_hl_chars,
4698     &editor_el_chars_ptr,               &num_editor_el_chars
4699   },
4700   {
4701     &setup.editor.el_steel_chars,
4702     &setup.editor_cascade.el_steel_chars,
4703     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
4704     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
4705   },
4706   {
4707     &setup.editor.el_custom,
4708     &setup.editor_cascade.el_ce,
4709     &editor_hl_custom_ptr,              &num_editor_hl_custom,
4710     &editor_el_custom_ptr,              &num_editor_el_custom
4711   },
4712   {
4713     &setup.editor.el_custom,
4714     &setup.editor_cascade.el_ge,
4715     &editor_hl_group_ptr,               &num_editor_hl_group,
4716     &editor_el_group_ptr,               &num_editor_el_group
4717   },
4718   {
4719     &setup.editor.el_custom,
4720     &setup.editor_cascade.el_ref,
4721     &editor_hl_reference_ptr,           &num_editor_hl_reference,
4722     &editor_el_reference_ptr,           &num_editor_el_reference
4723   },
4724   {
4725     &setup.editor.el_user_defined,
4726     &setup.editor_cascade.el_user,
4727     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
4728     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
4729   },
4730   {
4731     &setup.editor.el_dynamic,
4732     &setup.editor_cascade.el_dynamic,
4733     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
4734     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
4735   },
4736   {
4737     &use_el_empty,
4738     &use_el_empty,
4739     &editor_hl_empty_ptr,               &num_editor_hl_empty,
4740     &editor_el_empty_ptr,               &num_editor_el_empty,
4741   },
4742   {
4743     NULL,
4744     NULL,
4745     NULL,                               NULL,
4746     NULL,                               NULL
4747   }
4748 };
4749
4750
4751 /*
4752   -----------------------------------------------------------------------------
4753   functions
4754   -----------------------------------------------------------------------------
4755 */
4756
4757 static int getMaxInfoTextLength()
4758 {
4759   return (SXSIZE / getFontWidth(FONT_TEXT_2));
4760 }
4761
4762 static int getTextWidthForGadget(char *text)
4763 {
4764   if (text == NULL)
4765     return 0;
4766
4767   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
4768 }
4769
4770 static int getTextWidthForDrawingArea(char *text)
4771 {
4772   if (text == NULL)
4773     return 0;
4774
4775   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
4776 }
4777
4778 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
4779 {
4780   return (gi->x + gi->width + getTextWidthForGadget(text));
4781 }
4782
4783 static char *getElementInfoText(int element)
4784 {
4785   char *info_text = NULL;
4786
4787   if (element < MAX_NUM_ELEMENTS)
4788   {
4789     if (strlen(element_info[element].description) > 0)
4790       info_text = element_info[element].description;
4791     else if (element_info[element].custom_description != NULL)
4792       info_text = element_info[element].custom_description;
4793     else if (element_info[element].editor_description != NULL)
4794       info_text = element_info[element].editor_description;
4795   }
4796
4797   if (info_text == NULL)
4798     info_text = INFOTEXT_UNKNOWN_ELEMENT;
4799
4800   return info_text;
4801 }
4802
4803 char *getElementDescriptionFilename(int element)
4804 {
4805   char *docs_dir = options.docs_directory;
4806   char *elements_subdir = "elements";
4807   static char *filename = NULL;
4808   char basename[MAX_FILENAME_LEN];
4809
4810   checked_free(filename);
4811
4812   /* 1st try: look for element description file for exactly this element */
4813   sprintf(basename, "%s.txt", element_info[element].token_name);
4814   filename = getPath3(docs_dir, elements_subdir, basename);
4815   if (fileExists(filename))
4816     return filename;
4817
4818   free(filename);
4819
4820   /* 2nd try: look for element description file for this element's class */
4821   sprintf(basename, "%s.txt", element_info[element].class_name);
4822   filename = getPath3(docs_dir, elements_subdir, basename);
4823   if (fileExists(filename))
4824     return filename;
4825
4826   return NULL;
4827 }
4828
4829 static void InitDynamicEditorElementList(int **elements, int *num_elements)
4830 {
4831   boolean element_found[NUM_FILE_ELEMENTS];
4832   int i, x, y;
4833
4834   /* initialize list of used elements to "not used" */
4835   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4836     element_found[i] = FALSE;
4837
4838   /* find all elements used in current level */
4839   for (y = 0; y < lev_fieldy; y++)
4840     for (x = 0; x < lev_fieldx; x++)
4841       if (Feld[x][y] < NUM_FILE_ELEMENTS)       /* should always be true */
4842         element_found[Feld[x][y]] = TRUE;
4843
4844   *num_elements = 0;
4845
4846   /* count number of elements used in current level */
4847   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4848     if (element_found[i])
4849       (*num_elements)++;
4850
4851   /* add space for up to 3 more elements for padding that may be needed */
4852   *num_elements += 3;
4853
4854   /* free memory for old list of elements, if needed */
4855   checked_free(*elements);
4856
4857   /* allocate memory for new list of elements */
4858   *elements = checked_malloc(*num_elements * sizeof(int));
4859
4860   *num_elements = 0;
4861
4862   /* add all elements used in current level (non-custom/group elements) */
4863   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4864     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
4865       (*elements)[(*num_elements)++] = i;
4866
4867   /* add all elements used in current level (custom/group elements) */
4868   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
4869     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
4870       (*elements)[(*num_elements)++] = i;
4871
4872   while (*num_elements % 4)     /* pad with empty elements, if needed */
4873     (*elements)[(*num_elements)++] = EL_EMPTY;
4874 }
4875
4876 static void ReinitializeElementList()
4877 {
4878   static boolean initialization_needed = TRUE;
4879   int pos = 0;
4880   int i, j;
4881
4882   if (initialization_needed)
4883   {
4884     LoadSetup_EditorCascade();          /* load last editor cascade state */
4885
4886     /* initialize editor cascade element from saved cascade state */
4887     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
4888     {
4889       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
4890       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
4891
4892       if (IS_EDITOR_CASCADE(*cascade_element))
4893         *cascade_element =
4894           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
4895            EL_CASCADE_INACTIVE(*cascade_element));
4896     }
4897
4898     initialization_needed = FALSE;
4899   }
4900
4901   checked_free(editor_elements);
4902
4903   /* reload optional user defined element list for each invocation of editor */
4904   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
4905                                    &num_editor_el_user_defined);
4906
4907   /* initialize dynamic level element list for each invocation of editor */
4908   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
4909                                &num_editor_el_dynamic);
4910
4911   /* initialize list of empty elements (used for padding, if needed) */
4912   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
4913     editor_el_empty[i] = EL_EMPTY;
4914
4915   /* do some sanity checks for each element from element list */
4916   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
4917   {
4918     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
4919     {
4920       int element = (*editor_elements_info[i].element_list)[j];
4921
4922       if (element >= NUM_FILE_ELEMENTS)
4923         Error(ERR_WARN, "editor element %d is runtime element", element);
4924
4925       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
4926         Error(ERR_WARN, "no element description for element %d", element);
4927     }
4928   }
4929
4930   num_editor_elements = 0;
4931   use_el_empty = FALSE;
4932
4933   /* determine size of element list */
4934   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
4935   {
4936     boolean found_inactive_cascade = FALSE;
4937
4938     if (*editor_elements_info[i].setup_value)
4939     {
4940       if (setup.editor.el_headlines)
4941       {
4942         num_editor_elements += *editor_elements_info[i].headline_list_size;
4943
4944         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
4945         {
4946           int element = (*editor_elements_info[i].headline_list)[j];
4947
4948           if (IS_EDITOR_CASCADE_INACTIVE(element))
4949             found_inactive_cascade = TRUE;
4950         }
4951       }
4952
4953       if (found_inactive_cascade)
4954         continue;
4955
4956       num_editor_elements += *editor_elements_info[i].element_list_size;
4957     }
4958   }
4959
4960   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
4961   {
4962     /* offer at least as many elements as element buttons exist */
4963     use_el_empty = TRUE;
4964     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
4965
4966     num_editor_elements += num_editor_el_empty;
4967   }
4968
4969   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
4970
4971   /* fill element list */
4972   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
4973   {
4974     boolean found_inactive_cascade = FALSE;
4975
4976     if (*editor_elements_info[i].setup_value)
4977     {
4978       if (setup.editor.el_headlines)
4979       {
4980         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
4981         {
4982           int element = (*editor_elements_info[i].headline_list)[j];
4983
4984           editor_elements[pos++] = element;
4985
4986           if (IS_EDITOR_CASCADE_INACTIVE(element))
4987             found_inactive_cascade = TRUE;
4988         }
4989       }
4990
4991       if (found_inactive_cascade)
4992         continue;
4993
4994       for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
4995         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
4996     }
4997   }
4998
4999   /* (this function is also called before editor gadgets are initialized!) */
5000   AdjustElementListScrollbar();
5001 }
5002
5003 void PrintEditorElementList()
5004 {
5005   boolean *stop = &setup.editor.el_user_defined;
5006   int i, j;
5007
5008   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
5009   {
5010     int cascade_element = (*editor_elements_info[i].headline_list)[0];
5011
5012     if (IS_EDITOR_CASCADE(cascade_element))
5013     {
5014       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
5015       char *headline = element_info[cascade_element_show].editor_description;
5016
5017       printf_line_with_prefix("# ", "-", 77);
5018       printf("# %s\n", headline);
5019       printf_line_with_prefix("# ", "-", 77);
5020     }
5021
5022     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
5023     {
5024       int element = (*editor_elements_info[i].headline_list)[j];
5025
5026       if (IS_EDITOR_CASCADE(element))
5027         element = EL_CHAR_MINUS;
5028
5029       printf("# %s\n", element_info[element].token_name);
5030     }
5031
5032     if (j > 0)
5033       printf("#\n");
5034
5035     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
5036     {
5037       int element = (*editor_elements_info[i].element_list)[j];
5038
5039       printf("# %s\n", element_info[element].token_name);
5040     }
5041
5042     if (j > 0)
5043       printf("#\n");
5044   }
5045 }
5046
5047 static void ReinitializeElementListButtons()
5048 {
5049   static boolean last_setup_value_headlines = FALSE;
5050   static boolean initialization_needed = TRUE;
5051   int i;
5052
5053   if (!initialization_needed)   /* check if editor element setup has changed */
5054   {
5055     if (last_setup_value_headlines != setup.editor.el_headlines)
5056       initialization_needed = TRUE;
5057
5058     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5059       if (editor_elements_info[i].last_setup_value !=
5060           *editor_elements_info[i].setup_value)
5061         initialization_needed = TRUE;
5062   }
5063
5064   if (!initialization_needed)
5065     return;
5066
5067   FreeLevelEditorGadgets();
5068   CreateLevelEditorGadgets();
5069
5070   /* store current setup values for next invocation of this function */
5071   last_setup_value_headlines = setup.editor.el_headlines;
5072   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5073     editor_elements_info[i].last_setup_value =
5074       *editor_elements_info[i].setup_value;
5075
5076   initialization_needed = FALSE;
5077 }
5078
5079 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
5080                               boolean input)
5081 {
5082   int border_graphic =
5083     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
5084   Bitmap *src_bitmap;
5085   int src_x, src_y;
5086   int bx = (input ? 4 : 8);
5087   int by = (input ? 4 : 8);
5088   int bx2 = TILEX - bx;
5089   int by2 = TILEY - by;
5090   int i;
5091
5092   getGraphicSource(border_graphic, 0, &src_bitmap, &src_x, &src_y);
5093
5094   BlitBitmap(src_bitmap, drawto, src_x, src_y,
5095              bx, by, dest_x - bx, dest_y - by);
5096   BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y,
5097              bx, by, dest_x + width, dest_y - by);
5098   BlitBitmap(src_bitmap, drawto, src_x, src_y + by2,
5099              bx, by, dest_x - bx, dest_y + height);
5100   BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by2,
5101              bx, by, dest_x + width, dest_y + height);
5102
5103   for (i = 0; i < width / MINI_TILEX; i++)
5104   {
5105     BlitBitmap(src_bitmap, drawto, src_x + bx, src_y, MINI_TILEX, by,
5106                dest_x + i * MINI_TILEX, dest_y - by);
5107     BlitBitmap(src_bitmap, drawto, src_x + bx, src_y + by2, MINI_TILEX, by,
5108                dest_x + i * MINI_TILEX, dest_y + height);
5109   }
5110
5111   for (i = 0; i < height / MINI_TILEY; i++)
5112   {
5113     BlitBitmap(src_bitmap, drawto, src_x, src_y + by, bx, MINI_TILEY,
5114                dest_x - bx, dest_y + i * MINI_TILEY);
5115     BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by, bx, MINI_TILEY,
5116                dest_x + width, dest_y + i * MINI_TILEY);
5117   }
5118
5119   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
5120 }
5121
5122 static void DrawDrawingArea(int id)
5123 {
5124   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
5125   int x, y;
5126
5127   int *value = drawingarea_info[id].value;
5128   int area_xsize = drawingarea_info[id].area_xsize;
5129   int area_ysize = drawingarea_info[id].area_ysize;
5130
5131   for (x = 0; x < area_xsize; x++)
5132     for (y = 0; y < area_ysize; y++)
5133       DrawMiniGraphicExt(drawto,
5134                          gi->x + x * MINI_TILEX,
5135                          gi->y + y * MINI_TILEY,
5136                          el2edimg(value[x * area_ysize + y]));
5137 }
5138
5139 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
5140 {
5141 #if 0
5142   /* (directly solved in BlitBitmap() now) */
5143   static Bitmap *tmp_backbuffer = NULL;
5144 #endif
5145   int x, y;
5146   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
5147   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
5148
5149 #if 0
5150   /* (directly solved in BlitBitmap() now) */
5151   if (tmp_backbuffer == NULL)
5152     tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5153
5154   /* needed when blitting directly to same bitmap -- should not be needed with
5155      recent SDL libraries, but apparently does not work in 1.2.11 directly */
5156   BlitBitmap(drawto, tmp_backbuffer,
5157              SX + (dx == -1 ? MINI_TILEX : 0),
5158              SY + (dy == -1 ? MINI_TILEY : 0),
5159              (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
5160              (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
5161              SX + (dx == +1 ? MINI_TILEX : 0),
5162              SY + (dy == +1 ? MINI_TILEY : 0));
5163   BlitBitmap(tmp_backbuffer, drawto,
5164              SX + (dx == +1 ? MINI_TILEX : 0),
5165              SY + (dy == +1 ? MINI_TILEY : 0),
5166              (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
5167              (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
5168              SX + (dx == +1 ? MINI_TILEX : 0),
5169              SY + (dy == +1 ? MINI_TILEY : 0));
5170
5171 #else
5172
5173   BlitBitmap(drawto, drawto,
5174              SX + (dx == -1 ? MINI_TILEX : 0),
5175              SY + (dy == -1 ? MINI_TILEY : 0),
5176              (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
5177              (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
5178              SX + (dx == +1 ? MINI_TILEX : 0),
5179              SY + (dy == +1 ? MINI_TILEY : 0));
5180 #endif
5181
5182   if (dx)
5183   {
5184     x = (dx == 1 ? 0 : ed_fieldx - 1);
5185     for (y = 0; y < ed_fieldy; y++)
5186       DrawMiniElementOrWall(x, y, from_x, from_y);
5187   }
5188   else if (dy)
5189   {
5190     y = (dy == 1 ? 0 : ed_fieldy - 1);
5191     for (x = 0; x < ed_fieldx; x++)
5192       DrawMiniElementOrWall(x, y, from_x, from_y);
5193   }
5194
5195   redraw_mask |= REDRAW_FIELD;
5196   BackToFront();
5197 }
5198
5199 static void CreateControlButtons()
5200 {
5201   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5202   struct GadgetInfo *gi;
5203   unsigned long event_mask;
5204   int i;
5205
5206   /* create toolbox buttons */
5207   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
5208   {
5209     int id = i;
5210     int width, height;
5211     int gd_xoffset, gd_yoffset;
5212     int gd_x1, gd_x2, gd_y1, gd_y2;
5213     int button_type;
5214     int radio_button_nr;
5215     boolean checked;
5216
5217     if (id == GADGET_ID_SINGLE_ITEMS ||
5218         id == GADGET_ID_CONNECTED_ITEMS ||
5219         id == GADGET_ID_LINE ||
5220         id == GADGET_ID_ARC ||
5221         id == GADGET_ID_TEXT ||
5222         id == GADGET_ID_RECTANGLE ||
5223         id == GADGET_ID_FILLED_BOX ||
5224         id == GADGET_ID_FLOOD_FILL ||
5225         id == GADGET_ID_GRAB_BRUSH ||
5226         id == GADGET_ID_PICK_ELEMENT ||
5227         id == GADGET_ID_CUSTOM_COPY_FROM ||
5228         id == GADGET_ID_CUSTOM_COPY_TO ||
5229         id == GADGET_ID_CUSTOM_EXCHANGE)
5230     {
5231       button_type = GD_TYPE_RADIO_BUTTON;
5232       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
5233       checked = (id == drawing_function ? TRUE : FALSE);
5234       event_mask = GD_EVENT_PRESSED;
5235     }
5236     else
5237     {
5238       button_type = GD_TYPE_NORMAL_BUTTON;
5239       radio_button_nr = RADIO_NR_NONE;
5240       checked = FALSE;
5241
5242       if (id == GADGET_ID_WRAP_LEFT ||
5243           id == GADGET_ID_WRAP_RIGHT ||
5244           id == GADGET_ID_WRAP_UP ||
5245           id == GADGET_ID_WRAP_DOWN)
5246         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5247       else
5248         event_mask = GD_EVENT_RELEASED;
5249     }
5250
5251     if (id < ED_NUM_CTRL1_BUTTONS)
5252     {
5253       int x = i % ED_CTRL1_BUTTONS_HORIZ;
5254       int y = i / ED_CTRL1_BUTTONS_HORIZ;
5255
5256       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
5257       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
5258       width  = ED_CTRL1_BUTTON_XSIZE;
5259       height = ED_CTRL1_BUTTON_YSIZE;
5260
5261       gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
5262       gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
5263       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_GFX_YPOS     + gd_yoffset;
5264       gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
5265     }
5266     else if (id < ED_NUM_CTRL1_2_BUTTONS)
5267     {
5268       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
5269       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
5270
5271       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
5272       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
5273       width  = ED_CTRL2_BUTTON_XSIZE;
5274       height = ED_CTRL2_BUTTON_YSIZE;
5275
5276       gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
5277       gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
5278       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL2_BUTTONS_GFX_YPOS + gd_yoffset;
5279       gd_y2 = 0;        /* no alternative graphic for these buttons */
5280     }
5281     else if (id < ED_NUM_CTRL1_3_BUTTONS)
5282     {
5283       int x = (i - ED_NUM_CTRL1_2_BUTTONS) % ED_CTRL3_BUTTONS_HORIZ + 1;
5284       int y = (i - ED_NUM_CTRL1_2_BUTTONS) / ED_CTRL3_BUTTONS_HORIZ;
5285
5286       gd_xoffset = ED_CTRL3_BUTTONS_XPOS + x * ED_CTRL3_BUTTON_XSIZE;
5287       gd_yoffset = ED_CTRL3_BUTTONS_YPOS + y * ED_CTRL3_BUTTON_YSIZE;
5288       width  = ED_CTRL3_BUTTON_XSIZE;
5289       height = ED_CTRL3_BUTTON_YSIZE;
5290
5291       gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset;
5292       gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset;
5293       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_GFX_YPOS     + gd_yoffset;
5294       gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
5295     }
5296     else
5297     {
5298       int x = (i - ED_NUM_CTRL1_3_BUTTONS) % ED_CTRL4_BUTTONS_HORIZ;
5299       int y = (i - ED_NUM_CTRL1_3_BUTTONS) / ED_CTRL4_BUTTONS_HORIZ + 3;
5300
5301       gd_xoffset = ED_CTRL4_BUTTONS_XPOS + x * ED_CTRL4_BUTTON_XSIZE;
5302       gd_yoffset = ED_CTRL4_BUTTONS_YPOS + y * ED_CTRL4_BUTTON_YSIZE;
5303       width  = ED_CTRL4_BUTTON_XSIZE;
5304       height = ED_CTRL4_BUTTON_YSIZE;
5305
5306       gd_x1 = DOOR_GFX_PAGEX6 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
5307       gd_x2 = DOOR_GFX_PAGEX5 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
5308       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL4_BUTTONS_GFX_YPOS + gd_yoffset;
5309       gd_y2 = 0;        /* no alternative graphic for these buttons */
5310     }
5311
5312     gi = CreateGadget(GDI_CUSTOM_ID, id,
5313                       GDI_CUSTOM_TYPE_ID, i,
5314                       GDI_INFO_TEXT, control_info[i].text,
5315                       GDI_X, EX + gd_xoffset,
5316                       GDI_Y, EY + gd_yoffset,
5317                       GDI_WIDTH, width,
5318                       GDI_HEIGHT, height,
5319                       GDI_TYPE, button_type,
5320                       GDI_STATE, GD_BUTTON_UNPRESSED,
5321                       GDI_RADIO_NR, radio_button_nr,
5322                       GDI_CHECKED, checked,
5323                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5324                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
5325                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
5326                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5327                       GDI_EVENT_MASK, event_mask,
5328                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5329                       GDI_CALLBACK_ACTION, HandleControlButtons,
5330                       GDI_END);
5331
5332     if (gi == NULL)
5333       Error(ERR_EXIT, "cannot create gadget");
5334
5335     level_editor_gadget[id] = gi;
5336   }
5337
5338   /* create buttons for scrolling of drawing area and element list */
5339   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
5340   {
5341     int id = scrollbutton_info[i].gadget_id;
5342     int x, y, width, height;
5343     int gd_x1, gd_x2, gd_y1, gd_y2;
5344
5345     x = scrollbutton_info[i].x;
5346     y = scrollbutton_info[i].y;
5347
5348     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5349
5350     if (id == GADGET_ID_SCROLL_LIST_UP ||
5351         id == GADGET_ID_SCROLL_LIST_DOWN)
5352     {
5353       x += DX;
5354       y += DY;
5355       width = ED_SCROLLBUTTON2_XSIZE;
5356       height = ED_SCROLLBUTTON2_YSIZE;
5357       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
5358       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
5359       gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE;
5360       gd_y2 = gd_y1;
5361     }
5362     else
5363     {
5364       x += SX;
5365       y += SY;
5366       width = ED_SCROLLBUTTON_XSIZE;
5367       height = ED_SCROLLBUTTON_YSIZE;
5368       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
5369       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
5370       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
5371       gd_y2 = gd_y1;
5372     }
5373
5374     gi = CreateGadget(GDI_CUSTOM_ID, id,
5375                       GDI_CUSTOM_TYPE_ID, i,
5376                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5377                       GDI_X, x,
5378                       GDI_Y, y,
5379                       GDI_WIDTH, width,
5380                       GDI_HEIGHT, height,
5381                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5382                       GDI_STATE, GD_BUTTON_UNPRESSED,
5383                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5384                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5385                       GDI_EVENT_MASK, event_mask,
5386                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5387                       GDI_CALLBACK_ACTION, HandleControlButtons,
5388                       GDI_END);
5389
5390     if (gi == NULL)
5391       Error(ERR_EXIT, "cannot create gadget");
5392
5393     level_editor_gadget[id] = gi;
5394   }
5395
5396   /* create buttons for element list */
5397   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
5398   {
5399     Bitmap *deco_bitmap;
5400     int deco_x, deco_y, deco_xpos, deco_ypos;
5401     int gd_xoffset, gd_yoffset;
5402     int gd_x1, gd_x2, gd_y;
5403     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
5404     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
5405     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
5406     int element = editor_elements[i];
5407
5408     event_mask = GD_EVENT_RELEASED;
5409
5410     gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
5411     gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
5412
5413     gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE;
5414     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
5415     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
5416
5417     getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
5418     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
5419     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
5420
5421     gi = CreateGadget(GDI_CUSTOM_ID, id,
5422                       GDI_CUSTOM_TYPE_ID, i,
5423                       GDI_INFO_TEXT, getElementInfoText(element),
5424                       GDI_X, DX + gd_xoffset,
5425                       GDI_Y, DY + gd_yoffset,
5426                       GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
5427                       GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
5428                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5429                       GDI_STATE, GD_BUTTON_UNPRESSED,
5430                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
5431                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
5432                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5433                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5434                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
5435                       GDI_DECORATION_SHIFTING, 1, 1,
5436                       GDI_EVENT_MASK, event_mask,
5437                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5438                       GDI_CALLBACK_ACTION, HandleControlButtons,
5439                       GDI_END);
5440
5441     if (gi == NULL)
5442       Error(ERR_EXIT, "cannot create gadget");
5443
5444     level_editor_gadget[id] = gi;
5445   }
5446 }
5447
5448 static void CreateCounterButtons()
5449 {
5450   int max_infotext_len = getMaxInfoTextLength();
5451   int i;
5452
5453   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
5454   {
5455     int j;
5456     int x = SX + counterbutton_info[i].x;       /* down count button */
5457     int y = SY + counterbutton_info[i].y;
5458
5459     /* determine horizontal position to the right of specified gadget */
5460     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
5461       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
5462            ED_GADGET_TEXT_DISTANCE);
5463
5464     /* determine horizontal offset for leading text */
5465     if (counterbutton_info[i].text_left != NULL)
5466       x += getTextWidthForGadget(counterbutton_info[i].text_left);
5467
5468     for (j = 0; j < 2; j++)
5469     {
5470       Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5471       struct GadgetInfo *gi;
5472       int id = (j == 0 ?
5473                 counterbutton_info[i].gadget_id_down :
5474                 counterbutton_info[i].gadget_id_up);
5475       int gd_xoffset;
5476       int gd_x, gd_x1, gd_x2, gd_y;
5477       int x_size, y_size;
5478       unsigned long event_mask;
5479       char infotext[max_infotext_len + 1];
5480
5481       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5482
5483       if (i == ED_COUNTER_ID_SELECT_LEVEL)
5484       {
5485         int sid = (j == 0 ?
5486                    ED_SCROLLBUTTON_ID_AREA_LEFT :
5487                    ED_SCROLLBUTTON_ID_AREA_RIGHT);
5488
5489         event_mask |= GD_EVENT_RELEASED;
5490
5491         if (j == 1)
5492           x += 2 * ED_GADGET_DISTANCE;
5493         y += ED_GADGET_DISTANCE;
5494
5495         gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].gd_x;
5496         gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
5497         gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].gd_y;
5498         x_size = ED_SCROLLBUTTON_XSIZE;
5499         y_size = ED_SCROLLBUTTON_YSIZE;
5500       }
5501       else
5502       {
5503         gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
5504         gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
5505         gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
5506         gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
5507         x_size = ED_BUTTON_COUNT_XSIZE;
5508         y_size = ED_BUTTON_COUNT_YSIZE;
5509       }
5510
5511       sprintf(infotext, "%s counter value by 1, 5 or 10",
5512               (j == 0 ? "decrease" : "increase"));
5513
5514       gi = CreateGadget(GDI_CUSTOM_ID, id,
5515                         GDI_CUSTOM_TYPE_ID, i,
5516                         GDI_INFO_TEXT, infotext,
5517                         GDI_X, x,
5518                         GDI_Y, y,
5519                         GDI_WIDTH, x_size,
5520                         GDI_HEIGHT, y_size,
5521                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5522                         GDI_STATE, GD_BUTTON_UNPRESSED,
5523                         GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
5524                         GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
5525                         GDI_EVENT_MASK, event_mask,
5526                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5527                         GDI_CALLBACK_ACTION, HandleCounterButtons,
5528                         GDI_END);
5529
5530       if (gi == NULL)
5531         Error(ERR_EXIT, "cannot create gadget");
5532
5533       level_editor_gadget[id] = gi;
5534       right_gadget_border[id] =
5535         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5536
5537       x += gi->width + ED_GADGET_DISTANCE;      /* text count button */
5538
5539       if (j == 0)
5540       {
5541         int font_type = FONT_INPUT_1;
5542         int font_type_active = FONT_INPUT_1_ACTIVE;
5543         int gd_width = ED_WIN_COUNT_XSIZE;
5544
5545         id = counterbutton_info[i].gadget_id_text;
5546         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5547
5548         if (i == ED_COUNTER_ID_SELECT_LEVEL)
5549         {
5550           font_type = FONT_LEVEL_NUMBER;
5551 #if 1
5552           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
5553 #else
5554           font_type_active = FONT_LEVEL_NUMBER;
5555 #endif
5556           x += 2 * ED_GADGET_DISTANCE;
5557           y -= ED_GADGET_DISTANCE;
5558
5559           gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
5560           gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
5561           gd_width = ED_WIN_COUNT2_XSIZE;
5562         }
5563         else
5564         {
5565           gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
5566           gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
5567         }
5568
5569         gi = CreateGadget(GDI_CUSTOM_ID, id,
5570                           GDI_CUSTOM_TYPE_ID, i,
5571                           GDI_INFO_TEXT, "enter counter value",
5572                           GDI_X, x,
5573                           GDI_Y, y,
5574                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
5575                           GDI_NUMBER_VALUE, 0,
5576                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
5577                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
5578                           GDI_TEXT_SIZE, 3,     /* minimal counter text size */
5579                           GDI_TEXT_FONT, font_type,
5580                           GDI_TEXT_FONT_ACTIVE, font_type_active,
5581                           GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
5582                           GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
5583                           GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
5584                           GDI_DESIGN_WIDTH, gd_width,
5585                           GDI_EVENT_MASK, event_mask,
5586                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5587                           GDI_CALLBACK_ACTION, HandleCounterButtons,
5588                           GDI_END);
5589
5590         if (gi == NULL)
5591           Error(ERR_EXIT, "cannot create gadget");
5592
5593         level_editor_gadget[id] = gi;
5594         right_gadget_border[id] =
5595           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5596
5597         x += gi->width + ED_GADGET_DISTANCE;    /* up count button */
5598       }
5599     }
5600   }
5601 }
5602
5603 static void CreateDrawingAreas()
5604 {
5605   int i;
5606
5607   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
5608   {
5609     struct GadgetInfo *gi;
5610     unsigned long event_mask;
5611     int id = drawingarea_info[i].gadget_id;
5612     int x = SX + drawingarea_info[i].x;
5613     int y = SY + drawingarea_info[i].y;
5614     int area_xsize = drawingarea_info[i].area_xsize;
5615     int area_ysize = drawingarea_info[i].area_ysize;
5616
5617     event_mask =
5618       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
5619       GD_EVENT_OFF_BORDERS;
5620
5621     /* determine horizontal position to the right of specified gadget */
5622     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
5623       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
5624            ED_DRAWINGAREA_TEXT_DISTANCE);
5625
5626     /* determine horizontal offset for leading text */
5627     if (drawingarea_info[i].text_left != NULL)
5628       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
5629
5630     gi = CreateGadget(GDI_CUSTOM_ID, id,
5631                       GDI_CUSTOM_TYPE_ID, i,
5632                       GDI_X, x,
5633                       GDI_Y, y,
5634                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
5635                       GDI_AREA_SIZE, area_xsize, area_ysize,
5636                       GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
5637                       GDI_EVENT_MASK, event_mask,
5638                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
5639                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
5640                       GDI_END);
5641
5642     if (gi == NULL)
5643       Error(ERR_EXIT, "cannot create gadget");
5644
5645     level_editor_gadget[id] = gi;
5646     right_gadget_border[id] =
5647       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
5648   }
5649 }
5650
5651 static void CreateTextInputGadgets()
5652 {
5653   int max_infotext_len = getMaxInfoTextLength();
5654   int i;
5655
5656   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
5657   {
5658     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5659     int gd_x, gd_y;
5660     struct GadgetInfo *gi;
5661     unsigned long event_mask;
5662     char infotext[MAX_OUTPUT_LINESIZE + 1];
5663     int id = textinput_info[i].gadget_id;
5664
5665     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5666
5667     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
5668     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
5669
5670     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
5671     infotext[max_infotext_len] = '\0';
5672
5673     gi = CreateGadget(GDI_CUSTOM_ID, id,
5674                       GDI_CUSTOM_TYPE_ID, i,
5675                       GDI_INFO_TEXT, infotext,
5676                       GDI_X, SX + textinput_info[i].x,
5677                       GDI_Y, SY + textinput_info[i].y,
5678                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
5679                       GDI_TEXT_VALUE, textinput_info[i].value,
5680                       GDI_TEXT_SIZE, textinput_info[i].size,
5681                       GDI_TEXT_FONT, FONT_INPUT_1,
5682                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5683                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
5684                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
5685                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
5686                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
5687                       GDI_EVENT_MASK, event_mask,
5688                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5689                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
5690                       GDI_END);
5691
5692     if (gi == NULL)
5693       Error(ERR_EXIT, "cannot create gadget");
5694
5695     level_editor_gadget[id] = gi;
5696   }
5697 }
5698
5699 static void CreateTextAreaGadgets()
5700 {
5701   int max_infotext_len = getMaxInfoTextLength();
5702   int i;
5703
5704   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
5705   {
5706     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5707     int gd_x, gd_y;
5708     struct GadgetInfo *gi;
5709     unsigned long event_mask;
5710     char infotext[MAX_OUTPUT_LINESIZE + 1];
5711     int id = textarea_info[i].gadget_id;
5712     int area_xsize = textarea_info[i].xsize;
5713     int area_ysize = textarea_info[i].ysize;
5714
5715     event_mask = GD_EVENT_TEXT_LEAVING;
5716
5717     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
5718     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
5719
5720     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
5721     infotext[max_infotext_len] = '\0';
5722
5723     gi = CreateGadget(GDI_CUSTOM_ID, id,
5724                       GDI_CUSTOM_TYPE_ID, i,
5725                       GDI_INFO_TEXT, infotext,
5726                       GDI_X, SX + textarea_info[i].x,
5727                       GDI_Y, SY + textarea_info[i].y,
5728                       GDI_TYPE, GD_TYPE_TEXT_AREA,
5729                       GDI_AREA_SIZE, area_xsize, area_ysize,
5730                       GDI_TEXT_FONT, FONT_INPUT_1,
5731                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5732                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
5733                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
5734                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
5735                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
5736                       GDI_EVENT_MASK, event_mask,
5737                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5738                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
5739                       GDI_END);
5740
5741     if (gi == NULL)
5742       Error(ERR_EXIT, "cannot create gadget");
5743
5744     level_editor_gadget[id] = gi;
5745   }
5746 }
5747
5748 static void CreateSelectboxGadgets()
5749 {
5750   int max_infotext_len = getMaxInfoTextLength();
5751   int i, j;
5752
5753   for (i = 0; i < ED_NUM_SELECTBOX; i++)
5754   {
5755     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5756     int gd_x, gd_y;
5757     struct GadgetInfo *gi;
5758     unsigned long event_mask;
5759     char infotext[MAX_OUTPUT_LINESIZE + 1];
5760     int id = selectbox_info[i].gadget_id;
5761     int x = SX + selectbox_info[i].x;
5762     int y = SY + selectbox_info[i].y;
5763
5764     if (selectbox_info[i].size == -1)   /* dynamically determine size */
5765     {
5766       /* (we cannot use -1 for uninitialized values if we directly compare
5767          with results from strlen(), because the '<' and '>' operation will
5768          implicitely cast -1 to an unsigned integer value!) */
5769       selectbox_info[i].size = 0;
5770
5771       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
5772         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
5773           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
5774
5775       selectbox_info[i].size++;         /* add one character empty space */
5776     }
5777
5778     event_mask = GD_EVENT_RELEASED |
5779       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5780
5781     gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
5782     gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
5783
5784     /* determine horizontal position to the right of specified gadget */
5785     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
5786       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
5787            ED_GADGET_TEXT_DISTANCE);
5788
5789     /* determine horizontal offset for leading text */
5790     if (selectbox_info[i].text_left != NULL)
5791       x += getTextWidthForGadget(selectbox_info[i].text_left);
5792
5793     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
5794     infotext[max_infotext_len] = '\0';
5795
5796     gi = CreateGadget(GDI_CUSTOM_ID, id,
5797                       GDI_CUSTOM_TYPE_ID, i,
5798                       GDI_INFO_TEXT, infotext,
5799                       GDI_X, x,
5800                       GDI_Y, y,
5801                       GDI_TYPE, GD_TYPE_SELECTBOX,
5802                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
5803                       GDI_TEXT_SIZE, selectbox_info[i].size,
5804                       GDI_TEXT_FONT, FONT_INPUT_1,
5805                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5806                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
5807                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
5808                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
5809                       GDI_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE,
5810                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
5811                       GDI_EVENT_MASK, event_mask,
5812                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5813                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
5814                       GDI_END);
5815
5816     if (gi == NULL)
5817       Error(ERR_EXIT, "cannot create gadget");
5818
5819     level_editor_gadget[id] = gi;
5820     right_gadget_border[id] =
5821       getRightGadgetBorder(gi, selectbox_info[i].text_right);
5822   }
5823 }
5824
5825 static void CreateTextbuttonGadgets()
5826 {
5827   int max_infotext_len = getMaxInfoTextLength();
5828   int i;
5829
5830   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
5831   {
5832     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5833     int gd_x1, gd_x2, gd_y1, gd_y2;
5834     struct GadgetInfo *gi;
5835     unsigned long event_mask;
5836     char infotext[MAX_OUTPUT_LINESIZE + 1];
5837     int id = textbutton_info[i].gadget_id;
5838     int x = SX + textbutton_info[i].x;
5839     int y = SY + textbutton_info[i].y;
5840
5841     if (textbutton_info[i].size == -1)  /* dynamically determine size */
5842       textbutton_info[i].size = strlen(textbutton_info[i].text);
5843
5844     event_mask = GD_EVENT_RELEASED;
5845
5846     if ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
5847         (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE))
5848     {
5849       gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
5850       gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
5851       gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS;
5852       gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS;
5853     }
5854     else
5855     {
5856       gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS;
5857       gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS;
5858       gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS;
5859       gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS;
5860     }
5861
5862     sprintf(infotext, "%s", textbutton_info[i].infotext);
5863     infotext[max_infotext_len] = '\0';
5864
5865     /* determine horizontal position to the right of specified gadget */
5866     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
5867       x = (right_gadget_border[textbutton_info[i].gadget_id_align] +
5868            ED_GADGET_TEXT_DISTANCE);
5869
5870     /* determine horizontal offset for leading text */
5871     if (textbutton_info[i].text_left != NULL)
5872       x += getTextWidthForGadget(textbutton_info[i].text_left);
5873
5874     gi = CreateGadget(GDI_CUSTOM_ID, id,
5875                       GDI_CUSTOM_TYPE_ID, i,
5876                       GDI_INFO_TEXT, infotext,
5877                       GDI_X, x,
5878                       GDI_Y, y,
5879                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
5880                       GDI_TEXT_VALUE, textbutton_info[i].text,
5881                       GDI_TEXT_SIZE, textbutton_info[i].size,
5882                       GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE,
5883                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2,
5884                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5885                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
5886                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
5887                       GDI_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE,
5888                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
5889                       GDI_DECORATION_SHIFTING, 1, 1,
5890                       GDI_EVENT_MASK, event_mask,
5891                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5892                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
5893                       GDI_END);
5894
5895     if (gi == NULL)
5896       Error(ERR_EXIT, "cannot create gadget");
5897
5898     level_editor_gadget[id] = gi;
5899     right_gadget_border[id] =
5900       getRightGadgetBorder(gi, textbutton_info[i].text_right);
5901   }
5902 }
5903
5904 static void CreateGraphicbuttonGadgets()
5905 {
5906   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5907   struct GadgetInfo *gi;
5908   unsigned long event_mask;
5909   int i;
5910
5911   /* create buttons for scrolling of drawing area and element list */
5912   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
5913   {
5914     int id = graphicbutton_info[i].gadget_id;
5915     int gd_x1, gd_x2, gd_y1, gd_y2;
5916     int x = SX + graphicbutton_info[i].x;
5917     int y = SY + graphicbutton_info[i].y;
5918
5919     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5920
5921     if (i <= ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
5922     {
5923       gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
5924       gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
5925       gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
5926       gd_y2 = gd_y1;
5927     }
5928     else        /* (i <= ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) */
5929     {
5930       gd_x1 = DOOR_GFX_PAGEX6 + graphicbutton_info[i].gd_x;
5931       gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
5932       gd_x2 = gd_x1 - ED_BUTTON_COUNT_XSIZE;
5933       gd_y2 = gd_y1;
5934     }
5935
5936     /* determine horizontal position to the right of specified gadget */
5937     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
5938       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
5939            ED_GADGET_TEXT_DISTANCE);
5940
5941     /* determine horizontal offset for leading text */
5942     if (graphicbutton_info[i].text_left != NULL)
5943       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
5944
5945     gi = CreateGadget(GDI_CUSTOM_ID, id,
5946                       GDI_CUSTOM_TYPE_ID, i,
5947                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
5948                       GDI_X, x,
5949                       GDI_Y, y,
5950                       GDI_WIDTH, graphicbutton_info[i].width,
5951                       GDI_HEIGHT, graphicbutton_info[i].height,
5952                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5953                       GDI_STATE, GD_BUTTON_UNPRESSED,
5954                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5955                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5956                       GDI_EVENT_MASK, event_mask,
5957                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5958                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
5959                       GDI_END);
5960
5961     if (gi == NULL)
5962       Error(ERR_EXIT, "cannot create gadget");
5963
5964     level_editor_gadget[id] = gi;
5965     right_gadget_border[id] =
5966       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
5967   }
5968 }
5969
5970 static void CreateScrollbarGadgets()
5971 {
5972   int i;
5973
5974   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
5975   {
5976     int id = scrollbar_info[i].gadget_id;
5977     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5978     int gd_x1, gd_x2, gd_y1, gd_y2;
5979     struct GadgetInfo *gi;
5980     int items_max, items_visible, item_position;
5981     unsigned long event_mask;
5982
5983     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
5984     {
5985       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
5986       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
5987       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
5988     }
5989     else        /* drawing area scrollbars */
5990     {
5991       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
5992       {
5993         items_max = MAX(lev_fieldx + 2, ed_fieldx);
5994         items_visible = ed_fieldx;
5995         item_position = 0;
5996       }
5997       else
5998       {
5999         items_max = MAX(lev_fieldy + 2, ed_fieldy);
6000         items_visible = ed_fieldy;
6001         item_position = 0;
6002       }
6003     }
6004
6005     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
6006
6007     gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].gd_x;
6008     gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
6009                       scrollbar_info[i].height : scrollbar_info[i].width));
6010     gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
6011     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
6012
6013     gi = CreateGadget(GDI_CUSTOM_ID, id,
6014                       GDI_CUSTOM_TYPE_ID, i,
6015                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
6016                       GDI_X, scrollbar_info[i].x,
6017                       GDI_Y, scrollbar_info[i].y,
6018                       GDI_WIDTH, scrollbar_info[i].width,
6019                       GDI_HEIGHT, scrollbar_info[i].height,
6020                       GDI_TYPE, scrollbar_info[i].type,
6021                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
6022                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
6023                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
6024                       GDI_WHEEL_AREA_X, scrollbar_info[i].wheel_x,
6025                       GDI_WHEEL_AREA_Y, scrollbar_info[i].wheel_y,
6026                       GDI_WHEEL_AREA_WIDTH, scrollbar_info[i].wheel_width,
6027                       GDI_WHEEL_AREA_HEIGHT, scrollbar_info[i].wheel_height,
6028                       GDI_STATE, GD_BUTTON_UNPRESSED,
6029                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6030                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6031                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
6032                       GDI_EVENT_MASK, event_mask,
6033                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6034                       GDI_CALLBACK_ACTION, HandleControlButtons,
6035                       GDI_END);
6036
6037     if (gi == NULL)
6038       Error(ERR_EXIT, "cannot create gadget");
6039
6040     level_editor_gadget[id] = gi;
6041   }
6042 }
6043
6044 static void CreateCheckbuttonGadgets()
6045 {
6046   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6047   struct GadgetInfo *gi;
6048   unsigned long event_mask;
6049   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
6050   int i;
6051
6052   event_mask = GD_EVENT_PRESSED;
6053
6054   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
6055   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
6056   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
6057   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
6058   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
6059
6060   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
6061   {
6062     int id = checkbutton_info[i].gadget_id;
6063     int x = SX + checkbutton_info[i].x;
6064     int y = SY + checkbutton_info[i].y;
6065
6066     if (id == GADGET_ID_STICK_ELEMENT)
6067       gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
6068     else
6069       gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
6070
6071     /* determine horizontal position to the right of specified gadget */
6072     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6073       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
6074            ED_GADGET_TEXT_DISTANCE);
6075
6076     /* determine horizontal offset for leading text */
6077     if (checkbutton_info[i].text_left != NULL)
6078       x += getTextWidthForGadget(checkbutton_info[i].text_left);
6079
6080     gi = CreateGadget(GDI_CUSTOM_ID, id,
6081                       GDI_CUSTOM_TYPE_ID, i,
6082                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
6083                       GDI_X, x,
6084                       GDI_Y, y,
6085                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
6086                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
6087                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
6088                       GDI_CHECKED, *checkbutton_info[i].value,
6089                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6090                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6091                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
6092                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
6093                       GDI_EVENT_MASK, event_mask,
6094                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6095                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
6096                       GDI_END);
6097
6098     if (gi == NULL)
6099       Error(ERR_EXIT, "cannot create gadget");
6100
6101     level_editor_gadget[id] = gi;
6102     right_gadget_border[id] =
6103       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
6104   }
6105 }
6106
6107 static void CreateRadiobuttonGadgets()
6108 {
6109   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6110   struct GadgetInfo *gi;
6111   unsigned long event_mask;
6112   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
6113   int i;
6114
6115   event_mask = GD_EVENT_PRESSED;
6116
6117   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
6118   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
6119   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
6120   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
6121   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
6122
6123   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
6124   {
6125     int id = radiobutton_info[i].gadget_id;
6126     int x = SX + radiobutton_info[i].x;
6127     int y = SY + radiobutton_info[i].y;
6128
6129     int checked =
6130       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
6131
6132     /* determine horizontal position to the right of specified gadget */
6133     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
6134       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
6135            ED_GADGET_TEXT_DISTANCE);
6136
6137     /* determine horizontal offset for leading text */
6138     if (radiobutton_info[i].text_left != NULL)
6139       x += getTextWidthForGadget(radiobutton_info[i].text_left);
6140
6141     gi = CreateGadget(GDI_CUSTOM_ID, id,
6142                       GDI_CUSTOM_TYPE_ID, i,
6143                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
6144                       GDI_X, x,
6145                       GDI_Y, y,
6146                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
6147                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
6148                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
6149                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
6150                       GDI_CHECKED, checked,
6151                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6152                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6153                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
6154                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
6155                       GDI_EVENT_MASK, event_mask,
6156                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6157                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
6158                       GDI_END);
6159
6160     if (gi == NULL)
6161       Error(ERR_EXIT, "cannot create gadget");
6162
6163     level_editor_gadget[id] = gi;
6164     right_gadget_border[id] =
6165       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
6166   }
6167 }
6168
6169 void CreateLevelEditorGadgets()
6170 {
6171   int old_game_status = game_status;
6172
6173   /* setting 'game_status' is needed to get the right fonts for the editor */
6174   game_status = GAME_MODE_EDITOR;
6175
6176   ReinitializeElementList();
6177
6178   CreateControlButtons();
6179   CreateScrollbarGadgets();
6180
6181   /* order of function calls is important because of cross-references */
6182   CreateCheckbuttonGadgets();
6183   CreateCounterButtons();
6184   CreateRadiobuttonGadgets();
6185   CreateTextInputGadgets();
6186   CreateTextAreaGadgets();
6187   CreateSelectboxGadgets();
6188   CreateGraphicbuttonGadgets();
6189   CreateTextbuttonGadgets();
6190   CreateDrawingAreas();
6191
6192   game_status = old_game_status;
6193 }
6194
6195 void FreeLevelEditorGadgets()
6196 {
6197   int i;
6198
6199   for (i = 0; i < NUM_EDITOR_GADGETS; i++)
6200   {
6201     FreeGadget(level_editor_gadget[i]);
6202
6203     level_editor_gadget[i] = NULL;
6204   }
6205 }
6206
6207 static void MapCounterButtons(int id)
6208 {
6209   int gadget_id_down = counterbutton_info[id].gadget_id_down;
6210   int gadget_id_text = counterbutton_info[id].gadget_id_text;
6211   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
6212   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
6213   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
6214   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
6215   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
6216   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6217   int yoffset_above = MINI_TILEX + ED_GADGET_DISTANCE;
6218   int yoffset = ED_BORDER_SIZE;
6219   int x_left = gi_down->x - xoffset_left;
6220   int x_right;  /* set after gadget position was modified */
6221   int y_above = gi_down->y - yoffset_above;
6222   int x = gi_down->x;
6223   int y;        /* set after gadget position was modified */
6224
6225   /* counter limits must be changed first to prevent value truncation */
6226   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
6227                             counterbutton_info[id].max_value);
6228
6229   /* right text position might have changed after setting position above */
6230   x_right = gi_up->x + gi_up->width + xoffset_right;
6231
6232   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
6233
6234   /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */
6235   if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
6236       id <= ED_COUNTER_ID_ELEMENT_VALUE4)
6237   {
6238     ModifyGadget(gi_down, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
6239     ModifyGadget(gi_text, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
6240     ModifyGadget(gi_up,   GDI_Y, SY + counterbutton_info[id].y, GDI_END);
6241   }
6242
6243   /* vertical position might have changed after setting position above */
6244   y = gi_up->y + yoffset;
6245
6246   if (counterbutton_info[id].text_above)
6247     DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
6248
6249   if (counterbutton_info[id].text_left)
6250     DrawText(x_left, y, counterbutton_info[id].text_left, FONT_TEXT_1);
6251
6252   if (counterbutton_info[id].text_right)
6253     DrawText(x_right, y, counterbutton_info[id].text_right, FONT_TEXT_1);
6254
6255   MapGadget(gi_down);
6256   MapGadget(gi_text);
6257   MapGadget(gi_up);
6258 }
6259
6260 static void MapControlButtons()
6261 {
6262   int counter_id;
6263   int i;
6264
6265   /* map toolbox buttons (excluding special CE toolbox buttons) */
6266   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
6267     MapGadget(level_editor_gadget[i]);
6268
6269   /* map buttons to select elements */
6270   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
6271     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
6272   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
6273   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
6274   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
6275
6276   /* map buttons to select level */
6277   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
6278   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
6279   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
6280   MapCounterButtons(counter_id);
6281 }
6282
6283 static void MapDrawingArea(int id)
6284 {
6285   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
6286   int area_xsize = gi->drawing.area_xsize;
6287   int area_ysize = gi->drawing.area_ysize;
6288   int xoffset_left= getTextWidthForDrawingArea(drawingarea_info[id].text_left);
6289   int xoffset_below= getTextWidth(drawingarea_info[id].text_below,FONT_TEXT_1);
6290   int x_left  = gi->x - xoffset_left;
6291   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
6292   int x_below = gi->x + (gi->width - xoffset_below) / 2;
6293   int y_side  = gi->y + (gi->height - getFontHeight(FONT_TEXT_1)) / 2;
6294   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
6295
6296   if (drawingarea_info[id].text_left)
6297     DrawText(x_left, y_side, drawingarea_info[id].text_left, FONT_TEXT_1);
6298
6299   if (drawingarea_info[id].text_right)
6300     DrawText(x_right, y_side, drawingarea_info[id].text_right, FONT_TEXT_1);
6301
6302   if (drawingarea_info[id].text_below)
6303     DrawText(x_below, y_below, drawingarea_info[id].text_below, FONT_TEXT_1);
6304
6305   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
6306   {
6307     DrawElementBorder(gi->x, gi->y,
6308                       area_xsize * MINI_TILEX, area_ysize * MINI_TILEY, TRUE);
6309
6310     DrawDrawingArea(id);
6311   }
6312
6313   MapGadget(gi);
6314 }
6315
6316 static void MapTextInputGadget(int id)
6317 {
6318   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
6319   int xoffset_above = 0;
6320   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
6321   int x_above = textinput_info[id].x + xoffset_above;
6322   int y_above = textinput_info[id].y + yoffset_above;
6323
6324   if (textinput_info[id].text_above)
6325     DrawTextS(x_above, y_above, FONT_TEXT_1, textinput_info[id].text_above);
6326
6327   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
6328
6329   MapGadget(gi);
6330 }
6331
6332 static void MapTextAreaGadget(int id)
6333 {
6334   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
6335   int xoffset_above = 0;
6336   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
6337   int x_above = textarea_info[id].x + xoffset_above;
6338   int y_above = textarea_info[id].y + yoffset_above;
6339
6340   if (textarea_info[id].text_above)
6341     DrawTextS(x_above, y_above, FONT_TEXT_1, textarea_info[id].text_above);
6342
6343   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
6344
6345   MapGadget(gi);
6346 }
6347
6348 static void MapSelectboxGadget(int id)
6349 {
6350   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
6351   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
6352   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6353   int yoffset = ED_BORDER_SIZE;
6354   int x_left = gi->x - xoffset_left;
6355   int x_right = gi->x + gi->width + xoffset_right;
6356   int y = gi->y + yoffset;
6357
6358   if (selectbox_info[id].text_left)
6359     DrawText(x_left, y, selectbox_info[id].text_left, FONT_TEXT_1);
6360
6361   if (selectbox_info[id].text_right)
6362     DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1);
6363
6364   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
6365
6366   MapGadget(gi);
6367 }
6368
6369 static void MapTextbuttonGadget(int id)
6370 {
6371   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
6372   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
6373   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6374   int yoffset = ED_BORDER_SIZE;
6375   int x_left = gi->x - xoffset_left;
6376   int x_right = gi->x + gi->width + xoffset_right;
6377   int y = gi->y + yoffset;
6378
6379   /* only show button to delete change pages when more than minimum pages */
6380   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
6381       custom_element.num_change_pages == MIN_CHANGE_PAGES)
6382     return;
6383
6384   if (textbutton_info[id].text_left)
6385     DrawText(x_left, y, textbutton_info[id].text_left, FONT_TEXT_1);
6386
6387   if (textbutton_info[id].text_right)
6388     DrawText(x_right, y, textbutton_info[id].text_right, FONT_TEXT_1);
6389
6390   MapGadget(gi);
6391 }
6392
6393 static void MapGraphicbuttonGadget(int id)
6394 {
6395   struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id];
6396   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
6397   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6398   int yoffset = ED_BORDER_SIZE;
6399   int x_left = gi->x - xoffset_left;
6400   int x_right = gi->x + gi->width + xoffset_right;
6401   int y = gi->y + yoffset;
6402
6403   if (graphicbutton_info[id].text_left)
6404     DrawText(x_left, y, graphicbutton_info[id].text_left, FONT_TEXT_1);
6405
6406   if (graphicbutton_info[id].text_right)
6407     DrawText(x_right, y, graphicbutton_info[id].text_right, FONT_TEXT_1);
6408
6409   MapGadget(gi);
6410 }
6411
6412 static void MapRadiobuttonGadget(int id)
6413 {
6414   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
6415   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6416   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6417   int yoffset = ED_BORDER_SIZE;
6418   int x_left = gi->x - xoffset_left;
6419   int x_right = gi->x + gi->width + xoffset_right;
6420   int y = gi->y + yoffset;
6421   boolean checked =
6422     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
6423
6424   if (radiobutton_info[id].text_left)
6425     DrawText(x_left, y, radiobutton_info[id].text_left, FONT_TEXT_1);
6426
6427   if (radiobutton_info[id].text_right)
6428     DrawText(x_right, y, radiobutton_info[id].text_right, FONT_TEXT_1);
6429
6430   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
6431
6432   MapGadget(gi);
6433 }
6434
6435 static void MapCheckbuttonGadget(int id)
6436 {
6437   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
6438   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6439   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6440   int yoffset = ED_BORDER_SIZE;
6441   int x_left, x_right, y;       /* set after gadget position was modified */
6442
6443   /* set position for gadgets with dynamically determined position */
6444   if (checkbutton_info[id].x != -1)     /* do not change dynamic positions */
6445     ModifyGadget(gi, GDI_X, SX + checkbutton_info[id].x, GDI_END);
6446   ModifyGadget(gi, GDI_Y, SY + checkbutton_info[id].y, GDI_END);
6447
6448   x_left = gi->x - xoffset_left;
6449   x_right = gi->x + gi->width + xoffset_right;
6450   y = gi->y + yoffset;
6451
6452   if (checkbutton_info[id].text_left)
6453     DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1);
6454
6455   if (checkbutton_info[id].text_right)
6456     DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1);
6457
6458   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
6459
6460   MapGadget(gi);
6461 }
6462
6463 static void MapMainDrawingArea()
6464 {
6465   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
6466   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
6467   int i;
6468
6469   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
6470   {
6471     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
6472           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
6473          no_horizontal_scrollbar) ||
6474         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
6475           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
6476          no_vertical_scrollbar))
6477       continue;
6478
6479     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
6480   }
6481
6482   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
6483   {
6484     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
6485         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
6486       continue;
6487
6488     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
6489   }
6490
6491   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
6492 }
6493
6494 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
6495 {
6496   int i;
6497
6498   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
6499   {
6500     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
6501         i == GADGET_ID_CUSTOM_COPY_TO ||
6502         i == GADGET_ID_CUSTOM_EXCHANGE ||
6503         i == GADGET_ID_CUSTOM_COPY ||
6504         i == GADGET_ID_CUSTOM_PASTE)
6505     {
6506       if (map)
6507         MapGadget(level_editor_gadget[i]);
6508       else
6509         UnmapGadget(level_editor_gadget[i]);
6510     }
6511   }
6512 }
6513
6514 static void MapLevelEditorToolboxCustomGadgets()
6515 {
6516   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
6517 }
6518
6519 static void UnmapLevelEditorToolboxCustomGadgets()
6520 {
6521   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
6522 }
6523
6524 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
6525 {
6526   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6527   int i;
6528
6529   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
6530   {
6531     if (i != GADGET_ID_SINGLE_ITEMS &&
6532         i != GADGET_ID_PROPERTIES &&
6533         i != GADGET_ID_PICK_ELEMENT)
6534     {
6535       struct GadgetInfo *gi = level_editor_gadget[i];
6536
6537       if (map)
6538         MapGadget(gi);
6539       else
6540       {
6541         UnmapGadget(gi);
6542
6543         BlitBitmap(gd_bitmap, drawto,
6544                    DOOR_GFX_PAGEX6 + ED_CTRL_NO_BUTTONS_GFX_XPOS,
6545                    DOOR_GFX_PAGEY1 + ED_CTRL_NO_BUTTONS_GFX_YPOS,
6546                    gi->width, gi->height, gi->x, gi->y);
6547
6548         redraw_mask |= REDRAW_DOOR_3;
6549       }
6550     }
6551   }
6552 }
6553
6554 static void MapLevelEditorToolboxDrawingGadgets()
6555 {
6556   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
6557 }
6558
6559 static void UnmapLevelEditorToolboxDrawingGadgets()
6560 {
6561   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
6562 }
6563
6564 static void UnmapDrawingArea(int id)
6565 {
6566   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
6567 }
6568
6569 static void UnmapLevelEditorWindowGadgets()
6570 {
6571   int i;
6572
6573   for (i = 0; i < NUM_EDITOR_GADGETS; i++)
6574     if (level_editor_gadget[i]->x < SX + SXSIZE)
6575       UnmapGadget(level_editor_gadget[i]);
6576 }
6577
6578 void UnmapLevelEditorGadgets()
6579 {
6580   int i;
6581
6582   for (i = 0; i < NUM_EDITOR_GADGETS; i++)
6583     UnmapGadget(level_editor_gadget[i]);
6584 }
6585
6586 static void ResetUndoBuffer()
6587 {
6588   undo_buffer_position = -1;
6589   undo_buffer_steps = -1;
6590   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6591
6592   level.changed = FALSE;
6593 }
6594
6595 static void DrawEditModeWindow()
6596 {
6597   ModifyEditorElementList();
6598   RedrawDrawingElements();
6599
6600   if (edit_mode == ED_MODE_INFO)
6601     DrawLevelInfoWindow();
6602   else if (edit_mode == ED_MODE_PROPERTIES)
6603     DrawPropertiesWindow();
6604   else  /* edit_mode == ED_MODE_DRAWING */
6605     DrawDrawingWindow();
6606 }
6607
6608 static boolean LevelChanged()
6609 {
6610   boolean field_changed = FALSE;
6611   int x, y;
6612
6613   if (leveldir_current->readonly)
6614     return FALSE;
6615
6616   for (y = 0; y < lev_fieldy; y++) 
6617     for (x = 0; x < lev_fieldx; x++)
6618       if (Feld[x][y] != level.field[x][y])
6619         field_changed = TRUE;
6620
6621   return (level.changed || field_changed);
6622 }
6623
6624 static boolean LevelContainsPlayer()
6625 {
6626   boolean player_found = FALSE;
6627   int x, y;
6628
6629   return TRUE;          /* !!! CURRENTLY DEACTIVATED !!! */
6630
6631   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
6632   {
6633     if (Feld[x][y] == EL_PLAYER_1 ||
6634         Feld[x][y] == EL_SP_MURPHY) 
6635       player_found = TRUE;
6636   }
6637
6638   return player_found;
6639 }
6640
6641 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
6642                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
6643 {
6644   int x, y;
6645
6646   for (x = 0; x < lev_fieldx; x++)
6647     for (y = 0; y < lev_fieldy; y++) 
6648       dst[x][y] = src[x][y];
6649 }
6650
6651 static int setSelectboxValue(int selectbox_id, int new_value)
6652 {
6653   int new_index_value = 0;
6654   int i;
6655
6656   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
6657     if (selectbox_info[selectbox_id].options[i].value == new_value)
6658       new_index_value = i;
6659
6660   *selectbox_info[selectbox_id].value =
6661     selectbox_info[selectbox_id].options[new_index_value].value;
6662
6663   return new_index_value;
6664 }
6665
6666 static void setSelectboxSpecialActionVariablesIfNeeded()
6667 {
6668   int i;
6669
6670   /* change action mode and arg variables according to action type variable */
6671   for (i = 0; action_arg_options[i].value != -1; i++)
6672   {
6673     if (action_arg_options[i].value == custom_element_change.action_type)
6674     {
6675       int mode = action_arg_options[i].mode;
6676
6677       /* only change if corresponding selectbox has changed */
6678       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
6679           action_arg_modes[mode])
6680         custom_element_change.action_mode = -1;
6681
6682       /* only change if corresponding selectbox has changed */
6683       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
6684           action_arg_options[i].options)
6685         custom_element_change.action_arg = -1;
6686
6687       break;
6688     }
6689   }
6690 }
6691
6692 static void setSelectboxSpecialActionOptions()
6693 {
6694   int i;
6695
6696   /* change action mode and arg selectbox according to action type selectbox */
6697   for (i = 0; action_arg_options[i].value != -1; i++)
6698   {
6699     if (action_arg_options[i].value == custom_element_change.action_type)
6700     {
6701       int mode = action_arg_options[i].mode;
6702
6703       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
6704                                    action_arg_modes[mode]);
6705       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
6706                                  custom_element_change.action_mode);
6707
6708       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
6709                                    action_arg_options[i].options);
6710       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
6711                                  custom_element_change.action_arg);
6712       break;
6713     }
6714   }
6715 }
6716
6717 static void copy_custom_element_settings(int element_from, int element_to)
6718 {
6719   struct ElementInfo *ei_from = &element_info[element_from];
6720   struct ElementInfo *ei_to = &element_info[element_to];
6721
6722   copyElementInfo(ei_from, ei_to);
6723 }
6724
6725 static void replace_custom_element_in_settings(int element_from,
6726                                                int element_to)
6727 {
6728   int i, j, x, y;
6729
6730   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6731   {
6732     struct ElementInfo *ei = &element_info[i];
6733
6734     for (y = 0; y < 3; y++)
6735       for (x = 0; x < 3; x++)
6736         if (ei->content.e[x][y] == element_from)
6737           ei->content.e[x][y] = element_to;
6738
6739     for (j = 0; j < ei->num_change_pages; j++)
6740     {
6741       struct ElementChangeInfo *change = &ei->change_page[j];
6742
6743       if (change->target_element == element_from)
6744         change->target_element = element_to;
6745
6746       if (change->initial_trigger_element == element_from)
6747         change->initial_trigger_element = element_to;
6748
6749       if (change->action_element == element_from)
6750         change->action_element = element_to;
6751
6752       for (y = 0; y < 3; y++)
6753         for (x = 0; x < 3; x++)
6754           if (change->target_content.e[x][y] == element_from)
6755             change->target_content.e[x][y] = element_to;
6756     }
6757
6758     if (ei->group != NULL)                              /* group or internal */
6759       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
6760         if (ei->group->element[j] == element_from)
6761           ei->group->element[j] = element_to;
6762   }
6763 }
6764
6765 static void replace_custom_element_in_playfield(int element_from,
6766                                                 int element_to)
6767 {
6768   int x, y;
6769
6770   for (x = 0; x < lev_fieldx; x++)
6771     for (y = 0; y < lev_fieldy; y++)
6772       if (Feld[x][y] == element_from)
6773         Feld[x][y] = element_to;
6774 }
6775
6776 static boolean CopyCustomElement(int element_old, int element_new,
6777                                  int copy_mode)
6778 {
6779   if (copy_mode == GADGET_ID_CUSTOM_COPY)
6780   {
6781     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
6782                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
6783     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
6784   }
6785   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
6786   {
6787     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
6788                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
6789     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
6790
6791     level.changed = TRUE;
6792   }
6793   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
6794   {
6795     Request("Please choose custom element !", REQ_CONFIRM);
6796
6797     return FALSE;
6798   }
6799   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
6800   {
6801     Request("Please choose group element !", REQ_CONFIRM);
6802
6803     return FALSE;
6804   }
6805   else
6806   {
6807     level.changed = TRUE;
6808   }
6809
6810   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
6811   {
6812     copy_custom_element_settings(element_new, element_old);
6813   }
6814   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
6815   {
6816     copy_custom_element_settings(element_old, element_new);
6817   }
6818   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
6819   {
6820     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
6821     copy_custom_element_settings(element_new, element_old);
6822     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
6823
6824     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
6825     replace_custom_element_in_settings(element_new, element_old);
6826     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
6827
6828     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
6829     replace_custom_element_in_playfield(element_new, element_old);
6830     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
6831   }
6832
6833   UpdateCustomElementGraphicGadgets();
6834   DrawPropertiesWindow();
6835
6836   return TRUE;
6837 }
6838
6839 static void CopyCustomElementPropertiesToEditor(int element)
6840 {
6841   int i;
6842   int current_change_page = element_info[element].current_change_page;
6843
6844   /* dynamically (re)build selectbox for selecting change page */
6845   for (i = 0; i < element_info[element].num_change_pages; i++)
6846   {
6847     sprintf(options_change_page_strings[i], "%d", i + 1);
6848
6849     options_change_page[i].value = i;
6850     options_change_page[i].text = options_change_page_strings[i];
6851   }
6852
6853   options_change_page[i].value = -1;
6854   options_change_page[i].text = NULL;
6855
6856   /* needed here to initialize combined element properties */
6857   InitElementPropertiesEngine(level.game_version);
6858
6859   element_info[element].change =
6860     &element_info[element].change_page[current_change_page];
6861
6862   custom_element = element_info[element];
6863   custom_element_change = *element_info[element].change;
6864
6865   /* needed to initially set selectbox options for special action options */
6866   setSelectboxSpecialActionOptions();
6867
6868   /* needed to initially set selectbox value variables to reliable defaults */
6869   for (i = 0; i < ED_NUM_SELECTBOX; i++)
6870     setSelectboxValue(i, *selectbox_info[i].value);
6871
6872   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
6873     custom_element_properties[i] = HAS_PROPERTY(element, i);
6874
6875   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
6876     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
6877
6878   /* ---------- element settings: configure (custom elements) ------------- */
6879
6880   /* set accessible layer selectbox help value */
6881   custom_element.access_type =
6882     (IS_WALKABLE(element) ? EP_WALKABLE :
6883      IS_PASSABLE(element) ? EP_PASSABLE :
6884      custom_element.access_type);
6885   custom_element.access_layer =
6886     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
6887      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
6888      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
6889      custom_element.access_layer);
6890   custom_element.access_protected =
6891     (IS_PROTECTED(element) ? 1 : 0);
6892   custom_element_properties[EP_ACCESSIBLE] =
6893     (IS_ACCESSIBLE_OVER(element) ||
6894      IS_ACCESSIBLE_INSIDE(element) ||
6895      IS_ACCESSIBLE_UNDER(element));
6896
6897   /* set walk-to-object action selectbox help value */
6898   custom_element.walk_to_action =
6899     (IS_DIGGABLE(element) ? EP_DIGGABLE :
6900      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
6901      IS_DROPPABLE(element) ? EP_DROPPABLE :
6902      IS_THROWABLE(element) ? EP_THROWABLE :
6903      IS_PUSHABLE(element) ? EP_PUSHABLE :
6904      custom_element.walk_to_action);
6905   custom_element_properties[EP_WALK_TO_OBJECT] =
6906     (IS_DIGGABLE(element) ||
6907      IS_COLLECTIBLE_ONLY(element) ||
6908      IS_DROPPABLE(element) ||
6909      IS_THROWABLE(element) ||
6910      IS_PUSHABLE(element));
6911
6912   /* set smash targets selectbox help value */
6913   custom_element.smash_targets =
6914     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
6915      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
6916      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
6917      custom_element.smash_targets);
6918   custom_element_properties[EP_CAN_SMASH] =
6919     (CAN_SMASH_EVERYTHING(element) ||
6920      CAN_SMASH_ENEMIES(element) ||
6921      CAN_SMASH_PLAYER(element));
6922
6923   /* set deadliness selectbox help value */
6924   custom_element.deadliness =
6925     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
6926      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
6927      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
6928      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
6929      custom_element.deadliness);
6930   custom_element_properties[EP_DEADLY] =
6931     (DONT_TOUCH(element) ||
6932      DONT_GET_HIT_BY(element) ||
6933      DONT_COLLIDE_WITH(element) ||
6934      DONT_RUN_INTO(element));
6935
6936   /* ---------- element settings: advanced (custom elements) --------------- */
6937
6938   /* set "change by direct action" selectbox help value */
6939   custom_element_change.direct_action =
6940     (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
6941      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
6942      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
6943      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
6944      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
6945      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
6946      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
6947      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
6948      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
6949      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
6950      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
6951      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
6952      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
6953      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
6954      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
6955      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
6956      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
6957      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
6958      custom_element_change.direct_action);
6959
6960   /* set "change by other element action" selectbox help value */
6961   custom_element_change.other_action =
6962     (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
6963      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
6964      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
6965      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
6966      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
6967      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
6968      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
6969      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
6970      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
6971      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
6972      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
6973      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
6974      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
6975      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
6976      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
6977      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
6978      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
6979      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
6980      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
6981      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
6982      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
6983      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
6984      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
6985      custom_element_change.other_action);
6986 }
6987
6988 static void CopyGroupElementPropertiesToEditor(int element)
6989 {
6990   group_element_info = *element_info[element].group;
6991   custom_element = element_info[element];       /* needed for description */
6992 }
6993
6994 static void CopyClassicElementPropertiesToEditor(int element)
6995 {
6996   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
6997     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
6998       getMoveIntoAcidProperty(&level, element);
6999
7000   if (MAYBE_DONT_COLLIDE_WITH(element))
7001     custom_element_properties[EP_DONT_COLLIDE_WITH] =
7002       getDontCollideWithProperty(&level, element);
7003 }
7004
7005 static void CopyElementPropertiesToEditor(int element)
7006 {
7007   if (IS_CUSTOM_ELEMENT(element))
7008     CopyCustomElementPropertiesToEditor(element);
7009   else if (IS_GROUP_ELEMENT(element))
7010     CopyGroupElementPropertiesToEditor(element);
7011   else
7012     CopyClassicElementPropertiesToEditor(element);
7013 }
7014
7015 static void CopyCustomElementPropertiesToGame(int element)
7016 {
7017   int i;
7018   int access_type_and_layer;
7019
7020   /* mark that this custom element has been modified */
7021   custom_element.modified_settings = TRUE;
7022   level.changed = TRUE;
7023
7024   if (level.use_custom_template)
7025   {
7026     if (Request("Copy and modify level template ?", REQ_ASK))
7027     {
7028       level.use_custom_template = FALSE;
7029       ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
7030                    GDI_CHECKED, FALSE, GDI_END);
7031     }
7032     else
7033     {
7034       LoadLevelTemplate(-1);    /* this resets all element modifications ... */
7035
7036       DrawEditModeWindow();     /* ... and copies them to 'custom_element' */
7037     }
7038   }
7039
7040   element_info[element] = custom_element;
7041   *element_info[element].change = custom_element_change;
7042
7043   /* ---------- element settings: configure (custom elements) ------------- */
7044
7045   /* set accessible property from checkbox and selectbox */
7046   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
7047   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
7048   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
7049   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
7050   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
7051   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
7052   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
7053                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
7054                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
7055   custom_element_properties[access_type_and_layer] =
7056     custom_element_properties[EP_ACCESSIBLE];
7057   custom_element_properties[EP_PROTECTED] =
7058     (custom_element.access_protected != 0 &&
7059      custom_element_properties[EP_ACCESSIBLE]);
7060
7061   /* set walk-to-object property from checkbox and selectbox */
7062   custom_element_properties[EP_DIGGABLE] = FALSE;
7063   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
7064   custom_element_properties[EP_DROPPABLE] = FALSE;
7065   custom_element_properties[EP_THROWABLE] = FALSE;
7066   custom_element_properties[EP_PUSHABLE] = FALSE;
7067   custom_element_properties[custom_element.walk_to_action] =
7068     custom_element_properties[EP_WALK_TO_OBJECT];
7069
7070   /* set smash property from checkbox and selectbox */
7071   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
7072   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
7073   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
7074   custom_element_properties[custom_element.smash_targets] =
7075     custom_element_properties[EP_CAN_SMASH];
7076
7077   /* set deadliness property from checkbox and selectbox */
7078   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
7079   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
7080   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
7081   custom_element_properties[EP_DONT_TOUCH] = FALSE;
7082   custom_element_properties[custom_element.deadliness] =
7083     custom_element_properties[EP_DEADLY];
7084
7085   /* ---------- element settings: advanced (custom elements) --------------- */
7086
7087   /* set player change event from checkbox and selectbox */
7088   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
7089   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
7090   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
7091   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
7092   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
7093   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
7094   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
7095   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
7096   custom_element_change_events[CE_SWITCHED] = FALSE;
7097   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
7098   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
7099   custom_element_change_events[CE_BLOCKED] = FALSE;
7100   custom_element_change_events[CE_IMPACT] = FALSE;
7101   custom_element_change_events[CE_SMASHED] = FALSE;
7102   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
7103   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
7104   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
7105   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
7106   custom_element_change_events[custom_element_change.direct_action] =
7107     custom_element_change_events[CE_BY_DIRECT_ACTION];
7108
7109   /* set other element action change event from checkbox and selectbox */
7110   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
7111   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
7112   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
7113   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
7114   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
7115   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
7116   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
7117   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
7118   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
7119   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
7120   custom_element_change_events[CE_TOUCHING_X] = FALSE;
7121   custom_element_change_events[CE_HITTING_X] = FALSE;
7122   custom_element_change_events[CE_DIGGING_X] = FALSE;
7123   custom_element_change_events[CE_HIT_BY_X] = FALSE;
7124   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
7125   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
7126   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
7127   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
7128   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
7129   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
7130   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
7131   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
7132   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
7133   custom_element_change_events[custom_element_change.other_action] =
7134     custom_element_change_events[CE_BY_OTHER_ACTION];
7135
7136   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
7137     SET_PROPERTY(element, i, custom_element_properties[i]);
7138
7139   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
7140     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
7141
7142   /* copy change events also to special level editor variable */
7143   custom_element = element_info[element];
7144   custom_element_change = *element_info[element].change;
7145 }
7146
7147 static void CopyGroupElementPropertiesToGame(int element)
7148 {
7149   element_info[element] = custom_element;
7150   *element_info[element].group = group_element_info;
7151
7152   /* mark that this group element has been modified */
7153   element_info[element].modified_settings = TRUE;
7154   level.changed = TRUE;
7155 }
7156
7157 static void CopyClassicElementPropertiesToGame(int element)
7158 {
7159   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
7160     setMoveIntoAcidProperty(&level, element,
7161                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
7162
7163   if (MAYBE_DONT_COLLIDE_WITH(element))
7164     setDontCollideWithProperty(&level, element,
7165                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
7166 }
7167
7168 static void CopyElementPropertiesToGame(int element)
7169 {
7170   if (IS_CUSTOM_ELEMENT(element))
7171     CopyCustomElementPropertiesToGame(element);
7172   else if (IS_GROUP_ELEMENT(element))
7173     CopyGroupElementPropertiesToGame(element);
7174   else
7175     CopyClassicElementPropertiesToGame(element);
7176 }
7177
7178 void CheckElementDescriptions()
7179 {
7180   int i;
7181
7182   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7183     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
7184       Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
7185 }
7186
7187 void DrawLevelEd()
7188 {
7189   StopAnimation();
7190
7191   CloseDoor(DOOR_CLOSE_ALL);
7192
7193 #if 1
7194   FadeOut(REDRAW_FIELD);
7195 #endif
7196
7197   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
7198
7199 #if DEBUG
7200   CheckElementDescriptions();
7201 #endif
7202
7203   if (level_editor_test_game)
7204   {
7205     CopyPlayfield(level.field, Feld);
7206     CopyPlayfield(FieldBackup, level.field);
7207
7208     level_editor_test_game = FALSE;
7209   }
7210   else
7211   {
7212     edit_mode = ED_MODE_DRAWING;
7213     edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
7214     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
7215
7216     ResetUndoBuffer();
7217
7218     level_xpos = -1;
7219     level_ypos = -1;
7220   }
7221
7222   /* copy default editor door content to main double buffer */
7223   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
7224              DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
7225
7226   /* draw bigger door */
7227   DrawSpecialEditorDoor();
7228
7229   /* draw new control window */
7230   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
7231              DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
7232
7233   redraw_mask |= REDRAW_ALL;
7234
7235   ReinitializeElementList();            /* update dynamic level element list */
7236   ReinitializeElementListButtons();     /* custom element may look different */
7237
7238   InitElementPropertiesGfxElement();
7239
7240 #if 1
7241   UnmapAllGadgets();
7242 #else
7243   UnmapTapeButtons();
7244 #endif
7245   MapControlButtons();
7246
7247 #if 0
7248   FadeOut(REDRAW_FIELD);
7249 #endif
7250
7251   DrawEditModeWindow();
7252
7253 #if 1
7254   FadeIn(REDRAW_FIELD);
7255 #endif
7256
7257   /* copy actual editor door content to door double buffer for OpenDoor() */
7258   BlitBitmap(drawto, bitmap_db_door,
7259              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
7260
7261 #if 1
7262   /* draw new control window (with border) to window */
7263   redraw_mask |= REDRAW_ALL;
7264   BackToFront();
7265 #endif
7266
7267   OpenDoor(DOOR_OPEN_1);
7268 }
7269
7270 static void AdjustDrawingAreaGadgets()
7271 {
7272   int ed_xsize = lev_fieldx + 2;
7273   int ed_ysize = lev_fieldy + 2;
7274   int max_ed_fieldx = MAX_ED_FIELDX;
7275   int max_ed_fieldy = MAX_ED_FIELDY;
7276   boolean horizontal_scrollbar_needed;
7277   boolean vertical_scrollbar_needed;
7278   int x, y, width, height;
7279   int xoffset, yoffset;
7280
7281   /* check if we need any scrollbars */
7282   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7283   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
7284
7285   /* check if we have a smaller editor field because of scrollbars */
7286   if (horizontal_scrollbar_needed)
7287     max_ed_fieldy = MAX_ED_FIELDY - 1;
7288   if (vertical_scrollbar_needed)
7289     max_ed_fieldx = MAX_ED_FIELDX - 1;
7290
7291   /* check again if we now need more scrollbars because of less space */
7292   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7293   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
7294
7295   /* check if editor field gets even smaller after adding new scrollbars */
7296   if (horizontal_scrollbar_needed)
7297     max_ed_fieldy = MAX_ED_FIELDY - 1;
7298   if (vertical_scrollbar_needed)
7299     max_ed_fieldx = MAX_ED_FIELDX - 1;
7300
7301   ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
7302   ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
7303
7304   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
7305                GDI_WIDTH, ed_fieldx * MINI_TILEX,
7306                GDI_HEIGHT, ed_fieldy * MINI_TILEY,
7307                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
7308                GDI_END);
7309
7310   xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
7311   yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
7312
7313   x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
7314   y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
7315
7316   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
7317   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
7318
7319   width = scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
7320   height = scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
7321
7322   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
7323                GDI_WIDTH, width,
7324                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
7325                GDI_END);
7326   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
7327                GDI_HEIGHT, height,
7328                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
7329                GDI_END);
7330 }
7331
7332 static void AdjustLevelScrollPosition()
7333 {
7334   if (level_xpos < -1)
7335     level_xpos = -1;
7336   if (level_xpos > lev_fieldx - ed_fieldx + 1)
7337     level_xpos = lev_fieldx - ed_fieldx + 1;
7338   if (lev_fieldx < ed_fieldx - 2)
7339     level_xpos = -1;
7340
7341   if (level_ypos < -1)
7342     level_ypos = -1;
7343   if (level_ypos > lev_fieldy - ed_fieldy + 1)
7344     level_ypos = lev_fieldy - ed_fieldy + 1;
7345   if (lev_fieldy < ed_fieldy - 2)
7346     level_ypos = -1;
7347 }
7348
7349 static void AdjustEditorScrollbar(int id)
7350 {
7351   struct GadgetInfo *gi = level_editor_gadget[id];
7352   int items_max, items_visible, item_position;
7353
7354   if (id == GADGET_ID_SCROLL_HORIZONTAL)
7355   {
7356     items_max = MAX(lev_fieldx + 2, ed_fieldx);
7357     items_visible = ed_fieldx;
7358     item_position = level_xpos + 1;
7359   }
7360   else
7361   {
7362     items_max = MAX(lev_fieldy + 2, ed_fieldy);
7363     items_visible = ed_fieldy;
7364     item_position = level_ypos + 1;
7365   }
7366
7367   if (item_position > items_max - items_visible)
7368     item_position = items_max - items_visible;
7369
7370   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7371                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7372 }
7373
7374 static void AdjustElementListScrollbar()
7375 {
7376   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
7377   int items_max, items_visible, item_position;
7378
7379   /* correct position of element list scrollbar */
7380   if (element_shift < 0)
7381     element_shift = 0;
7382   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
7383     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
7384
7385   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
7386   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
7387   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
7388
7389   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7390                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
7391                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7392 }
7393
7394 static void ModifyEditorCounterValue(int counter_id, int new_value)
7395 {
7396   int *counter_value = counterbutton_info[counter_id].value;
7397   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7398   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7399
7400   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
7401
7402   if (counter_value != NULL)
7403     *counter_value = gi->textinput.number_value;
7404 }
7405
7406 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
7407 {
7408   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7409   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7410
7411   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
7412
7413   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
7414       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
7415   {
7416     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
7417     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
7418
7419     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
7420     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_DISTANCE,GDI_END);
7421   }
7422 }
7423
7424 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
7425 {
7426   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7427   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7428   int new_index_value = setSelectboxValue(selectbox_id, new_value);
7429
7430   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
7431 }
7432
7433 static void ModifyEditorSelectboxOptions(int selectbox_id,
7434                                          struct ValueTextInfo *options)
7435 {
7436   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7437   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7438
7439   selectbox_info[selectbox_id].options = options;
7440
7441   /* set index to zero -- list may be shorter now (correct later, if needed) */
7442   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
7443                GDI_SELECTBOX_OPTIONS, options, GDI_END);
7444 }
7445
7446 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
7447 {
7448   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
7449   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7450
7451   drawingarea_info[drawingarea_id].area_xsize = xsize;
7452   drawingarea_info[drawingarea_id].area_ysize = ysize;
7453
7454   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
7455 }
7456
7457 static void ModifyEditorElementList()
7458 {
7459   int i;
7460
7461   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7462   {
7463     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
7464     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7465     struct GadgetDesign *gd = &gi->deco.design;
7466     int element = editor_elements[element_shift + i];
7467
7468     UnmapGadget(gi);
7469
7470     getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
7471     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
7472
7473     MapGadget(gi);
7474   }
7475 }
7476
7477 static void PickDrawingElement(int button, int element)
7478 {
7479   if (button < 1 || button > 3)
7480     return;
7481
7482   if (button == 1)
7483   {
7484     new_element1 = element;
7485     DrawMiniGraphicExt(drawto,
7486                        DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
7487                        el2edimg(new_element1));
7488   }
7489   else if (button == 2)
7490   {
7491     new_element2 = element;
7492     DrawMiniGraphicExt(drawto,
7493                        DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
7494                        el2edimg(new_element2));
7495   }
7496   else
7497   {
7498     new_element3 = element;
7499     DrawMiniGraphicExt(drawto,
7500                        DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
7501                        el2edimg(new_element3));
7502   }
7503
7504   redraw_mask |= REDRAW_DOOR_1;
7505 }
7506
7507 static void RedrawDrawingElements()
7508 {
7509   PickDrawingElement(1, new_element1);
7510   PickDrawingElement(2, new_element2);
7511   PickDrawingElement(3, new_element3);
7512 }
7513
7514 static void DrawDrawingWindow()
7515 {
7516   stick_element_properties_window = FALSE;
7517
7518   SetMainBackgroundImage(IMG_UNDEFINED);
7519   ClearField();
7520
7521   UnmapLevelEditorWindowGadgets();
7522   UnmapLevelEditorToolboxCustomGadgets();
7523
7524   AdjustDrawingAreaGadgets();
7525   AdjustLevelScrollPosition();
7526   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
7527   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
7528
7529   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
7530
7531   MapMainDrawingArea();
7532   MapLevelEditorToolboxDrawingGadgets();
7533 }
7534
7535 static int getTabulatorBarWidth()
7536 {
7537   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
7538   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
7539
7540   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
7541 }
7542
7543 static void DrawLevelInfoTabulatorGadgets()
7544 {
7545   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
7546   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
7547   int gd_x = gd->x + gd_gi1->border.width / 2;
7548   int gd_y = gd->y + gd_gi1->height - 1;
7549   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
7550   int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL;
7551   int id_last  = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR;
7552 #if 1
7553 #else
7554   int max_tabs = 2;
7555 #endif
7556   int i;
7557
7558   for (i = id_first; i <= id_last; i++)
7559   {
7560     int gadget_id = textbutton_info[i].gadget_id;
7561     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7562     boolean active = (i != edit_mode_levelinfo);
7563
7564     /* draw background line below tabulator button */
7565     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
7566
7567     /* draw solid line below inactive tabulator buttons */
7568     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
7569       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, 1, tab_color);
7570
7571     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
7572     MapTextbuttonGadget(i);
7573   }
7574
7575 #if 1
7576   /* draw little border line below tabulator buttons */
7577   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
7578     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
7579                   getTabulatorBarWidth(), ED_GADGET_DISTANCE,
7580                   tab_color);
7581 #else
7582   /* draw little border line below tabulator buttons */
7583   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
7584     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
7585                   max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE,
7586                   ED_GADGET_DISTANCE, tab_color);
7587 #endif
7588 }
7589
7590 static void DrawPropertiesTabulatorGadgets()
7591 {
7592   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
7593   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
7594   int gd_x = gd->x + gd_gi1->border.width / 2;
7595   int gd_y = gd->y + gd_gi1->height - 1;
7596   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
7597   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
7598   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
7599 #if 1
7600 #else
7601   int max_tabs = 4;
7602 #endif
7603   int i;
7604
7605   /* draw two config tabulators for player elements */
7606   if (ELEM_IS_PLAYER(properties_element))
7607     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
7608
7609   /* draw two config and one "change" tabulator for custom elements */
7610   if (IS_CUSTOM_ELEMENT(properties_element))
7611     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
7612
7613   for (i = id_first; i <= id_last; i++)
7614   {
7615     int gadget_id = textbutton_info[i].gadget_id;
7616     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7617     boolean active = (i != edit_mode_properties);
7618
7619     /* use "config 1" and "config 2" instead of "config" for players and CEs */
7620     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
7621         (ELEM_IS_PLAYER(properties_element) ||
7622          IS_CUSTOM_ELEMENT(properties_element)))
7623       continue;
7624
7625     /* draw background line below tabulator button */
7626     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
7627
7628     /* draw solid line below inactive tabulator buttons */
7629     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
7630       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width, 1, tab_color);
7631
7632     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
7633     MapTextbuttonGadget(i);
7634   }
7635
7636 #if 1
7637   /* draw little border line below tabulator buttons */
7638   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
7639     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
7640                   getTabulatorBarWidth(), ED_GADGET_DISTANCE,
7641                   tab_color);
7642 #else
7643   /* draw little border line below tabulator buttons */
7644   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
7645     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height + 1,
7646                   max_tabs * gd_gi1->width + (max_tabs -1) * ED_GADGET_DISTANCE,
7647                   ED_GADGET_DISTANCE, tab_color);
7648 #endif
7649 }
7650
7651 static void DrawLevelInfoLevel()
7652 {
7653   int i;
7654
7655   /* draw counter gadgets */
7656   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
7657     MapCounterButtons(i);
7658
7659   /* draw selectbox gadgets */
7660   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
7661     MapSelectboxGadget(i);
7662
7663   /* draw text input gadgets */
7664   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
7665     MapTextInputGadget(i);
7666 }
7667
7668 static void DrawLevelInfoEditor()
7669 {
7670   int i;
7671
7672   /* draw counter gadgets */
7673   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
7674     MapCounterButtons(i);
7675
7676   /* draw checkbutton gadgets */
7677   for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
7678     MapCheckbuttonGadget(i);
7679
7680   /* draw radiobutton gadgets */
7681   for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
7682     MapRadiobuttonGadget(i);
7683
7684   /* draw drawing area */
7685   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
7686 }
7687
7688 static void DrawLevelInfoWindow()
7689 {
7690   stick_element_properties_window = FALSE;
7691
7692   UnmapLevelEditorWindowGadgets();
7693
7694   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
7695   ClearField();
7696
7697 #if 1
7698 #if 1
7699   DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Global Settings");
7700 #else
7701   DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Level Settings");
7702   DrawTextSCentered(ED_SETTINGS2_YPOS, FONT_TITLE_1, "Editor Settings");
7703 #endif
7704 #else
7705   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
7706            "Level Settings", FONT_TITLE_1);
7707   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
7708            "Editor Settings", FONT_TITLE_1);
7709 #endif
7710
7711   DrawLevelInfoTabulatorGadgets();
7712
7713   if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL)
7714     DrawLevelInfoLevel();
7715   else  /* (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR) */
7716     DrawLevelInfoEditor();
7717 }
7718
7719 static void DrawCustomContentArea()
7720 {
7721   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
7722   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7723   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
7724   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
7725   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
7726   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
7727
7728   /* add distance for potential left text (without drawing area border) */
7729   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
7730
7731   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
7732
7733   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
7734 }
7735
7736 static void DrawCustomChangeContentArea()
7737 {
7738   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
7739   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7740   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
7741   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
7742   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
7743   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
7744
7745   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
7746
7747   MapDrawingArea(id);
7748 }
7749
7750 static void DrawYamYamContentAreas()
7751 {
7752   int x = SX + ED_AREA_YAMYAM_CONTENT_XPOS(3) + 4 * MINI_TILEX;
7753   int y = SY + ED_AREA_YAMYAM_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE;
7754   int i;
7755
7756   /* display counter to choose number of element content areas */
7757   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
7758
7759   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7760   {
7761     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
7762
7763     if (i < level.num_yamyam_contents)
7764     {
7765       MapDrawingArea(id);
7766     }
7767     else
7768     {
7769       int font_height = getFontHeight(FONT_TEXT_1);
7770
7771       UnmapDrawingArea(id);
7772
7773       /* delete content areas in case of reducing number of them */
7774       DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
7775                      SY + drawingarea_info[id].y - MINI_TILEY / 2,
7776                      4 * MINI_TILEX,
7777                      4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height);
7778     }
7779   }
7780
7781   DrawText(x, y + 0 * MINI_TILEY, "content", FONT_TEXT_1);
7782   DrawText(x, y + 1 * MINI_TILEY, "when",    FONT_TEXT_1);
7783   DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1);
7784 }
7785
7786 static void DrawMagicBallContentAreas()
7787 {
7788   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_XPOS(3) + 4 * MINI_TILEX;
7789   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE;
7790   int i;
7791
7792   /* display counter to choose number of element content areas */
7793   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
7794
7795   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7796   {
7797     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
7798
7799     if (i < level.num_ball_contents)
7800     {
7801       MapDrawingArea(id);
7802     }
7803     else
7804     {
7805       int font_height = getFontHeight(FONT_TEXT_1);
7806
7807       UnmapDrawingArea(id);
7808
7809       /* delete content areas in case of reducing number of them */
7810       DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
7811                      SY + drawingarea_info[id].y - MINI_TILEY / 2,
7812                      4 * MINI_TILEX,
7813                      4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height);
7814     }
7815   }
7816
7817   DrawText(x, y + 0 * MINI_TILEY, "generated", FONT_TEXT_1);
7818   DrawText(x, y + 1 * MINI_TILEY, "when",      FONT_TEXT_1);
7819   DrawText(x, y + 2 * MINI_TILEY, "active",    FONT_TEXT_1);
7820 }
7821
7822 static void DrawAndroidElementArea(int element)
7823 {
7824   int num_elements = level.num_android_clone_elements;
7825   int id = ED_DRAWING_ID_ANDROID_CONTENT;
7826   int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
7827   int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
7828   int xsize = MAX_ANDROID_ELEMENTS;
7829   int ysize = 1;
7830
7831   /* display counter to choose number of element areas */
7832   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
7833
7834   if (drawingarea_info[id].text_left != NULL)
7835     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
7836
7837   UnmapDrawingArea(id);
7838
7839   ModifyEditorDrawingArea(id, num_elements, 1);
7840
7841   /* delete content areas in case of reducing number of them */
7842   DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
7843
7844   MapDrawingArea(id);
7845 }
7846
7847 static void DrawGroupElementArea(int element)
7848 {
7849   int num_elements = group_element_info.num_elements;
7850   int id = ED_DRAWING_ID_GROUP_CONTENT;
7851   int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
7852   int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
7853   int xsize = MAX_ELEMENTS_IN_GROUP;
7854   int ysize = 1;
7855
7856   if (drawingarea_info[id].text_left != NULL)
7857     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
7858
7859   UnmapDrawingArea(id);
7860
7861   ModifyEditorDrawingArea(id, num_elements, 1);
7862
7863   /* delete content areas in case of reducing number of them */
7864   DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
7865
7866   MapDrawingArea(id);
7867 }
7868
7869 static void DrawPlayerInitialInventoryArea(int element)
7870 {
7871   int player_nr = GET_PLAYER_NR(element);
7872   int num_elements = level.initial_inventory_size[player_nr];
7873   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
7874   int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
7875   int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
7876   int xsize = MAX_INITIAL_INVENTORY_SIZE;
7877   int ysize = 1;
7878
7879   /* determine horizontal position to the right of specified gadget */
7880   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
7881     sx += (right_gadget_border[drawingarea_info[id].gadget_id_align] +
7882            ED_DRAWINGAREA_TEXT_DISTANCE);
7883
7884   /* determine horizontal offset for leading text */
7885   if (drawingarea_info[id].text_left != NULL)
7886     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
7887
7888   UnmapDrawingArea(id);
7889
7890   ModifyEditorDrawingArea(id, num_elements, 1);
7891
7892   /* delete content areas in case of reducing number of them */
7893   DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
7894
7895   MapDrawingArea(id);
7896 }
7897
7898 static void DrawEnvelopeTextArea(int envelope_nr)
7899 {
7900   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
7901   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
7902
7903   UnmapGadget(gi);
7904   DrawBackground(gi->x, gi->y, gi->width, gi->height);
7905
7906   if (envelope_nr != -1)
7907     textarea_info[id].value = level.envelope[envelope_nr].text;
7908
7909   ModifyGadget(gi, GDI_AREA_SIZE,
7910                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
7911                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
7912                GDI_END);
7913
7914   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
7915 }
7916
7917 static boolean PrintInfoText(char *text, int font_nr, int start_line)
7918 {
7919   int font_height = getFontHeight(font_nr);
7920   int pad_x = ED_ELEMENT_SETTINGS_XPOS(0);
7921   int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
7922   int sx = SX + pad_x;
7923   int sy = SY + pad_y;
7924   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
7925
7926   if (start_line >= max_lines_per_screen)
7927     return FALSE;
7928
7929   DrawText(sx, sy + start_line * font_height, text, font_nr);
7930
7931   return TRUE;
7932 }
7933
7934 static int PrintElementDescriptionFromFile(char *filename, int start_line)
7935 {
7936   int font_nr = FONT_TEXT_2;
7937   int font_width = getFontWidth(font_nr);
7938   int font_height = getFontHeight(font_nr);
7939   int pad_x = ED_ELEMENT_SETTINGS_XPOS(0);
7940   int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
7941   int sx = SX + pad_x;
7942   int sy = SY + pad_y + start_line * font_height;
7943   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
7944   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
7945
7946   return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1,
7947                       max_lines_per_screen, -1, TRUE, FALSE, FALSE);
7948 }
7949
7950 static void DrawPropertiesInfo()
7951 {
7952   static struct
7953   {
7954     int value;
7955     char *text;
7956   }
7957   properties[] =
7958   {
7959     /* configurable properties */
7960
7961     { EP_WALKABLE_OVER,         "- player can walk over it"             },
7962     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
7963     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
7964     { EP_PASSABLE_OVER,         "- player can pass over it"             },
7965     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
7966     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
7967     { EP_PROTECTED,             "- player is protected by it"           },
7968
7969     { EP_DIGGABLE,              "- can be digged away"                  },
7970     { EP_COLLECTIBLE,           "- can be collected"                    },
7971     { EP_DROPPABLE,             "- can be dropped after collecting"     },
7972     { EP_THROWABLE,             "- can be thrown after collecting"      },
7973     { EP_PUSHABLE,              "- can be pushed"                       },
7974
7975     { EP_CAN_FALL,              "- can fall"                            },
7976     { EP_CAN_MOVE,              "- can move"                            },
7977
7978     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
7979 #if 0
7980     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
7981 #endif
7982     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
7983
7984     { EP_SLIPPERY,              "- slippery for falling elements"       },
7985     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
7986
7987     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
7988     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
7989     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
7990     { EP_DONT_TOUCH,            "- deadly when touching"                },
7991
7992     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
7993
7994     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
7995     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
7996     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
7997
7998     { EP_CAN_CHANGE,            "- can change to other element"         },
7999
8000     /* pre-defined properties */
8001     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
8002     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
8003     { EP_SWITCHABLE,            "- can be switched"                     },
8004 #if 0
8005     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
8006 #endif
8007
8008     { -1,                       NULL                                    }
8009   };
8010   char *filename = getElementDescriptionFilename(properties_element);
8011   char *percentage_text = "In this level:";
8012   char *properties_text = "Standard properties:";
8013   float percentage;
8014   int num_elements_in_level;
8015   int num_standard_properties = 0;
8016   int font1_nr = FONT_TEXT_1;
8017   int font2_nr = FONT_TEXT_2;
8018   int font1_width = getFontWidth(font1_nr);
8019   int font2_height = getFontHeight(font2_nr);
8020   int pad_x = ED_ELEMENT_SETTINGS_XPOS(0);
8021   int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
8022   int screen_line = 0;
8023   int i, x, y;
8024
8025   if (setup.editor.show_element_token)
8026   {
8027     DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
8028               "[%s]", element_info[properties_element].token_name);
8029     screen_line++;
8030   }
8031
8032   /* ----- print number of elements / percentage of this element in level */
8033
8034   num_elements_in_level = 0;
8035   for (y = 0; y < lev_fieldy; y++) 
8036     for (x = 0; x < lev_fieldx; x++)
8037       if (Feld[x][y] == properties_element)
8038         num_elements_in_level++;
8039   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
8040
8041   DrawTextS(pad_x, pad_y + screen_line * font2_height, font1_nr,
8042             percentage_text);
8043   DrawTextF(pad_x + strlen(percentage_text) * font1_width,
8044             pad_y + screen_line++ * font2_height, font2_nr,
8045             "%d (%.2f%%)", num_elements_in_level, percentage);
8046
8047   screen_line++;
8048
8049   /* ----- print standard properties of this element */
8050
8051   DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
8052             properties_text);
8053
8054   for (i = 0; properties[i].value != -1; i++)
8055   {
8056     if (!HAS_PROPERTY(properties_element, properties[i].value))
8057       continue;
8058
8059     DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
8060               properties[i].text);
8061     num_standard_properties++;
8062   }
8063
8064   if (num_standard_properties == 0)
8065     DrawTextS(pad_x + strlen(properties_text) * font1_width,
8066               pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
8067
8068   screen_line++;
8069
8070   /* ----- print special description of this element */
8071
8072   PrintInfoText("Description:", FONT_TEXT_1, screen_line);
8073   if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
8074     PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
8075 }
8076
8077 #define TEXT_COLLECTING         "Score for collecting"
8078 #define TEXT_SMASHING           "Score for smashing"
8079 #define TEXT_SLURPING           "Score for slurping robot"
8080 #define TEXT_CRACKING           "Score for cracking"
8081 #define TEXT_AMOEBA_SPEED       "Speed of amoeba growth"
8082 #define TEXT_DURATION           "Duration when activated"
8083 #define TEXT_BALL_DELAY         "Element generation delay"
8084 #define TEXT_MOVE_SPEED         "Speed of android moving"
8085 #define TEXT_CLONE_SPEED        "Speed of android cloning"
8086 #define TEXT_GAME_OF_LIFE_1     "Min neighbours to survive"
8087 #define TEXT_GAME_OF_LIFE_2     "Max neighbours to survive"
8088 #define TEXT_GAME_OF_LIFE_3     "Min neighbours to create"
8089 #define TEXT_GAME_OF_LIFE_4     "Max neighbours to create"
8090 #define TEXT_TIME_BONUS         "Extra time to solve level"
8091
8092 static struct
8093 {
8094   int element;
8095   int *value;
8096   char *text;
8097 } elements_with_counter[] =
8098 {
8099   { EL_EMERALD,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
8100   { EL_BD_DIAMOND,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
8101   { EL_EMERALD_YELLOW,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8102   { EL_EMERALD_RED,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8103   { EL_EMERALD_PURPLE,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8104   { EL_SP_INFOTRON,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8105   { EL_DIAMOND,         &level.score[SC_DIAMOND],       TEXT_COLLECTING },
8106   { EL_CRYSTAL,         &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
8107   { EL_PEARL,           &level.score[SC_PEARL],         TEXT_COLLECTING },
8108   { EL_BUG,             &level.score[SC_BUG],           TEXT_SMASHING   },
8109   { EL_BUG_RIGHT,       &level.score[SC_BUG],           TEXT_SMASHING   },
8110   { EL_BUG_UP,          &level.score[SC_BUG],           TEXT_SMASHING   },
8111   { EL_BUG_LEFT,        &level.score[SC_BUG],           TEXT_SMASHING   },
8112   { EL_BUG_DOWN,        &level.score[SC_BUG],           TEXT_SMASHING   },
8113   { EL_BD_BUTTERFLY,    &level.score[SC_BUG],           TEXT_SMASHING   },
8114   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],         TEXT_SMASHING   },
8115   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],         TEXT_SMASHING   },
8116   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],         TEXT_SMASHING   },
8117   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],         TEXT_SMASHING   },
8118   { EL_SP_ELECTRON,     &level.score[SC_BUG],           TEXT_SMASHING   },
8119   { EL_SPACESHIP,       &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8120   { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8121   { EL_SPACESHIP_UP,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8122   { EL_SPACESHIP_LEFT,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8123   { EL_SPACESHIP_DOWN,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8124   { EL_BD_FIREFLY,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8125   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8126   { EL_BD_FIREFLY_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8127   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8128   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8129   { EL_SP_SNIKSNAK,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8130   { EL_YAMYAM,          &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8131   { EL_YAMYAM_LEFT,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8132   { EL_YAMYAM_RIGHT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8133   { EL_YAMYAM_UP,       &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8134   { EL_YAMYAM_DOWN,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8135   { EL_DARK_YAMYAM,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8136   { EL_ROBOT,           &level.score[SC_ROBOT],         TEXT_SMASHING   },
8137   { EL_PACMAN,          &level.score[SC_PACMAN],        TEXT_SMASHING   },
8138   { EL_PACMAN_RIGHT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
8139   { EL_PACMAN_UP,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
8140   { EL_PACMAN_LEFT,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8141   { EL_PACMAN_DOWN,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8142   { EL_NUT,             &level.score[SC_NUT],           TEXT_CRACKING   },
8143   { EL_DYNAMITE,        &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8144   { EL_EM_DYNAMITE,     &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8145   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
8146   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8147   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8148   { EL_SHIELD_NORMAL,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8149   { EL_SHIELD_DEADLY,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8150   { EL_EXTRA_TIME,      &level.extra_time_score,        TEXT_COLLECTING },
8151   { EL_KEY_1,           &level.score[SC_KEY],           TEXT_COLLECTING },
8152   { EL_KEY_2,           &level.score[SC_KEY],           TEXT_COLLECTING },
8153   { EL_KEY_3,           &level.score[SC_KEY],           TEXT_COLLECTING },
8154   { EL_KEY_4,           &level.score[SC_KEY],           TEXT_COLLECTING },
8155   { EL_EM_KEY_1,        &level.score[SC_KEY],           TEXT_COLLECTING },
8156   { EL_EM_KEY_2,        &level.score[SC_KEY],           TEXT_COLLECTING },
8157   { EL_EM_KEY_3,        &level.score[SC_KEY],           TEXT_COLLECTING },
8158   { EL_EM_KEY_4,        &level.score[SC_KEY],           TEXT_COLLECTING },
8159   { EL_EMC_KEY_5,       &level.score[SC_KEY],           TEXT_COLLECTING },
8160   { EL_EMC_KEY_6,       &level.score[SC_KEY],           TEXT_COLLECTING },
8161   { EL_EMC_KEY_7,       &level.score[SC_KEY],           TEXT_COLLECTING },
8162   { EL_EMC_KEY_8,       &level.score[SC_KEY],           TEXT_COLLECTING },
8163   { EL_DC_KEY_WHITE,    &level.score[SC_KEY],           TEXT_COLLECTING },
8164   { EL_AMOEBA_WET,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8165   { EL_AMOEBA_DRY,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8166   { EL_AMOEBA_FULL,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8167   { EL_BD_AMOEBA,       &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8168   { EL_EMC_DRIPPER,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8169   { EL_MAGIC_WALL,      &level.time_magic_wall,         TEXT_DURATION   },
8170   { EL_BD_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8171   { EL_DC_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8172   { EL_ROBOT_WHEEL,     &level.time_wheel,              TEXT_DURATION   },
8173
8174   { EL_TIMEGATE_SWITCH,   &level.time_timegate,         TEXT_DURATION   },
8175   { EL_DC_TIMEGATE_SWITCH,&level.time_timegate,         TEXT_DURATION   },
8176   { EL_LIGHT_SWITCH,    &level.time_light,              TEXT_DURATION   },
8177   { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,          TEXT_DURATION   },
8178   { EL_SHIELD_NORMAL,   &level.shield_normal_time,      TEXT_DURATION   },
8179   { EL_SHIELD_DEADLY,   &level.shield_deadly_time,      TEXT_DURATION   },
8180   { EL_EXTRA_TIME,      &level.extra_time,              TEXT_TIME_BONUS },
8181   { EL_TIME_ORB_FULL,   &level.time_orb_time,           TEXT_TIME_BONUS },
8182   { EL_GAME_OF_LIFE,    &level.game_of_life[0],         TEXT_GAME_OF_LIFE_1 },
8183   { EL_GAME_OF_LIFE,    &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
8184   { EL_GAME_OF_LIFE,    &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
8185   { EL_GAME_OF_LIFE,    &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
8186   { EL_BIOMAZE,         &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
8187   { EL_BIOMAZE,         &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
8188   { EL_BIOMAZE,         &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
8189   { EL_BIOMAZE,         &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
8190
8191   { EL_EMC_ANDROID,     &level.android_move_time,       TEXT_MOVE_SPEED },
8192   { EL_EMC_ANDROID,     &level.android_clone_time,      TEXT_CLONE_SPEED },
8193   { EL_EMC_MAGIC_BALL,  &level.ball_time,               TEXT_BALL_DELAY },
8194   { EL_EMC_LENSES,      &level.lenses_score,            TEXT_COLLECTING },
8195   { EL_EMC_MAGNIFIER,   &level.magnify_score,           TEXT_COLLECTING },
8196   { EL_SPRING,          &level.slurp_score,             TEXT_SLURPING   },
8197   { EL_EMC_LENSES,      &level.lenses_time,             TEXT_DURATION   },
8198   { EL_EMC_MAGNIFIER,   &level.magnify_time,            TEXT_DURATION   },
8199
8200   { -1,                 NULL,                           NULL            }
8201 };
8202
8203 static boolean checkPropertiesConfig(int element)
8204 {
8205   int i;
8206
8207   if (IS_GEM(element) ||
8208       IS_CUSTOM_ELEMENT(element) ||
8209       IS_GROUP_ELEMENT(element) ||
8210       IS_ENVELOPE(element) ||
8211       ELEM_IS_PLAYER(element) ||
8212       HAS_EDITOR_CONTENT(element) ||
8213       CAN_GROW(element) ||
8214       COULD_MOVE_INTO_ACID(element) ||
8215       MAYBE_DONT_COLLIDE_WITH(element))
8216     return TRUE;
8217   else
8218     for (i = 0; elements_with_counter[i].element != -1; i++)
8219       if (elements_with_counter[i].element == element)
8220         return TRUE;
8221
8222   return FALSE;
8223 }
8224
8225 static void DrawPropertiesConfig()
8226 {
8227   int max_num_element_counters = 4;
8228   int num_element_counters = 0;
8229   int i;
8230
8231   if (!checkPropertiesConfig(properties_element))
8232   {
8233     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
8234
8235     return;
8236   }
8237
8238   /* check if there are elements where a value can be chosen for */
8239   for (i = 0; elements_with_counter[i].element != -1; i++)
8240   {
8241     if (elements_with_counter[i].element == properties_element)
8242     {
8243       int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
8244
8245       counterbutton_info[counter_id].y =
8246         ED_ELEMENT_SETTINGS_YPOS(
8247                 (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
8248                 (CAN_GROW(properties_element)                ? 1 : 0) +
8249                 (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
8250                 (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
8251                 (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
8252                 num_element_counters);
8253
8254       counterbutton_info[counter_id].value = elements_with_counter[i].value;
8255       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
8256
8257       if (properties_element == EL_GAME_OF_LIFE ||
8258           properties_element == EL_BIOMAZE)
8259       {
8260         counterbutton_info[counter_id].min_value = 0;   /* min neighbours */
8261         counterbutton_info[counter_id].max_value = 8;   /* max neighbours */
8262       }
8263       else
8264       {
8265         /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */
8266         counterbutton_info[counter_id].min_value = MIN_SCORE;
8267         counterbutton_info[counter_id].max_value = MAX_SCORE;
8268       }
8269
8270       MapCounterButtons(counter_id);
8271
8272       num_element_counters++;
8273       if (num_element_counters >= max_num_element_counters)
8274         break;
8275     }
8276   }
8277
8278   if (HAS_EDITOR_CONTENT(properties_element))
8279   {
8280     /* draw stickybutton gadget */
8281     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8282
8283     if (IS_AMOEBOID(properties_element))
8284       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
8285     else if (properties_element == EL_YAMYAM ||
8286              properties_element == EL_YAMYAM_LEFT ||
8287              properties_element == EL_YAMYAM_RIGHT ||
8288              properties_element == EL_YAMYAM_UP ||
8289              properties_element == EL_YAMYAM_DOWN)
8290       DrawYamYamContentAreas();
8291     else if (properties_element == EL_EMC_MAGIC_BALL)
8292     {
8293       DrawMagicBallContentAreas();
8294
8295       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
8296       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE);
8297     }
8298     else if (properties_element == EL_EMC_ANDROID)
8299       DrawAndroidElementArea(properties_element);
8300   }
8301
8302   if (ELEM_IS_PLAYER(properties_element))
8303   {
8304     int player_nr = GET_PLAYER_NR(properties_element);
8305
8306     /* these properties can be set for every player individually */
8307
8308     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8309     {
8310       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
8311         &level.start_element[player_nr];
8312       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
8313         &level.artwork_element[player_nr];
8314       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
8315         &level.explosion_element[player_nr];
8316
8317       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
8318         &level.use_start_element[player_nr];
8319       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
8320         &level.use_artwork_element[player_nr];
8321       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
8322         &level.use_explosion_element[player_nr];
8323       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
8324         &level.initial_player_gravity[player_nr];
8325
8326       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
8327         &level.initial_player_stepsize[player_nr];
8328
8329       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
8330       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
8331                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
8332                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
8333       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
8334       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
8335       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
8336       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
8337       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
8338       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
8339       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
8340       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
8341       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
8342
8343       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
8344       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
8345       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
8346
8347       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
8348     }
8349     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
8350     {
8351       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
8352         &level.initial_inventory_content[player_nr][0];
8353
8354       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
8355         &level.initial_inventory_size[player_nr];
8356
8357       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
8358         &level.use_initial_inventory[player_nr];
8359
8360       /* draw checkbutton gadgets */
8361       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
8362
8363       /* draw counter gadgets */
8364       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
8365
8366       /* draw drawing area gadgets */
8367       DrawPlayerInitialInventoryArea(properties_element);
8368     }
8369   }
8370
8371   if (IS_GEM(properties_element))
8372     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
8373
8374   if (properties_element == EL_EM_DYNAMITE)
8375     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
8376
8377   if (COULD_MOVE_INTO_ACID(properties_element) &&
8378       !ELEM_IS_PLAYER(properties_element) &&
8379       (!IS_CUSTOM_ELEMENT(properties_element) ||
8380        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
8381   {
8382     /* set position for checkbutton for "can move into acid" */
8383     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
8384       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
8385     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
8386       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
8387                        HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8388
8389     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
8390   }
8391
8392   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
8393     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
8394
8395   if (properties_element == EL_SPRING)
8396     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
8397
8398   if (properties_element == EL_TIME_ORB_FULL)
8399     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
8400
8401   if (CAN_GROW(properties_element))
8402   {
8403     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
8404       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8405
8406     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
8407   }
8408
8409   if (IS_ENVELOPE(properties_element))
8410   {
8411     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
8412     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
8413     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
8414     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
8415     int envelope_nr = properties_element - EL_ENVELOPE_1;
8416
8417     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
8418     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
8419
8420     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
8421     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
8422
8423     /* display counter to choose size of envelope text area */
8424     MapCounterButtons(counter1_id);
8425     MapCounterButtons(counter2_id);
8426
8427     /* display checkbuttons to choose auto-wrap and alignment properties */
8428     MapCheckbuttonGadget(button1_id);
8429     MapCheckbuttonGadget(button2_id);
8430
8431     DrawEnvelopeTextArea(envelope_nr);
8432   }
8433
8434   if (IS_CUSTOM_ELEMENT(properties_element))
8435   {
8436     /* draw stickybutton gadget */
8437     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8438
8439     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8440     {
8441       /* draw checkbutton gadgets */
8442       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
8443            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
8444         MapCheckbuttonGadget(i);
8445
8446       /* draw counter gadgets */
8447       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
8448            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
8449         MapCounterButtons(i);
8450
8451       /* draw selectbox gadgets */
8452       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
8453            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
8454         MapSelectboxGadget(i);
8455
8456       /* draw textbutton gadgets */
8457       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
8458
8459       /* draw text input gadgets */
8460       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
8461
8462       /* draw drawing area gadgets */
8463       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
8464     }
8465     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
8466     {
8467       /* draw checkbutton gadgets */
8468       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
8469            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
8470         MapCheckbuttonGadget(i);
8471
8472       /* draw counter gadgets */
8473       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
8474            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
8475         MapCounterButtons(i);
8476
8477       /* draw selectbox gadgets */
8478       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
8479            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
8480         MapSelectboxGadget(i);
8481
8482       /* draw drawing area gadgets */
8483       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
8484       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
8485       DrawCustomContentArea();
8486     }
8487   }
8488   else if (IS_GROUP_ELEMENT(properties_element))
8489   {
8490     /* draw stickybutton gadget */
8491     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8492
8493     /* draw checkbutton gadgets */
8494     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
8495     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE);
8496
8497     /* draw counter gadgets */
8498     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
8499
8500     /* draw selectbox gadgets */
8501     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
8502
8503     /* draw textbutton gadgets */
8504     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
8505
8506     /* draw drawing area gadgets */
8507     DrawGroupElementArea(properties_element);
8508
8509     /* draw text input gadgets */
8510     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
8511
8512     /* draw drawing area gadgets */
8513     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
8514   }
8515 }
8516
8517 static void DrawPropertiesChangeDrawingAreas()
8518 {
8519   if (IS_CUSTOM_ELEMENT(properties_element))
8520   {
8521     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
8522     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
8523     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
8524
8525     DrawCustomChangeContentArea();
8526   }
8527
8528   redraw_mask |= REDRAW_FIELD;
8529 }
8530
8531 static void DrawPropertiesChange()
8532 {
8533   int i;
8534
8535   /* needed to initially set selectbox options for special action options */
8536   setSelectboxSpecialActionOptions();
8537
8538   /* draw stickybutton gadget */
8539   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8540
8541   /* draw checkbutton gadgets */
8542   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
8543        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
8544     MapCheckbuttonGadget(i);
8545
8546   /* draw counter gadgets */
8547   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
8548        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
8549     MapCounterButtons(i);
8550
8551   /* draw selectbox gadgets */
8552   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
8553        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
8554     MapSelectboxGadget(i);
8555
8556   /* draw textbutton gadgets */
8557   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
8558        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
8559     MapTextbuttonGadget(i);
8560
8561   /* draw graphicbutton gadgets */
8562   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
8563        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
8564     MapGraphicbuttonGadget(i);
8565
8566   /* draw drawing area gadgets */
8567   DrawPropertiesChangeDrawingAreas();
8568 }
8569
8570 static void DrawEditorElementAnimation(int x, int y)
8571 {
8572   int graphic = el2img(properties_element);
8573   int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
8574                custom_element.ce_value_fixed_initial :
8575                ANIM_MODE(graphic) == ANIM_CE_SCORE ?
8576                custom_element.collect_score_initial : FrameCounter);
8577
8578   DrawGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
8579 }
8580
8581 static void DrawEditorElementName(int x, int y, int element)
8582 {
8583   char *element_name = getElementInfoText(element);
8584   int font_nr = FONT_TEXT_1;
8585   int font_width = getFontWidth(font_nr);
8586   int font_height = getFontHeight(font_nr);
8587   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_XPOS(0);
8588   int max_chars_per_line = max_text_width / font_width;
8589   char buffer[max_chars_per_line + 1];
8590
8591   if (strlen(element_name) <= max_chars_per_line)
8592     DrawTextS(x, y, font_nr, element_name);
8593   else
8594   {
8595     int next_pos = max_chars_per_line;
8596
8597     strncpy(buffer, element_name, max_chars_per_line);
8598     buffer[max_chars_per_line] = '\0';
8599
8600     if (element_name[max_chars_per_line] == ' ')
8601       next_pos++;
8602     else
8603     {
8604       int i;
8605
8606       for (i = max_chars_per_line - 1; i >= 0; i--)
8607         if (buffer[i] == ' ')
8608           break;
8609
8610       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
8611       {
8612         buffer[i] = '\0';
8613         next_pos = i + 1;
8614       }
8615     }
8616
8617     DrawTextS(x, y - font_height / 2, font_nr, buffer);
8618
8619     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
8620     buffer[max_chars_per_line] = '\0';
8621
8622     DrawTextS(x, y + font_height / 2, font_nr, buffer);
8623   }
8624 }
8625
8626 static void DrawPropertiesWindow()
8627 {
8628   int xstart = 2;
8629   int ystart = 4;
8630
8631   stick_element_properties_window = FALSE;
8632
8633   /* make sure that previous properties edit mode exists for this element */
8634   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
8635       !IS_CUSTOM_ELEMENT(properties_element))
8636     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
8637
8638   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
8639       !ELEM_IS_PLAYER(properties_element) &&
8640       !IS_CUSTOM_ELEMENT(properties_element))
8641     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
8642
8643   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
8644       (ELEM_IS_PLAYER(properties_element) ||
8645        IS_CUSTOM_ELEMENT(properties_element)))
8646     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
8647
8648   CopyElementPropertiesToEditor(properties_element);
8649
8650   UnmapLevelEditorWindowGadgets();
8651   UnmapLevelEditorToolboxDrawingGadgets();
8652   UnmapLevelEditorToolboxCustomGadgets();
8653
8654   if (IS_CUSTOM_ELEMENT(properties_element) ||
8655       IS_GROUP_ELEMENT(properties_element))
8656     MapLevelEditorToolboxCustomGadgets();
8657
8658   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
8659   ClearField();
8660
8661 #if 1
8662   DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Element Settings");
8663 #else
8664   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
8665            "Element Settings", FONT_TITLE_1);
8666 #endif
8667
8668   FrameCounter = 0;     /* restart animation frame counter */
8669
8670   DrawElementBorder(SX + xstart * MINI_TILEX,
8671                     SY + ystart * MINI_TILEY + MINI_TILEY / 2,
8672                     TILEX, TILEY, FALSE);
8673
8674   DrawEditorElementAnimation(SX + xstart * MINI_TILEX,
8675                              SY + ystart * MINI_TILEY + MINI_TILEY / 2);
8676
8677   DrawEditorElementName((xstart + 3) * MINI_TILEX + 1,
8678                         (ystart + 1) * MINI_TILEY + 1,
8679                         properties_element);
8680
8681   DrawPropertiesTabulatorGadgets();
8682
8683   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
8684     DrawPropertiesInfo();
8685   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
8686     DrawPropertiesChange();
8687   else  /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */
8688     DrawPropertiesConfig();
8689 }
8690
8691 static void UpdateCustomElementGraphicGadgets()
8692 {
8693   struct ElementInfo *ei = &element_info[properties_element];
8694   int i;
8695
8696   ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial :
8697                      properties_element);
8698
8699   ModifyEditorElementList();
8700   RedrawDrawingElements();
8701
8702   /* force redraw of all mapped drawing area gadgets */
8703   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8704   {
8705     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
8706
8707     if (gi->mapped)
8708       MapDrawingArea(i);
8709   }
8710 }
8711
8712 static int getOpenDirectionFromTube(int element)
8713 {
8714   switch (element)
8715   {
8716     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
8717     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
8718     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
8719     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
8720     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
8721     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
8722     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
8723     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
8724     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
8725     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
8726     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
8727   }
8728
8729   return MV_NONE;
8730 }
8731
8732 static int getTubeFromOpenDirection(int direction)
8733 {
8734   switch (direction)
8735   {
8736     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
8737     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
8738     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
8739     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
8740     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
8741     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
8742     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
8743     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
8744     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
8745     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
8746     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
8747
8748     /* if only one direction, fall back to simple tube with that direction */
8749     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
8750     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
8751     case (MV_UP):                       return EL_TUBE_VERTICAL;
8752     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
8753   }
8754
8755   return EL_EMPTY;
8756 }
8757
8758 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
8759 {
8760   int element_new = getTubeFromOpenDirection(direction);
8761
8762   return (element_new != EL_EMPTY ? element_new : element_old);
8763 }
8764
8765 static int getOpenDirectionFromBelt(int element)
8766 {
8767   int belt_dir = getBeltDirFromBeltElement(element);
8768
8769   return (belt_dir == MV_LEFT ? MV_RIGHT :
8770           belt_dir == MV_RIGHT ? MV_LEFT :
8771           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
8772 }
8773
8774 static int getBeltFromNrAndOpenDirection(int nr, int direction)
8775 {
8776   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
8777                   direction == MV_RIGHT ? MV_LEFT :
8778                   direction == MV_HORIZONTAL ? MV_NONE : direction);
8779
8780   if (direction == MV_NONE)
8781     return EL_EMPTY;
8782
8783   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
8784 }
8785
8786 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
8787                                                  int element_old)
8788 {
8789   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
8790
8791   return (element_new != EL_EMPTY ? element_new : element_old);
8792 }
8793
8794 static int getOpenDirectionFromPool(int element)
8795 {
8796   switch (element)
8797   {
8798     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
8799     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
8800     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
8801     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
8802     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
8803     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
8804   }
8805
8806   return MV_NONE;
8807 }
8808
8809 static int getPoolFromOpenDirection(int direction)
8810 {
8811   switch (direction)
8812   {
8813     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
8814     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
8815     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
8816     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
8817     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
8818     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
8819   }
8820
8821   return EL_EMPTY;
8822 }
8823
8824 static int getPoolFromOpenDirectionExt(int direction, int help_element)
8825 {
8826   int element = getPoolFromOpenDirection(direction);
8827   int help_direction = getOpenDirectionFromPool(help_element);
8828
8829   if (element == EL_EMPTY)
8830   {
8831     int help_direction_vertical = help_direction & MV_VERTICAL;
8832
8833     element = getPoolFromOpenDirection(direction | help_direction_vertical);
8834   }
8835
8836   if (element == EL_EMPTY)
8837   {
8838     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
8839
8840     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
8841   }
8842
8843   return element;
8844 }
8845
8846 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
8847 {
8848   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
8849
8850   return (element_new != EL_EMPTY ? element_new : element_old);
8851 }
8852
8853 static int getOpenDirectionFromPillar(int element)
8854 {
8855   switch (element)
8856   {
8857     case EL_EMC_WALL_1:                 return (MV_DOWN);
8858     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
8859     case EL_EMC_WALL_3:                 return (MV_UP);
8860   }
8861
8862   return MV_NONE;
8863 }
8864
8865 static int getPillarFromOpenDirection(int direction)
8866 {
8867   switch (direction)
8868   {
8869     case (MV_DOWN):                     return EL_EMC_WALL_1;
8870     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
8871     case (MV_UP):                       return EL_EMC_WALL_3;
8872   }
8873
8874   return EL_EMPTY;
8875 }
8876
8877 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
8878 {
8879   int element_new = getPillarFromOpenDirection(direction);
8880
8881   return (element_new != EL_EMPTY ? element_new : element_old);
8882 }
8883
8884 static int getOpenDirectionFromSteel2(int element)
8885 {
8886   switch (element)
8887   {
8888     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
8889     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
8890     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
8891     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
8892     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
8893     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
8894     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
8895     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
8896   }
8897
8898   return MV_NONE;
8899 }
8900
8901 static int getSteel2FromOpenDirection(int direction)
8902 {
8903   switch (direction)
8904   {
8905     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
8906     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
8907     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
8908     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
8909     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
8910     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
8911     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
8912     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
8913   }
8914
8915   return EL_EMPTY;
8916 }
8917
8918 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
8919 {
8920   int element_new = getSteel2FromOpenDirection(direction);
8921
8922   return (element_new != EL_EMPTY ? element_new : element_old);
8923 }
8924
8925 static int getOpenDirectionFromChip(int element)
8926 {
8927   switch (element)
8928   {
8929     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
8930     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
8931     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
8932     case EL_SP_CHIP_TOP:                return (MV_DOWN);
8933     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
8934   }
8935
8936   return MV_NONE;
8937 }
8938
8939 static int getChipFromOpenDirection(int direction)
8940 {
8941   switch (direction)
8942   {
8943     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
8944     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
8945     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
8946     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
8947     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
8948   }
8949
8950   return EL_EMPTY;
8951 }
8952
8953 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
8954 {
8955   int element_new = getChipFromOpenDirection(direction);
8956
8957   return (element_new != EL_EMPTY ? element_new : element_old);
8958 }
8959
8960 static int getClosedTube(int x, int y)
8961 {
8962   static int xy[4][2] =
8963   {
8964     { -1, 0 },
8965     { +1, 0 },
8966     { 0, -1 },
8967     { 0, +1 }
8968   };
8969   int element_old = IntelliDrawBuffer[x][y];
8970   int direction_old = getOpenDirectionFromTube(element_old);
8971   int direction_new = MV_NONE;
8972   int i;
8973
8974   for (i = 0; i < NUM_DIRECTIONS; i++)
8975   {
8976     int xx = x + xy[i][0];
8977     int yy = y + xy[i][1];
8978     int dir = MV_DIR_FROM_BIT(i);
8979     int dir_opposite = MV_DIR_OPPOSITE(dir);
8980
8981     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
8982         (direction_old & dir) &&
8983         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
8984       direction_new |= dir;
8985   }
8986
8987   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
8988 }
8989
8990 static int getClosedBelt(int x, int y)
8991 {
8992   static int xy[4][2] =
8993   {
8994     { -1, 0 },
8995     { +1, 0 },
8996     { 0, -1 },
8997     { 0, +1 }
8998   };
8999   int element_old = IntelliDrawBuffer[x][y];
9000   int nr = getBeltNrFromBeltElement(element_old);
9001   int direction_old = getOpenDirectionFromBelt(element_old);
9002   int direction_new = MV_NONE;
9003   int i;
9004
9005   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9006   {
9007     int xx = x + xy[i][0];
9008     int yy = y + xy[i][1];
9009     int dir = MV_DIR_FROM_BIT(i);
9010     int dir_opposite = MV_DIR_OPPOSITE(dir);
9011
9012     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
9013         (direction_old & dir) &&
9014         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9015       direction_new |= dir;
9016   }
9017
9018   return getBeltFromNrAndOpenDirection(nr, direction_new);
9019 }
9020
9021 static int getClosedPool(int x, int y)
9022 {
9023   static int xy[4][2] =
9024   {
9025     { -1, 0 },
9026     { +1, 0 },
9027     { 0, -1 },
9028     { 0, +1 }
9029   };
9030   int element_old = IntelliDrawBuffer[x][y];
9031   int direction_old = getOpenDirectionFromPool(element_old);
9032   int direction_new = MV_NONE;
9033   int i;
9034
9035   for (i = 0; i < NUM_DIRECTIONS; i++)
9036   {
9037     int xx = x + xy[i][0];
9038     int yy = y + xy[i][1];
9039     int dir = MV_DIR_FROM_BIT(i);
9040     int dir_opposite = MV_DIR_OPPOSITE(dir);
9041
9042     if (IN_LEV_FIELD(xx, yy) &&
9043         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
9044         (direction_old & dir) &&
9045         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9046       direction_new |= dir;
9047   }
9048
9049   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
9050 }
9051
9052 static int getClosedPillar(int x, int y)
9053 {
9054   static int xy[4][2] =
9055   {
9056     { -1, 0 },
9057     { +1, 0 },
9058     { 0, -1 },
9059     { 0, +1 }
9060   };
9061   int element_old = IntelliDrawBuffer[x][y];
9062   int direction_old = getOpenDirectionFromPillar(element_old);
9063   int direction_new = MV_NONE;
9064   int i;
9065
9066   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9067   {
9068     int xx = x + xy[i][0];
9069     int yy = y + xy[i][1];
9070     int dir = MV_DIR_FROM_BIT(i);
9071     int dir_opposite = MV_DIR_OPPOSITE(dir);
9072
9073     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
9074         (direction_old & dir) &&
9075         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9076       direction_new |= dir;
9077   }
9078
9079   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
9080 }
9081
9082 static int getClosedSteel2(int x, int y)
9083 {
9084   static int xy[4][2] =
9085   {
9086     { -1, 0 },
9087     { +1, 0 },
9088     { 0, -1 },
9089     { 0, +1 }
9090   };
9091   int element_old = IntelliDrawBuffer[x][y];
9092   int direction_old = getOpenDirectionFromSteel2(element_old);
9093   int direction_new = MV_NONE;
9094   int i;
9095
9096   for (i = 0; i < NUM_DIRECTIONS; i++)
9097   {
9098     int xx = x + xy[i][0];
9099     int yy = y + xy[i][1];
9100     int dir = MV_DIR_FROM_BIT(i);
9101     int dir_opposite = MV_DIR_OPPOSITE(dir);
9102
9103     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
9104         (direction_old & dir) &&
9105         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9106       direction_new |= dir;
9107   }
9108
9109   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
9110 }
9111
9112 static int getClosedChip(int x, int y)
9113 {
9114   static int xy[4][2] =
9115   {
9116     { -1, 0 },
9117     { +1, 0 },
9118     { 0, -1 },
9119     { 0, +1 }
9120   };
9121   int element_old = IntelliDrawBuffer[x][y];
9122   int direction_old = getOpenDirectionFromChip(element_old);
9123   int direction_new = MV_NONE;
9124   int i;
9125
9126   for (i = 0; i < NUM_DIRECTIONS; i++)
9127   {
9128     int xx = x + xy[i][0];
9129     int yy = y + xy[i][1];
9130     int dir = MV_DIR_FROM_BIT(i);
9131     int dir_opposite = MV_DIR_OPPOSITE(dir);
9132
9133     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
9134         (direction_old & dir) &&
9135         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9136       direction_new |= dir;
9137   }
9138
9139   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
9140 }
9141
9142 static void SetElementSimple(int x, int y, int element, boolean change_level)
9143 {
9144   int sx = x - level_xpos;
9145   int sy = y - level_ypos;
9146
9147   IntelliDrawBuffer[x][y] = element;
9148
9149   if (change_level)
9150     Feld[x][y] = element;
9151
9152   if (IN_ED_FIELD(sx, sy))
9153     DrawMiniElement(sx, sy, element);
9154 }
9155
9156 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
9157                                            int x2, int y2, int *element2,
9158                                            int (*close_function)(int, int),
9159                                            boolean change_level)
9160 {
9161   /* set neighbour elements to newly determined connections */
9162   SetElementSimple(x1, y1, *element1, change_level);
9163   SetElementSimple(x2, y2, *element2, change_level);
9164
9165   /* remove all open connections of neighbour elements */
9166   *element1 = close_function(x1, y1);
9167   *element2 = close_function(x2, y2);
9168
9169   /* set neighbour elements to new, minimized connections */
9170   SetElementSimple(x1, y1, *element1, change_level);
9171   SetElementSimple(x2, y2, *element2, change_level);
9172 }
9173
9174 static void SetElementIntelliDraw(int x, int y, int new_element,
9175                                   boolean change_level, int button)
9176 {
9177   static int xy[4][2] =
9178   {
9179     { -1, 0 },
9180     { +1, 0 },
9181     { 0, -1 },
9182     { 0, +1 }
9183   };
9184   static int last_x = -1;
9185   static int last_y = -1;
9186   int old_element = IntelliDrawBuffer[x][y];
9187
9188   if (new_element == EL_UNDEFINED)
9189   {
9190     last_x = -1;
9191     last_y = -1;
9192
9193     return;
9194   }
9195
9196   if (IS_TUBE(new_element))
9197   {
9198     int last_element_new = EL_UNDEFINED;
9199     int direction = MV_NONE;
9200     int i;
9201
9202     /* if old element is of same kind, keep all existing directions */
9203     if (IS_TUBE(old_element))
9204       direction |= getOpenDirectionFromTube(old_element);
9205
9206     for (i = 0; i < NUM_DIRECTIONS; i++)
9207     {
9208       int xx = x + xy[i][0];
9209       int yy = y + xy[i][1];
9210
9211       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9212           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
9213       {
9214         int dir = MV_DIR_FROM_BIT(i);
9215         int dir_opposite = MV_DIR_OPPOSITE(dir);
9216         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9217         int last_direction_old = getOpenDirectionFromTube(last_element_old);
9218         int last_direction_new = last_direction_old | dir_opposite;
9219
9220         last_element_new = getTubeFromOpenDirection(last_direction_new);
9221
9222         direction |= dir;
9223       }
9224     }
9225
9226     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
9227
9228     if (last_element_new != EL_UNDEFINED)
9229       MergeAndCloseNeighbourElements(x, y, &new_element,
9230                                      last_x, last_y, &last_element_new,
9231                                      getClosedTube, change_level);
9232   }
9233   else if (IS_BELT(new_element))
9234   {
9235     int belt_nr = getBeltNrFromBeltElement(new_element);
9236     int last_element_new = EL_UNDEFINED;
9237     int direction = MV_NONE;
9238     int i;
9239
9240     /* if old element is of same kind, keep all existing directions */
9241     if (IS_BELT(old_element))
9242       direction |= getOpenDirectionFromBelt(old_element);
9243
9244     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9245     {
9246       int xx = x + xy[i][0];
9247       int yy = y + xy[i][1];
9248
9249       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9250           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
9251       {
9252         int dir = MV_DIR_FROM_BIT(i);
9253         int dir_opposite = MV_DIR_OPPOSITE(dir);
9254         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9255         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
9256         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
9257         int last_direction_new = last_direction_old | dir_opposite;
9258
9259         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
9260                                                          last_direction_new);
9261         direction |= dir;
9262       }
9263     }
9264
9265     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
9266                                                         new_element);
9267     if (last_element_new != EL_UNDEFINED)
9268       MergeAndCloseNeighbourElements(x, y, &new_element,
9269                                      last_x, last_y, &last_element_new,
9270                                      getClosedBelt, change_level);
9271   }
9272   else if (IS_ACID_POOL_OR_ACID(new_element))
9273   {
9274     int last_element_new = EL_UNDEFINED;
9275     int direction = MV_NONE;
9276     int i;
9277
9278     /* if old element is of same kind, keep all existing directions */
9279     if (IS_ACID_POOL_OR_ACID(old_element))
9280       direction |= getOpenDirectionFromPool(old_element);
9281
9282     for (i = 0; i < NUM_DIRECTIONS; i++)
9283     {
9284       int xx = x + xy[i][0];
9285       int yy = y + xy[i][1];
9286
9287       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9288           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
9289       {
9290         int dir = MV_DIR_FROM_BIT(i);
9291         int dir_opposite = MV_DIR_OPPOSITE(dir);
9292         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9293         int last_direction_old = getOpenDirectionFromPool(last_element_old);
9294         int last_direction_new = last_direction_old | dir_opposite;
9295
9296         last_element_new = getPoolFromOpenDirection(last_direction_new);
9297
9298         direction |= dir;
9299       }
9300     }
9301
9302     /* special corrections needed for intuitively correct acid pool drawing */
9303     if (last_element_new == EL_EMPTY)
9304       last_element_new = new_element;
9305     else if (last_element_new != EL_UNDEFINED)
9306       new_element = last_element_new;
9307
9308     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
9309
9310     if (last_element_new != EL_UNDEFINED)
9311       MergeAndCloseNeighbourElements(x, y, &new_element,
9312                                      last_x, last_y, &last_element_new,
9313                                      getClosedPool, change_level);
9314   }
9315   else if (IS_EMC_PILLAR(new_element))
9316   {
9317     int last_element_new = EL_UNDEFINED;
9318     int direction = MV_NONE;
9319     int i;
9320
9321     /* if old element is of same kind, keep all existing directions */
9322     if (IS_EMC_PILLAR(old_element))
9323       direction |= getOpenDirectionFromPillar(old_element);
9324
9325     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9326     {
9327       int xx = x + xy[i][0];
9328       int yy = y + xy[i][1];
9329
9330       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9331           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
9332       {
9333         int dir = MV_DIR_FROM_BIT(i);
9334         int dir_opposite = MV_DIR_OPPOSITE(dir);
9335         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9336         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
9337         int last_direction_new = last_direction_old | dir_opposite;
9338
9339         last_element_new = getPillarFromOpenDirection(last_direction_new);
9340
9341         direction |= dir;
9342       }
9343     }
9344
9345     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
9346
9347     if (last_element_new != EL_UNDEFINED)
9348       MergeAndCloseNeighbourElements(x, y, &new_element,
9349                                      last_x, last_y, &last_element_new,
9350                                      getClosedPillar, change_level);
9351   }
9352   else if (IS_DC_STEELWALL_2(new_element))
9353   {
9354     int last_element_new = EL_UNDEFINED;
9355     int direction = MV_NONE;
9356     int i;
9357
9358     /* if old element is of same kind, keep all existing directions */
9359     if (IS_DC_STEELWALL_2(old_element))
9360       direction |= getOpenDirectionFromSteel2(old_element);
9361
9362     for (i = 0; i < NUM_DIRECTIONS; i++)
9363     {
9364       int xx = x + xy[i][0];
9365       int yy = y + xy[i][1];
9366
9367       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9368           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
9369       {
9370         int dir = MV_DIR_FROM_BIT(i);
9371         int dir_opposite = MV_DIR_OPPOSITE(dir);
9372         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9373         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
9374         int last_direction_new = last_direction_old | dir_opposite;
9375
9376         last_element_new = getSteel2FromOpenDirection(last_direction_new);
9377
9378         direction |= dir;
9379       }
9380     }
9381
9382     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
9383
9384     if (last_element_new != EL_UNDEFINED)
9385       MergeAndCloseNeighbourElements(x, y, &new_element,
9386                                      last_x, last_y, &last_element_new,
9387                                      getClosedSteel2, change_level);
9388   }
9389   else if (IS_SP_CHIP(new_element))
9390   {
9391     int last_element_new = EL_UNDEFINED;
9392     int direction = MV_NONE;
9393     int i;
9394
9395     /* (do not keep existing directions, regardless of kind of old element) */
9396
9397     for (i = 0; i < NUM_DIRECTIONS; i++)
9398     {
9399       int xx = x + xy[i][0];
9400       int yy = y + xy[i][1];
9401
9402       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9403           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
9404       {
9405         int dir = MV_DIR_FROM_BIT(i);
9406         int dir_opposite = MV_DIR_OPPOSITE(dir);
9407         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9408         int last_direction_old = getOpenDirectionFromChip(last_element_old);
9409         int last_direction_new = last_direction_old | dir_opposite;
9410
9411         if (last_direction_old == MV_NONE)
9412         {
9413           last_element_new = getChipFromOpenDirection(last_direction_new);
9414           direction |= dir;
9415         }
9416         else if (last_direction_old & (dir | dir_opposite))
9417         {
9418           direction |= MV_DIR_OPPOSITE(last_direction_old);
9419         }
9420         else
9421         {
9422           direction |= MV_DIR_OPPOSITE(dir);
9423         }
9424       }
9425     }
9426
9427     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
9428
9429     if (last_element_new != EL_UNDEFINED)
9430       MergeAndCloseNeighbourElements(x, y, &new_element,
9431                                      last_x, last_y, &last_element_new,
9432                                      getClosedChip, change_level);
9433   }
9434   else if (IS_SP_HARDWARE_BASE(new_element))
9435   {
9436     int nr = GetSimpleRandom(6);
9437
9438     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
9439                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
9440                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
9441                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
9442                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
9443   }
9444   else if (new_element == EL_SP_HARDWARE_GREEN ||
9445            new_element == EL_SP_HARDWARE_BLUE ||
9446            new_element == EL_SP_HARDWARE_RED)
9447   {
9448     int nr = GetSimpleRandom(3);
9449
9450     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
9451                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
9452   }
9453   else if (IS_GROUP_ELEMENT(new_element))
9454   {
9455     boolean connected_drawing = FALSE;
9456     int i;
9457
9458     for (i = 0; i < NUM_DIRECTIONS; i++)
9459     {
9460       int xx = x + xy[i][0];
9461       int yy = y + xy[i][1];
9462
9463       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9464           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
9465         connected_drawing = TRUE;
9466     }
9467
9468     if (!connected_drawing)
9469       ResolveGroupElement(new_element);
9470
9471     new_element = GetElementFromGroupElement(new_element);
9472   }
9473   else if (IS_BELT_SWITCH(old_element))
9474   {
9475     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
9476     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
9477
9478     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
9479                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
9480
9481     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
9482   }
9483   else
9484   {
9485     static int swappable_elements[][2] =
9486     {
9487       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
9488       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
9489       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
9490       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
9491       { EL_EMERALD,                     EL_WALL_EMERALD                 },
9492       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
9493       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
9494       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
9495       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
9496       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
9497       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
9498       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
9499       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
9500       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
9501       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
9502       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
9503       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
9504       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
9505       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
9506       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
9507       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
9508       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
9509       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
9510       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
9511       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
9512       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
9513       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
9514       { EL_PEARL,                       EL_WALL_PEARL                   },
9515       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
9516       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
9517       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
9518       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
9519       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
9520       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
9521       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
9522       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
9523       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
9524       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
9525       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
9526       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
9527
9528       { -1,                             -1                              },
9529     };
9530     static int rotatable_elements[][4] =
9531     {
9532       {
9533         EL_BUG_UP,
9534         EL_BUG_RIGHT,
9535         EL_BUG_DOWN,
9536         EL_BUG_LEFT
9537       },
9538
9539       {
9540         EL_SPACESHIP_UP,
9541         EL_SPACESHIP_RIGHT,
9542         EL_SPACESHIP_DOWN,
9543         EL_SPACESHIP_LEFT
9544       },
9545
9546       {
9547         EL_BD_BUTTERFLY_UP,
9548         EL_BD_BUTTERFLY_RIGHT,
9549         EL_BD_BUTTERFLY_DOWN,
9550         EL_BD_BUTTERFLY_LEFT
9551       },
9552
9553       {
9554         EL_BD_FIREFLY_UP,
9555         EL_BD_FIREFLY_RIGHT,
9556         EL_BD_FIREFLY_DOWN,
9557         EL_BD_FIREFLY_LEFT
9558       },
9559
9560       {
9561         EL_PACMAN_UP,
9562         EL_PACMAN_RIGHT,
9563         EL_PACMAN_DOWN,
9564         EL_PACMAN_LEFT
9565       },
9566
9567       {
9568         EL_YAMYAM_UP,
9569         EL_YAMYAM_RIGHT,
9570         EL_YAMYAM_DOWN,
9571         EL_YAMYAM_LEFT
9572       },
9573
9574       {
9575         EL_ARROW_UP,
9576         EL_ARROW_RIGHT,
9577         EL_ARROW_DOWN,
9578         EL_ARROW_LEFT
9579       },
9580
9581       {
9582         EL_SP_PORT_UP,
9583         EL_SP_PORT_RIGHT,
9584         EL_SP_PORT_DOWN,
9585         EL_SP_PORT_LEFT
9586       },
9587
9588       {
9589         EL_SP_GRAVITY_PORT_UP,
9590         EL_SP_GRAVITY_PORT_RIGHT,
9591         EL_SP_GRAVITY_PORT_DOWN,
9592         EL_SP_GRAVITY_PORT_LEFT
9593       },
9594
9595       {
9596         EL_MOLE_UP,
9597         EL_MOLE_RIGHT,
9598         EL_MOLE_DOWN,
9599         EL_MOLE_LEFT
9600       },
9601
9602       {
9603         EL_BALLOON_SWITCH_UP,
9604         EL_BALLOON_SWITCH_RIGHT,
9605         EL_BALLOON_SWITCH_DOWN,
9606         EL_BALLOON_SWITCH_LEFT
9607       },
9608
9609       {
9610         EL_SP_GRAVITY_ON_PORT_UP,
9611         EL_SP_GRAVITY_ON_PORT_RIGHT,
9612         EL_SP_GRAVITY_ON_PORT_DOWN,
9613         EL_SP_GRAVITY_ON_PORT_LEFT
9614       },
9615
9616       {
9617         EL_SP_GRAVITY_OFF_PORT_UP,
9618         EL_SP_GRAVITY_OFF_PORT_RIGHT,
9619         EL_SP_GRAVITY_OFF_PORT_DOWN,
9620         EL_SP_GRAVITY_OFF_PORT_LEFT
9621       },
9622
9623       {
9624         -1,
9625         -1,
9626         -1,
9627         -1,
9628       },
9629     };
9630     int i, j;
9631
9632     for (i = 0; swappable_elements[i][0] != -1; i++)
9633     {
9634       int element1 = swappable_elements[i][0];
9635       int element2 = swappable_elements[i][1];
9636
9637       if (old_element == element1 || old_element == element2)
9638         new_element = (old_element == element1 ? element2 : element1);
9639     }
9640
9641     for (i = 0; rotatable_elements[i][0] != -1; i++)
9642     {
9643       for (j = 0; j < 4; j++)
9644       {
9645         int element = rotatable_elements[i][j];
9646
9647         if (old_element == element)
9648           new_element = (button == 1 ? rotatable_elements[i][(j + 3) % 4] :
9649                          button == 2 ? rotatable_elements[i][0]           :
9650                          button == 3 ? rotatable_elements[i][(j + 1) % 4] :
9651                          old_element);
9652       }
9653     }
9654   }
9655
9656   SetElementSimple(x, y, new_element, change_level);
9657
9658   last_x = x;
9659   last_y = y;
9660 }
9661
9662 static void ResetIntelliDraw()
9663 {
9664   int x, y;
9665
9666   for (x = 0; x < lev_fieldx; x++)
9667     for (y = 0; y < lev_fieldy; y++)
9668       IntelliDrawBuffer[x][y] = Feld[x][y];
9669
9670   SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
9671 }
9672
9673 static void SetElementExt(int x, int y, int element, boolean change_level,
9674                           int button)
9675 {
9676   if (element < 0)
9677     SetElementSimple(x, y, Feld[x][y], change_level);
9678   else if (GetKeyModState() & KMOD_Shift)
9679     SetElementIntelliDraw(x, y, element, change_level, button);
9680   else
9681     SetElementSimple(x, y, element, change_level);
9682 }
9683
9684 static void SetElement(int x, int y, int element)
9685 {
9686   SetElementExt(x, y, element, TRUE, -1);
9687 }
9688
9689 static void SetElementButton(int x, int y, int element, int button)
9690 {
9691   SetElementExt(x, y, element, TRUE, button);
9692 }
9693
9694 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
9695 {
9696   int lx = sx + level_xpos;
9697   int ly = sy + level_ypos;
9698
9699   SetElementExt(lx, ly, element, change_level, -1);
9700 }
9701
9702 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
9703                      int element, boolean change_level)
9704 {
9705   int xsize = ABS(to_x - from_x);
9706   int ysize = ABS(to_y - from_y);
9707   int dx = (to_x < from_x ? -1 : +1);
9708   int dy = (to_y < from_y ? -1 : +1);
9709   int i;
9710
9711   if (from_y == to_y)                   /* horizontal line */
9712   {
9713     for (i = 0; i <= xsize; i++)
9714       DrawLineElement(from_x + i * dx, from_y, element, change_level);
9715   }
9716   else if (from_x == to_x)              /* vertical line */
9717   {
9718     for (i = 0; i <= ysize; i++)
9719       DrawLineElement(from_x, from_y + i * dy, element, change_level);
9720   }
9721   else                                  /* diagonal line */
9722   {
9723     if (ysize < xsize)                  /* a < 1 */
9724     {
9725       float a = (float)ysize / (float)xsize;
9726
9727       for (i = 0; i <= xsize; i++)
9728       {
9729         int x = dx * i;
9730         int y = dy * (int)(a * i + 0.5);
9731
9732         DrawLineElement(from_x + x, from_y + y, element, change_level);
9733       }
9734     }
9735     else                                /* a >= 1 */
9736     {
9737       float a = (float)xsize / (float)ysize;
9738
9739       for (i = 0; i <= ysize; i++)
9740       {
9741         int x = dx * (int)(a * i + 0.5);
9742         int y = dy * i;
9743
9744         DrawLineElement(from_x + x, from_y + y, element, change_level);
9745       }
9746     }
9747   }
9748 }
9749
9750 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
9751                     int element, boolean change_level)
9752 {
9753   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
9754   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
9755   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
9756   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
9757 }
9758
9759 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
9760                           int element, boolean change_level)
9761 {
9762   int y;
9763
9764   if (from_y > to_y)
9765     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
9766
9767   for (y = from_y; y <= to_y; y++)
9768     DrawLine(from_x, y, to_x, y, element, change_level);
9769 }
9770
9771 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
9772                        int element, boolean change_level)
9773 {
9774   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
9775   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
9776   int len_x = ABS(to_x - from_x);
9777   int len_y = ABS(to_y - from_y);
9778   int radius, x, y;
9779
9780   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
9781
9782   /* not optimal (some points get drawn twice) but simple,
9783      and fast enough for the few points we are drawing */
9784
9785   for (x = 0; x <= radius; x++)
9786   {
9787     int sx, sy, lx, ly;
9788
9789     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
9790
9791     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
9792     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
9793     lx = sx + level_xpos;
9794     ly = sy + level_ypos;
9795
9796     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
9797       DrawLineElement(sx, sy, element, change_level);
9798   }
9799
9800   for (y = 0; y <= radius; y++)
9801   {
9802     int sx, sy, lx, ly;
9803
9804     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
9805
9806     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
9807     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
9808     lx = sx + level_xpos;
9809     ly = sy + level_ypos;
9810
9811     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
9812       DrawLineElement(sx, sy, element, change_level);
9813   }
9814 }
9815
9816 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
9817                     int element, boolean change_level)
9818 {
9819   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
9820   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
9821
9822   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
9823 }
9824
9825 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
9826
9827 #if DRAW_CIRCLES_BUTTON_AVAILABLE
9828 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
9829                        int element, boolean change_level)
9830 {
9831   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
9832   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
9833   int mirror_to_x2 = from_x - (to_x2 - from_x);
9834   int mirror_to_y2 = from_y - (to_y2 - from_y);
9835
9836   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
9837   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
9838   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
9839   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
9840 }
9841 #endif
9842
9843 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
9844 {
9845   int from_sx, from_sy;
9846   int to_sx, to_sy;
9847
9848   if (from_x > to_x)
9849     swap_numbers(&from_x, &to_x);
9850
9851   if (from_y > to_y)
9852     swap_numbers(&from_y, &to_y);
9853
9854   from_sx = SX + from_x * MINI_TILEX;
9855   from_sy = SY + from_y * MINI_TILEY;
9856   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
9857   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
9858
9859   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
9860   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
9861   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
9862   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
9863
9864   if (from_x == to_x && from_y == to_y)
9865     MarkTileDirty(from_x/2, from_y/2);
9866   else
9867     redraw_mask |= REDRAW_FIELD;
9868 }
9869
9870 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
9871                        int element, boolean change_level)
9872 {
9873   if (element == -1 || change_level)
9874     DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
9875   else
9876     DrawAreaBorder(from_x, from_y, to_x, to_y);
9877 }
9878
9879 /* values for CopyBrushExt() */
9880 #define CB_AREA_TO_BRUSH        0
9881 #define CB_BRUSH_TO_CURSOR      1
9882 #define CB_BRUSH_TO_LEVEL       2
9883 #define CB_DELETE_OLD_CURSOR    3
9884 #define CB_DUMP_BRUSH           4
9885 #define CB_DUMP_BRUSH_SMALL     5
9886
9887 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
9888                          int button, int mode)
9889 {
9890   static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
9891   static int brush_width, brush_height;
9892   static int last_cursor_x = -1, last_cursor_y = -1;
9893   static boolean delete_old_brush;
9894   int new_element = BUTTON_ELEMENT(button);
9895   int x, y;
9896
9897   if (mode == CB_DUMP_BRUSH ||
9898       mode == CB_DUMP_BRUSH_SMALL)
9899   {
9900     if (!draw_with_brush)
9901     {
9902       Error(ERR_WARN, "no brush selected");
9903
9904       return;
9905     }
9906
9907     for (y = 0; y < brush_height; y++)
9908     {
9909       for (x = 0; x < brush_width; x++)
9910       {
9911         int element = brush_buffer[x][y];
9912         int element_mapped = element;
9913
9914         if (IS_CUSTOM_ELEMENT(element))
9915           element_mapped = EL_CUSTOM_START;
9916         else if (IS_GROUP_ELEMENT(element))
9917           element_mapped = EL_GROUP_START;
9918         else if (element >= NUM_FILE_ELEMENTS)
9919           element_mapped = EL_UNKNOWN;
9920
9921         printf("%c%03d", (mode == CB_DUMP_BRUSH ? '`' : '¸'), element_mapped);
9922       }
9923
9924       printf("\n");
9925     }
9926
9927     return;
9928   }
9929
9930   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
9931     return;
9932
9933   if (mode == CB_AREA_TO_BRUSH)
9934   {
9935     int from_lx, from_ly;
9936
9937     if (from_x > to_x)
9938       swap_numbers(&from_x, &to_x);
9939
9940     if (from_y > to_y)
9941       swap_numbers(&from_y, &to_y);
9942
9943     brush_width = to_x - from_x + 1;
9944     brush_height = to_y - from_y + 1;
9945
9946     from_lx = from_x + level_xpos;
9947     from_ly = from_y + level_ypos;
9948
9949     for (y = 0; y < brush_height; y++)
9950     {
9951       for (x = 0; x < brush_width; x++)
9952       {
9953         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
9954
9955         if (button != 1)
9956           DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
9957       }
9958     }
9959
9960     if (button != 1)
9961       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9962
9963     delete_old_brush = FALSE;
9964   }
9965   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
9966            mode == CB_BRUSH_TO_LEVEL)
9967   {
9968     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
9969     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
9970     int cursor_from_x = cursor_x - brush_width / 2;
9971     int cursor_from_y = cursor_y - brush_height / 2;
9972     int border_from_x = cursor_x, border_from_y = cursor_y;
9973     int border_to_x = cursor_x, border_to_y = cursor_y;
9974
9975     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
9976       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
9977
9978     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
9979         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
9980     {
9981       delete_old_brush = FALSE;
9982       return;
9983     }
9984
9985     for (y = 0; y < brush_height; y++)
9986     {
9987       for (x = 0; x < brush_width; x++)
9988       {
9989         int sx = cursor_from_x + x;
9990         int sy = cursor_from_y + y;
9991         int lx = sx + level_xpos;
9992         int ly = sy + level_ypos;
9993         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
9994         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
9995                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
9996                        brush_buffer[x][y] : new_element);
9997
9998         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
9999         {
10000           if (sx < border_from_x)
10001             border_from_x = sx;
10002           else if (sx > border_to_x)
10003             border_to_x = sx;
10004           if (sy < border_from_y)
10005             border_from_y = sy;
10006           else if (sy > border_to_y)
10007             border_to_y = sy;
10008
10009           DrawLineElement(sx, sy, element, change_level);
10010         }
10011       }
10012     }
10013
10014     if (mode != CB_DELETE_OLD_CURSOR)
10015       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
10016
10017     last_cursor_x = cursor_x;
10018     last_cursor_y = cursor_y;
10019     delete_old_brush = TRUE;
10020   }
10021 }
10022
10023 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
10024                             int button)
10025 {
10026   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
10027 }
10028
10029 static void CopyBrushToLevel(int x, int y, int button)
10030 {
10031   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
10032 }
10033
10034 static void CopyBrushToCursor(int x, int y)
10035 {
10036   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
10037 }
10038
10039 static void DeleteBrushFromCursor()
10040 {
10041   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
10042 }
10043
10044 void DumpBrush()
10045 {
10046   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
10047 }
10048
10049 void DumpBrush_Small()
10050 {
10051   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
10052 }
10053
10054 static void FloodFill(int from_x, int from_y, int fill_element)
10055 {
10056   FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy);
10057 }
10058
10059 /* values for DrawLevelText() modes */
10060 #define TEXT_INIT               0
10061 #define TEXT_SETCURSOR          1
10062 #define TEXT_WRITECHAR          2
10063 #define TEXT_BACKSPACE          3
10064 #define TEXT_NEWLINE            4
10065 #define TEXT_END                5
10066 #define TEXT_QUERY_TYPING       6
10067
10068 static int DrawLevelText(int sx, int sy, char letter, int mode)
10069 {
10070   static short delete_buffer[MAX_LEV_FIELDX];
10071   static int start_sx, start_sy;
10072   static int last_sx, last_sy;
10073   static boolean typing = FALSE;
10074   int letter_element = EL_CHAR_ASCII0 + letter;
10075   int lx = 0, ly = 0;
10076
10077   /* map lower case letters to upper case and convert special characters */
10078   if (letter >= 'a' && letter <= 'z')
10079     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
10080   else if (letter == 'ä' || letter == 'Ä')
10081     letter_element = EL_CHAR_AUMLAUT;
10082   else if (letter == 'ö' || letter == 'Ö')
10083     letter_element = EL_CHAR_OUMLAUT;
10084   else if (letter == 'ü' || letter == 'Ãœ')
10085     letter_element = EL_CHAR_UUMLAUT;
10086   else if (letter == '^')
10087     letter_element = EL_CHAR_COPYRIGHT;
10088   else
10089     letter_element = EL_CHAR_ASCII0 + letter;
10090
10091   if (mode != TEXT_INIT)
10092   {
10093     if (!typing)
10094       return FALSE;
10095
10096     if (mode != TEXT_SETCURSOR)
10097     {
10098       sx = last_sx;
10099       sy = last_sy;
10100     }
10101
10102     lx = last_sx + level_xpos;
10103     ly = last_sy + level_ypos;
10104   }
10105
10106   switch (mode)
10107   {
10108     case TEXT_INIT:
10109       if (typing)
10110         DrawLevelText(0, 0, 0, TEXT_END);
10111
10112       typing = TRUE;
10113       start_sx = last_sx = sx;
10114       start_sy = last_sy = sy;
10115       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
10116       break;
10117
10118     case TEXT_SETCURSOR:
10119       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
10120       DrawAreaBorder(sx, sy, sx, sy);
10121       last_sx = sx;
10122       last_sy = sy;
10123       break;
10124
10125     case TEXT_WRITECHAR:
10126       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
10127       {
10128         delete_buffer[sx - start_sx] = Feld[lx][ly];
10129         Feld[lx][ly] = letter_element;
10130
10131         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
10132           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
10133         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
10134           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10135         else
10136           DrawLevelText(0, 0, 0, TEXT_END);
10137
10138         level.changed = TRUE;
10139       }
10140       break;
10141
10142     case TEXT_BACKSPACE:
10143       if (sx > start_sx)
10144       {
10145         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
10146         DrawMiniElement(sx - 1, sy, Feld[lx - 1][ly]);
10147         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
10148       }
10149       break;
10150
10151     case TEXT_NEWLINE:
10152       if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
10153         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10154       else
10155         DrawLevelText(0, 0, 0, TEXT_END);
10156       break;
10157
10158     case TEXT_END:
10159       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10160       DrawMiniElement(sx, sy, Feld[lx][ly]);
10161       typing = FALSE;
10162       break;
10163
10164     case TEXT_QUERY_TYPING:
10165       break;
10166
10167     default:
10168       break;
10169   }
10170
10171   return typing;
10172 }
10173
10174 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
10175                           int element, boolean change_level)
10176 {
10177   int lx = sx + level_xpos;
10178   int ly = sy + level_ypos;
10179
10180   if (element == -1)
10181     DrawMiniElement(sx, sy, Feld[lx][ly]);
10182   else
10183     DrawAreaBorder(sx, sy, sx, sy);
10184 }
10185
10186 static void CheckLevelBorderElement(boolean redraw_playfield)
10187 {
10188   int last_border_element = BorderElement;
10189
10190   SetBorderElement();
10191
10192   if (redraw_playfield && BorderElement != last_border_element)
10193     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10194 }
10195
10196 static void CopyLevelToUndoBuffer(int mode)
10197 {
10198   static boolean accumulated_undo = FALSE;
10199   boolean new_undo_buffer_position = TRUE;
10200   int x, y;
10201
10202   switch (mode)
10203   {
10204     case UNDO_IMMEDIATE:
10205       accumulated_undo = FALSE;
10206       break;
10207
10208     case UNDO_ACCUMULATE:
10209       if (accumulated_undo)
10210         new_undo_buffer_position = FALSE;
10211       accumulated_undo = TRUE;
10212       break;
10213
10214     default:
10215       break;
10216   }
10217
10218   if (new_undo_buffer_position)
10219   {
10220     /* new position in undo buffer ring */
10221     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
10222
10223     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
10224       undo_buffer_steps++;
10225   }
10226
10227   for (x = 0; x < lev_fieldx; x++)
10228     for (y = 0; y < lev_fieldy; y++)
10229       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
10230
10231   /* check if drawing operation forces change of border style */
10232   CheckLevelBorderElement(TRUE);
10233
10234   level.changed = TRUE;
10235 }
10236
10237 static void RandomPlacement(int new_element)
10238 {
10239   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
10240   int num_free_positions = 0;
10241   int num_percentage, num_elements;
10242   int x, y;
10243
10244 #if 1
10245   ResetIntelliDraw();
10246 #endif
10247
10248   /* determine number of free positions for randomly placing the new element */
10249   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
10250   {
10251     free_position[x][y] =
10252       (random_placement_background_restricted ?
10253        Feld[x][y] == random_placement_background_element :
10254        Feld[x][y] != new_element);
10255
10256     if (free_position[x][y])
10257       num_free_positions++;
10258   }
10259
10260   /* determine number of new elements to place there */
10261   num_percentage = num_free_positions * random_placement_value / 100;
10262   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
10263                   num_percentage : random_placement_value);
10264
10265   /* if less free positions than elements to place, fill all these positions */
10266   if (num_free_positions < num_elements)
10267   {
10268     for (x = 0; x < lev_fieldx; x++)
10269       for (y = 0; y < lev_fieldy; y++)
10270         if (free_position[x][y])
10271 #if 1
10272           SetElement(x, y, new_element);
10273 #else
10274           Feld[x][y] = new_element;
10275 #endif
10276   }
10277   else
10278   {
10279     while (num_elements > 0)
10280     {
10281       x = GetSimpleRandom(lev_fieldx);
10282       y = GetSimpleRandom(lev_fieldy);
10283
10284       /* don't place element at the same position twice */
10285       if (free_position[x][y])
10286       {
10287         free_position[x][y] = FALSE;
10288 #if 1
10289         SetElement(x, y, new_element);
10290 #else
10291         Feld[x][y] = new_element;
10292 #endif
10293         num_elements--;
10294       }
10295     }
10296   }
10297
10298   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10299   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10300 }
10301
10302 void WrapLevel(int dx, int dy)
10303 {
10304   int wrap_dx = lev_fieldx - dx;
10305   int wrap_dy = lev_fieldy - dy;
10306   int x, y;
10307
10308   for (x = 0; x < lev_fieldx; x++)
10309     for (y = 0; y < lev_fieldy; y++)
10310       FieldBackup[x][y] = Feld[x][y];
10311
10312   for (x = 0; x < lev_fieldx; x++)
10313     for (y = 0; y < lev_fieldy; y++)
10314       Feld[x][y] =
10315         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
10316
10317   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10318   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
10319 }
10320
10321 static void HandleDrawingAreas(struct GadgetInfo *gi)
10322 {
10323   static boolean started_inside_drawing_area = FALSE;
10324   int id = gi->custom_id;
10325   boolean button_press_event;
10326   boolean button_release_event;
10327   boolean inside_drawing_area = !gi->event.off_borders;
10328   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
10329   int actual_drawing_function;
10330   int button = gi->event.button;
10331   int new_element = BUTTON_ELEMENT(button);
10332   int sx = gi->event.x, sy = gi->event.y;
10333   int min_sx = 0, min_sy = 0;
10334   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
10335   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
10336   int lx = 0, ly = 0;
10337   int min_lx = 0, min_ly = 0;
10338   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
10339   int x, y;
10340
10341   /* handle info callback for each invocation of action callback */
10342   gi->callback_info(gi);
10343
10344   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
10345   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
10346
10347   /* make sure to stay inside drawing area boundaries */
10348   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
10349   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
10350
10351   if (draw_level)
10352   {
10353     /* get positions inside level field */
10354     lx = sx + level_xpos;
10355     ly = sy + level_ypos;
10356
10357     if (!IN_LEV_FIELD(lx, ly))
10358       inside_drawing_area = FALSE;
10359
10360     /* make sure to stay inside level field boundaries */
10361     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
10362     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
10363
10364     /* correct drawing area positions accordingly */
10365     sx = lx - level_xpos;
10366     sy = ly - level_ypos;
10367   }
10368
10369   if (button_press_event)
10370     started_inside_drawing_area = inside_drawing_area;
10371
10372   if (!started_inside_drawing_area)
10373     return;
10374
10375   if (!IS_VALID_BUTTON(button))
10376     return;
10377
10378   if (!button && !button_release_event)
10379     return;
10380
10381   /* automatically switch to 'single item' drawing mode, if needed */
10382   actual_drawing_function =
10383     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
10384      drawing_function : GADGET_ID_SINGLE_ITEMS);
10385
10386   /* clicking into drawing area with pressed Control key picks element */
10387   if (GetKeyModState() & KMOD_Control)
10388   {
10389     last_drawing_function = drawing_function;
10390     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
10391   }
10392
10393   if (GetKeyModState() & KMOD_Shift)
10394   {
10395     if (button_press_event || button_release_event)
10396       ResetIntelliDraw();
10397   }
10398
10399   switch (actual_drawing_function)
10400   {
10401     case GADGET_ID_SINGLE_ITEMS:
10402       if (draw_level)
10403       {
10404         if (button_release_event)
10405         {
10406           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10407
10408           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
10409               !inside_drawing_area)
10410             DeleteBrushFromCursor();
10411
10412 #if 0
10413           ResetIntelliDraw();
10414 #endif
10415         }
10416
10417         if (!button || button_release_event)
10418           break;
10419
10420         if (draw_with_brush)
10421         {
10422 #if 0
10423           if (!button_release_event)
10424 #endif
10425             CopyBrushToLevel(sx, sy, button);
10426         }
10427 #if 1
10428         else
10429 #else
10430         else if (new_element != Feld[lx][ly])
10431 #endif
10432         {
10433           if (new_element == EL_PLAYER_1)
10434           {
10435             /* remove player at old position */
10436             for (y = 0; y < lev_fieldy; y++)
10437             {
10438               for (x = 0; x < lev_fieldx; x++)
10439               {
10440                 if (Feld[x][y] == EL_PLAYER_1)
10441                 {
10442 #if 1
10443                   SetElement(x, y, EL_EMPTY);
10444 #else
10445                   Feld[x][y] = EL_EMPTY;
10446 #if 1
10447                   if (IN_ED_FIELD(x - level_xpos, y - level_ypos))
10448                     DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY);
10449 #else
10450                   if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
10451                       y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
10452                     DrawMiniElement(x - level_xpos, y - level_ypos, EL_EMPTY);
10453 #endif
10454 #endif
10455                 }
10456               }
10457             }
10458           }
10459
10460 #if 1
10461           SetElementButton(lx, ly, new_element, button);
10462 #else
10463           Feld[lx][ly] = new_element;
10464           DrawMiniElement(sx, sy, new_element);
10465 #endif
10466         }
10467       }
10468       else
10469       {
10470         int type_id = gi->custom_type_id;
10471         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
10472
10473         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
10474           DrawMiniGraphicExt(drawto,
10475                              gi->x + sx * MINI_TILEX,
10476                              gi->y + sy * MINI_TILEY,
10477                              el2edimg(new_element));
10478         else
10479           DrawGraphicExt(drawto,
10480                          gi->x + sx * TILEX,
10481                          gi->y + sy * TILEY,
10482                          el2img(new_element), 0);
10483
10484         if (id == GADGET_ID_CUSTOM_GRAPHIC)
10485           new_element = GFX_ELEMENT(new_element);
10486
10487         drawingarea_info[type_id].value[pos] = new_element;
10488
10489         CopyElementPropertiesToGame(properties_element);
10490
10491         if (id == GADGET_ID_CUSTOM_GRAPHIC)
10492         {
10493           UpdateCustomElementGraphicGadgets();
10494
10495           FrameCounter = 0;     /* restart animation frame counter */
10496         }
10497       }
10498       break;
10499
10500     case GADGET_ID_CONNECTED_ITEMS:
10501       {
10502         static int last_sx = -1;
10503         static int last_sy = -1;
10504
10505         if (button_release_event)
10506           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10507
10508         if (button)
10509         {
10510           if (!button_press_event)
10511             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
10512
10513           last_sx = sx;
10514           last_sy = sy;
10515         }
10516       }
10517       break;
10518
10519     case GADGET_ID_LINE:
10520     case GADGET_ID_ARC:
10521     case GADGET_ID_RECTANGLE:
10522     case GADGET_ID_FILLED_BOX:
10523     case GADGET_ID_GRAB_BRUSH:
10524     case GADGET_ID_TEXT:
10525       {
10526         static int last_sx = -1;
10527         static int last_sy = -1;
10528         static int start_sx = -1;
10529         static int start_sy = -1;
10530         void (*draw_func)(int, int, int, int, int, boolean);
10531
10532         if (drawing_function == GADGET_ID_LINE)
10533           draw_func = DrawLine;
10534         else if (drawing_function == GADGET_ID_ARC)
10535           draw_func = DrawArc;
10536         else if (drawing_function == GADGET_ID_RECTANGLE)
10537           draw_func = DrawBox;
10538         else if (drawing_function == GADGET_ID_FILLED_BOX)
10539           draw_func = DrawFilledBox;
10540         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
10541           draw_func = SelectArea;
10542         else /* (drawing_function == GADGET_ID_TEXT) */
10543           draw_func = SetTextCursor;
10544
10545         if (button_press_event)
10546         {
10547           draw_func(sx, sy, sx, sy, new_element, FALSE);
10548           start_sx = last_sx = sx;
10549           start_sy = last_sy = sy;
10550
10551           if (drawing_function == GADGET_ID_TEXT)
10552             DrawLevelText(0, 0, 0, TEXT_END);
10553         }
10554         else if (button_release_event)
10555         {
10556           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
10557           if (drawing_function == GADGET_ID_GRAB_BRUSH)
10558           {
10559             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
10560             CopyBrushToCursor(sx, sy);
10561             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
10562                           MB_LEFTBUTTON);
10563             draw_with_brush = TRUE;
10564           }
10565           else if (drawing_function == GADGET_ID_TEXT)
10566             DrawLevelText(sx, sy, 0, TEXT_INIT);
10567           else
10568             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10569         }
10570         else if (last_sx != sx || last_sy != sy)
10571         {
10572           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
10573           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
10574           last_sx = sx;
10575           last_sy = sy;
10576         }
10577       }
10578       break;
10579
10580     case GADGET_ID_FLOOD_FILL:
10581       if (button_press_event && Feld[lx][ly] != new_element)
10582       {
10583         FloodFill(lx, ly, new_element);
10584         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10585         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10586       }
10587       break;
10588
10589     case GADGET_ID_PICK_ELEMENT:
10590       if (button_release_event)
10591         ClickOnGadget(level_editor_gadget[last_drawing_function],
10592                       MB_LEFTBUTTON);
10593       else if (draw_level)
10594         PickDrawingElement(button, Feld[lx][ly]);
10595       else
10596       {
10597         int type_id = gi->custom_type_id;
10598         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
10599
10600         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
10601       }
10602
10603       break;
10604
10605     default:
10606       break;
10607   }
10608 }
10609
10610 static void HandleCounterButtons(struct GadgetInfo *gi)
10611 {
10612   int gadget_id = gi->custom_id;
10613   int counter_id = gi->custom_type_id;
10614   int button = gi->event.button;
10615   int *counter_value = counterbutton_info[counter_id].value;
10616   int step = BUTTON_STEPSIZE(button) *
10617     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
10618
10619   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
10620   {
10621     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
10622     boolean released = (gi->event.type == GD_EVENT_RELEASED);
10623     boolean level_changed = LevelChanged();
10624
10625     if ((level_changed && pressed) || (!level_changed && released))
10626       return;
10627
10628     if (level_changed && !Request("Level has changed ! Discard changes ?",
10629                                   REQ_ASK))
10630     {
10631       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
10632         ModifyEditorCounterValue(counter_id, *counter_value);
10633
10634       return;
10635     }
10636   }
10637
10638   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
10639     *counter_value = gi->textinput.number_value;
10640   else
10641     ModifyEditorCounterValue(counter_id, *counter_value + step);
10642
10643   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
10644   {
10645       LoadLevel(level_nr);
10646       LoadScore(level_nr);
10647
10648       TapeErase();
10649
10650       ResetUndoBuffer();
10651       DrawEditModeWindow();
10652
10653       return;
10654   }
10655
10656   switch (counter_id)
10657   {
10658     case ED_COUNTER_ID_YAMYAM_CONTENT:
10659       DrawYamYamContentAreas();
10660       break;
10661
10662     case ED_COUNTER_ID_BALL_CONTENT:
10663       DrawMagicBallContentAreas();
10664       break;
10665
10666     case ED_COUNTER_ID_ANDROID_CONTENT:
10667       DrawAndroidElementArea(properties_element);
10668       break;
10669
10670     case ED_COUNTER_ID_GROUP_CONTENT:
10671       DrawGroupElementArea(properties_element);
10672       CopyGroupElementPropertiesToGame(properties_element);
10673       break;
10674
10675     case ED_COUNTER_ID_INVENTORY_SIZE:
10676       DrawPlayerInitialInventoryArea(properties_element);
10677       break;
10678
10679     case ED_COUNTER_ID_ENVELOPE_XSIZE:
10680     case ED_COUNTER_ID_ENVELOPE_YSIZE:
10681       DrawEnvelopeTextArea(-1);
10682       break;
10683
10684     case ED_COUNTER_ID_LEVEL_XSIZE:
10685     case ED_COUNTER_ID_LEVEL_YSIZE:
10686       lev_fieldx = level.fieldx;
10687       lev_fieldy = level.fieldy;
10688       break;
10689
10690     default:
10691       break;
10692   }
10693
10694   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
10695        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
10696       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
10697        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
10698     CopyElementPropertiesToGame(properties_element);
10699
10700   level.changed = TRUE;
10701 }
10702
10703 static void HandleTextInputGadgets(struct GadgetInfo *gi)
10704 {
10705   int type_id = gi->custom_type_id;
10706
10707   strcpy(textinput_info[type_id].value, gi->textinput.value);
10708
10709   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
10710   {
10711     CopyElementPropertiesToGame(properties_element);
10712
10713     ModifyEditorElementList();  /* update changed button info text */
10714   }
10715
10716   level.changed = TRUE;
10717 }
10718
10719 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
10720 {
10721   int type_id = gi->custom_type_id;
10722
10723 #if 1
10724   strncpy(textarea_info[type_id].value, gi->textarea.value,
10725           MAX_ENVELOPE_TEXT_LEN);
10726   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
10727 #else
10728   /* !!! BUGGY !!! MAX_ENVELOPE_TEXT_LEN != MAX_GADGET_TEXTSIZE !!! */
10729   strcpy(textarea_info[type_id].value, gi->textarea.value);
10730 #endif
10731
10732   level.changed = TRUE;
10733 }
10734
10735 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
10736 {
10737   int type_id = gi->custom_type_id;
10738   int value_old = *selectbox_info[type_id].value;
10739   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
10740
10741   *selectbox_info[type_id].value = value_new;
10742
10743   if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
10744   {
10745     element_info[properties_element].current_change_page = gi->selectbox.index;
10746
10747     DrawPropertiesWindow();
10748   }
10749   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
10750             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
10751            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
10752             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
10753            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
10754   {
10755     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
10756     {
10757       /* when changing action type, also check action mode and action arg */
10758       if (value_old != value_new)
10759         setSelectboxSpecialActionVariablesIfNeeded();
10760
10761       DrawPropertiesChange();
10762     }
10763
10764     CopyElementPropertiesToGame(properties_element);
10765
10766     level.changed = TRUE;
10767   }
10768 }
10769
10770 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
10771 {
10772   int type_id = gi->custom_type_id;
10773   int i;
10774
10775   if (type_id >= ED_TEXTBUTTON_ID_LEVELINFO_FIRST &&
10776       type_id <= ED_TEXTBUTTON_ID_LEVELINFO_LAST)
10777   {
10778     edit_mode_levelinfo = gi->custom_type_id;
10779
10780     DrawLevelInfoWindow();
10781   }
10782   else if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST &&
10783            type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST)
10784   {
10785     edit_mode_properties = gi->custom_type_id;
10786
10787     DrawPropertiesWindow();
10788   }
10789   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
10790   {
10791     char *template_filename = getDefaultLevelFilename(-1);
10792     boolean new_template = !fileExists(template_filename);
10793
10794     if (new_template ||
10795         Request("Save this template and kill the old ?", REQ_ASK))
10796       SaveLevelTemplate();
10797
10798     if (new_template)
10799       Request("Template saved !", REQ_CONFIRM);
10800   }
10801   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
10802            custom_element.num_change_pages < MAX_CHANGE_PAGES)
10803   {
10804     struct ElementInfo *ei = &element_info[properties_element];
10805
10806     setElementChangePages(ei, ei->num_change_pages + 1);
10807
10808     /* set new change page to be new current change page */
10809     ei->current_change_page = ei->num_change_pages - 1;
10810     ei->change = &ei->change_page[ei->current_change_page];
10811
10812     setElementChangeInfoToDefaults(ei->change);
10813
10814     DrawPropertiesWindow();
10815
10816     level.changed = TRUE;
10817   }
10818   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
10819            custom_element.num_change_pages > MIN_CHANGE_PAGES)
10820   {
10821     struct ElementInfo *ei = &element_info[properties_element];
10822
10823     /* copy all change pages after change page to be deleted */
10824     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
10825       ei->change_page[i] = ei->change_page[i + 1];
10826
10827     setElementChangePages(ei, ei->num_change_pages - 1);
10828
10829     DrawPropertiesWindow();
10830
10831     level.changed = TRUE;
10832   }
10833 }
10834
10835 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
10836 {
10837   int type_id = gi->custom_type_id;
10838
10839   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
10840       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
10841   {
10842     struct ElementInfo *ei = &element_info[properties_element];
10843     int step = BUTTON_STEPSIZE(gi->event.button);
10844
10845     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
10846     ei->current_change_page += step;
10847
10848     if (ei->current_change_page < 0)
10849       ei->current_change_page = 0;
10850     else if (ei->current_change_page >= ei->num_change_pages)
10851       ei->current_change_page = ei->num_change_pages - 1;
10852
10853     DrawPropertiesWindow();
10854   }
10855   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
10856            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
10857   {
10858     struct ElementInfo *ei = &element_info[properties_element];
10859     int current_change_page = ei->current_change_page;
10860
10861     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
10862       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
10863         ei->change_page[current_change_page];
10864     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
10865     {
10866       ei->change_page[current_change_page] =
10867         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
10868
10869       level.changed = TRUE;
10870     }
10871
10872     DrawPropertiesWindow();
10873   }
10874 }
10875
10876 static void HandleRadiobuttons(struct GadgetInfo *gi)
10877 {
10878   *radiobutton_info[gi->custom_type_id].value =
10879     radiobutton_info[gi->custom_type_id].checked_value;
10880
10881   level.changed = TRUE;
10882 }
10883
10884 static void HandleCheckbuttons(struct GadgetInfo *gi)
10885 {
10886   int type_id = gi->custom_type_id;
10887
10888   *checkbutton_info[type_id].value ^= TRUE;
10889
10890   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
10891       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
10892       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
10893       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
10894          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
10895         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
10896          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
10897        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
10898   {
10899     CopyElementPropertiesToGame(properties_element);
10900   }
10901
10902   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
10903   {
10904     UpdateCustomElementGraphicGadgets();
10905   }
10906   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
10907   {
10908     char *template_filename = getDefaultLevelFilename(-1);
10909
10910     if (level.use_custom_template && !fileExists(template_filename))
10911     {
10912       Request("No level template found !", REQ_CONFIRM);
10913
10914       level.use_custom_template = FALSE;
10915       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
10916
10917       return;
10918     }
10919
10920     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
10921
10922     DrawEditModeWindow();
10923   }
10924
10925   level.changed = TRUE;
10926 }
10927
10928 static void HandleControlButtons(struct GadgetInfo *gi)
10929 {
10930   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
10931   static int last_edit_mode = ED_MODE_DRAWING;
10932   static int last_custom_copy_mode = -1;
10933   int id = gi->custom_id;
10934   int button = gi->event.button;
10935   int step = BUTTON_STEPSIZE(button);
10936   int new_element = BUTTON_ELEMENT(button);
10937   int x, y;
10938
10939   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
10940     DrawLevelText(0, 0, 0, TEXT_END);
10941
10942   if (id < ED_NUM_CTRL1_BUTTONS &&
10943       id != GADGET_ID_SINGLE_ITEMS &&
10944       id != GADGET_ID_PROPERTIES &&
10945       id != GADGET_ID_PICK_ELEMENT &&
10946       edit_mode != ED_MODE_DRAWING &&
10947       drawing_function != GADGET_ID_PICK_ELEMENT &&
10948       !(GetKeyModState() & KMOD_Control))
10949   {
10950     DrawDrawingWindow();
10951     edit_mode = ED_MODE_DRAWING;
10952   }
10953
10954   /* element copy mode active, but no element button pressed => deactivate */
10955   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
10956     last_custom_copy_mode = -1;
10957
10958   switch (id)
10959   {
10960     case GADGET_ID_SCROLL_LEFT:
10961       if (level_xpos >= 0)
10962       {
10963         if (lev_fieldx < ed_fieldx - 2)
10964           break;
10965
10966         level_xpos -= step;
10967         if (level_xpos < -1)
10968           level_xpos = -1;
10969         if (button == 1)
10970           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
10971         else
10972           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10973
10974         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10975                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
10976       }
10977       break;
10978
10979     case GADGET_ID_SCROLL_RIGHT:
10980       if (level_xpos <= lev_fieldx - ed_fieldx)
10981       {
10982         if (lev_fieldx < ed_fieldx - 2)
10983           break;
10984
10985         level_xpos += step;
10986         if (level_xpos > lev_fieldx - ed_fieldx + 1)
10987           level_xpos = lev_fieldx - ed_fieldx + 1;
10988         if (button == 1)
10989           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
10990         else
10991           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10992
10993         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10994                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
10995       }
10996       break;
10997
10998     case GADGET_ID_SCROLL_UP:
10999       if (level_ypos >= 0)
11000       {
11001         if (lev_fieldy < ed_fieldy - 2)
11002           break;
11003
11004         level_ypos -= step;
11005         if (level_ypos < -1)
11006           level_ypos = -1;
11007         if (button == 1)
11008           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
11009         else
11010           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11011
11012         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11013                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11014       }
11015       break;
11016
11017     case GADGET_ID_SCROLL_DOWN:
11018       if (level_ypos <= lev_fieldy - ed_fieldy)
11019       {
11020         if (lev_fieldy < ed_fieldy - 2)
11021           break;
11022
11023         level_ypos += step;
11024         if (level_ypos > lev_fieldy - ed_fieldy + 1)
11025           level_ypos = lev_fieldy - ed_fieldy + 1;
11026         if (button == 1)
11027           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
11028         else
11029           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11030
11031         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11032                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11033       }
11034       break;
11035
11036     case GADGET_ID_SCROLL_HORIZONTAL:
11037       level_xpos = gi->event.item_position - 1;
11038       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11039       break;
11040
11041     case GADGET_ID_SCROLL_VERTICAL:
11042       level_ypos = gi->event.item_position - 1;
11043       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11044       break;
11045
11046     case GADGET_ID_SCROLL_LIST_UP:
11047     case GADGET_ID_SCROLL_LIST_DOWN:
11048     case GADGET_ID_SCROLL_LIST_VERTICAL:
11049       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
11050         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
11051       else
11052       {
11053         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
11054         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
11055
11056         if (element_shift < 0)
11057           element_shift = 0;
11058         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
11059           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
11060
11061         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
11062                      GDI_SCROLLBAR_ITEM_POSITION,
11063                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
11064       }
11065
11066       ModifyEditorElementList();
11067
11068       break;
11069
11070     case GADGET_ID_WRAP_LEFT:
11071       WrapLevel(-step, 0);
11072       break;
11073
11074     case GADGET_ID_WRAP_RIGHT:
11075       WrapLevel(step, 0);
11076       break;
11077
11078     case GADGET_ID_WRAP_UP:
11079       WrapLevel(0, -step);
11080       break;
11081
11082     case GADGET_ID_WRAP_DOWN:
11083       WrapLevel(0, step);
11084       break;
11085
11086     case GADGET_ID_SINGLE_ITEMS:
11087     case GADGET_ID_CONNECTED_ITEMS:
11088     case GADGET_ID_LINE:
11089     case GADGET_ID_ARC:
11090     case GADGET_ID_TEXT:
11091     case GADGET_ID_RECTANGLE:
11092     case GADGET_ID_FILLED_BOX:
11093     case GADGET_ID_FLOOD_FILL:
11094     case GADGET_ID_GRAB_BRUSH:
11095     case GADGET_ID_PICK_ELEMENT:
11096       if (drawing_function != GADGET_ID_PICK_ELEMENT)
11097         last_drawing_function = drawing_function;
11098       drawing_function = id;
11099       draw_with_brush = FALSE;
11100       break;
11101
11102     case GADGET_ID_RANDOM_PLACEMENT:
11103       RandomPlacement(new_element);
11104       break;
11105
11106     case GADGET_ID_PROPERTIES:
11107       if (edit_mode != ED_MODE_PROPERTIES)
11108       {
11109         properties_element = new_element;
11110         DrawPropertiesWindow();
11111         edit_mode = ED_MODE_PROPERTIES;
11112
11113         last_level_drawing_function = drawing_function;
11114         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
11115                       MB_LEFTBUTTON);
11116       }
11117       else
11118       {
11119         DrawDrawingWindow();
11120         edit_mode = ED_MODE_DRAWING;
11121
11122         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
11123                       MB_LEFTBUTTON);
11124       }
11125       break;
11126
11127     case GADGET_ID_CUSTOM_COPY_FROM:
11128     case GADGET_ID_CUSTOM_COPY_TO:
11129     case GADGET_ID_CUSTOM_EXCHANGE:
11130       last_custom_copy_mode = id;
11131       last_drawing_function = drawing_function;
11132       break;
11133
11134     case GADGET_ID_CUSTOM_COPY:
11135       CopyCustomElement(properties_element, -1, id);
11136       break;
11137
11138     case GADGET_ID_CUSTOM_PASTE:
11139       CopyCustomElement(-1, properties_element, id);
11140       break;
11141
11142     case GADGET_ID_UNDO:
11143       if (undo_buffer_steps == 0)
11144       {
11145         Request("Undo buffer empty !", REQ_CONFIRM);
11146         break;
11147       }
11148
11149       if (edit_mode != ED_MODE_DRAWING)
11150       {
11151         DrawDrawingWindow();
11152         edit_mode = ED_MODE_DRAWING;
11153       }
11154
11155       undo_buffer_position =
11156         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
11157       undo_buffer_steps--;
11158
11159       for (x = 0; x < lev_fieldx; x++)
11160         for (y = 0; y < lev_fieldy; y++)
11161           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
11162
11163       /* check if undo operation forces change of border style */
11164       CheckLevelBorderElement(FALSE);
11165
11166       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11167
11168       break;
11169
11170     case GADGET_ID_INFO:
11171       if (edit_mode != ED_MODE_INFO)
11172       {
11173         last_edit_mode = edit_mode;
11174         edit_mode = ED_MODE_INFO;
11175
11176         DrawLevelInfoWindow();
11177       }
11178       else
11179       {
11180         edit_mode = last_edit_mode;
11181
11182         DrawEditModeWindow();
11183       }
11184       break;
11185
11186     case GADGET_ID_CLEAR:
11187       if (edit_mode != ED_MODE_DRAWING)
11188       {
11189         DrawDrawingWindow();
11190         edit_mode = ED_MODE_DRAWING;
11191       }
11192
11193       for (x = 0; x < MAX_LEV_FIELDX; x++) 
11194         for (y = 0; y < MAX_LEV_FIELDY; y++) 
11195           Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
11196
11197       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
11198
11199       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11200       break;
11201
11202     case GADGET_ID_SAVE:
11203       if (leveldir_current->readonly)
11204       {
11205         Request("This level is read only !", REQ_CONFIRM);
11206         break;
11207       }
11208
11209       if (!LevelContainsPlayer())
11210         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
11211       else
11212       {
11213         char *level_filename = getDefaultLevelFilename(level_nr);
11214         boolean new_level = !fileExists(level_filename);
11215
11216         if (new_level ||
11217             Request("Save this level and kill the old ?", REQ_ASK))
11218         {
11219           CopyPlayfield(Feld, level.field);
11220
11221           SaveLevel(level_nr);
11222         }
11223
11224         if (new_level)
11225           Request("Level saved !", REQ_CONFIRM);
11226
11227         level.changed = FALSE;
11228       }
11229       break;
11230
11231     case GADGET_ID_TEST:
11232       if (!LevelContainsPlayer())
11233         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
11234       else
11235       {
11236         if (LevelChanged())
11237           level.game_version = GAME_VERSION_ACTUAL;
11238
11239         CopyPlayfield(level.field, FieldBackup);
11240         CopyPlayfield(Feld, level.field);
11241
11242         CopyNativeLevel_RND_to_Native(&level);
11243
11244         UnmapLevelEditorGadgets();
11245         UndrawSpecialEditorDoor();
11246
11247         CloseDoor(DOOR_CLOSE_ALL);
11248
11249         BackToFront();          /* force redraw of undrawn special door */
11250
11251         DrawCompleteVideoDisplay();
11252
11253         level_editor_test_game = TRUE;
11254
11255         StartGameActions(FALSE, setup.autorecord, level.random_seed);
11256       }
11257       break;
11258
11259     case GADGET_ID_EXIT:
11260       RequestExitLevelEditor(TRUE, FALSE);  /* if level has changed, ask user */
11261       break;
11262
11263     default:
11264       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
11265           id <= GADGET_ID_ELEMENTLIST_LAST)
11266       {
11267         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
11268         int new_element = editor_elements[element_position + element_shift];
11269
11270         if (IS_EDITOR_CASCADE(new_element))
11271         {
11272           int i;
11273
11274           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
11275           {
11276             int *cascade_element= &(*editor_elements_info[i].headline_list)[0];
11277             boolean *cascade_value=editor_elements_info[i].setup_cascade_value;
11278
11279             if (*cascade_element == new_element)
11280             {
11281               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
11282               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
11283
11284               /* update element selection list */
11285               ReinitializeElementList();
11286               ModifyEditorElementList();
11287
11288               /* update cascading gadget info text */
11289               PrintEditorGadgetInfoText(level_editor_gadget[id]);
11290
11291               /* save current editor cascading state */
11292               SaveSetup_EditorCascade();
11293
11294               break;
11295             }
11296           }
11297
11298           break;
11299         }
11300
11301         if (last_custom_copy_mode != -1)
11302         {
11303           if (CopyCustomElement(properties_element, new_element,
11304                                 last_custom_copy_mode))
11305           {
11306             ClickOnGadget(level_editor_gadget[last_drawing_function],
11307                           MB_LEFTBUTTON);
11308
11309             last_custom_copy_mode = -1;
11310           }
11311
11312           break;
11313         }
11314
11315         PickDrawingElement(button, new_element);
11316
11317         if (!stick_element_properties_window &&
11318             drawing_function != GADGET_ID_PICK_ELEMENT &&
11319             !(GetKeyModState() & KMOD_Control))
11320         {
11321           properties_element = new_element;
11322           if (edit_mode == ED_MODE_PROPERTIES)
11323             DrawPropertiesWindow();
11324         }
11325
11326         if (drawing_function == GADGET_ID_PICK_ELEMENT)
11327           ClickOnGadget(level_editor_gadget[last_drawing_function],
11328                         MB_LEFTBUTTON);
11329       }
11330 #ifdef DEBUG
11331       else if (gi->event.type == GD_EVENT_PRESSED)
11332         printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
11333       else if (gi->event.type == GD_EVENT_RELEASED)
11334         printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
11335       else if (gi->event.type == GD_EVENT_MOVING)
11336         printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
11337       else
11338         printf("default: HandleControlButtons: ? (id == %d)\n", id);
11339 #endif
11340       break;
11341   }
11342 }
11343
11344 void HandleLevelEditorKeyInput(Key key)
11345 {
11346   char letter = getCharFromKey(key);
11347   int button = MB_LEFTBUTTON;
11348
11349   if (drawing_function == GADGET_ID_TEXT &&
11350       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
11351   {
11352     if (letter)
11353       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
11354     else if (key == KSYM_Delete || key == KSYM_BackSpace)
11355       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
11356     else if (key == KSYM_Return)
11357       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
11358     else if (key == KSYM_Escape)
11359       DrawLevelText(0, 0, 0, TEXT_END);
11360   }
11361   else if (button_status == MB_RELEASED)
11362   {
11363     int id = GADGET_ID_NONE;
11364     int new_element_shift = element_shift;
11365     int i;
11366
11367     switch (key)
11368     {
11369       case KSYM_Left:
11370         id = GADGET_ID_SCROLL_LEFT;
11371         break;
11372       case KSYM_Right:
11373         id = GADGET_ID_SCROLL_RIGHT;
11374         break;
11375       case KSYM_Up:
11376         id = GADGET_ID_SCROLL_UP;
11377         break;
11378       case KSYM_Down:
11379         id = GADGET_ID_SCROLL_DOWN;
11380         break;
11381       case KSYM_Page_Up:
11382         id = GADGET_ID_SCROLL_LIST_UP;
11383         button = MB_RIGHTBUTTON;
11384         break;
11385       case KSYM_Page_Down:
11386         id = GADGET_ID_SCROLL_LIST_DOWN;
11387         button = MB_RIGHTBUTTON;
11388         break;
11389
11390       case KSYM_Home:
11391       case KSYM_End:
11392         element_shift = (key == KSYM_Home ? 0 :
11393                          num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
11394
11395         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
11396                      GDI_SCROLLBAR_ITEM_POSITION,
11397                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
11398
11399         ModifyEditorElementList();
11400
11401         break;
11402
11403       case KSYM_Insert:
11404       case KSYM_Delete:
11405
11406         /* this is needed to prevent interference with running "True X-Mouse" */
11407         if (GetKeyModStateFromEvents() & KMOD_Control)
11408           break;
11409
11410         /* check for last or next editor cascade block in element list */
11411         for (i = 0; i < num_editor_elements; i++)
11412         {
11413           if ((key == KSYM_Insert && i == element_shift) ||
11414               (key == KSYM_Delete && new_element_shift > element_shift))
11415             break;
11416
11417           /* jump to next cascade block (or to start of element list) */
11418           if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
11419             new_element_shift = i;
11420         }
11421
11422         if (i < num_editor_elements)
11423           element_shift = new_element_shift;
11424
11425         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
11426           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
11427
11428         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
11429                      GDI_SCROLLBAR_ITEM_POSITION,
11430                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
11431
11432         ModifyEditorElementList();
11433
11434         break;
11435
11436       case KSYM_Escape:
11437         if (edit_mode == ED_MODE_DRAWING)
11438         {
11439           RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
11440         }
11441         else if (edit_mode == ED_MODE_INFO)
11442         {
11443           HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
11444         }
11445         else if (edit_mode == ED_MODE_PROPERTIES)
11446         {
11447           HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
11448         }
11449         else            /* should never happen */
11450         {
11451           DrawDrawingWindow();
11452           edit_mode = ED_MODE_DRAWING;
11453         }
11454
11455         break;
11456
11457       default:
11458         break;
11459     }
11460
11461     if (id != GADGET_ID_NONE)
11462       ClickOnGadget(level_editor_gadget[id], button);
11463     else if (letter == '.')
11464       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
11465     else if (key == KSYM_Return || key == setup.shortcut.toggle_pause)
11466       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
11467     else
11468       for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
11469         if (letter && letter == control_info[i].shortcut)
11470           if (!anyTextGadgetActive())
11471             ClickOnGadget(level_editor_gadget[i], button);
11472   }
11473 }
11474
11475 void HandleLevelEditorIdle()
11476 {
11477   static unsigned long action_delay = 0;
11478   unsigned long action_delay_value = GameFrameDelay;
11479   int xpos = 1, ypos = 2;
11480   int i;
11481
11482   if (edit_mode != ED_MODE_PROPERTIES)
11483     return;
11484
11485   if (!DelayReached(&action_delay, action_delay_value))
11486     return;
11487
11488   for (i = 0; i < ED_NUM_SELECTBOX; i++)
11489   {
11490     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
11491
11492     if (gi->mapped && gi->active && gi->selectbox.open)
11493       return;
11494   }
11495
11496   DrawEditorElementAnimation(SX + xpos * TILEX,
11497                              SY + ypos * TILEY + MINI_TILEY / 2);
11498
11499   MarkTileDirty(xpos, ypos);
11500   MarkTileDirty(xpos, ypos + 1);
11501
11502   FrameCounter++;       /* increase animation frame counter */
11503 }
11504
11505 void ClearEditorGadgetInfoText()
11506 {
11507   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
11508 }
11509
11510 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
11511 {
11512   char infotext[MAX_OUTPUT_LINESIZE + 1];
11513   char shortcut[MAX_OUTPUT_LINESIZE + 1];
11514   int max_infotext_len = getMaxInfoTextLength();
11515
11516   if (gi == NULL || gi->info_text == NULL)
11517     return;
11518
11519   strncpy(infotext, gi->info_text, max_infotext_len);
11520   infotext[max_infotext_len] = '\0';
11521
11522   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
11523   {
11524     int key = control_info[gi->custom_id].shortcut;
11525
11526     if (key)
11527     {
11528       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)      /* special case 1 */
11529         sprintf(shortcut, " ('.' or '%c')", key);
11530       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT) /* special case 2 */
11531         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
11532       else if (gi->custom_id == GADGET_ID_TEST)         /* special case 3 */
11533         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
11534       else                                              /* normal case */
11535         sprintf(shortcut, " ('%s%c')",
11536                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
11537
11538       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
11539         strcat(infotext, shortcut);
11540     }
11541   }
11542
11543   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2);
11544 }
11545
11546 void HandleEditorGadgetInfoText(void *ptr)
11547 {
11548   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
11549
11550   if (game_status != GAME_MODE_EDITOR)
11551     return;
11552
11553   ClearEditorGadgetInfoText();
11554
11555   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
11556     return;
11557
11558   /* misuse this function to delete brush cursor, if needed */
11559   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
11560     DeleteBrushFromCursor();
11561
11562   PrintEditorGadgetInfoText(gi);
11563 }
11564
11565 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
11566 {
11567   static int start_lx, start_ly;
11568   int id = gi->custom_id;
11569   int type_id = gi->custom_type_id;
11570   int sx = gi->event.x;
11571   int sy = gi->event.y;
11572   int lx = sx + level_xpos;
11573   int ly = sy + level_ypos;
11574   int min_sx = 0, min_sy = 0;
11575   int max_sx = gi->drawing.area_xsize - 1;
11576   int max_sy = gi->drawing.area_ysize - 1;
11577   int actual_drawing_function = drawing_function;
11578   int max_infotext_len = getMaxInfoTextLength();
11579   char infotext[MAX_OUTPUT_LINESIZE + 1];
11580   char *text;
11581
11582   infotext[0] = '\0';           /* start with empty info text */
11583
11584   /* pressed Control key: simulate picking element */
11585   if (GetKeyModState() & KMOD_Control)
11586     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
11587
11588   ClearEditorGadgetInfoText();
11589
11590   if (gi->event.type == GD_EVENT_INFO_LEAVING)
11591     return;
11592
11593   /* make sure to stay inside drawing area boundaries */
11594   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
11595   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
11596
11597   if (id == GADGET_ID_DRAWING_LEVEL)
11598   {
11599     if (button_status)
11600     {
11601       int min_lx = 0, min_ly = 0;
11602       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
11603
11604       /* get positions inside level field */
11605       lx = sx + level_xpos;
11606       ly = sy + level_ypos;
11607
11608       /* make sure to stay inside level field boundaries */
11609       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
11610       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
11611
11612       /* correct drawing area positions accordingly */
11613       sx = lx - level_xpos;
11614       sy = ly - level_ypos;
11615     }
11616
11617     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
11618     {
11619       if (button_status)        /* if (gi->state == GD_BUTTON_PRESSED) */
11620       {
11621         if (gi->event.type == GD_EVENT_PRESSED)
11622         {
11623           start_lx = lx;
11624           start_ly = ly;
11625         }
11626
11627         switch (actual_drawing_function)
11628         {
11629           case GADGET_ID_SINGLE_ITEMS:
11630             text = "Drawing single items";
11631             break;
11632           case GADGET_ID_CONNECTED_ITEMS:
11633             text = "Drawing connected items";
11634             break;
11635           case GADGET_ID_LINE:
11636             text = "Drawing line";
11637             break;
11638           case GADGET_ID_ARC:
11639             text = "Drawing arc";
11640             break;
11641           case GADGET_ID_TEXT:
11642             text = "Setting text cursor";
11643             break;
11644           case GADGET_ID_RECTANGLE:
11645             text = "Drawing rectangle";
11646             break;
11647           case GADGET_ID_FILLED_BOX:
11648             text = "Drawing filled box";
11649             break;
11650           case GADGET_ID_FLOOD_FILL:
11651             text = "Flood fill";
11652             break;
11653           case GADGET_ID_GRAB_BRUSH:
11654             text = "Grabbing brush";
11655             break;
11656           case GADGET_ID_PICK_ELEMENT:
11657             text = "Picking element";
11658             break;
11659
11660           default:
11661             text = "Drawing position";
11662             break;
11663         }
11664
11665         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
11666           sprintf(infotext, "%s: %d, %d", text, lx, ly);
11667         else
11668           sprintf(infotext, "%s: %d, %d", text,
11669                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
11670       }
11671       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
11672         strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
11673       else
11674         sprintf(infotext, "Level position: %d, %d", lx, ly);
11675     }
11676
11677     /* misuse this function to draw brush cursor, if needed */
11678     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
11679     {
11680       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
11681         CopyBrushToCursor(sx, sy);
11682       else
11683         DeleteBrushFromCursor();
11684     }
11685   }
11686   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
11687   {
11688     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
11689     int element = drawingarea_info[type_id].value[pos];
11690
11691     strncpy(infotext, getElementInfoText(element), max_infotext_len);
11692   }
11693   else
11694   {
11695     if (id == GADGET_ID_CUSTOM_CONTENT)
11696       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
11697     else if (id == GADGET_ID_GROUP_CONTENT)
11698       sprintf(infotext, "group element position: %d", sx + 1);
11699     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
11700              id <= GADGET_ID_YAMYAM_CONTENT_7)
11701       sprintf(infotext, "content area %d position: %d, %d",
11702               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
11703     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
11704              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
11705       sprintf(infotext, "content area %d position: %d, %d",
11706               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
11707     else if (id == GADGET_ID_ANDROID_CONTENT)
11708       sprintf(infotext, "android element position: %d", sx + 1);
11709     else if (drawingarea_info[type_id].infotext != NULL)
11710       strcpy(infotext, drawingarea_info[type_id].infotext);
11711   }
11712
11713   infotext[max_infotext_len] = '\0';
11714
11715   if (strlen(infotext) > 0)
11716     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, infotext);
11717 }
11718
11719 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
11720                             boolean quick_quit)
11721 {
11722   if (!ask_if_level_has_changed ||
11723       !LevelChanged() ||
11724       Request("Level has changed ! Exit without saving ?",
11725               REQ_ASK | REQ_STAY_OPEN))
11726   {
11727     CloseDoor(DOOR_CLOSE_1);
11728     SetDoorState(DOOR_CLOSE_2);
11729
11730 #if 1
11731     if (quick_quit)
11732       FadeSkipNextFadeIn();
11733 #else
11734     if (quick_quit)
11735       fading = fading_none;
11736 #endif
11737
11738     game_status = GAME_MODE_MAIN;
11739 #if 1
11740     DrawAndFadeInMainMenu(REDRAW_FIELD);
11741 #else
11742     DrawMainMenu();
11743 #endif
11744   }
11745   else
11746   {
11747     CloseDoor(DOOR_CLOSE_1);
11748     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
11749   }
11750 }