cleanup of setup value fonts on setup screens
[rocksndiamonds.git] / src / editor.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // editor.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "game.h"
21 #include "init.h"
22 #include "tape.h"
23
24
25 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
26
27
28 // ----------------------------------------------------------------------------
29 // screen and artwork graphic pixel position definitions
30 // ----------------------------------------------------------------------------
31
32 // values for the control window
33 #define ED_CTRL1_BUTTONS_HORIZ          4       // toolbox
34 #define ED_CTRL1_BUTTONS_VERT           4
35 #define ED_CTRL2_BUTTONS_HORIZ          3       // level
36 #define ED_CTRL2_BUTTONS_VERT           2
37 #define ED_CTRL3_BUTTONS_HORIZ          3       // CE and GE
38 #define ED_CTRL3_BUTTONS_VERT           1
39 #define ED_CTRL4_BUTTONS_HORIZ          2       // CE and GE
40 #define ED_CTRL4_BUTTONS_VERT           1
41 #define ED_CTRL5_BUTTONS_HORIZ          1       // properties
42 #define ED_CTRL5_BUTTONS_VERT           1
43 #define ED_CTRL6_BUTTONS_HORIZ          3       // properties
44 #define ED_CTRL6_BUTTONS_VERT           1
45 #define ED_CTRL7_BUTTONS_HORIZ          1       // palette
46 #define ED_CTRL7_BUTTONS_VERT           1
47
48 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
49 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
50 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
51 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
52 #define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
53 #define ED_NUM_CTRL6_BUTTONS   (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT)
54 #define ED_NUM_CTRL7_BUTTONS   (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT)
55 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
56 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
57 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
58 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
59 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
60 #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS)
61 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_7_BUTTONS
62
63 // values for the element list
64 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
65 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
66 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
67 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
68 #define ED_ELEMENTLIST_COLS             MAX(1, editor.palette.cols)
69 #define ED_ELEMENTLIST_ROWS             MAX(1, editor.palette.rows)
70 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (ED_ELEMENTLIST_COLS)
71 #define ED_ELEMENTLIST_BUTTONS_VERT     (ED_ELEMENTLIST_ROWS)
72 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
73                                          ED_ELEMENTLIST_BUTTONS_VERT)
74
75 // standard distances
76 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
77 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
78 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
79 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
80 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
81 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
82 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
83                                          ED_DRAWINGAREA_BORDER_SIZE)
84 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
85
86 // values for drawingarea gadgets
87 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
88 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
89 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
90 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
91 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
92
93 // values for checkbutton gadgets
94 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
95 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
96
97 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
98 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
99
100 #define ED_SETTINGS_LEVEL_TABS_X        (editor.settings.tabs.x)
101 #define ED_SETTINGS_LEVEL_TABS_Y        (editor.settings.tabs.y)
102 #define ED_SETTINGS_ELEMENT_TABS_X      (editor.settings.tabs.x)
103 #define ED_SETTINGS_ELEMENT_TABS_Y      (editor.settings.tabs.y +       \
104                                          editor.settings.tabs.yoffset2)
105
106 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
107 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
108
109 #define ED_LEVEL_TABS_XSTART            (ED_SETTINGS_LEVEL_TABS_X)
110 #define ED_LEVEL_TABS_YSTART            (ED_SETTINGS_LEVEL_TABS_Y)
111 #define ED_LEVEL_SETTINGS_XSTART        (ED_SETTINGS_LEVEL_TABS_X +     \
112                                          ED_SETTINGS_TABS_XOFFSET)
113 #define ED_LEVEL_SETTINGS_YSTART        (ED_SETTINGS_LEVEL_TABS_Y +     \
114                                          ED_TABBUTTON_YSIZE +           \
115                                          ED_GADGET_TINY_DISTANCE +      \
116                                          ED_TAB_BAR_HEIGHT +            \
117                                          ED_SETTINGS_TABS_YOFFSET +     \
118                                          getFontHeight(FONT_TEXT_1) +   \
119                                          ED_GADGET_TEXT_DISTANCE)
120 #define ED_ELEMENT_TABS_XSTART          (ED_SETTINGS_ELEMENT_TABS_X)
121 #define ED_ELEMENT_TABS_YSTART          (ED_SETTINGS_ELEMENT_TABS_Y)
122 #define ED_ELEMENT_SETTINGS_XSTART      (ED_SETTINGS_ELEMENT_TABS_X +   \
123                                          ED_SETTINGS_TABS_XOFFSET)
124 #define ED_ELEMENT_SETTINGS_YSTART      (ED_SETTINGS_ELEMENT_TABS_Y +   \
125                                          ED_TABBUTTON_YSIZE +           \
126                                          ED_GADGET_TINY_DISTANCE +      \
127                                          ED_TAB_BAR_HEIGHT +            \
128                                          ED_SETTINGS_TABS_YOFFSET)
129
130 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
131                                          ED_GADGET_TEXT_DISTANCE)
132 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
133                                          ED_GADGET_LINE_DISTANCE)
134
135 #define ED_POS_RANGE                    (10000)
136 #define ED_POS_LEVEL_TABS_FIRST         (1 * ED_POS_RANGE)
137 #define ED_POS_LEVEL_TABS_LAST          (2 * ED_POS_RANGE - 1)
138 #define ED_POS_LEVEL_SETTINGS_FIRST     (2 * ED_POS_RANGE)
139 #define ED_POS_LEVEL_SETTINGS_LAST      (3 * ED_POS_RANGE - 1)
140 #define ED_POS_ELEMENT_TABS_FIRST       (3 * ED_POS_RANGE)
141 #define ED_POS_ELEMENT_TABS_LAST        (4 * ED_POS_RANGE - 1)
142 #define ED_POS_ELEMENT_SETTINGS_FIRST   (4 * ED_POS_RANGE)
143 #define ED_POS_ELEMENT_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
144
145 #define ED_LEVEL_TABS_XPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
146 #define ED_LEVEL_TABS_YPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
147
148 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
149 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
150
151 #define ED_ELEMENT_TABS_XPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
152 #define ED_ELEMENT_TABS_YPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
153
154 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
155 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
156
157 #define IS_POS_LEVEL_TABS(n)          ((n) >= ED_POS_LEVEL_TABS_FIRST && \
158                                        (n) <= ED_POS_LEVEL_TABS_LAST)
159 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
160                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
161 #define IS_POS_ELEMENT_TABS(n)        ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
162                                        (n) <= ED_POS_ELEMENT_TABS_LAST)
163 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
164                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
165
166 #define ED_LEVEL_TABS_LINE(n)           ((n) - ED_POS_LEVEL_TABS_FIRST)
167 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
168 #define ED_ELEMENT_TABS_LINE(n)         ((n) - ED_POS_ELEMENT_TABS_FIRST)
169 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
170
171 #define ED_LEVEL_TABS_X(n)              (ED_LEVEL_TABS_XSTART + \
172                                          (n) * ED_SETTINGS_TABS_XOFFSET)
173 #define ED_LEVEL_TABS_Y(n)              (ED_LEVEL_TABS_YSTART + \
174                                          (n) * ED_SETTINGS_TABS_YOFFSET)
175
176 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
177                                          (n) * ED_SETTINGS_XOFFSET)
178 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
179                                          (n) * ED_SETTINGS_YOFFSET)
180
181 #define ED_ELEMENT_TABS_X(n)            (ED_ELEMENT_TABS_XSTART +       \
182                                          (n) * ED_SETTINGS_TABS_XOFFSET)
183 #define ED_ELEMENT_TABS_Y(n)            (ED_ELEMENT_TABS_YSTART +       \
184                                          (n) * ED_SETTINGS_TABS_YOFFSET)
185
186 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
187                                          (n) * ED_SETTINGS_XOFFSET)
188 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
189                                          (n) * ED_SETTINGS_YOFFSET)
190
191 #define ED_POS_TO_LEVEL_TABS_X(n)       \
192   (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n)))
193 #define ED_POS_TO_LEVEL_TABS_Y(n)       \
194   (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n)))
195
196 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
197   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
198 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
199   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
200
201 #define ED_POS_TO_ELEMENT_TABS_X(n)     \
202   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
203 #define ED_POS_TO_ELEMENT_TABS_Y(n)     \
204   (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n)))
205
206 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
207   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
208 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
209   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
210
211 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_TABS(n) ? \
212                                          ED_POS_TO_LEVEL_TABS_X(n) : \
213                                          IS_POS_LEVEL_SETTINGS(n) ?     \
214                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
215                                          IS_POS_ELEMENT_TABS(n) ?       \
216                                          ED_POS_TO_ELEMENT_TABS_X(n) : \
217                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
218                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
219 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_TABS(n) ? \
220                                          ED_POS_TO_LEVEL_TABS_Y(n) : \
221                                          IS_POS_LEVEL_SETTINGS(n) ?     \
222                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
223                                          IS_POS_ELEMENT_TABS(n) ?       \
224                                          ED_POS_TO_ELEMENT_TABS_Y(n) : \
225                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
226                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
227
228 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
229                                          ED_DRAWINGAREA_TILE_SIZE)
230 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
231                                          ED_DRAWINGAREA_TILE_SIZE)
232
233 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
234                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
235 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
236                                          (ED_CHECKBUTTON_YSIZE -        \
237                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
238
239 #define ED_AREA_XOFFSET_2(n)      (0)
240 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
241                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
242
243 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
244                                     ED_SETTINGS_XOFF((i).xoffset) +     \
245                                     ED_AREA_XOFFSET_1((i).x) -          \
246                                     ED_AREA_XOFFSET_2((i).area_xsize))
247 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
248                                     ED_SETTINGS_YOFF((i).yoffset) +     \
249                                     ED_AREA_YOFFSET_1((i).y) -          \
250                                     ED_AREA_YOFFSET_2((i).area_ysize))
251
252 // values for element content drawing areas
253 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
254 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
255 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
256 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
257
258 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
259 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
260 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
261 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
262
263 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
264 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
265 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
266 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
267
268 // element content
269 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
270 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
271
272 // yamyam content
273 #define ED_XPOS_YAM                     0
274 #define ED_YPOS_YAM                     5
275 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
276 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
277 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
278 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
279 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
280                                          ED_SETTINGS_XOFF(n))
281 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
282                                          ED_SETTINGS_YOFF(n) +          \
283                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
284                                          ED_AREA_YOFFSET_2(3))
285
286 // magic ball content
287 #define ED_XPOS_BALL                    0
288 #define ED_YPOS_BALL                    6
289 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
290 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
291 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
292 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
293 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
294                                          ED_SETTINGS_XOFF(n))
295 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
296                                          ED_SETTINGS_YOFF(n) +          \
297                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
298                                          ED_AREA_YOFFSET_2(3))
299
300 // values for scrolling gadgets for drawing area
301 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
302 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
303
304 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
305 #define ED_SCROLL_UP_YPOS               (0)
306 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
307 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
308 #define ED_SCROLL_LEFT_XPOS             (0)
309 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
310 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
311 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
312 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
313                                          ED_SCROLLBUTTON_XSIZE)
314 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
315 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
316 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
317 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
318 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
319                                          ED_SCROLLBUTTON_YSIZE)
320 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
321 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
322
323 // values for scrolling gadgets for element list
324 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
325 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
326
327 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
328                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
329                                          ED_ELEMENTLIST_XSIZE)
330 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
331 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
332 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
333                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
334                                          ED_ELEMENTLIST_YSIZE -         \
335                                          ED_SCROLLBUTTON2_YSIZE)
336 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
337 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
338                                          ED_SCROLLBUTTON2_YSIZE)
339 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
340 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
341                                          ED_ELEMENTLIST_YSIZE -         \
342                                          2 * ED_SCROLLBUTTON2_YSIZE)
343
344 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText()
345 #define INFOTEXT_FONT           FONT_TEXT_2
346 #define INFOTEXT_XSIZE          SXSIZE
347 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
348 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
349 #define INFOTEXT_X              (editor.settings.tooltip.x)
350 #define INFOTEXT_Y              (editor.settings.tooltip.y)
351 #define INFOTEXT_XY_REDEFINED   (INFOTEXT_X != -1 || INFOTEXT_Y != -1)
352 #define INFOTEXT_XPOS           SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0)
353 #define INFOTEXT_YPOS           SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \
354                                       SYSIZE - INFOTEXT_YSIZE)
355
356
357 // ----------------------------------------------------------------------------
358 // editor gadget definitions
359 // ----------------------------------------------------------------------------
360
361 enum
362 {
363   GADGET_ID_NONE = -1,
364
365   // drawing toolbox buttons
366
367   GADGET_ID_SINGLE_ITEMS,
368   GADGET_ID_CONNECTED_ITEMS,
369   GADGET_ID_LINE,
370   GADGET_ID_ARC,
371   GADGET_ID_RECTANGLE,
372   GADGET_ID_FILLED_BOX,
373   GADGET_ID_WRAP_UP,
374   GADGET_ID_TEXT,
375   GADGET_ID_FLOOD_FILL,
376   GADGET_ID_WRAP_LEFT,
377   GADGET_ID_ZOOM,
378   GADGET_ID_WRAP_RIGHT,
379   GADGET_ID_RANDOM_PLACEMENT,
380   GADGET_ID_GRAB_BRUSH,
381   GADGET_ID_WRAP_DOWN,
382   GADGET_ID_PICK_ELEMENT,
383
384   GADGET_ID_UNDO,
385   GADGET_ID_CONF,
386   GADGET_ID_SAVE,
387   GADGET_ID_CLEAR,
388   GADGET_ID_TEST,
389   GADGET_ID_EXIT,
390
391   GADGET_ID_CUSTOM_COPY_FROM,
392   GADGET_ID_CUSTOM_COPY_TO,
393   GADGET_ID_CUSTOM_EXCHANGE,
394   GADGET_ID_CUSTOM_COPY,
395   GADGET_ID_CUSTOM_PASTE,
396
397   GADGET_ID_PROPERTIES,
398   GADGET_ID_ELEMENT_LEFT,
399   GADGET_ID_ELEMENT_MIDDLE,
400   GADGET_ID_ELEMENT_RIGHT,
401   GADGET_ID_PALETTE,
402
403   // counter gadget identifiers
404
405   GADGET_ID_SELECT_LEVEL_DOWN,
406   GADGET_ID_SELECT_LEVEL_TEXT,
407   GADGET_ID_SELECT_LEVEL_UP,
408   GADGET_ID_LEVEL_XSIZE_DOWN,
409   GADGET_ID_LEVEL_XSIZE_TEXT,
410   GADGET_ID_LEVEL_XSIZE_UP,
411   GADGET_ID_LEVEL_YSIZE_DOWN,
412   GADGET_ID_LEVEL_YSIZE_TEXT,
413   GADGET_ID_LEVEL_YSIZE_UP,
414   GADGET_ID_LEVEL_RANDOM_DOWN,
415   GADGET_ID_LEVEL_RANDOM_TEXT,
416   GADGET_ID_LEVEL_RANDOM_UP,
417   GADGET_ID_LEVEL_GEMSLIMIT_DOWN,
418   GADGET_ID_LEVEL_GEMSLIMIT_TEXT,
419   GADGET_ID_LEVEL_GEMSLIMIT_UP,
420   GADGET_ID_LEVEL_TIMELIMIT_DOWN,
421   GADGET_ID_LEVEL_TIMELIMIT_TEXT,
422   GADGET_ID_LEVEL_TIMELIMIT_UP,
423   GADGET_ID_LEVEL_TIMESCORE_DOWN,
424   GADGET_ID_LEVEL_TIMESCORE_TEXT,
425   GADGET_ID_LEVEL_TIMESCORE_UP,
426   GADGET_ID_LEVEL_RANDOM_SEED_DOWN,
427   GADGET_ID_LEVEL_RANDOM_SEED_TEXT,
428   GADGET_ID_LEVEL_RANDOM_SEED_UP,
429   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
430   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
431   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
432   GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,
433   GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,
434   GADGET_ID_BD_CYCLE_DELAY_MS_UP,
435   GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,
436   GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,
437   GADGET_ID_BD_CYCLE_DELAY_C64_UP,
438   GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,
439   GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,
440   GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
441   GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,
442   GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,
443   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
444   GADGET_ID_BD_PUSHING_PROB_DOWN,
445   GADGET_ID_BD_PUSHING_PROB_TEXT,
446   GADGET_ID_BD_PUSHING_PROB_UP,
447   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,
448   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,
449   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
450   GADGET_ID_ELEMENT_VALUE1_DOWN,
451   GADGET_ID_ELEMENT_VALUE1_TEXT,
452   GADGET_ID_ELEMENT_VALUE1_UP,
453   GADGET_ID_ELEMENT_VALUE2_DOWN,
454   GADGET_ID_ELEMENT_VALUE2_TEXT,
455   GADGET_ID_ELEMENT_VALUE2_UP,
456   GADGET_ID_ELEMENT_VALUE3_DOWN,
457   GADGET_ID_ELEMENT_VALUE3_TEXT,
458   GADGET_ID_ELEMENT_VALUE3_UP,
459   GADGET_ID_ELEMENT_VALUE4_DOWN,
460   GADGET_ID_ELEMENT_VALUE4_TEXT,
461   GADGET_ID_ELEMENT_VALUE4_UP,
462   GADGET_ID_YAMYAM_CONTENT_DOWN,
463   GADGET_ID_YAMYAM_CONTENT_TEXT,
464   GADGET_ID_YAMYAM_CONTENT_UP,
465   GADGET_ID_BALL_CONTENT_DOWN,
466   GADGET_ID_BALL_CONTENT_TEXT,
467   GADGET_ID_BALL_CONTENT_UP,
468   GADGET_ID_ANDROID_CONTENT_DOWN,
469   GADGET_ID_ANDROID_CONTENT_TEXT,
470   GADGET_ID_ANDROID_CONTENT_UP,
471   GADGET_ID_ENVELOPE_XSIZE_DOWN,
472   GADGET_ID_ENVELOPE_XSIZE_TEXT,
473   GADGET_ID_ENVELOPE_XSIZE_UP,
474   GADGET_ID_ENVELOPE_YSIZE_DOWN,
475   GADGET_ID_ENVELOPE_YSIZE_TEXT,
476   GADGET_ID_ENVELOPE_YSIZE_UP,
477   GADGET_ID_INVENTORY_SIZE_DOWN,
478   GADGET_ID_INVENTORY_SIZE_TEXT,
479   GADGET_ID_INVENTORY_SIZE_UP,
480   GADGET_ID_MM_BALL_CONTENT_DOWN,
481   GADGET_ID_MM_BALL_CONTENT_TEXT,
482   GADGET_ID_MM_BALL_CONTENT_UP,
483   GADGET_ID_CUSTOM_SCORE_DOWN,
484   GADGET_ID_CUSTOM_SCORE_TEXT,
485   GADGET_ID_CUSTOM_SCORE_UP,
486   GADGET_ID_CUSTOM_GEMCOUNT_DOWN,
487   GADGET_ID_CUSTOM_GEMCOUNT_TEXT,
488   GADGET_ID_CUSTOM_GEMCOUNT_UP,
489   GADGET_ID_CUSTOM_VALUE_FIX_DOWN,
490   GADGET_ID_CUSTOM_VALUE_FIX_TEXT,
491   GADGET_ID_CUSTOM_VALUE_FIX_UP,
492   GADGET_ID_CUSTOM_VALUE_RND_DOWN,
493   GADGET_ID_CUSTOM_VALUE_RND_TEXT,
494   GADGET_ID_CUSTOM_VALUE_RND_UP,
495   GADGET_ID_PUSH_DELAY_FIX_DOWN,
496   GADGET_ID_PUSH_DELAY_FIX_TEXT,
497   GADGET_ID_PUSH_DELAY_FIX_UP,
498   GADGET_ID_PUSH_DELAY_RND_DOWN,
499   GADGET_ID_PUSH_DELAY_RND_TEXT,
500   GADGET_ID_PUSH_DELAY_RND_UP,
501   GADGET_ID_DROP_DELAY_FIX_DOWN,
502   GADGET_ID_DROP_DELAY_FIX_TEXT,
503   GADGET_ID_DROP_DELAY_FIX_UP,
504   GADGET_ID_DROP_DELAY_RND_DOWN,
505   GADGET_ID_DROP_DELAY_RND_TEXT,
506   GADGET_ID_DROP_DELAY_RND_UP,
507   GADGET_ID_MOVE_DELAY_FIX_DOWN,
508   GADGET_ID_MOVE_DELAY_FIX_TEXT,
509   GADGET_ID_MOVE_DELAY_FIX_UP,
510   GADGET_ID_MOVE_DELAY_RND_DOWN,
511   GADGET_ID_MOVE_DELAY_RND_TEXT,
512   GADGET_ID_MOVE_DELAY_RND_UP,
513   GADGET_ID_STEP_DELAY_FIX_DOWN,
514   GADGET_ID_STEP_DELAY_FIX_TEXT,
515   GADGET_ID_STEP_DELAY_FIX_UP,
516   GADGET_ID_STEP_DELAY_RND_DOWN,
517   GADGET_ID_STEP_DELAY_RND_TEXT,
518   GADGET_ID_STEP_DELAY_RND_UP,
519   GADGET_ID_EXPLOSION_DELAY_DOWN,
520   GADGET_ID_EXPLOSION_DELAY_TEXT,
521   GADGET_ID_EXPLOSION_DELAY_UP,
522   GADGET_ID_IGNITION_DELAY_DOWN,
523   GADGET_ID_IGNITION_DELAY_TEXT,
524   GADGET_ID_IGNITION_DELAY_UP,
525   GADGET_ID_CHANGE_DELAY_FIX_DOWN,
526   GADGET_ID_CHANGE_DELAY_FIX_TEXT,
527   GADGET_ID_CHANGE_DELAY_FIX_UP,
528   GADGET_ID_CHANGE_DELAY_RND_DOWN,
529   GADGET_ID_CHANGE_DELAY_RND_TEXT,
530   GADGET_ID_CHANGE_DELAY_RND_UP,
531   GADGET_ID_CHANGE_CONT_RND_DOWN,
532   GADGET_ID_CHANGE_CONT_RND_TEXT,
533   GADGET_ID_CHANGE_CONT_RND_UP,
534   GADGET_ID_GROUP_CONTENT_DOWN,
535   GADGET_ID_GROUP_CONTENT_TEXT,
536   GADGET_ID_GROUP_CONTENT_UP,
537
538   // drawing area identifiers
539
540   GADGET_ID_DRAWING_LEVEL,
541   GADGET_ID_YAMYAM_CONTENT_0,
542   GADGET_ID_YAMYAM_CONTENT_1,
543   GADGET_ID_YAMYAM_CONTENT_2,
544   GADGET_ID_YAMYAM_CONTENT_3,
545   GADGET_ID_YAMYAM_CONTENT_4,
546   GADGET_ID_YAMYAM_CONTENT_5,
547   GADGET_ID_YAMYAM_CONTENT_6,
548   GADGET_ID_YAMYAM_CONTENT_7,
549   GADGET_ID_MAGIC_BALL_CONTENT_0,
550   GADGET_ID_MAGIC_BALL_CONTENT_1,
551   GADGET_ID_MAGIC_BALL_CONTENT_2,
552   GADGET_ID_MAGIC_BALL_CONTENT_3,
553   GADGET_ID_MAGIC_BALL_CONTENT_4,
554   GADGET_ID_MAGIC_BALL_CONTENT_5,
555   GADGET_ID_MAGIC_BALL_CONTENT_6,
556   GADGET_ID_MAGIC_BALL_CONTENT_7,
557   GADGET_ID_ANDROID_CONTENT,
558   GADGET_ID_AMOEBA_CONTENT,
559   GADGET_ID_BD_SNAP_ELEMENT,
560   GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,
561   GADGET_ID_BD_MAGIC_WALL_ROCK_TO,
562   GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
563   GADGET_ID_BD_MAGIC_WALL_NUT_TO,
564   GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
565   GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
566   GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
567   GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,
568   GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,
569   GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
570   GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
571   GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
572   GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
573   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
574   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
575   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
576   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
577   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
578   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
579   GADGET_ID_BD_ACID_EATS_ELEMENT,
580   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
581   GADGET_ID_BD_BITER_EATS_ELEMENT,
582   GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
583   GADGET_ID_BD_NUT_CONTENT,
584   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
585   GADGET_ID_BD_SAND_LOOKS_LIKE,
586   GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,
587   GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
588   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
589   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
590   GADGET_ID_BD_FIREFLY_EXPLODES_TO,
591   GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,
592   GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,
593   GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,
594   GADGET_ID_BD_STONEFLY_EXPLODES_TO,
595   GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,
596   GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,
597   GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,
598   GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,
599   GADGET_ID_BD_EXPLOSION_TURNS_TO,
600   GADGET_ID_START_ELEMENT,
601   GADGET_ID_ARTWORK_ELEMENT,
602   GADGET_ID_EXPLOSION_ELEMENT,
603   GADGET_ID_INVENTORY_CONTENT,
604   GADGET_ID_MM_BALL_CONTENT,
605   GADGET_ID_CUSTOM_GRAPHIC,
606   GADGET_ID_CUSTOM_CONTENT,
607   GADGET_ID_CUSTOM_MOVE_ENTER,
608   GADGET_ID_CUSTOM_MOVE_LEAVE,
609   GADGET_ID_CUSTOM_CHANGE_TARGET,
610   GADGET_ID_CUSTOM_CHANGE_CONTENT,
611   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
612   GADGET_ID_CUSTOM_CHANGE_ACTION,
613   GADGET_ID_GROUP_CONTENT,
614   GADGET_ID_RANDOM_BACKGROUND,
615
616   // text input identifiers
617
618   GADGET_ID_LEVEL_NAME,
619   GADGET_ID_LEVEL_AUTHOR,
620   GADGET_ID_LEVELSET_NAME,
621   GADGET_ID_LEVELSET_AUTHOR,
622   GADGET_ID_ELEMENT_NAME,
623
624   // text area identifiers
625
626   GADGET_ID_ENVELOPE_INFO,
627
628   // selectbox identifiers
629
630   GADGET_ID_TIME_OR_STEPS,
631   GADGET_ID_TIME_SCORE_BASE,
632   GADGET_ID_GAME_ENGINE_TYPE,
633   GADGET_ID_BD_SCHEDULING_TYPE,
634   GADGET_ID_LEVELSET_SAVE_MODE,
635   GADGET_ID_WIND_DIRECTION,
636   GADGET_ID_PLAYER_SPEED,
637   GADGET_ID_BD_GRAVITY_DIRECTION,
638   GADGET_ID_MM_BALL_CHOICE_MODE,
639   GADGET_ID_CUSTOM_WALK_TO_ACTION,
640   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
641   GADGET_ID_CUSTOM_DEADLINESS,
642   GADGET_ID_CUSTOM_MOVE_PATTERN,
643   GADGET_ID_CUSTOM_MOVE_DIRECTION,
644   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
645   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
646   GADGET_ID_CUSTOM_SMASH_TARGETS,
647   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
648   GADGET_ID_CUSTOM_ACCESS_TYPE,
649   GADGET_ID_CUSTOM_ACCESS_LAYER,
650   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
651   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
652   GADGET_ID_CHANGE_TIME_UNITS,
653   GADGET_ID_CHANGE_DIRECT_ACTION,
654   GADGET_ID_CHANGE_OTHER_ACTION,
655   GADGET_ID_CHANGE_SIDE,
656   GADGET_ID_CHANGE_PLAYER,
657   GADGET_ID_CHANGE_PAGE,
658   GADGET_ID_CHANGE_REPLACE_WHEN,
659   GADGET_ID_ACTION_TYPE,
660   GADGET_ID_ACTION_MODE,
661   GADGET_ID_ACTION_ARG,
662   GADGET_ID_SELECT_CHANGE_PAGE,
663   GADGET_ID_GROUP_CHOICE_MODE,
664
665   // textbutton identifiers
666
667   GADGET_ID_LEVELCONFIG_LEVEL,
668   GADGET_ID_LEVELCONFIG_LEVELSET,
669   GADGET_ID_LEVELCONFIG_EDITOR,
670   GADGET_ID_LEVELCONFIG_ENGINE,
671   GADGET_ID_PROPERTIES_INFO,
672   GADGET_ID_PROPERTIES_CONFIG,
673   GADGET_ID_PROPERTIES_CONFIG_1,
674   GADGET_ID_PROPERTIES_CONFIG_2,
675   GADGET_ID_PROPERTIES_CHANGE,
676   GADGET_ID_SAVE_AS_TEMPLATE_1,
677   GADGET_ID_SAVE_AS_TEMPLATE_2,
678   GADGET_ID_SAVE_LEVELSET,
679   GADGET_ID_ADD_CHANGE_PAGE,
680   GADGET_ID_DEL_CHANGE_PAGE,
681
682   // graphicbutton identifiers
683
684   GADGET_ID_PREV_CHANGE_PAGE,
685   GADGET_ID_NEXT_CHANGE_PAGE,
686   GADGET_ID_COPY_CHANGE_PAGE,
687   GADGET_ID_PASTE_CHANGE_PAGE,
688
689   // gadgets for scrolling of drawing area
690
691   GADGET_ID_SCROLL_UP,
692   GADGET_ID_SCROLL_DOWN,
693   GADGET_ID_SCROLL_LEFT,
694   GADGET_ID_SCROLL_RIGHT,
695   GADGET_ID_SCROLL_HORIZONTAL,
696   GADGET_ID_SCROLL_VERTICAL,
697
698   // gadgets for scrolling element list
699
700   GADGET_ID_SCROLL_LIST_UP,
701   GADGET_ID_SCROLL_LIST_DOWN,
702   GADGET_ID_SCROLL_LIST_VERTICAL,
703
704   // checkbuttons/radiobuttons for level/element properties
705
706   GADGET_ID_AUTO_COUNT_GEMS,
707   GADGET_ID_RATE_TIME_OVER_SCORE,
708   GADGET_ID_USE_LEVELSET_ARTWORK,
709   GADGET_ID_COPY_LEVEL_TEMPLATE,
710   GADGET_ID_RANDOM_PERCENTAGE,
711   GADGET_ID_RANDOM_QUANTITY,
712   GADGET_ID_RANDOM_RESTRICTED,
713   GADGET_ID_BD_INTERMISSION,
714   GADGET_ID_BD_PAL_TIMING,
715   GADGET_ID_BD_LINE_SHIFTING_BORDERS,
716   GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
717   GADGET_ID_BD_SHORT_EXPLOSIONS,
718   GADGET_ID_STICK_ELEMENT,
719   GADGET_ID_EM_SLIPPERY_GEMS,
720   GADGET_ID_EM_EXPLODES_BY_FIRE,
721   GADGET_ID_USE_SPRING_BUG,
722   GADGET_ID_USE_TIME_ORB_BUG,
723   GADGET_ID_USE_LIFE_BUGS,
724   GADGET_ID_RANDOM_BALL_CONTENT,
725   GADGET_ID_INITIAL_BALL_ACTIVE,
726   GADGET_ID_GROW_INTO_DIGGABLE,
727   GADGET_ID_SB_FIELDS_NEEDED,
728   GADGET_ID_SB_OBJECTS_NEEDED,
729   GADGET_ID_AUTO_EXIT_SOKOBAN,
730   GADGET_ID_SOLVED_BY_ONE_PLAYER,
731   GADGET_ID_FINISH_DIG_COLLECT,
732   GADGET_ID_KEEP_WALKABLE_CE,
733   GADGET_ID_CONTINUOUS_SNAPPING,
734   GADGET_ID_BLOCK_SNAP_FIELD,
735   GADGET_ID_BLOCK_LAST_FIELD,
736   GADGET_ID_SP_BLOCK_LAST_FIELD,
737   GADGET_ID_INSTANT_RELOCATION,
738   GADGET_ID_SHIFTED_RELOCATION,
739   GADGET_ID_LAZY_RELOCATION,
740   GADGET_ID_USE_START_ELEMENT,
741   GADGET_ID_USE_ARTWORK_ELEMENT,
742   GADGET_ID_USE_EXPLOSION_ELEMENT,
743   GADGET_ID_INITIAL_GRAVITY,
744   GADGET_ID_USE_INITIAL_INVENTORY,
745   GADGET_ID_CAN_PASS_TO_WALKABLE,
746   GADGET_ID_CAN_FALL_INTO_ACID,
747   GADGET_ID_CAN_MOVE_INTO_ACID,
748   GADGET_ID_DONT_COLLIDE_WITH,
749   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
750   GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
751   GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
752   GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,
753   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
754   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
755   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
756   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
757   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
758   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
759   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
760   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
761   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
762   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
763   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
764   GADGET_ID_BD_REPLICATORS_ACTIVE,
765   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
766   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
767   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
768   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
769   GADGET_ID_BD_INFINITE_ROCKETS,
770   GADGET_ID_BD_CREATURES_START_BACKWARDS,
771   GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
772   GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
773   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
774   GADGET_ID_ENVELOPE_AUTOWRAP,
775   GADGET_ID_ENVELOPE_CENTERED,
776   GADGET_ID_MM_LASER_RED,
777   GADGET_ID_MM_LASER_GREEN,
778   GADGET_ID_MM_LASER_BLUE,
779   GADGET_ID_DF_LASER_RED,
780   GADGET_ID_DF_LASER_GREEN,
781   GADGET_ID_DF_LASER_BLUE,
782   GADGET_ID_ROTATE_MM_BALL_CONTENT,
783   GADGET_ID_EXPLODE_MM_BALL,
784   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
785   GADGET_ID_CUSTOM_CAN_EXPLODE,
786   GADGET_ID_CUSTOM_EXPLODE_FIRE,
787   GADGET_ID_CUSTOM_EXPLODE_SMASH,
788   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
789   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
790   GADGET_ID_CUSTOM_DEADLY,
791   GADGET_ID_CUSTOM_CAN_MOVE,
792   GADGET_ID_CUSTOM_CAN_FALL,
793   GADGET_ID_CUSTOM_CAN_SMASH,
794   GADGET_ID_CUSTOM_SLIPPERY,
795   GADGET_ID_CUSTOM_ACCESSIBLE,
796   GADGET_ID_CUSTOM_GRAV_REACHABLE,
797   GADGET_ID_CUSTOM_USE_LAST_VALUE,
798   GADGET_ID_CUSTOM_USE_GRAPHIC,
799   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
800   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
801   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
802   GADGET_ID_CUSTOM_CAN_CHANGE,
803   GADGET_ID_CHANGE_USE_CONTENT,
804   GADGET_ID_CHANGE_USE_EXPLOSION,
805   GADGET_ID_CHANGE_ONLY_COMPLETE,
806   GADGET_ID_CHANGE_USE_RANDOM,
807   GADGET_ID_CHANGE_HAS_ACTION,
808   GADGET_ID_CHANGE_DELAY,
809   GADGET_ID_CHANGE_BY_DIRECT_ACT,
810   GADGET_ID_CHANGE_BY_OTHER_ACT,
811
812   NUM_STATIC_GADGET_IDS
813 };
814
815 // gadgets for buttons in element list (dynamic)
816 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
817 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
818                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
819
820 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
821
822 // radio button numbers
823 enum
824 {
825   RADIO_NR_NONE,
826   RADIO_NR_DRAWING_TOOLBOX,
827   RADIO_NR_RANDOM_ELEMENTS
828 };
829
830 // values for counter gadgets
831 enum
832 {
833   ED_COUNTER_ID_SELECT_LEVEL,
834   ED_COUNTER_ID_LEVEL_XSIZE,
835   ED_COUNTER_ID_LEVEL_YSIZE,
836   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
837   ED_COUNTER_ID_LEVEL_TIMELIMIT,
838   ED_COUNTER_ID_LEVEL_TIMESCORE,
839   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
840   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
841   ED_COUNTER_ID_LEVEL_RANDOM,
842   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
843   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
844   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
845   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
846   ED_COUNTER_ID_BD_PUSHING_PROB,
847   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
848   ED_COUNTER_ID_ELEMENT_VALUE1,
849   ED_COUNTER_ID_ELEMENT_VALUE2,
850   ED_COUNTER_ID_ELEMENT_VALUE3,
851   ED_COUNTER_ID_ELEMENT_VALUE4,
852   ED_COUNTER_ID_YAMYAM_CONTENT,
853   ED_COUNTER_ID_BALL_CONTENT,
854   ED_COUNTER_ID_ANDROID_CONTENT,
855   ED_COUNTER_ID_ENVELOPE_XSIZE,
856   ED_COUNTER_ID_ENVELOPE_YSIZE,
857   ED_COUNTER_ID_INVENTORY_SIZE,
858   ED_COUNTER_ID_MM_BALL_CONTENT,
859   ED_COUNTER_ID_CUSTOM_SCORE,
860   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
861   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
862   ED_COUNTER_ID_CUSTOM_VALUE_RND,
863   ED_COUNTER_ID_PUSH_DELAY_FIX,
864   ED_COUNTER_ID_PUSH_DELAY_RND,
865   ED_COUNTER_ID_DROP_DELAY_FIX,
866   ED_COUNTER_ID_DROP_DELAY_RND,
867   ED_COUNTER_ID_MOVE_DELAY_FIX,
868   ED_COUNTER_ID_MOVE_DELAY_RND,
869   ED_COUNTER_ID_STEP_DELAY_FIX,
870   ED_COUNTER_ID_STEP_DELAY_RND,
871   ED_COUNTER_ID_EXPLOSION_DELAY,
872   ED_COUNTER_ID_IGNITION_DELAY,
873   ED_COUNTER_ID_GROUP_CONTENT,
874   ED_COUNTER_ID_CHANGE_DELAY_FIX,
875   ED_COUNTER_ID_CHANGE_DELAY_RND,
876   ED_COUNTER_ID_CHANGE_CONT_RND,
877
878   ED_NUM_COUNTERBUTTONS
879 };
880
881 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
882 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
883 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
884 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
885 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
886 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
887
888 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
889 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
890 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
891 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
892 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
893 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
894
895 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
896 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
897
898 // values for scrollbutton gadgets
899 enum
900 {
901   ED_SCROLLBUTTON_ID_AREA_UP,
902   ED_SCROLLBUTTON_ID_AREA_DOWN,
903   ED_SCROLLBUTTON_ID_AREA_LEFT,
904   ED_SCROLLBUTTON_ID_AREA_RIGHT,
905   ED_SCROLLBUTTON_ID_LIST_UP,
906   ED_SCROLLBUTTON_ID_LIST_DOWN,
907
908   ED_NUM_SCROLLBUTTONS
909 };
910
911 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
912 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
913
914 // values for scrollbar gadgets
915 enum
916 {
917   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
918   ED_SCROLLBAR_ID_AREA_VERTICAL,
919   ED_SCROLLBAR_ID_LIST_VERTICAL,
920
921   ED_NUM_SCROLLBARS
922 };
923
924 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
925 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
926
927 // values for text input gadgets
928 enum
929 {
930   ED_TEXTINPUT_ID_LEVEL_NAME,
931   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
932   ED_TEXTINPUT_ID_LEVELSET_NAME,
933   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
934   ED_TEXTINPUT_ID_ELEMENT_NAME,
935
936   ED_NUM_TEXTINPUT
937 };
938
939 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
940 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
941
942 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
943 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
944
945 // values for text area gadgets
946 enum
947 {
948   ED_TEXTAREA_ID_ENVELOPE_INFO,
949
950   ED_NUM_TEXTAREAS
951 };
952
953 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
954 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
955
956 // values for selectbox gadgets
957 enum
958 {
959   ED_SELECTBOX_ID_TIME_OR_STEPS,
960   ED_SELECTBOX_ID_TIME_SCORE_BASE,
961   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
962   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
963   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
964   ED_SELECTBOX_ID_WIND_DIRECTION,
965   ED_SELECTBOX_ID_PLAYER_SPEED,
966   ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
967   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
968   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
969   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
970   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
971   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
972   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
973   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
974   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
975   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
976   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
977   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
978   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
979   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
980   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
981   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
982   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
983   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
984   ED_SELECTBOX_ID_CHANGE_SIDE,
985   ED_SELECTBOX_ID_CHANGE_PLAYER,
986   ED_SELECTBOX_ID_CHANGE_PAGE,
987   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
988   ED_SELECTBOX_ID_ACTION_TYPE,
989   ED_SELECTBOX_ID_ACTION_MODE,
990   ED_SELECTBOX_ID_ACTION_ARG,
991   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
992   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
993
994   ED_NUM_SELECTBOX
995 };
996
997 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
998 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
999
1000 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1001 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1002
1003 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1004 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1005
1006 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
1007 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
1008 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
1009 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
1010 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
1011 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
1012
1013 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
1014 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
1015
1016 // values for textbutton gadgets
1017 enum
1018 {
1019   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
1020   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1021   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1022   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1023   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1024   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1025   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1026   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1027   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1028   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1029   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1030   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1031   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1032   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1033
1034   ED_NUM_TEXTBUTTONS
1035 };
1036
1037 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1038 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1039
1040 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1041 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1042
1043 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1044 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1045
1046 // values for graphicbutton gadgets
1047 enum
1048 {
1049   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1050   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1051   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1052   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1053
1054   ED_NUM_GRAPHICBUTTONS
1055 };
1056
1057 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1058 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1059
1060 // values for checkbutton gadgets
1061 enum
1062 {
1063   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1064   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1065   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1066   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1067   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1068   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1069   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1070   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1071   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1072   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1073   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1074   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1075   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1076   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1077   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1078   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1079   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1080   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1081   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1082   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1083   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1084   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1085   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1086   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1087   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1088   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1089   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1090   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1091   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1092   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1093   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1094   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1095   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1096   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1097   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1098   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1099   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1100   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1101   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1102   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1103   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1104   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1105   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1106   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1107   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1108   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1109   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
1110   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1111   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1112   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1113   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1114   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1115   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1116   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1117   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1118   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1119   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1120   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1121   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1122   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1123   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1124   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1125   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1126   ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
1127   ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
1128   ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
1129   ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
1130   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1131   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1132   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1133   ED_CHECKBUTTON_ID_MM_LASER_RED,
1134   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1135   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1136   ED_CHECKBUTTON_ID_DF_LASER_RED,
1137   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1138   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1139   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1140   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1141   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1142   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1143   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1144   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1145   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1146   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1147   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1148   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1149   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1150   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1151   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1152   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1153   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1154   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1155   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1156   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1157   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1158   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1159   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1160   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1161   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1162   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1163   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1164   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1165   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1166
1167   ED_NUM_CHECKBUTTONS
1168 };
1169
1170 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1171 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1172
1173 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1174 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1175
1176 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1177 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1178
1179 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1180 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
1181
1182 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1183 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1184 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1185 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1186 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1187 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1188
1189 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1190 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1191
1192 // values for radiobutton gadgets
1193 enum
1194 {
1195   ED_RADIOBUTTON_ID_PERCENTAGE,
1196   ED_RADIOBUTTON_ID_QUANTITY,
1197
1198   ED_NUM_RADIOBUTTONS
1199 };
1200
1201 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1202 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1203
1204 // values for drawing area gadgets
1205 enum
1206 {
1207   ED_DRAWING_ID_DRAWING_LEVEL,
1208   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1209   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1210   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1211   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1212   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1213   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1214   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1215   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1216   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1217   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1218   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1219   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1220   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1221   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1222   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1223   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1224   ED_DRAWING_ID_ANDROID_CONTENT,
1225   ED_DRAWING_ID_AMOEBA_CONTENT,
1226   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1227   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1228   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1229   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1230   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1231   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1232   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1233   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1234   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1235   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1236   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1237   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1238   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1239   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1240   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1241   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1242   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1243   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1244   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1245   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1246   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1247   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1248   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1249   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1250   ED_DRAWING_ID_BD_NUT_CONTENT,
1251   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1252   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1253   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
1254   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
1255   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
1256   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
1257   ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
1258   ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
1259   ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
1260   ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
1261   ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
1262   ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
1263   ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
1264   ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
1265   ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
1266   ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
1267   ED_DRAWING_ID_START_ELEMENT,
1268   ED_DRAWING_ID_ARTWORK_ELEMENT,
1269   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1270   ED_DRAWING_ID_INVENTORY_CONTENT,
1271   ED_DRAWING_ID_MM_BALL_CONTENT,
1272   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1273   ED_DRAWING_ID_CUSTOM_CONTENT,
1274   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1275   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1276   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1277   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1278   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1279   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1280   ED_DRAWING_ID_GROUP_CONTENT,
1281   ED_DRAWING_ID_RANDOM_BACKGROUND,
1282
1283   ED_NUM_DRAWING_AREAS
1284 };
1285
1286 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1287 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1288
1289
1290 // ----------------------------------------------------------------------------
1291 // some internally used definitions
1292 // ----------------------------------------------------------------------------
1293
1294 // values for CopyLevelToUndoBuffer()
1295 #define UNDO_IMMEDIATE                  0
1296 #define UNDO_ACCUMULATE                 1
1297
1298 // values for scrollbars
1299 #define ED_SCROLL_NO                    0
1300 #define ED_SCROLL_LEFT                  1
1301 #define ED_SCROLL_RIGHT                 2
1302 #define ED_SCROLL_UP                    4
1303 #define ED_SCROLL_DOWN                  8
1304
1305 // screens in the level editor
1306 #define ED_MODE_DRAWING                 0
1307 #define ED_MODE_LEVELCONFIG             1
1308 #define ED_MODE_PROPERTIES              2
1309 #define ED_MODE_PALETTE                 3
1310
1311 // sub-screens in the global settings section
1312 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1313 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1314 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1315 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1316
1317 // sub-screens in the element properties section
1318 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1319 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1320 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1321 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1322 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1323
1324 // how many steps can be cancelled
1325 #define NUM_UNDO_STEPS                  (64 + 1)
1326
1327 // values for elements with score for certain actions
1328 #define MIN_SCORE                       0
1329 #define MAX_SCORE                       999
1330
1331 // values for elements with count for collecting
1332 #define MIN_COLLECT_COUNT               0
1333 #define MAX_COLLECT_COUNT               999
1334
1335 // values for random placement
1336 #define RANDOM_USE_PERCENTAGE           0
1337 #define RANDOM_USE_QUANTITY             1
1338
1339 // values for level set save mode
1340 #define LEVELSET_SAVE_MODE_UPDATE       0
1341 #define LEVELSET_SAVE_MODE_CREATE       1
1342
1343 // default value for element tile size in drawing area
1344 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1345 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1346
1347
1348 // ----------------------------------------------------------------------------
1349 // some internally used data structure definitions
1350 // ----------------------------------------------------------------------------
1351
1352 static struct
1353 {
1354   int graphic;
1355   int gadget_id;
1356   struct XYTileSize *pos;
1357   int gadget_type;
1358   char *infotext;
1359   char shortcut;
1360 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1361 {
1362   // note: some additional characters are already reserved for "cheat mode"
1363   // shortcuts (":XYZ" style) -- for details, see "events.c"
1364
1365   // ---------- toolbox control buttons ---------------------------------------
1366
1367   {
1368     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1369     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1370     "Draw single items",                        's'
1371   },
1372   {
1373     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1374     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1375     "Draw connected items",                     'd'
1376   },
1377   {
1378     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1379     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1380     "Draw lines",                               'l'
1381   },
1382   {
1383     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1384     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1385     "Draw arcs",                                'a'
1386   },
1387   {
1388     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1389     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1390     "Draw outline rectangles",                  'r'
1391   },
1392   {
1393     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1394     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1395     "Draw filled rectangles",                   'R'
1396   },
1397   {
1398     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1399     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1400     "Wrap (rotate) level up",                   0
1401   },
1402   {
1403     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1404     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1405     "Enter text elements",                      't'
1406   },
1407   {
1408     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1409     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1410     "Flood fill",                               'f'
1411   },
1412   {
1413     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1414     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1415     "Wrap (rotate) level left",                 0
1416   },
1417   {
1418     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1419     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1420     "Zoom level tile size",                     '+'
1421   },
1422   {
1423     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1424     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1425     "Wrap (rotate) level right",                0
1426   },
1427   {
1428     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1429     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1430     "Random element placement",                 0
1431   },
1432   {
1433     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1434     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1435     "Grab brush",                               'b'
1436   },
1437   {
1438     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1439     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1440     "Wrap (rotate) level down",                 0
1441   },
1442   {
1443     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1444     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1445     "Pick drawing element",                     ','
1446   },
1447
1448   // ---------- level control buttons -----------------------------------------
1449
1450   {
1451     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1452     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1453     "Undo/redo last operation",                 'u'
1454   },
1455   {
1456     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1457     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1458     "Level and editor settings",                'I'
1459   },
1460   {
1461     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1462     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1463     "Save level",                               'S'
1464   },
1465   {
1466     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1467     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1468     "Clear level",                              'C'
1469   },
1470   {
1471     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1472     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1473     "Test level",                               'T'
1474   },
1475   {
1476     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1477     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1478     "Exit level editor",                        'E'
1479   },
1480
1481   // ---------- CE and GE control buttons -------------------------------------
1482
1483   {
1484     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1485     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1486     "Copy settings from other element",         0
1487   },
1488   {
1489     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1490     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1491     "Copy settings to other element",           0
1492   },
1493   {
1494     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1495     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1496     "Exchange element with other element",      0
1497   },
1498   {
1499     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1500     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1501     "Copy settings from this element",          0
1502   },
1503   {
1504     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1505     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1506     "Paste settings to this element",           0
1507   },
1508
1509   // ---------- palette control buttons ---------------------------------------
1510
1511   {
1512     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1513     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1514     "Properties of drawing element",            'p'
1515   },
1516   {
1517     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1518     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1519     "Properties of drawing element 1",          '1'
1520   },
1521   {
1522     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1523     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1524     "Properties of drawing element 2",          '2'
1525   },
1526   {
1527     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1528     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1529     "Properties of drawing element 3",          '3'
1530   },
1531   {
1532     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1533     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1534     "Show list of elements",                    'e'
1535   }
1536 };
1537
1538 static int random_placement_value = 10;
1539 static int random_placement_method = RANDOM_USE_QUANTITY;
1540 static int random_placement_background_element = EL_SAND;
1541 static boolean random_placement_background_restricted = FALSE;
1542 static boolean stick_element_properties_window = FALSE;
1543 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1544 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1545 static struct ElementChangeInfo custom_element_change;
1546 static struct ElementGroupInfo group_element_info;
1547 static struct ElementInfo custom_element;
1548
1549 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1550 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1551 static int levelset_num_levels = 100;
1552 static boolean levelset_use_levelset_artwork = FALSE;
1553 static boolean levelset_copy_level_template = FALSE;
1554 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1555
1556 static struct
1557 {
1558   int gadget_type_id;
1559   int x, y;
1560   int min_value, max_value;
1561   int gadget_id_down, gadget_id_up;
1562   int gadget_id_text;
1563   int gadget_id_align;
1564   int *value;
1565   char *text_above, *text_left, *text_right;
1566 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1567 {
1568   // ---------- current level number ------------------------------------------
1569
1570   {
1571     ED_COUNTER_ID_SELECT_LEVEL,
1572     -1, -1,     // these values are not constant, but can change at runtime
1573     1,                                          100,
1574     GADGET_ID_SELECT_LEVEL_DOWN,                GADGET_ID_SELECT_LEVEL_UP,
1575     GADGET_ID_SELECT_LEVEL_TEXT,                GADGET_ID_NONE,
1576     &level_nr,
1577     NULL,                                       NULL, NULL
1578   },
1579
1580   // ---------- level and editor settings -------------------------------------
1581
1582   {
1583     ED_COUNTER_ID_LEVEL_XSIZE,
1584     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1585     MIN_LEV_FIELDX,                             MAX_LEV_FIELDX,
1586     GADGET_ID_LEVEL_XSIZE_DOWN,                 GADGET_ID_LEVEL_XSIZE_UP,
1587     GADGET_ID_LEVEL_XSIZE_TEXT,                 GADGET_ID_NONE,
1588     &level.fieldx,
1589     "Playfield size:",                          NULL, "Width",
1590   },
1591   {
1592     ED_COUNTER_ID_LEVEL_YSIZE,
1593     -1,                                         ED_LEVEL_SETTINGS_YPOS(4),
1594     MIN_LEV_FIELDY,                             MAX_LEV_FIELDY,
1595     GADGET_ID_LEVEL_YSIZE_DOWN,                 GADGET_ID_LEVEL_YSIZE_UP,
1596     GADGET_ID_LEVEL_YSIZE_TEXT,                 GADGET_ID_LEVEL_XSIZE_UP,
1597     &level.fieldy,
1598     NULL,                                       " ", "Height",
1599   },
1600   {
1601     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1602     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
1603     0,                                          999,
1604     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,             GADGET_ID_LEVEL_GEMSLIMIT_UP,
1605     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,             GADGET_ID_NONE,
1606     &level.gems_needed,
1607     NULL,                                       "Number of gems to collect:", NULL
1608   },
1609   {
1610     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1611     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
1612     0,                                          9999,
1613     GADGET_ID_LEVEL_TIMELIMIT_DOWN,             GADGET_ID_LEVEL_TIMELIMIT_UP,
1614     GADGET_ID_LEVEL_TIMELIMIT_TEXT,             GADGET_ID_NONE,
1615     &level.time,
1616     "Time or step limit to solve level:",       NULL, NULL
1617   },
1618   {
1619     ED_COUNTER_ID_LEVEL_TIMESCORE,
1620     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
1621     0,                                          999,
1622     GADGET_ID_LEVEL_TIMESCORE_DOWN,             GADGET_ID_LEVEL_TIMESCORE_UP,
1623     GADGET_ID_LEVEL_TIMESCORE_TEXT,             GADGET_ID_NONE,
1624     &level.score[SC_TIME_BONUS],
1625     "Score for time or steps left:",            NULL, NULL
1626   },
1627   {
1628     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1629     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(13),
1630     0,                                          9999,
1631     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,           GADGET_ID_LEVEL_RANDOM_SEED_UP,
1632     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,           GADGET_ID_NONE,
1633     &level.random_seed,
1634     NULL,                                       "Random seed:", "(0 => random)"
1635   },
1636   {
1637     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1638     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1639     1,                                          MAX_LEVELS,
1640     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,         GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1641     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,         GADGET_ID_NONE,
1642     &levelset_num_levels,
1643     "Number of levels:",                        NULL, NULL,
1644   },
1645   {
1646     ED_COUNTER_ID_LEVEL_RANDOM,
1647     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1648     1,                                          100,
1649     GADGET_ID_LEVEL_RANDOM_DOWN,                GADGET_ID_LEVEL_RANDOM_UP,
1650     GADGET_ID_LEVEL_RANDOM_TEXT,                GADGET_ID_NONE,
1651     &random_placement_value,
1652     "Random element placement:",                NULL, "in"
1653   },
1654   {
1655     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1656     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1657     50,                                         500,
1658     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,           GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1659     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,           GADGET_ID_NONE,
1660     &level.bd_cycle_delay_ms,
1661     NULL,                                       NULL, "Game cycle delay (ms)"
1662   },
1663   {
1664     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1665     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1666     0,                                          32,
1667     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,          GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1668     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,          GADGET_ID_NONE,
1669     &level.bd_cycle_delay_c64,
1670     NULL,                                       NULL, "Game cycle delay (C64-style)"
1671   },
1672   {
1673     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1674     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1675     1,                                          40,
1676     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1677     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1678     &level.bd_hatching_delay_cycles,
1679     NULL,                                       NULL, "Hatching delay (cycles)"
1680   },
1681   {
1682     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1683     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1684     1,                                          40,
1685     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1686     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1687     &level.bd_hatching_delay_seconds,
1688     NULL,                                       NULL, "Hatching delay (seconds)"
1689   },
1690
1691   // ---------- element settings: configure (various elements) ----------------
1692
1693   {
1694     ED_COUNTER_ID_BD_PUSHING_PROB,
1695     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1696     0,                                          100,
1697     GADGET_ID_BD_PUSHING_PROB_DOWN,             GADGET_ID_BD_PUSHING_PROB_UP,
1698     GADGET_ID_BD_PUSHING_PROB_TEXT,             GADGET_ID_NONE,
1699     &level.bd_pushing_prob,
1700     NULL,                                       NULL, "Push probability"
1701   },
1702   {
1703     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1704     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1705     0,                                          100,
1706     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1707     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1708     &level.bd_pushing_prob_with_sweet,
1709     NULL,                                       NULL, "Push probability with sweet"
1710   },
1711   {
1712     ED_COUNTER_ID_ELEMENT_VALUE1,
1713     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1714     MIN_SCORE,                                  MAX_SCORE,
1715     GADGET_ID_ELEMENT_VALUE1_DOWN,              GADGET_ID_ELEMENT_VALUE1_UP,
1716     GADGET_ID_ELEMENT_VALUE1_TEXT,              GADGET_ID_NONE,
1717     NULL,                                       // will be set when used
1718     NULL,                                       NULL, NULL
1719   },
1720   {
1721     ED_COUNTER_ID_ELEMENT_VALUE2,
1722     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
1723     MIN_SCORE,                                  MAX_SCORE,
1724     GADGET_ID_ELEMENT_VALUE2_DOWN,              GADGET_ID_ELEMENT_VALUE2_UP,
1725     GADGET_ID_ELEMENT_VALUE2_TEXT,              GADGET_ID_NONE,
1726     NULL,                                       // will be set when used
1727     NULL,                                       NULL, NULL
1728   },
1729   {
1730     ED_COUNTER_ID_ELEMENT_VALUE3,
1731     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1732     MIN_SCORE,                                  MAX_SCORE,
1733     GADGET_ID_ELEMENT_VALUE3_DOWN,              GADGET_ID_ELEMENT_VALUE3_UP,
1734     GADGET_ID_ELEMENT_VALUE3_TEXT,              GADGET_ID_NONE,
1735     NULL,                                       // will be set when used
1736     NULL,                                       NULL, NULL
1737   },
1738   {
1739     ED_COUNTER_ID_ELEMENT_VALUE4,
1740     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1741     MIN_SCORE,                                  MAX_SCORE,
1742     GADGET_ID_ELEMENT_VALUE4_DOWN,              GADGET_ID_ELEMENT_VALUE4_UP,
1743     GADGET_ID_ELEMENT_VALUE4_TEXT,              GADGET_ID_NONE,
1744     NULL,                                       // will be set when used
1745     NULL,                                       NULL, NULL
1746   },
1747   {
1748     ED_COUNTER_ID_YAMYAM_CONTENT,
1749     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1750     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1751     GADGET_ID_YAMYAM_CONTENT_DOWN,              GADGET_ID_YAMYAM_CONTENT_UP,
1752     GADGET_ID_YAMYAM_CONTENT_TEXT,              GADGET_ID_NONE,
1753     &level.num_yamyam_contents,
1754     NULL,                                       NULL, "Number of content areas"
1755   },
1756   {
1757     ED_COUNTER_ID_BALL_CONTENT,
1758     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1759     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1760     GADGET_ID_BALL_CONTENT_DOWN,                GADGET_ID_BALL_CONTENT_UP,
1761     GADGET_ID_BALL_CONTENT_TEXT,                GADGET_ID_NONE,
1762     &level.num_ball_contents,
1763     NULL,                                       NULL, "Number of content areas"
1764   },
1765   {
1766     ED_COUNTER_ID_ANDROID_CONTENT,
1767     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1768     MIN_ANDROID_ELEMENTS,                       MAX_ANDROID_ELEMENTS,
1769     GADGET_ID_ANDROID_CONTENT_DOWN,             GADGET_ID_ANDROID_CONTENT_UP,
1770     GADGET_ID_ANDROID_CONTENT_TEXT,             GADGET_ID_NONE,
1771     &level.num_android_clone_elements,
1772     NULL,                                       NULL, "Number of clonable elements"
1773   },
1774   {
1775     ED_COUNTER_ID_ENVELOPE_XSIZE,
1776     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1777     MIN_ENVELOPE_XSIZE,                         MAX_ENVELOPE_XSIZE,
1778     GADGET_ID_ENVELOPE_XSIZE_DOWN,              GADGET_ID_ENVELOPE_XSIZE_UP,
1779     GADGET_ID_ENVELOPE_XSIZE_TEXT,              GADGET_ID_NONE,
1780     NULL,                                       // will be set when used
1781     NULL,                                       NULL, "Width",
1782   },
1783   {
1784     ED_COUNTER_ID_ENVELOPE_YSIZE,
1785     -1,                                         ED_ELEMENT_SETTINGS_YPOS(0),
1786     MIN_ENVELOPE_YSIZE,                         MAX_ENVELOPE_YSIZE,
1787     GADGET_ID_ENVELOPE_YSIZE_DOWN,              GADGET_ID_ENVELOPE_YSIZE_UP,
1788     GADGET_ID_ENVELOPE_YSIZE_TEXT,              GADGET_ID_ENVELOPE_XSIZE_UP,
1789     NULL,                                       // will be set when used
1790     NULL,                                       " ", "Height",
1791   },
1792   {
1793     ED_COUNTER_ID_INVENTORY_SIZE,
1794     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1795     MIN_INITIAL_INVENTORY_SIZE,                 MAX_INITIAL_INVENTORY_SIZE,
1796     GADGET_ID_INVENTORY_SIZE_DOWN,              GADGET_ID_INVENTORY_SIZE_UP,
1797     GADGET_ID_INVENTORY_SIZE_TEXT,              GADGET_ID_NONE,
1798     &level.initial_inventory_size[0],
1799     NULL,                                       NULL, "Number of inventory elements"
1800   },
1801   {
1802     ED_COUNTER_ID_MM_BALL_CONTENT,
1803     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1804     MIN_ELEMENTS_IN_GROUP,                      MAX_MM_BALL_CONTENTS,
1805     GADGET_ID_MM_BALL_CONTENT_DOWN,             GADGET_ID_MM_BALL_CONTENT_UP,
1806     GADGET_ID_MM_BALL_CONTENT_TEXT,             GADGET_ID_NONE,
1807     &level.num_mm_ball_contents,
1808     NULL,                                       NULL, "Number of content elements"
1809   },
1810
1811   // ---------- element settings: configure 1 (custom elements) ---------------
1812
1813   {
1814     ED_COUNTER_ID_CUSTOM_SCORE,
1815     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1816     MIN_SCORE,                                  MAX_SCORE,
1817     GADGET_ID_CUSTOM_SCORE_DOWN,                GADGET_ID_CUSTOM_SCORE_UP,
1818     GADGET_ID_CUSTOM_SCORE_TEXT,                GADGET_ID_NONE,
1819     &custom_element.collect_score_initial,
1820     NULL,                                       "CE score", " "
1821   },
1822   {
1823     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1824     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1825     MIN_COLLECT_COUNT,                          MAX_COLLECT_COUNT,
1826     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,             GADGET_ID_CUSTOM_GEMCOUNT_UP,
1827     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,             GADGET_ID_CUSTOM_SCORE_UP,
1828     &custom_element.collect_count_initial,
1829     NULL,                                       "CE count", NULL
1830   },
1831   {
1832     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1833     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1834     0,                                          9999,
1835     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1836     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,            GADGET_ID_NONE,
1837     &custom_element.ce_value_fixed_initial,
1838     NULL,                                       "CE value", NULL
1839   },
1840   {
1841     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1842     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1843     0,                                          9999,
1844     GADGET_ID_CUSTOM_VALUE_RND_DOWN,            GADGET_ID_CUSTOM_VALUE_RND_UP,
1845     GADGET_ID_CUSTOM_VALUE_RND_TEXT,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1846     &custom_element.ce_value_random_initial,
1847     NULL,                                       "+random", NULL
1848   },
1849   {
1850     ED_COUNTER_ID_PUSH_DELAY_FIX,
1851     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1852     0,                                          999,
1853     GADGET_ID_PUSH_DELAY_FIX_DOWN,              GADGET_ID_PUSH_DELAY_FIX_UP,
1854     GADGET_ID_PUSH_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1855     &custom_element.push_delay_fixed,
1856     NULL,                                       "Push delay", NULL
1857   },
1858   {
1859     ED_COUNTER_ID_PUSH_DELAY_RND,
1860     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1861     0,                                          999,
1862     GADGET_ID_PUSH_DELAY_RND_DOWN,              GADGET_ID_PUSH_DELAY_RND_UP,
1863     GADGET_ID_PUSH_DELAY_RND_TEXT,              GADGET_ID_PUSH_DELAY_FIX_UP,
1864     &custom_element.push_delay_random,
1865     NULL,                                       "+random", NULL
1866   },
1867   {
1868     ED_COUNTER_ID_DROP_DELAY_FIX,
1869     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(7),
1870     0,                                          999,
1871     GADGET_ID_DROP_DELAY_FIX_DOWN,              GADGET_ID_DROP_DELAY_FIX_UP,
1872     GADGET_ID_DROP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1873     &custom_element.drop_delay_fixed,
1874     NULL,                                       "Drop delay", NULL
1875   },
1876   {
1877     ED_COUNTER_ID_DROP_DELAY_RND,
1878     -1,                                         ED_ELEMENT_SETTINGS_YPOS(7),
1879     0,                                          999,
1880     GADGET_ID_DROP_DELAY_RND_DOWN,              GADGET_ID_DROP_DELAY_RND_UP,
1881     GADGET_ID_DROP_DELAY_RND_TEXT,              GADGET_ID_DROP_DELAY_FIX_UP,
1882     &custom_element.drop_delay_random,
1883     NULL,                                       "+random", NULL
1884   },
1885
1886   // ---------- element settings: configure 2 (custom elements) ---------------
1887
1888   {
1889     ED_COUNTER_ID_MOVE_DELAY_FIX,
1890     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1891     0,                                          999,
1892     GADGET_ID_MOVE_DELAY_FIX_DOWN,              GADGET_ID_MOVE_DELAY_FIX_UP,
1893     GADGET_ID_MOVE_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1894     &custom_element.move_delay_fixed,
1895     NULL,                                       "Move delay", NULL
1896   },
1897   {
1898     ED_COUNTER_ID_MOVE_DELAY_RND,
1899     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1900     0,                                          999,
1901     GADGET_ID_MOVE_DELAY_RND_DOWN,              GADGET_ID_MOVE_DELAY_RND_UP,
1902     GADGET_ID_MOVE_DELAY_RND_TEXT,              GADGET_ID_MOVE_DELAY_FIX_UP,
1903     &custom_element.move_delay_random,
1904     NULL,                                       "+random", NULL
1905   },
1906   {
1907     ED_COUNTER_ID_STEP_DELAY_FIX,
1908     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1909     0,                                          999,
1910     GADGET_ID_STEP_DELAY_FIX_DOWN,              GADGET_ID_STEP_DELAY_FIX_UP,
1911     GADGET_ID_STEP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1912     &custom_element.step_delay_fixed,
1913     NULL,                                       "Step delay", NULL
1914   },
1915   {
1916     ED_COUNTER_ID_STEP_DELAY_RND,
1917     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1918     0,                                          999,
1919     GADGET_ID_STEP_DELAY_RND_DOWN,              GADGET_ID_STEP_DELAY_RND_UP,
1920     GADGET_ID_STEP_DELAY_RND_TEXT,              GADGET_ID_STEP_DELAY_FIX_UP,
1921     &custom_element.step_delay_random,
1922     NULL,                                       "+random", NULL
1923   },
1924   {
1925     ED_COUNTER_ID_EXPLOSION_DELAY,
1926     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
1927     0,                                          999,
1928     GADGET_ID_EXPLOSION_DELAY_DOWN,             GADGET_ID_EXPLOSION_DELAY_UP,
1929     GADGET_ID_EXPLOSION_DELAY_TEXT,             GADGET_ID_NONE,
1930     &custom_element.explosion_delay,
1931     NULL,                                       "Explosion delay", NULL
1932   },
1933   {
1934     ED_COUNTER_ID_IGNITION_DELAY,
1935     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
1936     0,                                          999,
1937     GADGET_ID_IGNITION_DELAY_DOWN,              GADGET_ID_IGNITION_DELAY_UP,
1938     GADGET_ID_IGNITION_DELAY_TEXT,              GADGET_ID_NONE,
1939     &custom_element.ignition_delay,
1940     NULL,                                       "Ignition delay", "(by fire)"
1941   },
1942
1943   // ---------- element settings: configure (group elements) ------------------
1944
1945   {
1946     ED_COUNTER_ID_GROUP_CONTENT,
1947     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1948     MIN_ELEMENTS_IN_GROUP,                      MAX_ELEMENTS_IN_GROUP,
1949     GADGET_ID_GROUP_CONTENT_DOWN,               GADGET_ID_GROUP_CONTENT_UP,
1950     GADGET_ID_GROUP_CONTENT_TEXT,               GADGET_ID_NONE,
1951     &group_element_info.num_elements,
1952     NULL,                                       NULL, "Number of elements in group"
1953   },
1954
1955   // ---------- element settings: advanced (custom elements) ------------------
1956
1957   {
1958     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1959     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(2),
1960     0,                                          999,
1961     GADGET_ID_CHANGE_DELAY_FIX_DOWN,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1962     GADGET_ID_CHANGE_DELAY_FIX_TEXT,            GADGET_ID_NONE,
1963     &custom_element_change.delay_fixed,
1964     NULL,                                       "CE delay", NULL,
1965   },
1966   {
1967     ED_COUNTER_ID_CHANGE_DELAY_RND,
1968     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
1969     0,                                          999,
1970     GADGET_ID_CHANGE_DELAY_RND_DOWN,            GADGET_ID_CHANGE_DELAY_RND_UP,
1971     GADGET_ID_CHANGE_DELAY_RND_TEXT,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1972     &custom_element_change.delay_random,
1973     NULL,                                       "+random", NULL
1974   },
1975   {
1976     ED_COUNTER_ID_CHANGE_CONT_RND,
1977     ED_ELEMENT_SETTINGS_XPOS(3),                ED_ELEMENT_SETTINGS_YPOS(12),
1978     0,                                          100,
1979     GADGET_ID_CHANGE_CONT_RND_DOWN,             GADGET_ID_CHANGE_CONT_RND_UP,
1980     GADGET_ID_CHANGE_CONT_RND_TEXT,             GADGET_ID_NONE,
1981     &custom_element_change.random_percentage,
1982     NULL,                                       "Use random replace:", "%"
1983   },
1984 };
1985
1986 static struct
1987 {
1988   int gadget_type_id;
1989   int x, y;
1990   int gadget_id;
1991   int size;
1992   char *value;
1993   char *text_above, *infotext;
1994 } textinput_info[ED_NUM_TEXTINPUT] =
1995 {
1996   {
1997     ED_TEXTINPUT_ID_LEVEL_NAME,
1998     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1999     GADGET_ID_LEVEL_NAME,
2000     MAX_LEVEL_NAME_LEN,
2001     level.name,
2002     "Title:", "Title for this level"
2003   },
2004   {
2005     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
2006     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2007     GADGET_ID_LEVEL_AUTHOR,
2008     MAX_LEVEL_AUTHOR_LEN,
2009     level.author,
2010     "Author:", "Author for this level"
2011   },
2012   {
2013     ED_TEXTINPUT_ID_LEVELSET_NAME,
2014     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
2015     GADGET_ID_LEVELSET_NAME,
2016     MAX_LEVEL_NAME_LEN,
2017     levelset_name,
2018     "Title:", "Title for this or new level set"
2019   },
2020   {
2021     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
2022     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2023     GADGET_ID_LEVELSET_AUTHOR,
2024     MAX_LEVEL_AUTHOR_LEN,
2025     levelset_author,
2026     "Author:", "Author for this or new level set"
2027   },
2028   {
2029     ED_TEXTINPUT_ID_ELEMENT_NAME,
2030     -1, -1,     // these values are not constant, but can change at runtime
2031     GADGET_ID_ELEMENT_NAME,
2032     MAX_ELEMENT_NAME_LEN - 2,                   // currently 2 chars less editable
2033     custom_element.description,
2034     NULL, "Element name"
2035   }
2036 };
2037
2038 static struct
2039 {
2040   int gadget_type_id;
2041   int x, y;
2042   int gadget_id;
2043   int xsize, ysize;
2044   char *value;
2045   char *text_above, *text_above_cropped, *infotext;
2046 } textarea_info[ED_NUM_TEXTAREAS] =
2047 {
2048   {
2049     ED_TEXTAREA_ID_ENVELOPE_INFO,
2050     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
2051     GADGET_ID_ENVELOPE_INFO,
2052     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2053     NULL,
2054     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2055   }
2056 };
2057
2058 static struct ValueTextInfo options_time_or_steps[] =
2059 {
2060   { 0,                                  "seconds"                       },
2061   { 1,                                  "steps"                         },
2062
2063   { -1,                                 NULL                            }
2064 };
2065
2066 static struct ValueTextInfo options_time_score_base[] =
2067 {
2068   { 1,                                  "per second/step"               },
2069   { 10,                                 "per 10 seconds/steps"          },
2070
2071   { -1,                                 NULL                            }
2072 };
2073
2074 static struct ValueTextInfo options_game_engine_type[] =
2075 {
2076   { GAME_ENGINE_TYPE_RND,               "Rocks'n'Diamonds"              },
2077   { GAME_ENGINE_TYPE_BD,                "Boulder Dash"                  },
2078   { GAME_ENGINE_TYPE_EM,                "Emerald Mine"                  },
2079   { GAME_ENGINE_TYPE_SP,                "Supaplex"                      },
2080   { GAME_ENGINE_TYPE_MM,                "Mirror Magic"                  },
2081
2082   { -1,                                 NULL                            }
2083 };
2084
2085 static struct ValueTextInfo options_levelset_save_mode[] =
2086 {
2087   { LEVELSET_SAVE_MODE_UPDATE,          "Update this level set"         },
2088   { LEVELSET_SAVE_MODE_CREATE,          "Create new level set"          },
2089
2090   { -1,                                 NULL                            }
2091 };
2092
2093 static struct ValueTextInfo options_bd_gravity_direction[] =
2094 {
2095   { GD_MV_DOWN,                         "down"                          },
2096   { GD_MV_UP,                           "up"                            },
2097   { GD_MV_LEFT,                         "left"                          },
2098   { GD_MV_RIGHT,                        "right"                         },
2099
2100   { -1,                                 NULL                            }
2101 };
2102
2103 static struct ValueTextInfo options_wind_direction[] =
2104 {
2105   { MV_START_NONE,                      "none"                          },
2106   { MV_START_LEFT,                      "left"                          },
2107   { MV_START_RIGHT,                     "right"                         },
2108   { MV_START_UP,                        "up"                            },
2109   { MV_START_DOWN,                      "down"                          },
2110
2111   { -1,                                 NULL                            }
2112 };
2113
2114 static struct ValueTextInfo options_player_speed[] =
2115 {
2116   { 0,                                  "frozen"                        },
2117   { 1,                                  "very slow"                     },
2118   { 2,                                  "slow"                          },
2119   { 4,                                  "normal"                        },
2120   { 8,                                  "fast"                          },
2121   { 16,                                 "very fast"                     },
2122   { 32,                                 "ultrafast"                     },
2123
2124   { -1,                                 NULL                            }
2125 };
2126
2127 static struct ValueTextInfo options_access_type[] =
2128 {
2129   { EP_WALKABLE,                        "walkable"                      },
2130   { EP_PASSABLE,                        "passable"                      },
2131
2132   { -1,                                 NULL                            }
2133 };
2134
2135 static struct ValueTextInfo options_access_layer[] =
2136 {
2137   { EP_ACCESSIBLE_OVER,                 "over"                          },
2138   { EP_ACCESSIBLE_INSIDE,               "inside"                        },
2139   { EP_ACCESSIBLE_UNDER,                "under"                         },
2140
2141   { -1,                                 NULL                            }
2142 };
2143
2144 static struct ValueTextInfo options_access_protected[] =
2145 {
2146   { 0,                                  "unprotected"                   },
2147   { 1,                                  "protected"                     },
2148
2149   { -1,                                 NULL                            }
2150 };
2151
2152 static struct ValueTextInfo options_access_direction[] =
2153 {
2154   { MV_NO_DIRECTION,                    "no direction"                  },
2155   { MV_LEFT,                            "left"                          },
2156   { MV_RIGHT,                           "right"                         },
2157   { MV_UP,                              "up"                            },
2158   { MV_DOWN,                            "down"                          },
2159   { MV_LEFT  | MV_UP,                   "left + up"                     },
2160   { MV_LEFT  | MV_DOWN,                 "left + down"                   },
2161   { MV_RIGHT | MV_UP,                   "right + up"                    },
2162   { MV_RIGHT | MV_DOWN,                 "right + down"                  },
2163   { MV_HORIZONTAL,                      "horizontal"                    },
2164   { MV_VERTICAL,                        "vertical"                      },
2165   { MV_HORIZONTAL | MV_UP,              "horizontal + up"               },
2166   { MV_HORIZONTAL | MV_DOWN,            "horizontal + down"             },
2167   { MV_VERTICAL   | MV_LEFT,            "vertical + left"               },
2168   { MV_VERTICAL   | MV_RIGHT,           "vertical + right"              },
2169   { MV_ALL_DIRECTIONS,                  "all directions"                },
2170
2171   { -1,                                 NULL                            }
2172 };
2173
2174 static struct ValueTextInfo options_walk_to_action[] =
2175 {
2176   { EP_DIGGABLE,                        "diggable"                      },
2177   { EP_COLLECTIBLE_ONLY,                "collectible"                   },
2178   { EP_DROPPABLE,                       "collectible & droppable"       },
2179   { EP_THROWABLE,                       "collectible & throwable"       },
2180   { EP_PUSHABLE,                        "pushable"                      },
2181
2182   { -1,                                 NULL                            }
2183 };
2184
2185 static struct ValueTextInfo options_move_pattern[] =
2186 {
2187   { MV_LEFT,                            "left"                          },
2188   { MV_RIGHT,                           "right"                         },
2189   { MV_UP,                              "up"                            },
2190   { MV_DOWN,                            "down"                          },
2191   { MV_HORIZONTAL,                      "horizontal"                    },
2192   { MV_VERTICAL,                        "vertical"                      },
2193   { MV_ALL_DIRECTIONS,                  "all directions"                },
2194   { MV_WIND_DIRECTION,                  "wind direction"                },
2195   { MV_TOWARDS_PLAYER,                  "towards player"                },
2196   { MV_AWAY_FROM_PLAYER,                "away from player"              },
2197   { MV_ALONG_LEFT_SIDE,                 "along left side"               },
2198   { MV_ALONG_RIGHT_SIDE,                "along right side"              },
2199   { MV_TURNING_LEFT,                    "turning left"                  },
2200   { MV_TURNING_RIGHT,                   "turning right"                 },
2201   { MV_TURNING_LEFT_RIGHT,              "turning left, right"           },
2202   { MV_TURNING_RIGHT_LEFT,              "turning right, left"           },
2203   { MV_TURNING_RANDOM,                  "turning random"                },
2204   { MV_MAZE_RUNNER,                     "maze runner style"             },
2205   { MV_MAZE_HUNTER,                     "maze hunter style"             },
2206   { MV_WHEN_PUSHED,                     "when pushed"                   },
2207   { MV_WHEN_DROPPED,                    "when dropped/thrown"           },
2208
2209   { -1,                                 NULL                            }
2210 };
2211
2212 static struct ValueTextInfo options_move_direction[] =
2213 {
2214   { MV_START_AUTOMATIC,                 "automatic"                     },
2215   { MV_START_LEFT,                      "left"                          },
2216   { MV_START_RIGHT,                     "right"                         },
2217   { MV_START_UP,                        "up"                            },
2218   { MV_START_DOWN,                      "down"                          },
2219   { MV_START_RANDOM,                    "random"                        },
2220   { MV_START_PREVIOUS,                  "previous"                      },
2221
2222   { -1,                                 NULL                            }
2223 };
2224
2225 static struct ValueTextInfo options_move_stepsize[] =
2226 {
2227   { 0,                                  "not moving"                    },
2228   { 1,                                  "very slow"                     },
2229   { 2,                                  "slow"                          },
2230   { 4,                                  "normal"                        },
2231   { 8,                                  "fast"                          },
2232   { 16,                                 "very fast"                     },
2233   { 32,                                 "even faster"                   },
2234
2235   { -1,                                 NULL                            }
2236 };
2237
2238 static struct ValueTextInfo options_move_leave_type[] =
2239 {
2240   { LEAVE_TYPE_UNLIMITED,               "leave behind"                  },
2241   { LEAVE_TYPE_LIMITED,                 "change it to"                  },
2242
2243   { -1,                                 NULL                            }
2244 };
2245
2246 static struct ValueTextInfo options_smash_targets[] =
2247 {
2248   { EP_CAN_SMASH_PLAYER,                "player"                        },
2249 #if 0
2250   { EP_CAN_SMASH_ENEMIES,               "enemies"                       },
2251 #endif
2252   { EP_CAN_SMASH_EVERYTHING,            "everything"                    },
2253
2254   { -1,                                 NULL                            }
2255 };
2256
2257 static struct ValueTextInfo options_slippery_type[] =
2258 {
2259   { SLIPPERY_ANY_RANDOM,                "random"                        },
2260   { SLIPPERY_ANY_LEFT_RIGHT,            "left, right"                   },
2261   { SLIPPERY_ANY_RIGHT_LEFT,            "right, left"                   },
2262   { SLIPPERY_ONLY_LEFT,                 "only left"                     },
2263   { SLIPPERY_ONLY_RIGHT,                "only right"                    },
2264
2265   { -1,                                 NULL                            }
2266 };
2267
2268 static struct ValueTextInfo options_deadliness[] =
2269 {
2270   { EP_DONT_RUN_INTO,                   "running into"                  },
2271   { EP_DONT_COLLIDE_WITH,               "colliding with"                },
2272   { EP_DONT_GET_HIT_BY,                 "getting hit by"                },
2273   { EP_DONT_TOUCH,                      "touching"                      },
2274
2275   { -1,                                 NULL                            }
2276 };
2277
2278 static struct ValueTextInfo options_explosion_type[] =
2279 {
2280   { EXPLODES_3X3,                       "3x3"                           },
2281   { EXPLODES_CROSS,                     "3+3"                           },
2282   { EXPLODES_1X1,                       "1x1"                           },
2283
2284   { -1,                                 NULL                            }
2285 };
2286
2287 static struct ValueTextInfo options_time_units[] =
2288 {
2289   { 1,                                  "frames"                        },
2290   { FRAMES_PER_SECOND,                  "seconds"                       },
2291
2292   { -1,                                 NULL                            }
2293 };
2294
2295 static struct ValueTextInfo options_change_direct_action[] =
2296 {
2297   { CE_TOUCHED_BY_PLAYER,               "touched by player"             },
2298   { CE_PRESSED_BY_PLAYER,               "pressed by player"             },
2299   { CE_SWITCHED_BY_PLAYER,              "switched by player"            },
2300   { CE_SNAPPED_BY_PLAYER,               "snapped by player"             },
2301   { CE_PUSHED_BY_PLAYER,                "pushed by player"              },
2302   { CE_ENTERED_BY_PLAYER,               "entered by player"             },
2303   { CE_LEFT_BY_PLAYER,                  "left by player"                },
2304   { CE_DROPPED_BY_PLAYER,               "dropped/thrown by player"      },
2305   { CE_SWITCHED,                        "switched"                      },
2306   { CE_HITTING_SOMETHING,               "hitting something"             },
2307   { CE_HIT_BY_SOMETHING,                "hit by something"              },
2308 #if 0
2309   { CE_BLOCKED,                         "blocked"                       },
2310 #endif
2311   { CE_IMPACT,                          "impact (on something)"         },
2312   { CE_SMASHED,                         "smashed (from above)"          },
2313 #if 0
2314   { CE_VALUE_CHANGES,                   "CE value changes"              },
2315   { CE_SCORE_CHANGES,                   "CE score changes"              },
2316 #endif
2317   { CE_VALUE_GETS_ZERO,                 "CE value gets 0"               },
2318   { CE_SCORE_GETS_ZERO,                 "CE score gets 0"               },
2319   { CE_UNDEFINED,                       " "                             },
2320   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2321   { CE_CLICKED_BY_MOUSE,                "clicked by mouse"              },
2322   { CE_PRESSED_BY_MOUSE,                "pressed by mouse"              },
2323   { CE_UNDEFINED,                       " "                             },
2324   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2325   { CE_NEXT_TO_PLAYER,                  "next to player"                },
2326
2327   { -1,                                 NULL                            }
2328 };
2329
2330 static struct ValueTextInfo options_change_other_action[] =
2331 {
2332   { CE_PLAYER_TOUCHES_X,                "player touches"                },
2333   { CE_PLAYER_PRESSES_X,                "player presses"                },
2334   { CE_PLAYER_SWITCHES_X,               "player switches"               },
2335   { CE_PLAYER_SNAPS_X,                  "player snaps"                  },
2336   { CE_PLAYER_PUSHES_X,                 "player pushes"                 },
2337   { CE_PLAYER_ENTERS_X,                 "player enters"                 },
2338   { CE_PLAYER_LEAVES_X,                 "player leaves"                 },
2339   { CE_PLAYER_DIGS_X,                   "player digs"                   },
2340   { CE_PLAYER_COLLECTS_X,               "player collects"               },
2341   { CE_PLAYER_DROPS_X,                  "player drops/throws"           },
2342   { CE_TOUCHING_X,                      "touching"                      },
2343   { CE_HITTING_X,                       "hitting"                       },
2344   { CE_DIGGING_X,                       "digging"                       },
2345   { CE_HIT_BY_X,                        "hit by"                        },
2346   { CE_SWITCH_OF_X,                     "switch of"                     },
2347   { CE_CHANGE_OF_X,                     "change by page of"             },
2348   { CE_EXPLOSION_OF_X,                  "explosion of"                  },
2349   { CE_MOVE_OF_X,                       "move of"                       },
2350   { CE_CREATION_OF_X,                   "creation of"                   },
2351   { CE_VALUE_CHANGES_OF_X,              "CE value changes of"           },
2352   { CE_SCORE_CHANGES_OF_X,              "CE score changes of"           },
2353   { CE_VALUE_GETS_ZERO_OF_X,            "CE value gets 0 of"            },
2354   { CE_SCORE_GETS_ZERO_OF_X,            "CE score gets 0 of"            },
2355   { CE_UNDEFINED,                       " "                             },
2356   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2357   { CE_MOUSE_CLICKED_ON_X,              "mouse clicked on"              },
2358   { CE_MOUSE_PRESSED_ON_X,              "mouse pressed on"              },
2359   { CE_UNDEFINED,                       " "                             },
2360   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2361   { CE_PLAYER_NEXT_TO_X,                "player next to"                },
2362   { CE_NEXT_TO_X,                       "next to"                       },
2363
2364   { -1,                                 NULL                            }
2365 };
2366
2367 static struct ValueTextInfo options_change_trigger_side[] =
2368 {
2369   { CH_SIDE_LEFT,                       "left"                          },
2370   { CH_SIDE_RIGHT,                      "right"                         },
2371   { CH_SIDE_TOP,                        "top"                           },
2372   { CH_SIDE_BOTTOM,                     "bottom"                        },
2373   { CH_SIDE_LEFT_RIGHT,                 "left/right"                    },
2374   { CH_SIDE_TOP_BOTTOM,                 "top/bottom"                    },
2375   { CH_SIDE_ANY,                        "any"                           },
2376
2377   { -1,                                 NULL                            }
2378 };
2379
2380 static struct ValueTextInfo options_change_trigger_player[] =
2381 {
2382   { CH_PLAYER_1,                        "1"                             },
2383   { CH_PLAYER_2,                        "2"                             },
2384   { CH_PLAYER_3,                        "3"                             },
2385   { CH_PLAYER_4,                        "4"                             },
2386   { CH_PLAYER_ANY,                      "any"                           },
2387
2388   { -1,                                 NULL                            }
2389 };
2390
2391 static struct ValueTextInfo options_change_trigger_page[] =
2392 {
2393   { (1u << 0),                          "1"                             },
2394   { (1u << 1),                          "2"                             },
2395   { (1u << 2),                          "3"                             },
2396   { (1u << 3),                          "4"                             },
2397   { (1u << 4),                          "5"                             },
2398   { (1u << 5),                          "6"                             },
2399   { (1u << 6),                          "7"                             },
2400   { (1u << 7),                          "8"                             },
2401   { (1u << 8),                          "9"                             },
2402   { (1u << 9),                          "10"                            },
2403   { (1u << 10),                         "11"                            },
2404   { (1u << 11),                         "12"                            },
2405   { (1u << 12),                         "13"                            },
2406   { (1u << 13),                         "14"                            },
2407   { (1u << 14),                         "15"                            },
2408   { (1u << 15),                         "16"                            },
2409   { (1u << 16),                         "17"                            },
2410   { (1u << 17),                         "18"                            },
2411   { (1u << 18),                         "19"                            },
2412   { (1u << 19),                         "20"                            },
2413   { (1u << 20),                         "21"                            },
2414   { (1u << 21),                         "22"                            },
2415   { (1u << 22),                         "23"                            },
2416   { (1u << 23),                         "24"                            },
2417   { (1u << 24),                         "25"                            },
2418   { (1u << 25),                         "26"                            },
2419   { (1u << 26),                         "27"                            },
2420   { (1u << 27),                         "28"                            },
2421   { (1u << 28),                         "29"                            },
2422   { (1u << 29),                         "30"                            },
2423   { (1u << 30),                         "31"                            },
2424   { (1u << 31),                         "32"                            },
2425   { CH_PAGE_ANY,                        "any"                           },
2426
2427   { -1,                                 NULL                            }
2428 };
2429
2430 static struct ValueTextInfo options_change_replace_when[] =
2431 {
2432   { CP_WHEN_EMPTY,                      "empty"                         },
2433   { CP_WHEN_WALKABLE,                   "walkable"                      },
2434   { CP_WHEN_DIGGABLE,                   "diggable"                      },
2435   { CP_WHEN_COLLECTIBLE,                "collectible"                   },
2436   { CP_WHEN_REMOVABLE,                  "removable"                     },
2437   { CP_WHEN_DESTRUCTIBLE,               "destructible"                  },
2438
2439   { -1,                                 NULL                            }
2440 };
2441
2442 static struct ValueTextInfo options_action_type[] =
2443 {
2444   { CA_NO_ACTION,                       "no action"                     },
2445   { CA_UNDEFINED,                       " "                             },
2446   { CA_HEADLINE_LEVEL_ACTIONS,          "[level]"                       },
2447   { CA_RESTART_LEVEL,                   "restart level"                 },
2448   { CA_SHOW_ENVELOPE,                   "show envelope"                 },
2449   { CA_SET_LEVEL_TIME,                  "set time"                      },
2450   { CA_SET_LEVEL_SCORE,                 "set score"                     },
2451   { CA_SET_LEVEL_GEMS,                  "set gems"                      },
2452   { CA_SET_LEVEL_WIND,                  "set wind dir."                 },
2453   { CA_SET_LEVEL_RANDOM_SEED,           "set random seed"               },
2454   { CA_UNDEFINED,                       " "                             },
2455   { CA_HEADLINE_PLAYER_ACTIONS,         "[player]"                      },
2456   { CA_MOVE_PLAYER,                     "move player"                   },
2457   { CA_MOVE_PLAYER_NEW,                 "move player new"               },
2458   { CA_EXIT_PLAYER,                     "exit player"                   },
2459   { CA_KILL_PLAYER,                     "kill player"                   },
2460   { CA_SET_PLAYER_KEYS,                 "set keys"                      },
2461   { CA_SET_PLAYER_SPEED,                "set speed"                     },
2462   { CA_SET_PLAYER_SHIELD,               "set shield"                    },
2463   { CA_SET_PLAYER_GRAVITY,              "set gravity"                   },
2464   { CA_SET_PLAYER_ARTWORK,              "set artwork"                   },
2465   { CA_SET_PLAYER_INVENTORY,            "set inventory"                 },
2466   { CA_UNDEFINED,                       " "                             },
2467   { CA_HEADLINE_CE_ACTIONS,             "[CE]"                          },
2468   { CA_SET_CE_VALUE,                    "set CE value"                  },
2469   { CA_SET_CE_SCORE,                    "set CE score"                  },
2470   { CA_SET_CE_ARTWORK,                  "set CE artwork"                },
2471   { CA_UNDEFINED,                       " "                             },
2472   { CA_HEADLINE_ENGINE_ACTIONS,         "[engine]"                      },
2473   { CA_SET_ENGINE_SCAN_MODE,            "set scan mode"                 },
2474
2475   { -1,                                 NULL                            }
2476 };
2477
2478 static struct ValueTextInfo options_action_mode_none[] =
2479 {
2480   { CA_MODE_UNDEFINED,                  " "                             },
2481
2482   { -1,                                 NULL                            }
2483 };
2484
2485 static struct ValueTextInfo options_action_mode_assign[] =
2486 {
2487   { CA_MODE_SET,                        "="                             },
2488
2489   { -1,                                 NULL                            }
2490 };
2491
2492 static struct ValueTextInfo options_action_mode_add_remove[] =
2493 {
2494   { CA_MODE_ADD,                        "+"                             },
2495   { CA_MODE_SUBTRACT,                   "-"                             },
2496
2497   { -1,                                 NULL                            }
2498 };
2499
2500 static struct ValueTextInfo options_action_mode_calculate[] =
2501 {
2502   { CA_MODE_SET,                        "="                             },
2503   { CA_MODE_ADD,                        "+"                             },
2504   { CA_MODE_SUBTRACT,                   "-"                             },
2505   { CA_MODE_MULTIPLY,                   "*"                             },
2506   { CA_MODE_DIVIDE,                     "/"                             },
2507   { CA_MODE_MODULO,                     "%"                             },
2508
2509   { -1,                                 NULL                            }
2510 };
2511
2512 static struct ValueTextInfo options_action_arg_none[] =
2513 {
2514   { CA_ARG_UNDEFINED,                   "         "                     },
2515
2516   { -1,                                 NULL                            }
2517 };
2518
2519 static struct ValueTextInfo options_action_arg_player[] =
2520 {
2521   { CA_ARG_PLAYER_HEADLINE,             "[player]"                      },
2522   { CA_ARG_PLAYER_1,                    "1"                             },
2523   { CA_ARG_PLAYER_2,                    "2"                             },
2524   { CA_ARG_PLAYER_3,                    "3"                             },
2525   { CA_ARG_PLAYER_4,                    "4"                             },
2526   { CA_ARG_PLAYER_ANY,                  "any"                           },
2527   { CA_ARG_PLAYER_TRIGGER,              "trigger"                       },
2528   { CA_ARG_PLAYER_ACTION,               "action ->"                     },
2529
2530   { -1,                                 NULL                            }
2531 };
2532
2533 static struct ValueTextInfo options_action_arg_number[] =
2534 {
2535   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2536   { CA_ARG_0,                           "0"                             },
2537   { CA_ARG_1,                           "1"                             },
2538   { CA_ARG_2,                           "2"                             },
2539   { CA_ARG_3,                           "3"                             },
2540   { CA_ARG_4,                           "4"                             },
2541   { CA_ARG_5,                           "5"                             },
2542   { CA_ARG_10,                          "10"                            },
2543   { CA_ARG_100,                         "100"                           },
2544   { CA_ARG_1000,                        "1000"                          },
2545   { CA_ARG_UNDEFINED,                   " "                             },
2546   { CA_ARG_NUMBER_MIN,                  "min"                           },
2547   { CA_ARG_NUMBER_MAX,                  "max"                           },
2548   { CA_ARG_UNDEFINED,                   " "                             },
2549   { CA_ARG_NUMBER_RESET,                "reset"                         },
2550   { CA_ARG_UNDEFINED,                   " "                             },
2551   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2552   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2553   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2554   { CA_ARG_UNDEFINED,                   " "                             },
2555   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2556   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2557   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2558   { CA_ARG_UNDEFINED,                   " "                             },
2559   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2560   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2561   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2562   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2563   { CA_ARG_UNDEFINED,                   " "                             },
2564   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2565   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2566   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2567   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2568
2569   { -1,                                 NULL                            }
2570 };
2571
2572 static struct ValueTextInfo options_action_arg_value[] =
2573 {
2574   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2575   { CA_ARG_0,                           "0"                             },
2576   { CA_ARG_1,                           "1"                             },
2577   { CA_ARG_2,                           "2"                             },
2578   { CA_ARG_3,                           "3"                             },
2579   { CA_ARG_4,                           "4"                             },
2580   { CA_ARG_5,                           "5"                             },
2581   { CA_ARG_10,                          "10"                            },
2582   { CA_ARG_100,                         "100"                           },
2583   { CA_ARG_1000,                        "1000"                          },
2584   { CA_ARG_UNDEFINED,                   " "                             },
2585   { CA_ARG_NUMBER_MIN,                  "min"                           },
2586   { CA_ARG_NUMBER_MAX,                  "max"                           },
2587   { CA_ARG_UNDEFINED,                   " "                             },
2588   { CA_ARG_NUMBER_RESET,                "reset"                         },
2589   { CA_ARG_UNDEFINED,                   " "                             },
2590   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2591   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2592   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2593   { CA_ARG_UNDEFINED,                   " "                             },
2594   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2595   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2596   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2597   { CA_ARG_UNDEFINED,                   " "                             },
2598   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2599   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2600   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2601   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2602   { CA_ARG_UNDEFINED,                   " "                             },
2603   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2604   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2605   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2606   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2607   { CA_ARG_UNDEFINED,                   " "                             },
2608   { CA_ARG_ELEMENT_NR_HEADLINE,         "[element]"                     },
2609   { CA_ARG_ELEMENT_NR_TARGET,           "target"                        },
2610   { CA_ARG_ELEMENT_NR_TRIGGER,          "trigger"                       },
2611   { CA_ARG_ELEMENT_NR_ACTION,           "action ->"                     },
2612
2613   { -1,                                 NULL                            }
2614 };
2615
2616 static struct ValueTextInfo options_action_arg_envelope[] =
2617 {
2618   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2619   { CA_ARG_1,                           "1"                             },
2620   { CA_ARG_2,                           "2"                             },
2621   { CA_ARG_3,                           "3"                             },
2622   { CA_ARG_4,                           "4"                             },
2623   { CA_ARG_UNDEFINED,                   " "                             },
2624   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2625   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2626   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2627   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2628
2629   { -1,                                 NULL                            }
2630 };
2631
2632 static struct ValueTextInfo options_action_arg_key[] =
2633 {
2634   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2635   { CA_ARG_1,                           "1"                             },
2636   { CA_ARG_2,                           "2"                             },
2637   { CA_ARG_3,                           "3"                             },
2638   { CA_ARG_4,                           "4"                             },
2639   { CA_ARG_5,                           "5"                             },
2640   { CA_ARG_6,                           "6"                             },
2641   { CA_ARG_7,                           "7"                             },
2642   { CA_ARG_8,                           "8"                             },
2643   { CA_ARG_UNDEFINED,                   " "                             },
2644   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2645   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2646   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2647   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2648
2649   { -1,                                 NULL                            }
2650 };
2651
2652 static struct ValueTextInfo options_action_arg_speed[] =
2653 {
2654   { CA_ARG_SPEED_HEADLINE,              "[speed]"                       },
2655   { CA_ARG_SPEED_NOT_MOVING,            "frozen"                        },
2656   { CA_ARG_SPEED_VERY_SLOW,             "very slow"                     },
2657   { CA_ARG_SPEED_SLOW,                  "slow"                          },
2658   { CA_ARG_SPEED_NORMAL,                "normal"                        },
2659   { CA_ARG_SPEED_FAST,                  "fast"                          },
2660   { CA_ARG_SPEED_VERY_FAST,             "very fast"                     },
2661   { CA_ARG_SPEED_EVEN_FASTER,           "ultrafast"                     },
2662   { CA_ARG_UNDEFINED,                   " "                             },
2663   { CA_ARG_SPEED_SLOWER,                "slower"                        },
2664   { CA_ARG_SPEED_FASTER,                "faster"                        },
2665   { CA_ARG_UNDEFINED,                   " "                             },
2666   { CA_ARG_SPEED_RESET,                 "reset"                         },
2667
2668   { -1,                                 NULL                            }
2669 };
2670
2671 static struct ValueTextInfo options_action_arg_shield[] =
2672 {
2673   { CA_ARG_SHIELD_HEADLINE,             "[shield]"                      },
2674   { CA_ARG_SHIELD_OFF,                  "off"                           },
2675   { CA_ARG_SHIELD_NORMAL,               "normal"                        },
2676   { CA_ARG_SHIELD_DEADLY,               "deadly"                        },
2677
2678   { -1,                                 NULL                            }
2679 };
2680
2681 static struct ValueTextInfo options_action_arg_artwork[] =
2682 {
2683   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2684   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2685   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2686   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2687   { CA_ARG_UNDEFINED,                   " "                             },
2688   { CA_ARG_ELEMENT_RESET,               "reset"                         },
2689
2690   { -1,                                 NULL                            }
2691 };
2692
2693 static struct ValueTextInfo options_action_arg_gravity[] =
2694 {
2695   { CA_ARG_GRAVITY_HEADLINE,            "[gravity]"                     },
2696   { CA_ARG_GRAVITY_ON,                  "on"                            },
2697   { CA_ARG_GRAVITY_OFF,                 "off"                           },
2698   { CA_ARG_GRAVITY_TOGGLE,              "toggle"                        },
2699
2700   { -1,                                 NULL                            }
2701 };
2702
2703 static struct ValueTextInfo options_action_arg_direction[] =
2704 {
2705   { CA_ARG_DIRECTION_HEADLINE,          "[dir.]"                        },
2706   { CA_ARG_DIRECTION_NONE,              "none"                          },
2707   { CA_ARG_DIRECTION_LEFT,              "left"                          },
2708   { CA_ARG_DIRECTION_RIGHT,             "right"                         },
2709   { CA_ARG_DIRECTION_UP,                "up"                            },
2710   { CA_ARG_DIRECTION_DOWN,              "down"                          },
2711   { CA_ARG_DIRECTION_TRIGGER,           "trigger"                       },
2712   { CA_ARG_DIRECTION_TRIGGER_BACK,      "-trigger"                      },
2713
2714   { -1,                                 NULL                            }
2715 };
2716
2717 static struct ValueTextInfo options_action_arg_scan_mode[] =
2718 {
2719   { CA_ARG_SCAN_MODE_HEADLINE,          "[mode]"                        },
2720   { CA_ARG_SCAN_MODE_NORMAL,            "normal"                        },
2721   { CA_ARG_SCAN_MODE_REVERSE,           "reverse"                       },
2722
2723   { -1,                                 NULL                            }
2724 };
2725
2726 static struct ValueTextInfo options_action_arg_inventory[] =
2727 {
2728   { CA_ARG_INVENTORY_HEADLINE,          "[add]"                         },
2729   { CA_ARG_ELEMENT_TARGET,              "+ target"                      },
2730   { CA_ARG_ELEMENT_TRIGGER,             "+ trigger"                     },
2731   { CA_ARG_ELEMENT_ACTION,              "+ action"                      },
2732   { CA_ARG_UNDEFINED,                   " "                             },
2733   { CA_ARG_INVENTORY_RM_HEADLINE,       "[remove]"                      },
2734   { CA_ARG_INVENTORY_RM_TARGET,         "- target"                      },
2735   { CA_ARG_INVENTORY_RM_TRIGGER,        "- trigger"                     },
2736   { CA_ARG_INVENTORY_RM_ACTION,         "- action"                      },
2737   { CA_ARG_INVENTORY_RM_FIRST,          "- first"                       },
2738   { CA_ARG_INVENTORY_RM_LAST,           "- last"                        },
2739   { CA_ARG_INVENTORY_RM_ALL,            "- all"                         },
2740   { CA_ARG_UNDEFINED,                   " "                             },
2741   { CA_ARG_INVENTORY_RESET,             "reset"                         },
2742
2743   { -1,                                 NULL                            }
2744 };
2745
2746 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2747 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2748 {
2749   { -1,                                 NULL                            }
2750 };
2751
2752 static struct ValueTextInfo options_group_choice_mode[] =
2753 {
2754   { ANIM_RANDOM,                        "random"                        },
2755   { ANIM_LOOP,                          "loop"                          },
2756   { ANIM_LINEAR,                        "linear"                        },
2757   { ANIM_PINGPONG,                      "pingpong"                      },
2758   { ANIM_PINGPONG2,                     "pingpong 2"                    },
2759   { ANIM_LEVEL_NR,                      "level number"                  },
2760
2761   { -1,                                 NULL                            }
2762 };
2763
2764 static struct ValueTextInfo options_bd_scheduling_type[] =
2765 {
2766   { GD_SCHEDULING_MILLISECONDS,         "Milliseconds"                  },
2767   { GD_SCHEDULING_BD1,                  "BD1"                           },
2768   { GD_SCHEDULING_BD2,                  "BD2"                           },
2769   { GD_SCHEDULING_PLCK,                 "Construction Kit"              },
2770   { GD_SCHEDULING_CRDR,                 "Crazy Dream 7"                 },
2771   { GD_SCHEDULING_BD1_ATARI,            "Atari BD1"                     },
2772   { GD_SCHEDULING_BD2_PLCK_ATARI,       "Atari BD2 / PLCK"              },
2773
2774   { -1,                                   NULL                          }
2775 };
2776
2777 static struct ValueTextInfo *action_arg_modes[] =
2778 {
2779   options_action_mode_none,
2780   options_action_mode_assign,
2781   options_action_mode_add_remove,
2782   options_action_mode_calculate,
2783 };
2784
2785 static struct
2786 {
2787   int value;
2788   int mode;
2789   struct ValueTextInfo *options;
2790 }
2791 action_arg_options[] =
2792 {
2793   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2794   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2795   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2796   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2797   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2798   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2799   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2800   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2801   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2802   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2803   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2804   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2805   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2806   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2807   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2808   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2809   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2810   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2811   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2812   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2813   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2814   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2815
2816   { -1,                         FALSE,  NULL                            }
2817 };
2818
2819 static struct
2820 {
2821   int gadget_type_id;
2822   int x, y;
2823   int gadget_id;
2824   int gadget_id_align;
2825   int size;     // char size of selectbox or '-1' (dynamically determined)
2826   struct ValueTextInfo *options;
2827   int *value;
2828   char *text_above, *text_left, *text_right, *infotext;
2829 } selectbox_info[ED_NUM_SELECTBOX] =
2830 {
2831   // ---------- level and editor settings -------------------------------------
2832
2833   {
2834     ED_SELECTBOX_ID_TIME_OR_STEPS,
2835     -1,                                         ED_LEVEL_SETTINGS_YPOS(8),
2836     GADGET_ID_TIME_OR_STEPS,                    GADGET_ID_LEVEL_TIMELIMIT_UP,
2837     -1,
2838     options_time_or_steps,
2839     &level.use_step_counter,
2840     NULL, NULL, "(0 => no limit)",              "Select time or step limit"
2841   },
2842   {
2843     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2844     -1,                                         ED_LEVEL_SETTINGS_YPOS(10),
2845     GADGET_ID_TIME_SCORE_BASE,                  GADGET_ID_LEVEL_TIMESCORE_UP,
2846     -1,
2847     options_time_score_base,
2848     &level.time_score_base,
2849     NULL, NULL, NULL,                           "Select time score for 1 or 10 seconds/steps"
2850   },
2851   {
2852     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2853     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(12),
2854     GADGET_ID_GAME_ENGINE_TYPE,                 GADGET_ID_NONE,
2855     -1,
2856     options_game_engine_type,
2857     &level.game_engine_type,
2858     NULL, "Game engine:", NULL,                 "Select game engine"
2859   },
2860   {
2861     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2862     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
2863     GADGET_ID_BD_SCHEDULING_TYPE,               GADGET_ID_NONE,
2864     -1,
2865     options_bd_scheduling_type,
2866     &level.bd_scheduling_type,
2867     NULL, "Scheduling type:", NULL,             "Select level timing"
2868   },
2869   {
2870     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2871     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
2872     GADGET_ID_LEVELSET_SAVE_MODE,               GADGET_ID_NONE,
2873     -1,
2874     options_levelset_save_mode,
2875     &levelset_save_mode,
2876     "Action:", NULL, NULL,                      "Select action when saving level set"
2877   },
2878
2879   // ---------- element settings: configure (several elements) ----------------
2880
2881   {
2882     ED_SELECTBOX_ID_WIND_DIRECTION,
2883     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2884     GADGET_ID_WIND_DIRECTION,                   GADGET_ID_NONE,
2885     -1,
2886     options_wind_direction,
2887     &level.wind_direction_initial,
2888     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2889   },
2890   {
2891     ED_SELECTBOX_ID_PLAYER_SPEED,
2892     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(7),
2893     GADGET_ID_PLAYER_SPEED,                     GADGET_ID_NONE,
2894     -1,
2895     options_player_speed,
2896     &level.initial_player_stepsize[0],
2897     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2898   },
2899   {
2900     ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
2901     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2902     GADGET_ID_BD_GRAVITY_DIRECTION,             GADGET_ID_NONE,
2903     -1,
2904     options_bd_gravity_direction,
2905     &level.bd_gravity_direction,
2906     NULL, "Gravity direction:", NULL,           "Select initial gravity direction"
2907   },
2908   {
2909     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2910     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
2911     GADGET_ID_MM_BALL_CHOICE_MODE,              GADGET_ID_NONE,
2912     -1,
2913     options_group_choice_mode,
2914     &level.mm_ball_choice_mode,
2915     NULL, "Choice type:", NULL,                 "Select type of content choice"
2916   },
2917
2918   // ---------- element settings: configure 1 (custom elements) ---------------
2919
2920   {
2921     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2922     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2923     GADGET_ID_CUSTOM_ACCESS_TYPE,               GADGET_ID_NONE,
2924     -1,
2925     options_access_type,
2926     &custom_element.access_type,
2927     NULL, NULL, NULL,                           "Select type of access to this field"
2928   },
2929   {
2930     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2931     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2932     GADGET_ID_CUSTOM_ACCESS_LAYER,              GADGET_ID_CUSTOM_ACCESS_TYPE,
2933     -1,
2934     options_access_layer,
2935     &custom_element.access_layer,
2936     NULL, NULL, NULL,                           "Select layer of access for this field"
2937   },
2938   {
2939     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2940     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2941     GADGET_ID_CUSTOM_ACCESS_PROTECTED,          GADGET_ID_CUSTOM_ACCESS_LAYER,
2942     -1,
2943     options_access_protected,
2944     &custom_element.access_protected,
2945     NULL, NULL, NULL,                           "Select protected access for this field"
2946   },
2947   {
2948     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2949     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2950     GADGET_ID_CUSTOM_ACCESS_DIRECTION,          GADGET_ID_NONE,
2951     -1,
2952     options_access_direction,
2953     &custom_element.access_direction,
2954     NULL, "from", NULL,                         "Select access direction for this field"
2955   },
2956   {
2957     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2958     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2959     GADGET_ID_CUSTOM_WALK_TO_ACTION,            GADGET_ID_NONE,
2960     -1,
2961     options_walk_to_action,
2962     &custom_element.walk_to_action,
2963     NULL, NULL, NULL,                           "Select diggable/collectible/pushable"
2964   },
2965
2966   // ---------- element settings: configure 2 (custom elements) ---------------
2967
2968   {
2969     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2970     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(1),
2971     GADGET_ID_CUSTOM_MOVE_PATTERN,              GADGET_ID_NONE,
2972     -1,
2973     options_move_pattern,
2974     &custom_element.move_pattern,
2975     NULL, "Can move", NULL,                     "Select element move pattern"
2976   },
2977   {
2978     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2979     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2980     GADGET_ID_CUSTOM_MOVE_DIRECTION,            GADGET_ID_NONE,
2981     -1,
2982     options_move_direction,
2983     &custom_element.move_direction_initial,
2984     NULL, "Starts moving", NULL,                "Select initial element move direction"
2985   },
2986   {
2987     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2988     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2989     GADGET_ID_CUSTOM_MOVE_STEPSIZE,             GADGET_ID_NONE,
2990     -1,
2991     options_move_stepsize,
2992     &custom_element.move_stepsize,
2993     NULL, "Move/fall speed", NULL,              "Select speed of element movement"
2994   },
2995   {
2996     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2997     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2998     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,           GADGET_ID_NONE,
2999     -1,
3000     options_move_leave_type,
3001     &custom_element.move_leave_type,
3002     // left text with leading spaces to place gadget next to "can dig" gadget
3003     // (needed because drawing area gadgets created after selectbox gadgets)
3004     // NULL, "can dig:    can", ":",            "leave behind or change element"
3005     NULL, "            Can", ":",               "Select leave behind or change element"
3006   },
3007   {
3008     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
3009     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
3010     GADGET_ID_CUSTOM_SMASH_TARGETS,             GADGET_ID_CUSTOM_CAN_SMASH,
3011     -1,
3012     options_smash_targets,
3013     &custom_element.smash_targets,
3014     NULL, "Can smash", NULL,                    "Select elements that can be smashed"
3015   },
3016   {
3017     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
3018     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
3019     GADGET_ID_CUSTOM_SLIPPERY_TYPE,             GADGET_ID_NONE,
3020     -1,
3021     options_slippery_type,
3022     &custom_element.slippery_type,
3023     NULL, "Slippery", NULL,                     "Select where other elements fall down"
3024   },
3025   {
3026     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
3027     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(10),
3028     GADGET_ID_CUSTOM_DEADLINESS,                GADGET_ID_NONE,
3029     -1,
3030     options_deadliness,
3031     &custom_element.deadliness,
3032     NULL, "Deadly when", NULL,                  "Select deadliness of element"
3033   },
3034   {
3035     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
3036     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(11),
3037     GADGET_ID_CUSTOM_EXPLOSION_TYPE,            GADGET_ID_NONE,
3038     -1,
3039     options_explosion_type,
3040     &custom_element.explosion_type,
3041     NULL, "Can explode", NULL,                  "Select explosion type"
3042   },
3043
3044   // ---------- element settings: advanced (custom elements) ------------------
3045
3046   {
3047     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
3048     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(3),
3049     GADGET_ID_CHANGE_TIME_UNITS,                GADGET_ID_NONE,
3050     -1,
3051     options_time_units,
3052     &custom_element_change.delay_frames,
3053     NULL, "Delay time given in", NULL,          "Select delay time units for change"
3054   },
3055   {
3056     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
3057     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(4),
3058     GADGET_ID_CHANGE_DIRECT_ACTION,             GADGET_ID_NONE,
3059     -1,
3060     options_change_direct_action,
3061     &custom_element_change.direct_action,
3062     NULL, NULL, NULL,                           "Select type of direct action"
3063   },
3064   {
3065     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3066     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(5),
3067     GADGET_ID_CHANGE_OTHER_ACTION,              GADGET_ID_NONE,
3068     -1,
3069     options_change_other_action,
3070     &custom_element_change.other_action,
3071     NULL, NULL, "element:",                     "Select type of other element action"
3072   },
3073   {
3074     ED_SELECTBOX_ID_CHANGE_SIDE,
3075     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(6),
3076     GADGET_ID_CHANGE_SIDE,                      GADGET_ID_NONE,
3077     -1,
3078     options_change_trigger_side,
3079     &custom_element_change.trigger_side,
3080     NULL, "at", "side",                         "Select element side triggering change"
3081   },
3082   {
3083     ED_SELECTBOX_ID_CHANGE_PLAYER,
3084     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3085     GADGET_ID_CHANGE_PLAYER,                    GADGET_ID_NONE,
3086     -1,
3087     options_change_trigger_player,
3088     &custom_element_change.trigger_player,
3089     NULL, "Player:", " ",                       "Select player that causes change"
3090   },
3091   {
3092     ED_SELECTBOX_ID_CHANGE_PAGE,
3093     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3094     GADGET_ID_CHANGE_PAGE,                      GADGET_ID_CHANGE_PLAYER,
3095     -1,
3096     options_change_trigger_page,
3097     &custom_element_change.trigger_page,
3098     NULL, "Page:", NULL,                        "Select change page that causes change"
3099   },
3100   {
3101     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3102     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(10),
3103     GADGET_ID_CHANGE_REPLACE_WHEN,              GADGET_ID_NONE,
3104     -1,
3105     options_change_replace_when,
3106     &custom_element_change.replace_when,
3107     NULL, "Replace when", NULL,                 "Select which elements can be replaced"
3108   },
3109   {
3110     ED_SELECTBOX_ID_ACTION_TYPE,
3111     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
3112     GADGET_ID_ACTION_TYPE,                      GADGET_ID_NONE,
3113     15,
3114     options_action_type,
3115     &custom_element_change.action_type,
3116     NULL, NULL, NULL,                           "Select action on specified condition"
3117   },
3118   {
3119     ED_SELECTBOX_ID_ACTION_MODE,
3120     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3121     GADGET_ID_ACTION_MODE,                      GADGET_ID_ACTION_TYPE,
3122     -1,
3123     options_action_mode_none,
3124     &custom_element_change.action_mode,
3125     NULL, NULL, NULL,                           "Select action operator"
3126   },
3127   {
3128     ED_SELECTBOX_ID_ACTION_ARG,
3129     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3130     GADGET_ID_ACTION_ARG,                       GADGET_ID_ACTION_MODE,
3131     -1,
3132     options_action_arg_none,
3133     &custom_element_change.action_arg,
3134     NULL, NULL, NULL,                           "Select action parameter"
3135   },
3136   {
3137     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3138     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
3139     GADGET_ID_SELECT_CHANGE_PAGE,               GADGET_ID_NONE,
3140     3,
3141     options_change_page,
3142     &custom_element.current_change_page,
3143     NULL, NULL, NULL,                           "Select element change page"
3144   },
3145
3146   // ---------- element settings: configure (group elements) ------------------
3147
3148   {
3149     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3150     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3151     GADGET_ID_GROUP_CHOICE_MODE,                GADGET_ID_NONE,
3152     -1,
3153     options_group_choice_mode,
3154     &group_element_info.choice_mode,
3155     NULL, "Choice type:", NULL,                 "Select type of group element choice"
3156   },
3157 };
3158
3159 static struct
3160 {
3161   int gadget_type_id;
3162   int x, y;
3163   int gadget_id;
3164   int gadget_id_align;
3165   int size;
3166   char *text;
3167   char *text_above, *text_left, *text_right, *infotext;
3168 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3169 {
3170   // ---------- level and editor settings (tabs) ------------------------------
3171
3172   {
3173     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3174     ED_LEVEL_TABS_XPOS(0),                      ED_LEVEL_TABS_YPOS(0),
3175     GADGET_ID_LEVELCONFIG_LEVEL,                GADGET_ID_NONE,
3176     8,                                          "Level",
3177     NULL, NULL, NULL,                           "Configure level settings"
3178   },
3179   {
3180     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3181     -1,                                         -1,
3182     GADGET_ID_LEVELCONFIG_LEVELSET,             GADGET_ID_LEVELCONFIG_LEVEL,
3183     8,                                          "Levelset",
3184     NULL, NULL, NULL,                           "Update this or create new level set"
3185   },
3186   {
3187     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3188     -1,                                         -1,
3189     GADGET_ID_LEVELCONFIG_EDITOR,               GADGET_ID_LEVELCONFIG_LEVELSET,
3190     8,                                          "Editor",
3191     NULL, NULL, NULL,                           "Configure editor settings"
3192   },
3193   {
3194     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3195     -1,                                         -1,
3196     GADGET_ID_LEVELCONFIG_ENGINE,               GADGET_ID_LEVELCONFIG_EDITOR,
3197     8,                                          "Engine",
3198     NULL, NULL, NULL,                           "Configure engine settings"
3199   },
3200
3201   // ---------- element settings (tabs) ---------------------------------------
3202
3203   {
3204     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3205     ED_ELEMENT_TABS_XPOS(0),                    ED_ELEMENT_TABS_YPOS(0),
3206     GADGET_ID_PROPERTIES_INFO,                  GADGET_ID_NONE,
3207     8,                                          "Info",
3208     NULL, NULL, NULL,                           "Show information about element"
3209   },
3210   {
3211     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3212     -1,                                         -1,
3213     GADGET_ID_PROPERTIES_CONFIG,                GADGET_ID_PROPERTIES_INFO,
3214     8,                                          "Config",
3215     NULL, NULL, NULL,                           "Configure element properties"
3216   },
3217   {
3218     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3219     -1,                                         -1,
3220     GADGET_ID_PROPERTIES_CONFIG_1,              GADGET_ID_PROPERTIES_INFO,
3221     8,                                          "Config 1",
3222     NULL, NULL, NULL,                           "Configure element properties, part 1"
3223   },
3224   {
3225     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3226     -1,                                         -1,
3227     GADGET_ID_PROPERTIES_CONFIG_2,              GADGET_ID_PROPERTIES_CONFIG_1,
3228     8,                                          "Config 2",
3229     NULL, NULL, NULL,                           "Configure element properties, part 2"
3230   },
3231   {
3232     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3233     -1,                                         -1,
3234     GADGET_ID_PROPERTIES_CHANGE,                GADGET_ID_PROPERTIES_CONFIG_2,
3235     8,                                          "Change",
3236     NULL, NULL, NULL,                           "Configure custom element change pages"
3237   },
3238
3239   // ---------- level and editor settings (buttons) ---------------------------
3240
3241   {
3242     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3243     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
3244     GADGET_ID_SAVE_LEVELSET,                    GADGET_ID_LEVELSET_SAVE_MODE,
3245     -1,                                         "Save",
3246     NULL, NULL, NULL,                           "Update or create level set"
3247   },
3248   {
3249     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3250     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3251     GADGET_ID_SAVE_AS_TEMPLATE_2,               GADGET_ID_NONE,
3252     -1,                                         "Save",
3253     NULL, NULL,                                 "this level as level template",
3254     "Save current settings as new template"
3255   },
3256
3257   // ---------- element settings (buttons) ------------------------------------
3258
3259   {
3260     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3261     -1,                                         -1,
3262     GADGET_ID_SAVE_AS_TEMPLATE_1,               GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3263     -1,                                         "Save",
3264     NULL, " ",                                  "As Template",
3265     "Save current settings as new template"
3266   },
3267   {
3268     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3269     -1,                                         -1,
3270     GADGET_ID_ADD_CHANGE_PAGE,                  GADGET_ID_PASTE_CHANGE_PAGE,
3271     -1,                                         "New",
3272     NULL, NULL, NULL,                           "Add new change page"
3273   },
3274   {
3275     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3276     -1,                                         -1,
3277     GADGET_ID_DEL_CHANGE_PAGE,                  GADGET_ID_ADD_CHANGE_PAGE,
3278     -1,                                         "Delete",
3279     NULL, NULL, NULL,                           "Delete current change page"
3280   },
3281 };
3282
3283 static struct
3284 {
3285   int gadget_type_id;
3286   int graphic;
3287   int x, y;
3288   int gadget_id;
3289   int gadget_id_align;
3290   char *text_left, *text_right, *infotext;
3291 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3292 {
3293   {
3294     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3295     IMG_EDITOR_COUNTER_DOWN,
3296     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3297     GADGET_ID_PREV_CHANGE_PAGE,                 GADGET_ID_NONE,
3298     NULL, NULL,                                 "Select previous change page"
3299   },
3300   {
3301     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3302     IMG_EDITOR_COUNTER_UP,
3303     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3304     GADGET_ID_NEXT_CHANGE_PAGE,                 GADGET_ID_SELECT_CHANGE_PAGE,
3305     NULL, "Change page",                        "Select next change page"
3306   },
3307   {
3308     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3309     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3310     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3311     GADGET_ID_COPY_CHANGE_PAGE,                 GADGET_ID_NEXT_CHANGE_PAGE,
3312     " ", NULL,                                  "Copy settings from this change page"
3313   },
3314   {
3315     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3316     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3317     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3318     GADGET_ID_PASTE_CHANGE_PAGE,                GADGET_ID_COPY_CHANGE_PAGE,
3319     NULL, NULL,                                 "Paste settings to this change page"
3320   },
3321 };
3322
3323 static struct
3324 {
3325   int x, y;
3326 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3327
3328 static struct
3329 {
3330   int gadget_type_id;
3331   int graphic;
3332   int gadget_id;
3333   char *infotext;
3334 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3335 {
3336   {
3337     ED_SCROLLBUTTON_ID_AREA_UP,
3338     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3339     GADGET_ID_SCROLL_UP,
3340     "Scroll level editing area up"
3341   },
3342   {
3343     ED_SCROLLBUTTON_ID_AREA_DOWN,
3344     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3345     GADGET_ID_SCROLL_DOWN,
3346     "Scroll level editing area down"
3347   },
3348   {
3349     ED_SCROLLBUTTON_ID_AREA_LEFT,
3350     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3351     GADGET_ID_SCROLL_LEFT,
3352     "Scroll level editing area left"
3353   },
3354   {
3355     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3356     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3357     GADGET_ID_SCROLL_RIGHT,
3358     "Scroll level editing area right"
3359   },
3360   {
3361     ED_SCROLLBUTTON_ID_LIST_UP,
3362     IMG_EDITOR_PALETTE_SCROLL_UP,
3363     GADGET_ID_SCROLL_LIST_UP,
3364     "Scroll element list up ('Page Up')"
3365   },
3366   {
3367     ED_SCROLLBUTTON_ID_LIST_DOWN,
3368     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3369     GADGET_ID_SCROLL_LIST_DOWN,
3370     "Scroll element list down ('Page Down')"
3371   },
3372 };
3373
3374 static struct
3375 {
3376   int x, y;
3377   int width, height;
3378   int wheel_x, wheel_y;
3379   int wheel_width, wheel_height;
3380 } scrollbar_pos[ED_NUM_SCROLLBARS];
3381
3382 static struct
3383 {
3384   int gadget_type_id;
3385   int graphic;
3386   int type;
3387   int gadget_id;
3388   char *infotext;
3389 } scrollbar_info[ED_NUM_SCROLLBARS] =
3390 {
3391   {
3392     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3393     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3394     GD_TYPE_SCROLLBAR_HORIZONTAL,
3395     GADGET_ID_SCROLL_HORIZONTAL,
3396     "Scroll level editing area horizontally"
3397   },
3398   {
3399     ED_SCROLLBAR_ID_AREA_VERTICAL,
3400     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3401     GD_TYPE_SCROLLBAR_VERTICAL,
3402     GADGET_ID_SCROLL_VERTICAL,
3403     "Scroll level editing area vertically"
3404   },
3405   {
3406     ED_SCROLLBAR_ID_LIST_VERTICAL,
3407     IMG_EDITOR_PALETTE_SCROLLBAR,
3408     GD_TYPE_SCROLLBAR_VERTICAL,
3409     GADGET_ID_SCROLL_LIST_VERTICAL,
3410     "Scroll element list vertically"
3411   }
3412 };
3413
3414
3415 static struct
3416 {
3417   int gadget_type_id;
3418   int x, y;
3419   int gadget_id;
3420   int gadget_id_align;
3421   int radio_button_nr;
3422   int *value;
3423   int checked_value;
3424   char *text_left, *text_right, *infotext;
3425 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3426 {
3427   {
3428     ED_RADIOBUTTON_ID_PERCENTAGE,
3429     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3430     GADGET_ID_RANDOM_PERCENTAGE,                GADGET_ID_LEVEL_RANDOM_UP,
3431     RADIO_NR_RANDOM_ELEMENTS,
3432     &random_placement_method,                   RANDOM_USE_PERCENTAGE,
3433     " ", "percentage",                          "Use percentage for random elements"
3434   },
3435   {
3436     ED_RADIOBUTTON_ID_QUANTITY,
3437     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3438     GADGET_ID_RANDOM_QUANTITY,                  GADGET_ID_RANDOM_PERCENTAGE,
3439     RADIO_NR_RANDOM_ELEMENTS,
3440     &random_placement_method,                   RANDOM_USE_QUANTITY,
3441     " ", "quantity",                            "Use quantity for random elements"
3442   }
3443 };
3444
3445 static struct
3446 {
3447   int gadget_type_id;
3448   int x, y;
3449   int gadget_id;
3450   int gadget_id_align;
3451   boolean *value;
3452   char *text_above, *text_left, *text_right, *infotext;
3453 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3454 {
3455   // ---------- level and editor settings -------------------------------------
3456
3457   {
3458     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3459     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3460     GADGET_ID_AUTO_COUNT_GEMS,                  GADGET_ID_NONE,
3461     &level.auto_count_gems,
3462     NULL, NULL,
3463     "Automatically count gems needed",          "Set counter to number of gems"
3464   },
3465   {
3466     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3467     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(11),
3468     GADGET_ID_RATE_TIME_OVER_SCORE,             GADGET_ID_NONE,
3469     &level.rate_time_over_score,
3470     NULL, NULL,
3471     "Rate time/steps used over score",          "Sort high scores by playing time/steps"
3472   },
3473   {
3474     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3475     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3476     GADGET_ID_USE_LEVELSET_ARTWORK,             GADGET_ID_NONE,
3477     &levelset_use_levelset_artwork,
3478     NULL, NULL,
3479     "Use current custom artwork",               "Use custom artwork of this level set"
3480   },
3481   {
3482     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3483     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3484     GADGET_ID_COPY_LEVEL_TEMPLATE,              GADGET_ID_NONE,
3485     &levelset_copy_level_template,
3486     NULL, NULL,
3487     "Copy current level template",              "Copy level template of this level set"
3488   },
3489   {
3490     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3491     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
3492     GADGET_ID_RANDOM_RESTRICTED,                GADGET_ID_NONE,
3493     &random_placement_background_restricted,
3494     NULL, NULL,
3495     "Restrict random placement to:",            "Set random placement restriction"
3496   },
3497   {
3498     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3499     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
3500     GADGET_ID_CUSTOM_USE_TEMPLATE_3,            GADGET_ID_NONE,
3501     &setup.editor.use_template_for_new_levels,
3502     "Template for new levels and CE/GE:", NULL,
3503     "Use template for new levels",              "Use template for level properties"
3504   },
3505   {
3506     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3507     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
3508     GADGET_ID_CUSTOM_USE_TEMPLATE_2,            GADGET_ID_NONE,
3509     &level.use_custom_template,
3510     NULL, NULL,
3511     "Use template for custom elements",         "Use template for custom properties"
3512   },
3513   {
3514     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3515     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
3516     GADGET_ID_BD_INTERMISSION,                  GADGET_ID_NONE,
3517     &level.bd_intermission,
3518     "Boulder Dash game engine settings:", NULL,
3519     "Intermission",                             "Level is an intermission level"
3520   },
3521   {
3522     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3523     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
3524     GADGET_ID_BD_PAL_TIMING,                    GADGET_ID_NONE,
3525     &level.bd_pal_timing,
3526     NULL, NULL,
3527     "PAL timing",                               "Use slower timer (like PAL C64)"
3528   },
3529   {
3530     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3531     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3532     GADGET_ID_BD_LINE_SHIFTING_BORDERS,         GADGET_ID_NONE,
3533     &level.bd_line_shifting_borders,
3534     "Compatibility settings:", NULL,
3535     "Line-shifting borders",                    "Use line-shifting wrap-around"
3536   },
3537   {
3538     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3539     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3540     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,       GADGET_ID_NONE,
3541     &level.bd_scan_first_and_last_row,
3542     NULL, NULL,
3543     "Scan first and last row",                  "Also process top/bottom border rows"
3544   },
3545   {
3546     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3547     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3548     GADGET_ID_BD_SHORT_EXPLOSIONS,              GADGET_ID_NONE,
3549     &level.bd_short_explosions,
3550     NULL, NULL,
3551     "Short explosions",                         "Use four game cycles for explosions"
3552   },
3553
3554   // ---------- element settings: configure (various elements) ----------------
3555
3556   {
3557     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3558     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3559     GADGET_ID_STICK_ELEMENT,                    GADGET_ID_NONE,
3560     &stick_element_properties_window,
3561     NULL, NULL,
3562     "Stick this screen to edit content",        "Stick this screen to edit content"
3563   },
3564   {
3565     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3566     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3567     GADGET_ID_EM_SLIPPERY_GEMS,                 GADGET_ID_NONE,
3568     &level.em_slippery_gems,
3569     NULL, NULL,
3570     "Slip down from certain flat walls",        "Use EM/DC style slipping behaviour"
3571   },
3572   {
3573     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3574     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3575     GADGET_ID_EM_EXPLODES_BY_FIRE,              GADGET_ID_NONE,
3576     &level.em_explodes_by_fire,
3577     NULL, NULL,
3578     "Explodes with chain reaction",             "Use R'n'D style explosion behaviour"
3579   },
3580   {
3581     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3582     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3583     GADGET_ID_USE_SPRING_BUG,                   GADGET_ID_NONE,
3584     &level.use_spring_bug,
3585     NULL, NULL,
3586     "Use spring pushing bug",                   "Use odd spring pushing behaviour"
3587   },
3588   {
3589     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3590     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3591     GADGET_ID_USE_TIME_ORB_BUG,                 GADGET_ID_NONE,
3592     &level.use_time_orb_bug,
3593     NULL, NULL,
3594     "Use time orb bug",                         "Use odd time orb behaviour"
3595   },
3596   {
3597     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3598     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3599     GADGET_ID_USE_LIFE_BUGS,                    GADGET_ID_NONE,
3600     &level.use_life_bugs,
3601     NULL, NULL,
3602     "Use buggy element behaviour",              "Use odd (historic) element behaviour"
3603   },
3604   {
3605     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3606     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3607     GADGET_ID_RANDOM_BALL_CONTENT,              GADGET_ID_NONE,
3608     &level.ball_random,
3609     NULL, NULL,
3610     "Create single random element",             "Only create one element from content"
3611   },
3612   {
3613     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3614     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3615     GADGET_ID_INITIAL_BALL_ACTIVE,              GADGET_ID_NONE,
3616     &level.ball_active_initial,
3617     NULL, NULL,
3618     "Magic ball initially activated",           "Activate magic ball after level start"
3619   },
3620   {
3621     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3622     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3623     GADGET_ID_GROW_INTO_DIGGABLE,               GADGET_ID_NONE,
3624     &level.grow_into_diggable,
3625     NULL, NULL,
3626     "Can grow into anything diggable",          "Grow into more than just sand"
3627   },
3628   {
3629     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3630     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3631     GADGET_ID_SB_FIELDS_NEEDED,                 GADGET_ID_NONE,
3632     &level.sb_fields_needed,
3633     NULL, NULL,
3634     "All fields need to be filled",             "Require all SB fields to be solved"
3635   },
3636   {
3637     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3638     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3639     GADGET_ID_SB_OBJECTS_NEEDED,                GADGET_ID_NONE,
3640     &level.sb_objects_needed,
3641     NULL, NULL,
3642     "All objects need to be placed",            "Require all SB objects to be solved"
3643   },
3644   {
3645     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3646     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3647     GADGET_ID_AUTO_EXIT_SOKOBAN,                GADGET_ID_NONE,
3648     &level.auto_exit_sokoban,
3649     NULL, NULL,
3650     "Exit level if all tasks solved",           "Automatically finish Sokoban levels"
3651   },
3652   {
3653     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3654     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3655     GADGET_ID_SOLVED_BY_ONE_PLAYER,             GADGET_ID_NONE,
3656     &level.solved_by_one_player,
3657     NULL, NULL,
3658     "Only one player must enter exit",          "Level solved by first player in exit"
3659   },
3660   {
3661     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3662     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3663     GADGET_ID_FINISH_DIG_COLLECT,               GADGET_ID_NONE,
3664     &level.finish_dig_collect,
3665     NULL, NULL,
3666     "CE action on finished dig/collect",        "Only finished dig/collect triggers CE"
3667   },
3668   {
3669     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3670     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3671     GADGET_ID_KEEP_WALKABLE_CE,                 GADGET_ID_NONE,
3672     &level.keep_walkable_ce,
3673     NULL, NULL,
3674     "Keep walkable CE changed to player",       "Keep CE changing to player if walkable"
3675   },
3676   {
3677     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3678     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3679     GADGET_ID_CONTINUOUS_SNAPPING,              GADGET_ID_NONE,
3680     &level.continuous_snapping,
3681     NULL, NULL,
3682     "Continuous snapping",                      "Use snapping without releasing key"
3683   },
3684   {
3685     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3686     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
3687     GADGET_ID_BLOCK_SNAP_FIELD,                 GADGET_ID_NONE,
3688     &level.block_snap_field,
3689     NULL, NULL,
3690     "Block snapped field when snapping",        "Use snapping delay to show animation"
3691   },
3692   {
3693     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3694     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3695     GADGET_ID_BLOCK_LAST_FIELD,                 GADGET_ID_NONE,
3696     &level.block_last_field,
3697     NULL, NULL,
3698     "Block last field when moving",             "Player blocks last field when moving"
3699   },
3700   {
3701     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3702     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3703     GADGET_ID_SP_BLOCK_LAST_FIELD,              GADGET_ID_NONE,
3704     &level.sp_block_last_field,
3705     NULL, NULL,
3706     "Block last field when moving",             "Player blocks last field when moving"
3707   },
3708   {
3709     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3710     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3711     GADGET_ID_INSTANT_RELOCATION,               GADGET_ID_NONE,
3712     &level.instant_relocation,
3713     NULL, NULL,
3714     "No scrolling when relocating",             "Player gets relocated without delay"
3715   },
3716   {
3717     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3718     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3719     GADGET_ID_SHIFTED_RELOCATION,               GADGET_ID_NONE,
3720     &level.shifted_relocation,
3721     NULL, NULL,
3722     "No centering when relocating",             "Level not centered after relocation"
3723   },
3724   {
3725     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3726     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3727     GADGET_ID_LAZY_RELOCATION,                  GADGET_ID_NONE,
3728     &level.lazy_relocation,
3729     NULL, NULL,
3730     "Only redraw off-screen relocation",        "No redraw if relocation target visible"
3731   },
3732   {
3733     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3734     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
3735     GADGET_ID_USE_START_ELEMENT,                GADGET_ID_NONE,
3736     &level.use_start_element[0],
3737     NULL, NULL,
3738     "Use level start element:",                "Start level at this element's position"
3739   },
3740   {
3741     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3742     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
3743     GADGET_ID_USE_ARTWORK_ELEMENT,              GADGET_ID_NONE,
3744     &level.use_artwork_element[0],
3745     NULL, NULL,
3746     "Use artwork from element:",                "Use player artwork from other element"
3747   },
3748   {
3749     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3750     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(12),
3751     GADGET_ID_USE_EXPLOSION_ELEMENT,            GADGET_ID_NONE,
3752     &level.use_explosion_element[0],
3753     NULL, NULL,
3754     "Use explosion from element:",              "Use explosion properties from element"
3755   },
3756   {
3757     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3758     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
3759     GADGET_ID_INITIAL_GRAVITY,                  GADGET_ID_NONE,
3760     &level.initial_player_gravity[0],
3761     NULL, NULL,
3762     "Use initial gravity",                      "Set initial player gravity"
3763   },
3764   {
3765     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3766     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3767     GADGET_ID_USE_INITIAL_INVENTORY,            GADGET_ID_NONE,
3768     &level.use_initial_inventory[0],
3769     NULL, NULL,
3770     "Use initial inventory:",                   "Use collected elements on level start"
3771   },
3772   {
3773     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3774     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
3775     GADGET_ID_CAN_PASS_TO_WALKABLE,             GADGET_ID_NONE,
3776     &level.can_pass_to_walkable,
3777     NULL, NULL,
3778     "Can pass to walkable element",             "Player can pass to empty or walkable"
3779   },
3780   {
3781     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3782     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3783     GADGET_ID_CAN_FALL_INTO_ACID,               GADGET_ID_NONE,
3784     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3785     NULL, NULL,
3786     "Can fall into acid (with gravity)",        "Player can fall into acid pool"
3787   },
3788   {
3789     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3790     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3791     GADGET_ID_CAN_MOVE_INTO_ACID,               GADGET_ID_NONE,
3792     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3793     NULL, NULL,
3794     "Can move into acid",                       "Element can move into acid pool"
3795   },
3796   {
3797     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3798     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3799     GADGET_ID_DONT_COLLIDE_WITH,                GADGET_ID_NONE,
3800     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3801     NULL, NULL,
3802     "Deadly when colliding with",               "Element is deadly when hitting player"
3803   },
3804   {
3805     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3806     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3807     GADGET_ID_BD_DIAGONAL_MOVEMENTS,            GADGET_ID_NONE,
3808     &level.bd_diagonal_movements,
3809     NULL, NULL,
3810     "Can move diagonally",                      "Player can move diagonally"
3811   },
3812   {
3813     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3814     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3815     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,         GADGET_ID_NONE,
3816     &level.bd_topmost_player_active,
3817     NULL, NULL,
3818     "Topmost player is active",                 "Use first player found on playfield"
3819   },
3820   {
3821     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3822     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3823     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,     GADGET_ID_NONE,
3824     &level.bd_push_mega_rock_with_sweet,
3825     NULL, NULL,
3826     "Mega rocks pushable with sweet",           "Push mega rocks after eating sweet"
3827   },
3828   {
3829     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
3830     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3831     GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,      GADGET_ID_NONE,
3832     &level.bd_magic_wall_zero_infinite,
3833     NULL, NULL,
3834     "Run forever if duration is zero",          "Run infinitely if timer is zero"
3835   },
3836   {
3837     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3838     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3839     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,      GADGET_ID_NONE,
3840     &level.bd_magic_wall_wait_hatching,
3841     NULL, NULL,
3842     "Wait for player's birth",                  "Timer start waits for player's birth"
3843   },
3844   {
3845     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3846     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3847     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,       GADGET_ID_NONE,
3848     &level.bd_magic_wall_stops_amoeba,
3849     NULL, NULL,
3850     "Stop amoeba and turn to diamonds",         "Activation changes amoeba to diamonds"
3851   },
3852   {
3853     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3854     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3855     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,      GADGET_ID_NONE,
3856     &level.bd_amoeba_wait_for_hatching,
3857     NULL, NULL,
3858     "Wait for player's birth",                  "Timer start waits for player's birth"
3859   },
3860   {
3861     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3862     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3863     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,      GADGET_ID_NONE,
3864     &level.bd_amoeba_start_immediately,
3865     NULL, NULL,
3866     "Start growing immediately",                "Start slow growth time immediately"
3867   },
3868   {
3869     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3870     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3871     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,    GADGET_ID_NONE,
3872     &level.bd_amoeba_2_explode_by_amoeba,
3873     NULL, NULL,
3874     "Explodes if touched by amoeba",            "Amoeba 2 explodes if touched by amoeba"
3875   },
3876   {
3877     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3878     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3879     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,      GADGET_ID_NONE,
3880     &level.bd_voodoo_collects_diamonds,
3881     NULL, NULL,
3882     "Can collect diamonds",                     "Can collect diamonds for the player"
3883   },
3884   {
3885     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3886     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3887     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,      GADGET_ID_NONE,
3888     &level.bd_voodoo_hurt_kills_player,
3889     NULL, NULL,
3890     "Player is killed if hurt",                 "If hurt in any way, player is killed"
3891   },
3892   {
3893     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3894     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3895     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,           GADGET_ID_NONE,
3896     &level.bd_voodoo_dies_by_rock,
3897     NULL, NULL,
3898     "Killed by falling rock",                   "Can be killed by a falling rock"
3899   },
3900   {
3901     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3902     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3903     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,    GADGET_ID_NONE,
3904     &level.bd_voodoo_vanish_by_explosion,
3905     NULL, NULL,
3906     "Disappears in explosions",                 "Can be destroyed by explosions"
3907   },
3908   {
3909     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3910     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3911     GADGET_ID_BD_SLIME_IS_PREDICTABLE,          GADGET_ID_NONE,
3912     &level.bd_slime_is_predictable,
3913     NULL, NULL,
3914     "Slime is predictable",                     "Use predictable random numbers"
3915   },
3916   {
3917     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3918     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3919     GADGET_ID_BD_CHANGE_EXPANDING_WALL,         GADGET_ID_NONE,
3920     &level.bd_change_expanding_wall,
3921     NULL, NULL,
3922     "Change direction",                         "Switch horizontal/vertical direction"
3923   },
3924   {
3925     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3926     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3927     GADGET_ID_BD_REPLICATORS_ACTIVE,            GADGET_ID_NONE,
3928     &level.bd_replicators_active,
3929     NULL, NULL,
3930     "Active at start",                          "Replicators start in active state"
3931   },
3932   {
3933     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3934     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3935     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,         GADGET_ID_NONE,
3936     &level.bd_conveyor_belts_active,
3937     NULL, NULL,
3938     "Active at start",                          "Conveyor belts start in active state"
3939   },
3940   {
3941     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3942     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3943     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,        GADGET_ID_NONE,
3944     &level.bd_conveyor_belts_changed,
3945     NULL, NULL,
3946     "Change direction",                         "Switch conveyor belt direction"
3947   },
3948   {
3949     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3950     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3951     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,        GADGET_ID_NONE,
3952     &level.bd_water_cannot_flow_down,
3953     NULL, NULL,
3954     "Does not flow downwards",                  "Water can only flow up, left and right"
3955   },
3956   {
3957     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3958     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3959     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,         GADGET_ID_NONE,
3960     &level.bd_hammer_walls_reappear,
3961     NULL, NULL,
3962     "Hammered walls reappear",                  "Hammered walls reappear after delay"
3963   },
3964   {
3965     ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
3966     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3967     GADGET_ID_BD_INFINITE_ROCKETS,              GADGET_ID_NONE,
3968     &level.bd_infinite_rockets,
3969     NULL, NULL,
3970     "Infinite rockets",                         "Rocket launcher has infinite rockets"
3971   },
3972   {
3973     ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
3974     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3975     GADGET_ID_BD_CREATURES_START_BACKWARDS,     GADGET_ID_NONE,
3976     &level.bd_creatures_start_backwards,
3977     NULL, NULL,
3978     "Creatures start moving backwards",         "Creatures start in opposite direction"
3979   },
3980   {
3981     ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
3982     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3983     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3984     &level.bd_creatures_turn_on_hatching,
3985     NULL, NULL,
3986     "Creatures auto turn on hatching",          "Creatures change direction on hatching"
3987   },
3988   {
3989     ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
3990     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3991     GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,         GADGET_ID_NONE,
3992     &level.bd_gravity_switch_active,
3993     NULL, NULL,
3994     "Gravity switch active at start",           "Gravity switch starts in active state"
3995   },
3996   {
3997     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
3998     ED_LEVEL_SETTINGS_XPOS(0),                  ED_ELEMENT_SETTINGS_YPOS(3),
3999     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,           GADGET_ID_NONE,
4000     &level.bd_gravity_affects_all,
4001     NULL, NULL,
4002     "Gravity change affects everything",        "Gravity affects all falling objects"
4003   },
4004   {
4005     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
4006     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4007     GADGET_ID_ENVELOPE_AUTOWRAP,                GADGET_ID_NONE,
4008     &level.envelope[0].autowrap,
4009     NULL, NULL,
4010     "Auto-wrap",                                "Automatically wrap envelope text"
4011   },
4012   {
4013     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
4014     -1,                                         ED_ELEMENT_SETTINGS_YPOS(1),
4015     GADGET_ID_ENVELOPE_CENTERED,                GADGET_ID_ENVELOPE_AUTOWRAP,
4016     &level.envelope[0].centered,
4017     NULL, " ",
4018     "Centered",                                 "Automatically center envelope text"
4019   },
4020   {
4021     ED_CHECKBUTTON_ID_MM_LASER_RED,
4022     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4023     GADGET_ID_MM_LASER_RED,                     GADGET_ID_NONE,
4024     &level.mm_laser_red,
4025     "Choose color components for laser:", NULL,
4026     "Red",                                      "Use red color components in laser"
4027   },
4028   {
4029     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
4030     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4031     GADGET_ID_MM_LASER_GREEN,                   GADGET_ID_NONE,
4032     &level.mm_laser_green,
4033     NULL, NULL,
4034     "Green",                                    "Use green color components in laser"
4035   },
4036   {
4037     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
4038     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4039     GADGET_ID_MM_LASER_BLUE,                    GADGET_ID_NONE,
4040     &level.mm_laser_blue,
4041     NULL, NULL,
4042     "Blue",                                     "Use blue color components in laser"
4043   },
4044   {
4045     ED_CHECKBUTTON_ID_DF_LASER_RED,
4046     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4047     GADGET_ID_DF_LASER_RED,                     GADGET_ID_NONE,
4048     &level.df_laser_red,
4049     "Choose color components for laser:", NULL,
4050     "Red",                                      "Use red color components in laser"
4051   },
4052   {
4053     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
4054     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4055     GADGET_ID_DF_LASER_GREEN,                   GADGET_ID_NONE,
4056     &level.df_laser_green,
4057     NULL, NULL,
4058     "Green",                                    "Use green color components in laser"
4059   },
4060   {
4061     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
4062     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4063     GADGET_ID_DF_LASER_BLUE,                    GADGET_ID_NONE,
4064     &level.df_laser_blue,
4065     NULL, NULL,
4066     "Blue",                                     "Use blue color components in laser"
4067   },
4068   {
4069     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
4070     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
4071     GADGET_ID_ROTATE_MM_BALL_CONTENT,           GADGET_ID_NONE,
4072     &level.rotate_mm_ball_content,
4073     NULL, NULL,
4074     "Randomly rotate created content",          "Randomly rotate newly created content"
4075   },
4076   {
4077     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
4078     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
4079     GADGET_ID_EXPLODE_MM_BALL,                  GADGET_ID_NONE,
4080     &level.explode_mm_ball,
4081     NULL, NULL,
4082     "Explode ball instead of melting",          "Use explosion to release ball content"
4083   },
4084
4085   // ---------- element settings: configure 1 (custom elements) ---------------
4086
4087   {
4088     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
4089     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4090     GADGET_ID_CUSTOM_USE_GRAPHIC,               GADGET_ID_NONE,
4091     &custom_element.use_gfx_element,
4092     NULL, NULL,
4093     "Use graphic of element:",                  "Use existing element graphic"
4094   },
4095   {
4096     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
4097     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
4098     GADGET_ID_CUSTOM_USE_TEMPLATE_1,            GADGET_ID_NONE,
4099     &level.use_custom_template,
4100     NULL, NULL,
4101     "Use template",                             "Use template for custom properties"
4102   },
4103   {
4104     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4105     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4106     GADGET_ID_CUSTOM_ACCESSIBLE,                GADGET_ID_NONE,
4107     &custom_element_properties[EP_ACCESSIBLE],
4108     NULL, NULL,
4109     NULL,                                       "Player can walk to or pass this field"
4110   },
4111   {
4112     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4113     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4114     GADGET_ID_CUSTOM_GRAV_REACHABLE,            GADGET_ID_NONE,
4115     &custom_element_properties[EP_GRAVITY_REACHABLE],
4116     NULL, NULL,
4117     "Reachable despite gravity",                "Player can walk/dig despite gravity"
4118   },
4119   {
4120     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4121     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4122     GADGET_ID_CUSTOM_USE_LAST_VALUE,            GADGET_ID_NONE,
4123     &custom_element.use_last_ce_value,
4124     NULL, NULL,
4125     "Use last CE value after change",           "Use last CE value after change"
4126   },
4127   {
4128     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4129     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
4130     GADGET_ID_CUSTOM_WALK_TO_OBJECT,            GADGET_ID_NONE,
4131     &custom_element_properties[EP_WALK_TO_OBJECT],
4132     NULL, NULL,
4133     NULL,                                       "Player can dig/collect/push element"
4134   },
4135   {
4136     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4137     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4138     GADGET_ID_CUSTOM_INDESTRUCTIBLE,            GADGET_ID_NONE,
4139     &custom_element_properties[EP_INDESTRUCTIBLE],
4140     NULL, NULL,
4141     "Indestructible",                           "Element is indestructible"
4142   },
4143
4144   // ---------- element settings: configure 2 (custom elements) ---------------
4145
4146   {
4147     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4148     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4149     GADGET_ID_CUSTOM_CAN_MOVE,                  GADGET_ID_NONE,
4150     &custom_element_properties[EP_CAN_MOVE],
4151     NULL, NULL,
4152     NULL,                                       "Element can move with some pattern"
4153   },
4154   {
4155     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4156     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4157     GADGET_ID_CUSTOM_CAN_FALL,                  GADGET_ID_NONE,
4158     &custom_element_properties[EP_CAN_FALL],
4159     NULL, NULL,
4160     "Can fall",                                 "Element can fall down"
4161   },
4162   {
4163     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4164     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
4165     GADGET_ID_CUSTOM_CAN_SMASH,                 GADGET_ID_CUSTOM_CAN_FALL,
4166     &custom_element_properties[EP_CAN_SMASH],
4167     NULL, " ",
4168     NULL,                                       "Element can smash other elements"
4169   },
4170   {
4171     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4172     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4173     GADGET_ID_CUSTOM_SLIPPERY,                  GADGET_ID_NONE,
4174     &custom_element_properties[EP_SLIPPERY],
4175     NULL, NULL,
4176     NULL,                                       "Other elements can fall down from it"
4177   },
4178   {
4179     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4180     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
4181     GADGET_ID_CUSTOM_DEADLY,                    GADGET_ID_NONE,
4182     &custom_element_properties[EP_DEADLY],
4183     NULL, NULL,
4184     NULL,                                       "Element can kill the player"
4185   },
4186   {
4187     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4188     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4189     GADGET_ID_CUSTOM_CAN_EXPLODE,               GADGET_ID_NONE,
4190     &custom_element_properties[EP_CAN_EXPLODE],
4191     NULL, NULL,
4192     NULL,                                       "Element can explode"
4193   },
4194   {
4195     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4196     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(12),
4197     GADGET_ID_CUSTOM_EXPLODE_FIRE,              GADGET_ID_NONE,
4198     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4199     NULL, NULL,
4200     "By fire",                                  "Element can explode by fire/explosion"
4201   },
4202   {
4203     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4204     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4205     GADGET_ID_CUSTOM_EXPLODE_SMASH,             GADGET_ID_CUSTOM_EXPLODE_FIRE,
4206     &custom_element_properties[EP_EXPLODES_SMASHED],
4207     NULL, " ",
4208     "Smashed",                                  "Element can explode when smashed"
4209   },
4210   {
4211     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4212     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4213     GADGET_ID_CUSTOM_EXPLODE_IMPACT,            GADGET_ID_CUSTOM_EXPLODE_SMASH,
4214     &custom_element_properties[EP_EXPLODES_IMPACT],
4215     NULL, " ",
4216     "Impact",                                   "Element can explode on impact"
4217   },
4218
4219   // ---------- element settings: advanced (custom elements) ------------------
4220
4221   {
4222     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4223     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4224     GADGET_ID_CUSTOM_CAN_CHANGE,                GADGET_ID_NONE,
4225     &custom_element_change.can_change,
4226     NULL, NULL,
4227     "Element changes to:",                      "Change element on specified condition"
4228   },
4229   {
4230     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4231     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
4232     GADGET_ID_CHANGE_DELAY,                     GADGET_ID_NONE,
4233     &custom_element_change_events[CE_DELAY],
4234     NULL, NULL,
4235     NULL,                                       "Element changes after delay"
4236   },
4237   {
4238     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4239     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
4240     GADGET_ID_CHANGE_BY_DIRECT_ACT,             GADGET_ID_NONE,
4241     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4242     NULL, NULL,
4243     NULL,                                       "Element changes by direct action"
4244   },
4245   {
4246     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4247     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
4248     GADGET_ID_CHANGE_BY_OTHER_ACT,              GADGET_ID_NONE,
4249     &custom_element_change_events[CE_BY_OTHER_ACTION],
4250     NULL, NULL,
4251     NULL,                                       "Element changes by other element"
4252   },
4253   {
4254     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4255     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(8),
4256     GADGET_ID_CHANGE_USE_EXPLOSION,             GADGET_ID_NONE,
4257     &custom_element_change.explode,
4258     NULL, NULL,
4259     "Explode instead of change",                "Element explodes instead of change"
4260   },
4261   {
4262     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4263     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
4264     GADGET_ID_CHANGE_USE_CONTENT,               GADGET_ID_NONE,
4265     &custom_element_change.use_target_content,
4266     NULL, NULL,
4267     "Use extended change target:",              "Element changes to more elements"
4268   },
4269   {
4270     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4271     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(11),
4272     GADGET_ID_CHANGE_ONLY_COMPLETE,             GADGET_ID_NONE,
4273     &custom_element_change.only_if_complete,
4274     NULL, NULL,
4275     "Replace all or nothing",                   "Only replace when all can be changed"
4276   },
4277   {
4278     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4279     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(12),
4280     GADGET_ID_CHANGE_USE_RANDOM,                GADGET_ID_NONE,
4281     &custom_element_change.use_random_replace,
4282     NULL, NULL,
4283     NULL,                                       "Use percentage for random replace"
4284   },
4285   {
4286     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4287     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
4288     GADGET_ID_CHANGE_HAS_ACTION,                GADGET_ID_NONE,
4289     &custom_element_change.has_action,
4290     NULL, NULL,
4291     NULL,                                       "Execute action on specified condition"
4292   },
4293 };
4294
4295 static struct
4296 {
4297   int gadget_type_id;
4298   int x, y;
4299   int xoffset, yoffset;
4300   int gadget_id;
4301   int gadget_id_align;
4302   int *value;
4303   int area_xsize, area_ysize;
4304   char *text_left, *text_right, *text_above, *text_below, *infotext;
4305 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4306 {
4307   // ---------- level playfield content ---------------------------------------
4308
4309   {
4310     ED_DRAWING_ID_DRAWING_LEVEL,
4311     0,                                          0,
4312     0,                                          0,
4313     GADGET_ID_DRAWING_LEVEL,                    GADGET_ID_NONE,
4314     NULL,
4315     -1, -1,     // these values are not constant, but can change at runtime
4316     NULL, NULL, NULL, NULL,                     NULL
4317   },
4318
4319   // ---------- yam yam content -----------------------------------------------
4320
4321   {
4322     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4323     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4324     ED_AREA_YAMYAM_CONTENT_XOFF(0),             ED_AREA_YAMYAM_CONTENT_YOFF(0),
4325     GADGET_ID_YAMYAM_CONTENT_0,                 GADGET_ID_NONE,
4326     &level.yamyam_content[0].e[0][0],           3, 3,
4327     NULL, NULL, NULL, "1",                      NULL
4328   },
4329   {
4330     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4331     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4332     ED_AREA_YAMYAM_CONTENT_XOFF(1),             ED_AREA_YAMYAM_CONTENT_YOFF(1),
4333     GADGET_ID_YAMYAM_CONTENT_1,                 GADGET_ID_NONE,
4334     &level.yamyam_content[1].e[0][0],           3, 3,
4335     NULL, NULL, NULL, "2",                      NULL
4336   },
4337   {
4338     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4339     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4340     ED_AREA_YAMYAM_CONTENT_XOFF(2),             ED_AREA_YAMYAM_CONTENT_YOFF(2),
4341     GADGET_ID_YAMYAM_CONTENT_2,                 GADGET_ID_NONE,
4342     &level.yamyam_content[2].e[0][0],           3, 3,
4343     NULL, NULL, NULL, "3",                      NULL
4344   },
4345   {
4346     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4347     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4348     ED_AREA_YAMYAM_CONTENT_XOFF(3),             ED_AREA_YAMYAM_CONTENT_YOFF(3),
4349     GADGET_ID_YAMYAM_CONTENT_3,                 GADGET_ID_NONE,
4350     &level.yamyam_content[3].e[0][0],           3, 3,
4351     NULL, NULL, NULL, "4",                      NULL
4352   },
4353   {
4354     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4355     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4356     ED_AREA_YAMYAM_CONTENT_XOFF(4),             ED_AREA_YAMYAM_CONTENT_YOFF(4),
4357     GADGET_ID_YAMYAM_CONTENT_4,                 GADGET_ID_NONE,
4358     &level.yamyam_content[4].e[0][0],           3, 3,
4359     NULL, NULL, NULL, "5",                      NULL
4360   },
4361   {
4362     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4363     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4364     ED_AREA_YAMYAM_CONTENT_XOFF(5),             ED_AREA_YAMYAM_CONTENT_YOFF(5),
4365     GADGET_ID_YAMYAM_CONTENT_5,                 GADGET_ID_NONE,
4366     &level.yamyam_content[5].e[0][0],           3, 3,
4367     NULL, NULL, NULL, "6",                      NULL
4368   },
4369   {
4370     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4371     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4372     ED_AREA_YAMYAM_CONTENT_XOFF(6),             ED_AREA_YAMYAM_CONTENT_YOFF(6),
4373     GADGET_ID_YAMYAM_CONTENT_6,                 GADGET_ID_NONE,
4374     &level.yamyam_content[6].e[0][0],           3, 3,
4375     NULL, NULL, NULL, "7",                      NULL
4376   },
4377   {
4378     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4379     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4380     ED_AREA_YAMYAM_CONTENT_XOFF(7),             ED_AREA_YAMYAM_CONTENT_YOFF(7),
4381     GADGET_ID_YAMYAM_CONTENT_7,                 GADGET_ID_NONE,
4382     &level.yamyam_content[7].e[0][0],           3, 3,
4383     NULL, NULL, NULL, "8",                      NULL
4384   },
4385
4386   // ---------- magic ball content --------------------------------------------
4387
4388   {
4389     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4390     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4391     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4392     GADGET_ID_MAGIC_BALL_CONTENT_0,             GADGET_ID_NONE,
4393     &level.ball_content[0].e[0][0],             3, 3,
4394     NULL, NULL, NULL, "1",                      NULL
4395   },
4396   {
4397     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4398     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4399     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4400     GADGET_ID_MAGIC_BALL_CONTENT_1,             GADGET_ID_NONE,
4401     &level.ball_content[1].e[0][0],             3, 3,
4402     NULL, NULL, NULL, "2",                      NULL
4403   },
4404   {
4405     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4406     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4407     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4408     GADGET_ID_MAGIC_BALL_CONTENT_2,             GADGET_ID_NONE,
4409     &level.ball_content[2].e[0][0],             3, 3,
4410     NULL, NULL, NULL, "3",                      NULL
4411   },
4412   {
4413     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4414     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4415     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4416     GADGET_ID_MAGIC_BALL_CONTENT_3,             GADGET_ID_NONE,
4417     &level.ball_content[3].e[0][0],             3, 3,
4418     NULL, NULL, NULL, "4",                      NULL
4419   },
4420   {
4421     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4422     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4423     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4424     GADGET_ID_MAGIC_BALL_CONTENT_4,             GADGET_ID_NONE,
4425     &level.ball_content[4].e[0][0],             3, 3,
4426     NULL, NULL, NULL, "5",                      NULL
4427   },
4428   {
4429     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4430     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4431     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4432     GADGET_ID_MAGIC_BALL_CONTENT_5,             GADGET_ID_NONE,
4433     &level.ball_content[5].e[0][0],             3, 3,
4434     NULL, NULL, NULL, "6",                      NULL
4435   },
4436   {
4437     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4438     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4439     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4440     GADGET_ID_MAGIC_BALL_CONTENT_6,             GADGET_ID_NONE,
4441     &level.ball_content[6].e[0][0],             3, 3,
4442     NULL, NULL, NULL, "7",                      NULL
4443   },
4444   {
4445     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4446     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4447     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4448     GADGET_ID_MAGIC_BALL_CONTENT_7,             GADGET_ID_NONE,
4449     &level.ball_content[7].e[0][0],             3, 3,
4450     NULL, NULL, NULL, "8",                      NULL
4451   },
4452
4453   // ---------- android content -----------------------------------------------
4454
4455   {
4456     ED_DRAWING_ID_ANDROID_CONTENT,
4457     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4458     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4459     GADGET_ID_ANDROID_CONTENT,                  GADGET_ID_NONE,
4460     &level.android_clone_element[0],            MAX_ANDROID_ELEMENTS, 1,
4461     NULL, NULL, "Elements:", NULL,              "Elements android can clone"
4462   },
4463
4464   // ---------- amoeba content ------------------------------------------------
4465
4466   {
4467     ED_DRAWING_ID_AMOEBA_CONTENT,
4468     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4469     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4470     GADGET_ID_AMOEBA_CONTENT,                   GADGET_ID_NONE,
4471     &level.amoeba_content,                      1, 1,
4472     "Content:", NULL, NULL, NULL,               "Amoeba content"
4473   },
4474
4475   // ---------- BD snap element -----------------------------------------------
4476
4477   {
4478     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4479     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4480     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4481     GADGET_ID_BD_SNAP_ELEMENT,                  GADGET_ID_NONE,
4482     &level.bd_snap_element,                     1, 1,
4483     "Snap element:", NULL, NULL, NULL,          "Element created when snapping"
4484   },
4485
4486   // ---------- BD magic wall elements ----------------------------------------
4487
4488   {
4489     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4490     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4491     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4492     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,         GADGET_ID_NONE,
4493     &level.bd_magic_wall_diamond_to,            1, 1,
4494     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4495   },
4496   {
4497     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4498     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4499     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4500     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,            GADGET_ID_NONE,
4501     &level.bd_magic_wall_rock_to,               1, 1,
4502     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4503   },
4504   {
4505     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4506     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4507     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4508     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,       GADGET_ID_NONE,
4509     &level.bd_magic_wall_mega_rock_to,          1, 1,
4510     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4511   },
4512   {
4513     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4514     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4515     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4516     GADGET_ID_BD_MAGIC_WALL_NUT_TO,             GADGET_ID_NONE,
4517     &level.bd_magic_wall_nut_to,                1, 1,
4518     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4519   },
4520   {
4521     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4522     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(9),
4523     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4524     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,      GADGET_ID_NONE,
4525     &level.bd_magic_wall_nitro_pack_to,         1, 1,
4526     "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
4527   },
4528   {
4529     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4530     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4531     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4532     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,  GADGET_ID_NONE,
4533     &level.bd_magic_wall_flying_diamond_to,     1, 1,
4534     "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
4535   },
4536   {
4537     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4538     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4539     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4540     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,     GADGET_ID_NONE,
4541     &level.bd_magic_wall_flying_rock_to,        1, 1,
4542     "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
4543   },
4544
4545   // ---------- BD amoeba content ---------------------------------------------
4546
4547   {
4548     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4549     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4550     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4551     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,        GADGET_ID_NONE,
4552     &level.bd_amoeba_content_too_big,           1, 1,
4553     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba content if too big"
4554   },
4555   {
4556     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4557     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4558     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4559     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,       GADGET_ID_NONE,
4560     &level.bd_amoeba_content_enclosed,          1, 1,
4561     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba content if enclosed"
4562   },
4563
4564   // ---------- BD amoeba 2 content -------------------------------------------
4565
4566   {
4567     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4568     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4569     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4570     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,      GADGET_ID_NONE,
4571     &level.bd_amoeba_2_content_too_big,         1, 1,
4572     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if too big"
4573   },
4574   {
4575     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4576     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4577     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4578     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,     GADGET_ID_NONE,
4579     &level.bd_amoeba_2_content_enclosed,        1, 1,
4580     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if enclosed"
4581   },
4582   {
4583     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4584     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4585     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4586     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,    GADGET_ID_NONE,
4587     &level.bd_amoeba_2_content_exploding,       1, 1,
4588     "If exploding, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if exploding"
4589   },
4590   {
4591     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4592     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4593     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4594     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4595     &level.bd_amoeba_2_content_looks_like,      1, 1,
4596     "Use graphic of element:", NULL, NULL, NULL, "BD amoeba 2 looks like this element"
4597   },
4598   {
4599     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4600     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4601     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4602     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,          GADGET_ID_NONE,
4603     &level.bd_slime_eats_element_1,             1, 1,
4604     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4605   },
4606   {
4607     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4608     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4609     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4610     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4611     &level.bd_slime_converts_to_element_1,      1, 1,
4612     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4613   },
4614   {
4615     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4616     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4617     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4618     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,          GADGET_ID_NONE,
4619     &level.bd_slime_eats_element_2,             1, 1,
4620     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4621   },
4622   {
4623     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4624     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4625     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4626     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4627     &level.bd_slime_converts_to_element_2,      1, 1,
4628     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4629   },
4630   {
4631     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4632     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4633     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4634     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,          GADGET_ID_NONE,
4635     &level.bd_slime_eats_element_3,             1, 1,
4636     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4637   },
4638   {
4639     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4640     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4641     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4642     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4643     &level.bd_slime_converts_to_element_3,      1, 1,
4644     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4645   },
4646   {
4647     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4648     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4649     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4650     GADGET_ID_BD_ACID_EATS_ELEMENT,             GADGET_ID_NONE,
4651     &level.bd_acid_eats_element,                1, 1,
4652     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4653   },
4654   {
4655     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4656     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4657     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4658     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,         GADGET_ID_NONE,
4659     &level.bd_acid_turns_to_element,            1, 1,
4660     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4661   },
4662   {
4663     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4664     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4665     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4666     GADGET_ID_BD_BITER_EATS_ELEMENT,            GADGET_ID_NONE,
4667     &level.bd_biter_eats_element,               1, 1,
4668     "Can eat:", NULL, NULL, NULL,               "Eats this element when moving"
4669   },
4670   {
4671     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4672     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4673     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4674     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
4675     &level.bd_bladder_converts_by_element,      1, 1,
4676     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
4677   },
4678   {
4679     ED_DRAWING_ID_BD_NUT_CONTENT,
4680     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4681     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4682     GADGET_ID_BD_NUT_CONTENT,                   GADGET_ID_NONE,
4683     &level.bd_nut_content,                      1, 1,
4684     "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
4685   },
4686   {
4687     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4688     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4689     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4690     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,     GADGET_ID_NONE,
4691     &level.bd_expanding_wall_looks_like,        1, 1,
4692     "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
4693   },
4694   {
4695     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4696     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4697     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4698     GADGET_ID_BD_SAND_LOOKS_LIKE,               GADGET_ID_NONE,
4699     &level.bd_sand_looks_like,                  1, 1,
4700     "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
4701   },
4702   {
4703     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
4704     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4705     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4706     GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,      GADGET_ID_NONE,
4707     &level.bd_rock_turns_to_on_falling,         1, 1,
4708     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4709   },
4710   {
4711     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
4712     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4713     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4714     GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,       GADGET_ID_NONE,
4715     &level.bd_rock_turns_to_on_impact,          1, 1,
4716     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4717   },
4718   {
4719     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
4720     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4721     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4722     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,   GADGET_ID_NONE,
4723     &level.bd_diamond_turns_to_on_falling,      1, 1,
4724     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4725   },
4726   {
4727     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
4728     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4729     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4730     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,    GADGET_ID_NONE,
4731     &level.bd_diamond_turns_to_on_impact,       1, 1,
4732     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4733   },
4734   {
4735     ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
4736     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4737     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4738     GADGET_ID_BD_FIREFLY_EXPLODES_TO,           GADGET_ID_NONE,
4739     &level.bd_firefly_explodes_to,              1, 1,
4740     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4741   },
4742   {
4743     ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
4744     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4745     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4746     GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,         GADGET_ID_NONE,
4747     &level.bd_firefly_2_explodes_to,            1, 1,
4748     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4749   },
4750   {
4751     ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
4752     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4753     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4754     GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,         GADGET_ID_NONE,
4755     &level.bd_butterfly_explodes_to,            1, 1,
4756     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4757   },
4758   {
4759     ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
4760     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4761     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4762     GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,       GADGET_ID_NONE,
4763     &level.bd_butterfly_2_explodes_to,          1, 1,
4764     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4765   },
4766   {
4767     ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
4768     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4769     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4770     GADGET_ID_BD_STONEFLY_EXPLODES_TO,          GADGET_ID_NONE,
4771     &level.bd_stonefly_explodes_to,             1, 1,
4772     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4773   },
4774   {
4775     ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
4776     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4777     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4778     GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,         GADGET_ID_NONE,
4779     &level.bd_dragonfly_explodes_to,            1, 1,
4780     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4781   },
4782   {
4783     ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
4784     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4785     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4786     GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,        GADGET_ID_NONE,
4787     &level.bd_diamond_birth_turns_to,           1, 1,
4788     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4789   },
4790   {
4791     ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
4792     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4793     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4794     GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,       GADGET_ID_NONE,
4795     &level.bd_bomb_explosion_turns_to,          1, 1,
4796     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4797   },
4798   {
4799     ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
4800     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4801     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4802     GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,      GADGET_ID_NONE,
4803     &level.bd_nitro_explosion_turns_to,         1, 1,
4804     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4805   },
4806   {
4807     ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
4808     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4809     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4810     GADGET_ID_BD_EXPLOSION_TURNS_TO,            GADGET_ID_NONE,
4811     &level.bd_explosion_turns_to,               1, 1,
4812     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4813   },
4814
4815   // ---------- level start element -------------------------------------------
4816
4817   {
4818     ED_DRAWING_ID_START_ELEMENT,
4819     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(10),
4820     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4821     GADGET_ID_START_ELEMENT,                    GADGET_ID_USE_START_ELEMENT,
4822     &level.start_element[0],                    1, 1,
4823     NULL, NULL, NULL, NULL,                     "Level start element"
4824   },
4825
4826   // ---------- player artwork element ----------------------------------------
4827
4828   {
4829     ED_DRAWING_ID_ARTWORK_ELEMENT,
4830     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(11),
4831     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4832     GADGET_ID_ARTWORK_ELEMENT,                  GADGET_ID_USE_ARTWORK_ELEMENT,
4833     &level.artwork_element[0],                  1, 1,
4834     NULL, NULL, NULL, NULL,                     "Element for player artwork"
4835   },
4836
4837   // ---------- player explosion element --------------------------------------
4838
4839   {
4840     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4841     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(12),
4842     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4843     GADGET_ID_EXPLOSION_ELEMENT,                GADGET_ID_USE_EXPLOSION_ELEMENT,
4844     &level.explosion_element[0],                1, 1,
4845     NULL, NULL, NULL, NULL,                     "Element for player explosion"
4846   },
4847
4848   // ---------- player initial inventory --------------------------------------
4849
4850   {
4851     ED_DRAWING_ID_INVENTORY_CONTENT,
4852     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4853     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4854     GADGET_ID_INVENTORY_CONTENT,                GADGET_ID_USE_INITIAL_INVENTORY,
4855     &level.initial_inventory_content[0][0],     MAX_INITIAL_INVENTORY_SIZE, 1,
4856     NULL, NULL, NULL, NULL,                     "Content for initial inventory"
4857   },
4858
4859   // ---------- gray ball content -----------------------------------------
4860
4861   {
4862     ED_DRAWING_ID_MM_BALL_CONTENT,
4863     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4864     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4865     GADGET_ID_MM_BALL_CONTENT,                  GADGET_ID_NONE,
4866     &level.mm_ball_content[0],                  MAX_MM_BALL_CONTENTS, 1,
4867     "Content:", NULL, NULL, NULL,               "Content for gray ball"
4868   },
4869
4870   // ---------- element settings: configure 1 (custom elements) ---------------
4871
4872   // ---------- custom graphic ------------------------------------------------
4873
4874   {
4875     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4876     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4877     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4878     GADGET_ID_CUSTOM_GRAPHIC,                   GADGET_ID_CUSTOM_USE_GRAPHIC,
4879     &custom_element.gfx_element_initial,        1, 1,
4880     NULL, NULL, NULL, NULL,                     "Custom graphic element"
4881   },
4882
4883   // ---------- element settings: configure 2 (custom elements) ---------------
4884
4885   // ---------- custom content (when exploding) -------------------------------
4886
4887   {
4888     ED_DRAWING_ID_CUSTOM_CONTENT,
4889     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(11),
4890     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4891     GADGET_ID_CUSTOM_CONTENT,                   GADGET_ID_NONE,         // align three rows
4892     &custom_element.content.e[0][0],            3, 3,
4893     "Content:", NULL, NULL, NULL,               NULL
4894   },
4895
4896   // ---------- custom enter and leave element (when moving) ------------------
4897
4898   {
4899     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4900     ED_AREA_1X1_SETTINGS_XPOS(1),               ED_AREA_1X1_SETTINGS_YPOS(3),
4901     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4902     GADGET_ID_CUSTOM_MOVE_ENTER,                GADGET_ID_NONE,
4903     &custom_element.move_enter_element,         1, 1,
4904     "Can dig:", " ", NULL, NULL,                "Element that can be digged/collected"
4905   },
4906   {
4907     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4908     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(3),
4909     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4910     GADGET_ID_CUSTOM_MOVE_LEAVE,                GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4911     &custom_element.move_leave_element,         1, 1,
4912     NULL, NULL, NULL, NULL,                     "Element that will be left behind"
4913   },
4914
4915   // ---------- element settings: advanced (custom elements) ------------------
4916
4917   // ---------- custom change target ------------------------------------------
4918
4919   {
4920     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4921     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4922     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4923     GADGET_ID_CUSTOM_CHANGE_TARGET,             GADGET_ID_CUSTOM_CAN_CHANGE,
4924     &custom_element_change.target_element,      1, 1,
4925     NULL, "after/when:", NULL, NULL,            "New target element after change"
4926   },
4927
4928   // ---------- custom change content (extended change target) ----------------
4929
4930   {
4931     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4932     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(9),
4933     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4934     GADGET_ID_CUSTOM_CHANGE_CONTENT,            GADGET_ID_NONE,         // align three rows
4935     &custom_element_change.target_content.e[0][0], 3, 3,
4936     NULL, NULL, NULL, NULL,                     "New extended elements after change"
4937   },
4938
4939   // ---------- custom change trigger (element causing change) ----------------
4940
4941   {
4942     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4943     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(5),
4944     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4945     GADGET_ID_CUSTOM_CHANGE_TRIGGER,            GADGET_ID_CHANGE_OTHER_ACTION,
4946     &custom_element_change.initial_trigger_element, 1, 1,
4947     NULL, NULL, NULL, NULL,                     "Other element triggering change"
4948   },
4949
4950   // ---------- custom change action (element used for action) ----------------
4951
4952   {
4953     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4954     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(13),
4955     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4956     GADGET_ID_CUSTOM_CHANGE_ACTION,             GADGET_ID_ACTION_ARG,
4957     &custom_element_change.action_element,      1, 1,
4958     NULL, NULL, NULL, NULL,                     "Element used as action parameter"
4959   },
4960
4961   // ---------- group element content -----------------------------------------
4962
4963   {
4964     ED_DRAWING_ID_GROUP_CONTENT,
4965     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4966     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4967     GADGET_ID_GROUP_CONTENT,                    GADGET_ID_NONE,
4968     &group_element_info.element[0],             MAX_ELEMENTS_IN_GROUP, 1,
4969     "Content:", NULL, NULL, NULL,               NULL
4970   },
4971
4972   // ---------- random background (for random painting) -----------------------
4973
4974   {
4975     ED_DRAWING_ID_RANDOM_BACKGROUND,
4976     -1,                                         ED_AREA_1X1_LSETTINGS_YPOS(1),
4977     0,                                          ED_AREA_1X1_LSETTINGS_YOFF,
4978     GADGET_ID_RANDOM_BACKGROUND,                GADGET_ID_RANDOM_RESTRICTED,
4979     &random_placement_background_element,       1, 1,
4980     NULL, NULL, NULL, NULL,                     "Random placement background"
4981   },
4982 };
4983
4984
4985 // ----------------------------------------------------------------------------
4986 // some internally used variables
4987 // ----------------------------------------------------------------------------
4988
4989 // maximal size of level editor drawing area
4990 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
4991
4992 // actual size of level editor drawing area
4993 static int ed_fieldx, ed_fieldy;
4994
4995 // actual position of level editor drawing area in level playfield
4996 static int level_xpos = -1, level_ypos = -1;
4997
4998 // actual tile size used to display playfield drawing area
4999 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
5000 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
5001
5002 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
5003
5004 // drawing elements on the three mouse buttons
5005 static int new_element1 = EL_WALL;
5006 static int new_element2 = EL_EMPTY;
5007 static int new_element3 = EL_SAND;
5008
5009 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
5010 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
5011                                 (button) == 2 ? new_element2 : \
5012                                 (button) == 3 ? new_element3 : EL_EMPTY)
5013
5014 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
5015
5016 static int use_permanent_palette = TRUE;
5017
5018 #define PX              (use_permanent_palette ? DX : SX)
5019 #define PY              (use_permanent_palette ? DY : SY)
5020 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
5021 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
5022
5023 // forward declaration for internal use
5024 static void CopyBrushToCursor(int, int);
5025 static void DeleteBrushFromCursor(void);
5026 static void ModifyEditorCounterValue(int, int);
5027 static void ModifyEditorCounterLimits(int, int, int);
5028 static void ModifyEditorSelectboxValue(int, int);
5029 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
5030 static void ModifyEditorDrawingArea(int, int, int);
5031 static void ModifyEditorElementList(void);
5032 static void AdjustElementListScrollbar(void);
5033 static void RedrawDrawingElements(void);
5034 static void DrawDrawingWindowExt(boolean);
5035 static void DrawDrawingWindow(void);
5036 static void DrawLevelConfigWindow(void);
5037 static void DrawPropertiesWindow(void);
5038 static void DrawPaletteWindow(void);
5039 static void UpdateCustomElementGraphicGadgets(void);
5040 static boolean checkPropertiesConfig(int);
5041 static void SetAutomaticNumberOfGemsNeeded(void);
5042 static void ClearEditorGadgetInfoText(void);
5043 static void CopyLevelToUndoBuffer(int);
5044 static void HandleDrawingAreas(struct GadgetInfo *);
5045 static void HandleCounterButtons(struct GadgetInfo *);
5046 static void HandleTextInputGadgets(struct GadgetInfo *);
5047 static void HandleTextAreaGadgets(struct GadgetInfo *);
5048 static void HandleSelectboxGadgets(struct GadgetInfo *);
5049 static void HandleTextbuttonGadgets(struct GadgetInfo *);
5050 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
5051 static void HandleRadiobuttons(struct GadgetInfo *);
5052 static void HandleCheckbuttons(struct GadgetInfo *);
5053 static void HandleControlButtons(struct GadgetInfo *);
5054 static void HandleDrawingAreaInfo(struct GadgetInfo *);
5055 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
5056 static boolean AskToCopyAndModifyLevelTemplate(void);
5057 static boolean getDrawModeHiRes(void);
5058 static int getTabulatorBarWidth(void);
5059 static int getTabulatorBarHeight(void);
5060 static Pixel getTabulatorBarColor(void);
5061 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
5062 static int numHiresTiles(int);
5063
5064 static int num_editor_gadgets = 0;      // dynamically determined
5065
5066 static struct GadgetInfo **level_editor_gadget = NULL;
5067 static int *right_gadget_border = NULL;
5068
5069 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
5070 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
5071 static boolean draw_with_brush = FALSE;
5072 static int properties_element = 0;
5073
5074 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5075 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5076 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5077 static int undo_buffer_position = 0;
5078 static int undo_buffer_steps = 0;
5079 static int redo_buffer_steps = 0;
5080
5081 static int edit_mode;
5082 static int edit_mode_levelconfig;
5083 static int edit_mode_properties;
5084
5085 static int element_shift = 0;
5086
5087 static int editor_el_players[] =
5088 {
5089   EL_PLAYER_1,
5090   EL_PLAYER_2,
5091   EL_PLAYER_3,
5092   EL_PLAYER_4
5093 };
5094 static int *editor_el_players_ptr = editor_el_players;
5095 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
5096
5097 static int editor_hl_boulderdash[] =
5098 {
5099   EL_INTERNAL_CASCADE_BD_ACTIVE,
5100   EL_CHAR('B'),
5101   EL_CHAR('D'),
5102   EL_EMPTY,
5103 };
5104
5105 static int editor_el_boulderdash[] =
5106 {
5107   EL_EMPTY,
5108   EL_SAND,
5109   EL_BD_ROCK,
5110   EL_BD_DIAMOND,
5111
5112   EL_STEELWALL,
5113   EL_BD_WALL,
5114   EL_BD_EXPANDABLE_WALL,
5115   EL_BD_MAGIC_WALL,
5116
5117   EL_BD_AMOEBA,
5118   EL_BD_BUTTERFLY_UP,
5119   EL_BD_FIREFLY_UP,
5120   EL_EXIT_CLOSED,
5121
5122   EL_BD_BUTTERFLY_LEFT,
5123   EL_BD_FIREFLY_LEFT,
5124   EL_BD_BUTTERFLY_RIGHT,
5125   EL_BD_FIREFLY_RIGHT,
5126
5127   EL_EMPTY,
5128   EL_BD_BUTTERFLY_DOWN,
5129   EL_BD_FIREFLY_DOWN,
5130   EL_EXIT_OPEN,
5131 };
5132 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
5133 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
5134 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
5135 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
5136
5137 static int editor_hl_boulderdash_native[] =
5138 {
5139   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
5140   EL_CHAR('B'),
5141   EL_CHAR('D'),
5142   EL_EMPTY,
5143 };
5144
5145 static int editor_el_boulderdash_native[] =
5146 {
5147   EL_EMPTY,
5148   EL_BD_SAND,
5149   EL_BD_ROCK,
5150   EL_BD_DIAMOND,
5151
5152   EL_BD_INBOX,
5153   EL_BD_STEELWALL,
5154   EL_BD_WALL,
5155   EL_BD_MAGIC_WALL,
5156
5157   EL_BD_AMOEBA,
5158   EL_BD_BUTTERFLY_UP,
5159   EL_BD_FIREFLY_UP,
5160   EL_BD_EXIT_CLOSED,
5161
5162   EL_BD_BUTTERFLY_LEFT,
5163   EL_BD_FIREFLY_LEFT,
5164   EL_BD_BUTTERFLY_RIGHT,
5165   EL_BD_FIREFLY_RIGHT,
5166
5167   EL_BD_SAND_2,
5168   EL_BD_BUTTERFLY_DOWN,
5169   EL_BD_FIREFLY_DOWN,
5170   EL_BD_EXIT_OPEN,
5171
5172   EL_BD_AMOEBA_2,
5173   EL_BD_BUTTERFLY_2_UP,
5174   EL_BD_FIREFLY_2_UP,
5175   EL_BD_SLIME,
5176
5177   EL_BD_BUTTERFLY_2_LEFT,
5178   EL_BD_FIREFLY_2_LEFT,
5179   EL_BD_BUTTERFLY_2_RIGHT,
5180   EL_BD_FIREFLY_2_RIGHT,
5181
5182   EL_BD_BOMB,
5183   EL_BD_BUTTERFLY_2_DOWN,
5184   EL_BD_FIREFLY_2_DOWN,
5185   EL_BD_FLYING_DIAMOND,
5186
5187   EL_BD_NITRO_PACK,
5188   EL_BD_DRAGONFLY_UP,
5189   EL_BD_STONEFLY_UP,
5190   EL_BD_DIAMOND_GLUED,
5191
5192   EL_BD_DRAGONFLY_LEFT,
5193   EL_BD_STONEFLY_LEFT,
5194   EL_BD_DRAGONFLY_RIGHT,
5195   EL_BD_STONEFLY_RIGHT,
5196
5197   EL_BD_NUT,
5198   EL_BD_DRAGONFLY_DOWN,
5199   EL_BD_STONEFLY_DOWN,
5200   EL_EMPTY,
5201
5202   EL_BD_BITER_SWITCH_1,
5203   EL_BD_BITER_UP,
5204   EL_BD_COW_UP,
5205   EL_EMPTY,
5206
5207   EL_BD_BITER_LEFT,
5208   EL_BD_COW_LEFT,
5209   EL_BD_BITER_RIGHT,
5210   EL_BD_COW_RIGHT,
5211
5212   EL_BD_VOODOO_DOLL,
5213   EL_BD_BITER_DOWN,
5214   EL_BD_COW_DOWN,
5215   EL_BD_GHOST,
5216
5217   EL_BD_SAND_GLUED,
5218   EL_BD_SAND_BALL,
5219   EL_BD_SAND_LOOSE,
5220   EL_BD_WALL_NON_SLOPED,
5221
5222   EL_BD_SAND_SLOPED_UP_LEFT,
5223   EL_BD_SAND_SLOPED_UP_RIGHT,
5224   EL_BD_WALL_SLOPED_UP_LEFT,
5225   EL_BD_WALL_SLOPED_UP_RIGHT,
5226
5227   EL_BD_SAND_SLOPED_DOWN_LEFT,
5228   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5229   EL_BD_WALL_SLOPED_DOWN_LEFT,
5230   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5231
5232   EL_BD_FLYING_ROCK,
5233   EL_BD_ROCK_GLUED,
5234   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5235   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5236
5237   EL_BD_WAITING_ROCK,
5238   EL_BD_CHASING_ROCK,
5239   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5240   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5241
5242   EL_BD_MEGA_ROCK,
5243   EL_BD_SWEET,
5244   EL_BD_INVISIBLE_EXIT_CLOSED,
5245   EL_BD_INVISIBLE_EXIT_OPEN,
5246
5247   EL_BD_STEELWALL_EXPLODABLE,
5248   EL_BD_STEELWALL_DIGGABLE,
5249   EL_BD_WALL_DIGGABLE,
5250   EL_BD_FALLING_WALL,
5251
5252   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5253   EL_BD_EXPANDABLE_WALL_VERTICAL,
5254   EL_BD_EXPANDABLE_WALL_ANY,
5255   EL_BD_EXPANDABLE_WALL_SWITCH,
5256
5257   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5258   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5259   EL_BD_EXPANDABLE_STEELWALL_ANY,
5260   EL_BD_CREATURE_SWITCH,
5261
5262   EL_BD_BLADDER,
5263   EL_BD_BLADDER_SPENDER,
5264   EL_BD_REPLICATOR,
5265   EL_BD_REPLICATOR_SWITCH,
5266
5267   EL_BD_CONVEYOR_LEFT,
5268   EL_BD_CONVEYOR_RIGHT,
5269   EL_BD_CONVEYOR_SWITCH,
5270   EL_BD_CONVEYOR_DIR_SWITCH,
5271
5272   EL_BD_CLOCK,
5273   EL_BD_TIME_PENALTY,
5274   EL_BD_GRAVESTONE,
5275   EL_BD_SKELETON,
5276
5277   EL_BD_WATER,
5278   EL_BD_ACID,
5279   EL_BD_LAVA,
5280   EL_BD_BOX,
5281
5282   EL_BD_GATE_1,
5283   EL_BD_GATE_2,
5284   EL_BD_GATE_3,
5285   EL_BD_TRAPPED_DIAMOND,
5286
5287   EL_BD_KEY_1,
5288   EL_BD_KEY_2,
5289   EL_BD_KEY_3,
5290   EL_BD_DIAMOND_KEY,
5291
5292   EL_BD_WALL_KEY_1,
5293   EL_BD_WALL_KEY_2,
5294   EL_BD_WALL_KEY_3,
5295   EL_BD_WALL_DIAMOND,
5296
5297   EL_BD_POT,
5298   EL_BD_GRAVITY_SWITCH,
5299   EL_BD_PNEUMATIC_HAMMER,
5300   EL_BD_TELEPORTER,
5301
5302   EL_BD_PLAYER,
5303   EL_BD_PLAYER_WITH_BOMB,
5304   EL_BD_PLAYER_WITH_ROCKET_LAUNCHER,
5305   EL_BD_ROCKET_LAUNCHER,
5306
5307   EL_BD_PLAYER_GLUED,
5308   EL_BD_PLAYER_STIRRING,
5309   EL_EMPTY,
5310   EL_EMPTY,
5311 };
5312 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5313 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5314 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5315 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5316
5317 static int editor_hl_boulderdash_effects[] =
5318 {
5319   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5320   EL_CHAR('B'),
5321   EL_CHAR('D'),
5322   EL_CHAR('E'),
5323 };
5324
5325 static int editor_el_boulderdash_effects[] =
5326 {
5327   EL_BD_DIAMOND_FALLING,
5328   EL_BD_ROCK_FALLING,
5329   EL_BD_MEGA_ROCK_FALLING,
5330   EL_BD_FLYING_DIAMOND_FLYING,
5331
5332   EL_BD_FALLING_WALL_FALLING,
5333   EL_BD_NITRO_PACK_FALLING,
5334   EL_BD_NUT_FALLING,
5335   EL_BD_FLYING_ROCK_FLYING,
5336
5337   EL_BD_PLAYER_GROWING_1,
5338   EL_BD_PLAYER_GROWING_2,
5339   EL_BD_PLAYER_GROWING_3,
5340   EL_BD_PLAYER,
5341
5342   EL_BD_PLAYER_WITH_BOMB,
5343   EL_BD_PLAYER_STIRRING,
5344   EL_BD_EXIT_OPEN,
5345   EL_BD_INVISIBLE_EXIT_OPEN,
5346
5347   EL_BD_BLADDER_1,
5348   EL_BD_BLADDER_2,
5349   EL_BD_BLADDER_3,
5350   EL_BD_BLADDER_4,
5351
5352   EL_BD_BLADDER_5,
5353   EL_BD_BLADDER_6,
5354   EL_BD_BLADDER_7,
5355   EL_BD_BLADDER_8,
5356
5357   EL_BD_SAND_2,
5358   EL_BD_COW_ENCLOSED_1,
5359   EL_BD_COW_ENCLOSED_2,
5360   EL_BD_COW_ENCLOSED_3,
5361
5362   EL_BD_COW_ENCLOSED_4,
5363   EL_BD_COW_ENCLOSED_5,
5364   EL_BD_COW_ENCLOSED_6,
5365   EL_BD_COW_ENCLOSED_7,
5366
5367   EL_BD_WATER_1,
5368   EL_BD_WATER_2,
5369   EL_BD_WATER_3,
5370   EL_BD_WATER_4,
5371
5372   EL_BD_WATER_5,
5373   EL_BD_WATER_6,
5374   EL_BD_WATER_7,
5375   EL_BD_WATER_8,
5376
5377   EL_BD_WATER_9,
5378   EL_BD_WATER_10,
5379   EL_BD_WATER_11,
5380   EL_BD_WATER_12,
5381
5382   EL_BD_WATER_13,
5383   EL_BD_WATER_14,
5384   EL_BD_WATER_15,
5385   EL_BD_WATER_16,
5386
5387   EL_BD_BOMB_TICKING_1,
5388   EL_BD_BOMB_TICKING_2,
5389   EL_BD_BOMB_TICKING_3,
5390   EL_BD_BOMB_TICKING_4,
5391
5392   EL_BD_BOMB_TICKING_5,
5393   EL_BD_BOMB_TICKING_6,
5394   EL_BD_BOMB_TICKING_7,
5395   EL_EMPTY,
5396
5397   EL_BD_BOMB_EXPLODING_1,
5398   EL_BD_BOMB_EXPLODING_2,
5399   EL_BD_BOMB_EXPLODING_3,
5400   EL_BD_BOMB_EXPLODING_4,
5401
5402   EL_BD_NUT_BREAKING_1,
5403   EL_BD_NUT_BREAKING_2,
5404   EL_BD_NUT_BREAKING_3,
5405   EL_BD_NUT_BREAKING_4,
5406
5407   EL_BD_EXPLODING_1,
5408   EL_BD_EXPLODING_2,
5409   EL_BD_EXPLODING_3,
5410   EL_BD_EXPLODING_4,
5411
5412   EL_BD_EXPLODING_5,
5413   EL_BD_TIME_PENALTY,
5414   EL_BD_DIAMOND_GROWING_1,
5415   EL_BD_DIAMOND_GROWING_2,
5416
5417   EL_BD_DIAMOND_GROWING_3,
5418   EL_BD_DIAMOND_GROWING_4,
5419   EL_BD_DIAMOND_GROWING_5,
5420   EL_BD_NITRO_PACK_EXPLODING,
5421
5422   EL_BD_NITRO_PACK_EXPLODING_1,
5423   EL_BD_NITRO_PACK_EXPLODING_2,
5424   EL_BD_NITRO_PACK_EXPLODING_3,
5425   EL_BD_NITRO_PACK_EXPLODING_4,
5426
5427   EL_BD_ROCK_GROWING_1,
5428   EL_BD_ROCK_GROWING_2,
5429   EL_BD_ROCK_GROWING_3,
5430   EL_BD_ROCK_GROWING_4,
5431
5432   EL_BD_STEELWALL_GROWING_1,
5433   EL_BD_STEELWALL_GROWING_2,
5434   EL_BD_STEELWALL_GROWING_3,
5435   EL_BD_STEELWALL_GROWING_4,
5436
5437   EL_BD_CLOCK_GROWING_1,
5438   EL_BD_CLOCK_GROWING_2,
5439   EL_BD_CLOCK_GROWING_3,
5440   EL_BD_CLOCK_GROWING_4,
5441
5442   EL_BD_GHOST_EXPLODING_1,
5443   EL_BD_GHOST_EXPLODING_2,
5444   EL_BD_GHOST_EXPLODING_3,
5445   EL_BD_GHOST_EXPLODING_4,
5446 };
5447 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5448 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5449 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5450 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5451
5452 static int editor_hl_emerald_mine[] =
5453 {
5454   EL_INTERNAL_CASCADE_EM_ACTIVE,
5455   EL_CHAR('E'),
5456   EL_CHAR('M'),
5457   EL_EMPTY,
5458 };
5459
5460 static int editor_el_emerald_mine[] =
5461 {
5462   EL_SAND,
5463   EL_ROCK,
5464   EL_QUICKSAND_EMPTY,
5465   EL_QUICKSAND_FULL,
5466
5467   EL_STEELWALL,
5468   EL_WALL,
5469   EL_WALL_SLIPPERY,
5470   EL_MAGIC_WALL,
5471
5472   EL_EMERALD,
5473   EL_DIAMOND,
5474   EL_NUT,
5475   EL_BOMB,
5476
5477   EL_EM_DYNAMITE,
5478   EL_EM_DYNAMITE_ACTIVE,
5479   EL_EM_EXIT_CLOSED,
5480   EL_EM_EXIT_OPEN,
5481
5482   EL_YAMYAM_UP,
5483   EL_BUG_UP,
5484   EL_SPACESHIP_UP,
5485   EL_ROBOT,
5486
5487   EL_BUG_LEFT,
5488   EL_SPACESHIP_LEFT,
5489   EL_BUG_RIGHT,
5490   EL_SPACESHIP_RIGHT,
5491
5492   EL_ROBOT_WHEEL,
5493   EL_BUG_DOWN,
5494   EL_SPACESHIP_DOWN,
5495   EL_INVISIBLE_WALL,
5496
5497   EL_ACID_POOL_TOPLEFT,
5498   EL_ACID,
5499   EL_ACID_POOL_TOPRIGHT,
5500   EL_AMOEBA_DROP,
5501
5502   EL_ACID_POOL_BOTTOMLEFT,
5503   EL_ACID_POOL_BOTTOM,
5504   EL_ACID_POOL_BOTTOMRIGHT,
5505   EL_AMOEBA_WET,
5506
5507   EL_EM_KEY_1,
5508   EL_EM_KEY_2,
5509   EL_EM_KEY_3,
5510   EL_EM_KEY_4,
5511
5512   EL_EM_GATE_1,
5513   EL_EM_GATE_2,
5514   EL_EM_GATE_3,
5515   EL_EM_GATE_4,
5516
5517   EL_EM_GATE_1_GRAY,
5518   EL_EM_GATE_2_GRAY,
5519   EL_EM_GATE_3_GRAY,
5520   EL_EM_GATE_4_GRAY,
5521 };
5522 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5523 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5524 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5525 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5526
5527 static int editor_hl_emerald_mine_club[] =
5528 {
5529   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5530   EL_CHAR('E'),
5531   EL_CHAR('M'),
5532   EL_CHAR('C'),
5533 };
5534
5535 static int editor_el_emerald_mine_club[] =
5536 {
5537   EL_EMC_KEY_5,
5538   EL_EMC_KEY_6,
5539   EL_EMC_KEY_7,
5540   EL_EMC_KEY_8,
5541
5542   EL_EMC_GATE_5,
5543   EL_EMC_GATE_6,
5544   EL_EMC_GATE_7,
5545   EL_EMC_GATE_8,
5546
5547   EL_EMC_GATE_5_GRAY,
5548   EL_EMC_GATE_6_GRAY,
5549   EL_EMC_GATE_7_GRAY,
5550   EL_EMC_GATE_8_GRAY,
5551
5552   EL_EMC_STEELWALL_1,
5553   EL_EMC_STEELWALL_2,
5554   EL_EMC_STEELWALL_3,
5555   EL_EMC_STEELWALL_4,
5556
5557   EL_EMC_WALL_13,
5558   EL_EMC_WALL_14,
5559   EL_EMC_WALL_15,
5560   EL_EMC_WALL_16,
5561
5562   EL_EMC_WALL_SLIPPERY_1,
5563   EL_EMC_WALL_SLIPPERY_2,
5564   EL_EMC_WALL_SLIPPERY_3,
5565   EL_EMC_WALL_SLIPPERY_4,
5566
5567   EL_EMC_WALL_1,
5568   EL_EMC_WALL_2,
5569   EL_EMC_WALL_3,
5570   EL_EMC_WALL_4,
5571
5572   EL_EMC_WALL_5,
5573   EL_EMC_WALL_6,
5574   EL_EMC_WALL_7,
5575   EL_EMC_WALL_8,
5576
5577   EL_EMC_WALL_9,
5578   EL_EMC_WALL_10,
5579   EL_EMC_WALL_11,
5580   EL_EMC_WALL_12,
5581
5582   EL_EMC_GRASS,
5583   EL_EMC_FAKE_GRASS,
5584   EL_EMC_PLANT,
5585   EL_EMC_DRIPPER,
5586
5587   EL_EMC_MAGIC_BALL,
5588   EL_EMC_MAGIC_BALL_SWITCH,
5589   EL_EMC_LENSES,
5590   EL_EMC_MAGNIFIER,
5591
5592   EL_SPRING_LEFT,
5593   EL_SPRING,
5594   EL_SPRING_RIGHT,
5595   EL_EMC_SPRING_BUMPER,
5596
5597   EL_BALLOON,
5598   EL_YAMYAM_UP,
5599   EL_BALLOON_SWITCH_UP,
5600   EL_BALLOON_SWITCH_ANY,
5601
5602   EL_YAMYAM_LEFT,
5603   EL_BALLOON_SWITCH_LEFT,
5604   EL_YAMYAM_RIGHT,
5605   EL_BALLOON_SWITCH_RIGHT,
5606
5607   EL_EMC_ANDROID,
5608   EL_YAMYAM_DOWN,
5609   EL_BALLOON_SWITCH_DOWN,
5610   EL_BALLOON_SWITCH_NONE,
5611 };
5612 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5613 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5614 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5615 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5616
5617 static int editor_hl_rnd[] =
5618 {
5619   EL_INTERNAL_CASCADE_RND_ACTIVE,
5620   EL_CHAR('R'),
5621   EL_CHAR('N'),
5622   EL_CHAR('D'),
5623 };
5624
5625 static int editor_el_rnd[] =
5626 {
5627   EL_DYNAMITE,                  // RND
5628   EL_DYNAMITE_ACTIVE,           // RND
5629   EL_EMPTY,
5630   EL_EMPTY,
5631
5632   EL_KEY_1,
5633   EL_KEY_2,
5634   EL_KEY_3,
5635   EL_KEY_4,
5636
5637   EL_GATE_1,
5638   EL_GATE_2,
5639   EL_GATE_3,
5640   EL_GATE_4,
5641
5642   EL_GATE_1_GRAY,
5643   EL_GATE_2_GRAY,
5644   EL_GATE_3_GRAY,
5645   EL_GATE_4_GRAY,
5646
5647   EL_ARROW_LEFT,
5648   EL_ARROW_RIGHT,
5649   EL_ARROW_UP,
5650   EL_ARROW_DOWN,
5651
5652   EL_AMOEBA_DEAD,
5653   EL_AMOEBA_DRY,
5654   EL_AMOEBA_FULL,
5655   EL_GAME_OF_LIFE,
5656
5657   EL_EMERALD_YELLOW,
5658   EL_EMERALD_RED,
5659   EL_EMERALD_PURPLE,
5660   EL_BIOMAZE,
5661
5662   EL_WALL_EMERALD_YELLOW,
5663   EL_WALL_EMERALD_RED,
5664   EL_WALL_EMERALD_PURPLE,
5665   EL_WALL_BD_DIAMOND,
5666
5667   EL_SPEED_PILL,
5668   EL_PACMAN_UP,
5669   EL_TIME_ORB_FULL,
5670   EL_TIME_ORB_EMPTY,
5671
5672   EL_PACMAN_LEFT,
5673   EL_DARK_YAMYAM,
5674   EL_PACMAN_RIGHT,
5675   EL_YAMYAM,                    // RND
5676
5677   EL_BLACK_ORB,
5678   EL_PACMAN_DOWN,
5679   EL_LAMP,
5680   EL_LAMP_ACTIVE,
5681
5682   EL_DYNABOMB_INCREASE_NUMBER,
5683   EL_DYNABOMB_INCREASE_SIZE,
5684   EL_DYNABOMB_INCREASE_POWER,
5685   EL_STONEBLOCK,
5686
5687   EL_MOLE,
5688   EL_PENGUIN,
5689   EL_PIG,
5690   EL_DRAGON,
5691
5692   EL_BUG,
5693   EL_MOLE_UP,
5694   EL_BD_BUTTERFLY,
5695   EL_BD_FIREFLY,
5696
5697   EL_MOLE_LEFT,
5698   EL_SATELLITE,
5699   EL_MOLE_RIGHT,
5700   EL_PACMAN,
5701
5702   EL_SPACESHIP,
5703   EL_MOLE_DOWN,
5704   EL_INVISIBLE_STEELWALL,
5705   EL_INVISIBLE_WALL,
5706
5707   EL_EXPANDABLE_WALL,
5708   EL_EXPANDABLE_WALL_HORIZONTAL,
5709   EL_EXPANDABLE_WALL_VERTICAL,
5710   EL_EXPANDABLE_WALL_ANY,
5711 };
5712 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5713 static int *editor_el_rnd_ptr = editor_el_rnd;
5714 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5715 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5716
5717 static int editor_hl_sokoban[] =
5718 {
5719   EL_INTERNAL_CASCADE_SB_ACTIVE,
5720   EL_CHAR('S'),
5721   EL_CHAR('B'),
5722   EL_EMPTY,
5723 };
5724
5725 static int editor_el_sokoban[] =
5726 {
5727   EL_SOKOBAN_OBJECT,
5728   EL_SOKOBAN_FIELD_EMPTY,
5729   EL_SOKOBAN_FIELD_FULL,
5730   EL_SOKOBAN_FIELD_PLAYER,
5731 };
5732 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5733 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5734 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5735 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5736
5737 static int editor_hl_supaplex[] =
5738 {
5739   EL_INTERNAL_CASCADE_SP_ACTIVE,
5740   EL_CHAR('S'),
5741   EL_CHAR('P'),
5742   EL_EMPTY,
5743 };
5744
5745 static int editor_el_supaplex[] =
5746 {
5747   EL_SP_MURPHY,
5748   EL_EMPTY,
5749   EL_SP_BASE,
5750   EL_SP_BUGGY_BASE,
5751
5752   EL_SP_INFOTRON,
5753   EL_SP_ZONK,
5754   EL_SP_SNIKSNAK,
5755   EL_SP_ELECTRON,
5756
5757   EL_SP_DISK_RED,
5758   EL_SP_DISK_ORANGE,
5759   EL_SP_DISK_YELLOW,
5760   EL_SP_TERMINAL,
5761
5762   EL_SP_EXIT_CLOSED,
5763   EL_SP_PORT_HORIZONTAL,
5764   EL_SP_PORT_VERTICAL,
5765   EL_SP_PORT_ANY,
5766
5767   EL_SP_PORT_LEFT,
5768   EL_SP_PORT_RIGHT,
5769   EL_SP_PORT_UP,
5770   EL_SP_PORT_DOWN,
5771
5772   EL_SP_GRAVITY_PORT_LEFT,
5773   EL_SP_GRAVITY_PORT_RIGHT,
5774   EL_SP_GRAVITY_PORT_UP,
5775   EL_SP_GRAVITY_PORT_DOWN,
5776
5777   EL_SP_GRAVITY_ON_PORT_LEFT,
5778   EL_SP_GRAVITY_ON_PORT_RIGHT,
5779   EL_SP_GRAVITY_ON_PORT_UP,
5780   EL_SP_GRAVITY_ON_PORT_DOWN,
5781
5782   EL_SP_GRAVITY_OFF_PORT_LEFT,
5783   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5784   EL_SP_GRAVITY_OFF_PORT_UP,
5785   EL_SP_GRAVITY_OFF_PORT_DOWN,
5786
5787   EL_SP_HARDWARE_GRAY,
5788   EL_SP_HARDWARE_GREEN,
5789   EL_SP_HARDWARE_BLUE,
5790   EL_SP_HARDWARE_RED,
5791
5792   EL_SP_HARDWARE_BASE_1,
5793   EL_SP_HARDWARE_BASE_2,
5794   EL_SP_HARDWARE_BASE_3,
5795   EL_SP_HARDWARE_BASE_4,
5796
5797   EL_SP_HARDWARE_BASE_5,
5798   EL_SP_HARDWARE_BASE_6,
5799   EL_SP_HARDWARE_YELLOW,
5800   EL_SP_CHIP_TOP,
5801
5802   EL_SP_CHIP_SINGLE,
5803   EL_SP_CHIP_LEFT,
5804   EL_SP_CHIP_RIGHT,
5805   EL_SP_CHIP_BOTTOM,
5806 };
5807 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5808 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5809 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5810 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5811
5812 static int editor_hl_diamond_caves[] =
5813 {
5814   EL_INTERNAL_CASCADE_DC_ACTIVE,
5815   EL_CHAR('D'),
5816   EL_CHAR('C'),
5817   EL_CHAR('2'),
5818 };
5819
5820 static int editor_el_diamond_caves[] =
5821 {
5822   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5823   EL_EM_STEEL_EXIT_OPEN,        // DC2
5824   EL_WALL_EMERALD,              // DC2
5825   EL_WALL_DIAMOND,              // DC2
5826
5827   EL_PEARL,
5828   EL_CRYSTAL,
5829   EL_WALL_PEARL,
5830   EL_WALL_CRYSTAL,
5831
5832   EL_CONVEYOR_BELT_1_LEFT,
5833   EL_CONVEYOR_BELT_1_MIDDLE,
5834   EL_CONVEYOR_BELT_1_RIGHT,
5835   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5836
5837   EL_CONVEYOR_BELT_2_LEFT,
5838   EL_CONVEYOR_BELT_2_MIDDLE,
5839   EL_CONVEYOR_BELT_2_RIGHT,
5840   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5841
5842   EL_CONVEYOR_BELT_3_LEFT,
5843   EL_CONVEYOR_BELT_3_MIDDLE,
5844   EL_CONVEYOR_BELT_3_RIGHT,
5845   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5846
5847   EL_CONVEYOR_BELT_4_LEFT,
5848   EL_CONVEYOR_BELT_4_MIDDLE,
5849   EL_CONVEYOR_BELT_4_RIGHT,
5850   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5851
5852   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5853   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5854   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5855   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5856
5857   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5858   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5859   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5860   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5861
5862   EL_TIMEGATE_CLOSED,
5863   EL_TIMEGATE_OPEN,
5864   EL_TIMEGATE_SWITCH,
5865   EL_DC_TIMEGATE_SWITCH,
5866
5867   EL_SWITCHGATE_CLOSED,
5868   EL_SWITCHGATE_OPEN,
5869   EL_SWITCHGATE_SWITCH_UP,
5870   EL_SWITCHGATE_SWITCH_DOWN,
5871
5872   EL_LIGHT_SWITCH,
5873   EL_LIGHT_SWITCH_ACTIVE,
5874   EL_DC_SWITCHGATE_SWITCH_UP,
5875   EL_DC_SWITCHGATE_SWITCH_DOWN,
5876
5877   EL_STEEL_EXIT_CLOSED,
5878   EL_STEEL_EXIT_OPEN,
5879   EL_STEELWALL_SLIPPERY,
5880   EL_INVISIBLE_SAND,
5881
5882   EL_QUICKSAND_FAST_EMPTY,
5883   EL_QUICKSAND_FAST_FULL,
5884   EL_LANDMINE,
5885   EL_DC_LANDMINE,
5886
5887   EL_SHIELD_NORMAL,
5888   EL_SHIELD_DEADLY,
5889   EL_EXTRA_TIME,
5890   EL_DC_MAGIC_WALL,
5891
5892   EL_ENVELOPE_1,
5893   EL_ENVELOPE_2,
5894   EL_ENVELOPE_3,
5895   EL_ENVELOPE_4,
5896
5897   EL_SIGN_RADIOACTIVITY,
5898   EL_SIGN_WHEELCHAIR,
5899   EL_SIGN_PARKING,
5900   EL_SIGN_NO_ENTRY,
5901
5902   EL_SIGN_GIVE_WAY,
5903   EL_SIGN_ENTRY_FORBIDDEN,
5904   EL_SIGN_EMERGENCY_EXIT,
5905   EL_SIGN_YIN_YANG,
5906
5907 #if 0
5908   EL_SIGN_SPERMS,
5909   EL_SIGN_BULLET,
5910   EL_SIGN_HEART,
5911   EL_SIGN_CROSS,
5912
5913   EL_SIGN_FRANKIE,
5914   EL_EMPTY,
5915   EL_EMPTY,
5916   EL_EMPTY,
5917
5918   EL_SPERMS,
5919   EL_BULLET,
5920   EL_HEART,
5921   EL_CROSS,
5922
5923   EL_FRANKIE,
5924   EL_EMPTY,
5925   EL_EMPTY,
5926   EL_EMPTY,
5927 #endif
5928
5929   EL_DC_STEELWALL_2_SINGLE,
5930   EL_DC_STEELWALL_2_TOP,
5931   EL_SIGN_EXCLAMATION,
5932   EL_SIGN_STOP,
5933
5934   EL_DC_STEELWALL_2_LEFT,
5935   EL_DC_STEELWALL_2_MIDDLE,
5936   EL_DC_STEELWALL_2_HORIZONTAL,
5937   EL_DC_STEELWALL_2_RIGHT,
5938
5939   EL_DC_STEELWALL_1_TOPLEFT,
5940   EL_DC_STEELWALL_2_VERTICAL,
5941   EL_DC_STEELWALL_1_TOPRIGHT,
5942   EL_DC_GATE_WHITE,
5943
5944   EL_DC_STEELWALL_1_VERTICAL,
5945   EL_DC_STEELWALL_2_BOTTOM,
5946   EL_DC_KEY_WHITE,
5947   EL_DC_GATE_WHITE_GRAY,
5948
5949   EL_DC_STEELWALL_1_BOTTOMLEFT,
5950   EL_DC_STEELWALL_1_HORIZONTAL,
5951   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5952   EL_DC_GATE_FAKE_GRAY,
5953
5954   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5955   EL_DC_STEELWALL_1_BOTTOM,
5956   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5957   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5958
5959   EL_DC_STEELWALL_1_RIGHT,
5960   EL_EMPTY,
5961   EL_DC_STEELWALL_1_LEFT,
5962   EL_EXPANDABLE_STEELWALL_VERTICAL,
5963
5964   EL_DC_STEELWALL_1_TOPRIGHT_2,
5965   EL_DC_STEELWALL_1_TOP,
5966   EL_DC_STEELWALL_1_TOPLEFT_2,
5967   EL_EXPANDABLE_STEELWALL_ANY,
5968 };
5969 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5970 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5971 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5972 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5973
5974 static int editor_hl_dx_boulderdash[] =
5975 {
5976   EL_INTERNAL_CASCADE_DX_ACTIVE,
5977   EL_CHAR('D'),
5978   EL_CHAR('X'),
5979   EL_EMPTY,
5980 };
5981
5982 static int editor_el_dx_boulderdash[] =
5983 {
5984   EL_EMPTY,
5985   EL_TUBE_RIGHT_DOWN,
5986   EL_TUBE_HORIZONTAL_DOWN,
5987   EL_TUBE_LEFT_DOWN,
5988
5989   EL_TUBE_HORIZONTAL,
5990   EL_TUBE_VERTICAL_RIGHT,
5991   EL_TUBE_ANY,
5992   EL_TUBE_VERTICAL_LEFT,
5993
5994   EL_TUBE_VERTICAL,
5995   EL_TUBE_RIGHT_UP,
5996   EL_TUBE_HORIZONTAL_UP,
5997   EL_TUBE_LEFT_UP,
5998
5999   EL_TRAP,
6000   EL_DX_SUPABOMB,
6001   EL_EMPTY,
6002   EL_EMPTY
6003 };
6004 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
6005 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
6006 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
6007 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
6008
6009 static int editor_hl_mirror_magic[] =
6010 {
6011   EL_INTERNAL_CASCADE_MM_ACTIVE,
6012   EL_CHAR('M'),
6013   EL_CHAR('M'),
6014   EL_EMPTY,
6015 };
6016
6017 static int editor_el_mirror_magic[] =
6018 {
6019   EL_MM_MCDUFFIN_RIGHT,
6020   EL_MM_MCDUFFIN_UP,
6021   EL_MM_MCDUFFIN_LEFT,
6022   EL_MM_MCDUFFIN_DOWN,
6023
6024   EL_MM_MIRROR_START,
6025   EL_MM_MIRROR_FIXED_START,
6026   EL_MM_POLARIZER_START,
6027   EL_MM_POLARIZER_CROSS_START,
6028
6029   EL_MM_TELEPORTER_RED_START,
6030   EL_MM_TELEPORTER_YELLOW_START,
6031   EL_MM_TELEPORTER_GREEN_START,
6032   EL_MM_TELEPORTER_BLUE_START,
6033
6034   EL_MM_PRISM,
6035   EL_MM_FUSE_ACTIVE,
6036   EL_MM_PACMAN_RIGHT,
6037   EL_MM_EXIT_CLOSED,
6038
6039   EL_MM_KETTLE,
6040   EL_MM_BOMB,
6041   EL_MM_KEY,
6042   EL_MM_FUEL_FULL,
6043
6044   EL_MM_LIGHTBULB,
6045   EL_MM_LIGHTBULB_ACTIVE,
6046   EL_MM_GRAY_BALL,
6047   EL_MM_LIGHTBALL,
6048
6049   EL_MM_STEEL_WALL,
6050   EL_MM_WOODEN_WALL,
6051   EL_MM_ICE_WALL,
6052   EL_MM_AMOEBA_WALL,
6053
6054   EL_MM_STEEL_LOCK,
6055   EL_MM_WOODEN_LOCK,
6056   EL_MM_STEEL_BLOCK,
6057   EL_MM_WOODEN_BLOCK,
6058
6059   EL_MM_STEEL_GRID_FIXED_1,
6060   EL_MM_STEEL_GRID_FIXED_2,
6061   EL_MM_STEEL_GRID_FIXED_3,
6062   EL_MM_STEEL_GRID_FIXED_4,
6063
6064   EL_MM_WOODEN_GRID_FIXED_1,
6065   EL_MM_WOODEN_GRID_FIXED_2,
6066   EL_MM_WOODEN_GRID_FIXED_3,
6067   EL_MM_WOODEN_GRID_FIXED_4,
6068
6069   EL_MM_ENVELOPE_1,
6070   EL_MM_ENVELOPE_2,
6071   EL_MM_ENVELOPE_3,
6072   EL_MM_ENVELOPE_4
6073 };
6074 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
6075 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
6076 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
6077 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
6078
6079 static int editor_hl_deflektor[] =
6080 {
6081   EL_INTERNAL_CASCADE_DF_ACTIVE,
6082   EL_CHAR('D'),
6083   EL_CHAR('F'),
6084   EL_EMPTY,
6085 };
6086
6087 static int editor_el_deflektor[] =
6088 {
6089   EL_DF_LASER_RIGHT,
6090   EL_DF_LASER_UP,
6091   EL_DF_LASER_LEFT,
6092   EL_DF_LASER_DOWN,
6093
6094   EL_DF_RECEIVER_RIGHT,
6095   EL_DF_RECEIVER_UP,
6096   EL_DF_RECEIVER_LEFT,
6097   EL_DF_RECEIVER_DOWN,
6098
6099   EL_DF_MIRROR_START,
6100   EL_DF_MIRROR_ROTATING_START,
6101   EL_DF_MIRROR_FIXED_START,
6102   EL_DF_CELL,
6103
6104   EL_DF_FIBRE_OPTIC_RED_1,
6105   EL_DF_FIBRE_OPTIC_YELLOW_1,
6106   EL_DF_FIBRE_OPTIC_GREEN_1,
6107   EL_DF_FIBRE_OPTIC_BLUE_1,
6108
6109   EL_DF_STEEL_GRID_FIXED_START,
6110   EL_DF_STEEL_GRID_ROTATING_START,
6111   EL_DF_WOODEN_GRID_FIXED_START,
6112   EL_DF_WOODEN_GRID_ROTATING_START,
6113
6114   EL_DF_STEEL_WALL,
6115   EL_DF_WOODEN_WALL,
6116   EL_DF_REFRACTOR,
6117   EL_DF_MINE,
6118
6119   EL_DF_SLOPE_1,
6120   EL_DF_SLOPE_2,
6121   EL_DF_SLOPE_3,
6122   EL_DF_SLOPE_4
6123 };
6124 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
6125 static int *editor_el_deflektor_ptr = editor_el_deflektor;
6126 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
6127 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
6128
6129 static int editor_hl_chars[] =
6130 {
6131   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
6132   EL_CHAR('T'),
6133   EL_CHAR('X'),
6134   EL_CHAR('T'),
6135 };
6136
6137 static int editor_el_chars[] =
6138 {
6139   EL_CHAR(' '),
6140   EL_CHAR('!'),
6141   EL_CHAR('"'),
6142   EL_CHAR('#'),
6143
6144   EL_CHAR('$'),
6145   EL_CHAR('%'),
6146   EL_CHAR('&'),
6147   EL_CHAR('\''),
6148
6149   EL_CHAR('('),
6150   EL_CHAR(')'),
6151   EL_CHAR('*'),
6152   EL_CHAR('+'),
6153
6154   EL_CHAR(','),
6155   EL_CHAR('-'),
6156   EL_CHAR('.'),
6157   EL_CHAR('/'),
6158
6159   EL_CHAR('0'),
6160   EL_CHAR('1'),
6161   EL_CHAR('2'),
6162   EL_CHAR('3'),
6163
6164   EL_CHAR('4'),
6165   EL_CHAR('5'),
6166   EL_CHAR('6'),
6167   EL_CHAR('7'),
6168
6169   EL_CHAR('8'),
6170   EL_CHAR('9'),
6171   EL_CHAR(':'),
6172   EL_CHAR(';'),
6173
6174   EL_CHAR('<'),
6175   EL_CHAR('='),
6176   EL_CHAR('>'),
6177   EL_CHAR('?'),
6178
6179   EL_CHAR('@'),
6180   EL_CHAR('A'),
6181   EL_CHAR('B'),
6182   EL_CHAR('C'),
6183
6184   EL_CHAR('D'),
6185   EL_CHAR('E'),
6186   EL_CHAR('F'),
6187   EL_CHAR('G'),
6188
6189   EL_CHAR('H'),
6190   EL_CHAR('I'),
6191   EL_CHAR('J'),
6192   EL_CHAR('K'),
6193
6194   EL_CHAR('L'),
6195   EL_CHAR('M'),
6196   EL_CHAR('N'),
6197   EL_CHAR('O'),
6198
6199   EL_CHAR('P'),
6200   EL_CHAR('Q'),
6201   EL_CHAR('R'),
6202   EL_CHAR('S'),
6203
6204   EL_CHAR('T'),
6205   EL_CHAR('U'),
6206   EL_CHAR('V'),
6207   EL_CHAR('W'),
6208
6209   EL_CHAR('X'),
6210   EL_CHAR('Y'),
6211   EL_CHAR('Z'),
6212   EL_CHAR('['),
6213
6214   EL_CHAR('\\'),
6215   EL_CHAR(']'),
6216   EL_CHAR('^'),
6217   EL_CHAR('_'),
6218
6219   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6220   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6221   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6222   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6223
6224   EL_CHAR(CHAR_BYTE_DEGREE),
6225   EL_CHAR(CHAR_BYTE_REGISTERED),
6226   EL_CHAR(FONT_ASCII_CURSOR),
6227   EL_CHAR(FONT_ASCII_BUTTON),
6228
6229   EL_CHAR(FONT_ASCII_UP),
6230   EL_CHAR(FONT_ASCII_DOWN),
6231   EL_CHAR(' '),
6232   EL_CHAR(' ')
6233 };
6234 static int *editor_hl_chars_ptr = editor_hl_chars;
6235 static int *editor_el_chars_ptr = editor_el_chars;
6236 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6237 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6238
6239 static int editor_hl_steel_chars[] =
6240 {
6241   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6242   EL_STEEL_CHAR('T'),
6243   EL_STEEL_CHAR('X'),
6244   EL_STEEL_CHAR('T'),
6245 };
6246
6247 static int editor_el_steel_chars[] =
6248 {
6249   EL_STEEL_CHAR(' '),
6250   EL_STEEL_CHAR('!'),
6251   EL_STEEL_CHAR('"'),
6252   EL_STEEL_CHAR('#'),
6253
6254   EL_STEEL_CHAR('$'),
6255   EL_STEEL_CHAR('%'),
6256   EL_STEEL_CHAR('&'),
6257   EL_STEEL_CHAR('\''),
6258
6259   EL_STEEL_CHAR('('),
6260   EL_STEEL_CHAR(')'),
6261   EL_STEEL_CHAR('*'),
6262   EL_STEEL_CHAR('+'),
6263
6264   EL_STEEL_CHAR(','),
6265   EL_STEEL_CHAR('-'),
6266   EL_STEEL_CHAR('.'),
6267   EL_STEEL_CHAR('/'),
6268
6269   EL_STEEL_CHAR('0'),
6270   EL_STEEL_CHAR('1'),
6271   EL_STEEL_CHAR('2'),
6272   EL_STEEL_CHAR('3'),
6273
6274   EL_STEEL_CHAR('4'),
6275   EL_STEEL_CHAR('5'),
6276   EL_STEEL_CHAR('6'),
6277   EL_STEEL_CHAR('7'),
6278
6279   EL_STEEL_CHAR('8'),
6280   EL_STEEL_CHAR('9'),
6281   EL_STEEL_CHAR(':'),
6282   EL_STEEL_CHAR(';'),
6283
6284   EL_STEEL_CHAR('<'),
6285   EL_STEEL_CHAR('='),
6286   EL_STEEL_CHAR('>'),
6287   EL_STEEL_CHAR('?'),
6288
6289   EL_STEEL_CHAR('@'),
6290   EL_STEEL_CHAR('A'),
6291   EL_STEEL_CHAR('B'),
6292   EL_STEEL_CHAR('C'),
6293
6294   EL_STEEL_CHAR('D'),
6295   EL_STEEL_CHAR('E'),
6296   EL_STEEL_CHAR('F'),
6297   EL_STEEL_CHAR('G'),
6298
6299   EL_STEEL_CHAR('H'),
6300   EL_STEEL_CHAR('I'),
6301   EL_STEEL_CHAR('J'),
6302   EL_STEEL_CHAR('K'),
6303
6304   EL_STEEL_CHAR('L'),
6305   EL_STEEL_CHAR('M'),
6306   EL_STEEL_CHAR('N'),
6307   EL_STEEL_CHAR('O'),
6308
6309   EL_STEEL_CHAR('P'),
6310   EL_STEEL_CHAR('Q'),
6311   EL_STEEL_CHAR('R'),
6312   EL_STEEL_CHAR('S'),
6313
6314   EL_STEEL_CHAR('T'),
6315   EL_STEEL_CHAR('U'),
6316   EL_STEEL_CHAR('V'),
6317   EL_STEEL_CHAR('W'),
6318
6319   EL_STEEL_CHAR('X'),
6320   EL_STEEL_CHAR('Y'),
6321   EL_STEEL_CHAR('Z'),
6322   EL_STEEL_CHAR('['),
6323
6324   EL_STEEL_CHAR('\\'),
6325   EL_STEEL_CHAR(']'),
6326   EL_STEEL_CHAR('^'),
6327   EL_STEEL_CHAR('_'),
6328
6329   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6330   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6331   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6332   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6333
6334   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6335   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6336   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6337   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6338
6339   EL_STEEL_CHAR(FONT_ASCII_UP),
6340   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6341   EL_STEEL_CHAR(' '),
6342   EL_STEEL_CHAR(' ')
6343 };
6344 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6345 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6346 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6347 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6348
6349 static int editor_hl_custom[] =
6350 {
6351   EL_INTERNAL_CASCADE_CE_ACTIVE,
6352   EL_CHAR('C'),
6353   EL_CHAR('E'),
6354   EL_EMPTY,
6355 };
6356
6357 static int editor_el_custom[] =
6358 {
6359   EL_CUSTOM_START + 0,
6360   EL_CUSTOM_START + 1,
6361   EL_CUSTOM_START + 2,
6362   EL_CUSTOM_START + 3,
6363
6364   EL_CUSTOM_START + 4,
6365   EL_CUSTOM_START + 5,
6366   EL_CUSTOM_START + 6,
6367   EL_CUSTOM_START + 7,
6368
6369   EL_CUSTOM_START + 8,
6370   EL_CUSTOM_START + 9,
6371   EL_CUSTOM_START + 10,
6372   EL_CUSTOM_START + 11,
6373
6374   EL_CUSTOM_START + 12,
6375   EL_CUSTOM_START + 13,
6376   EL_CUSTOM_START + 14,
6377   EL_CUSTOM_START + 15,
6378
6379   EL_CUSTOM_START + 16,
6380   EL_CUSTOM_START + 17,
6381   EL_CUSTOM_START + 18,
6382   EL_CUSTOM_START + 19,
6383
6384   EL_CUSTOM_START + 20,
6385   EL_CUSTOM_START + 21,
6386   EL_CUSTOM_START + 22,
6387   EL_CUSTOM_START + 23,
6388
6389   EL_CUSTOM_START + 24,
6390   EL_CUSTOM_START + 25,
6391   EL_CUSTOM_START + 26,
6392   EL_CUSTOM_START + 27,
6393
6394   EL_CUSTOM_START + 28,
6395   EL_CUSTOM_START + 29,
6396   EL_CUSTOM_START + 30,
6397   EL_CUSTOM_START + 31,
6398
6399   EL_CUSTOM_START + 32,
6400   EL_CUSTOM_START + 33,
6401   EL_CUSTOM_START + 34,
6402   EL_CUSTOM_START + 35,
6403
6404   EL_CUSTOM_START + 36,
6405   EL_CUSTOM_START + 37,
6406   EL_CUSTOM_START + 38,
6407   EL_CUSTOM_START + 39,
6408
6409   EL_CUSTOM_START + 40,
6410   EL_CUSTOM_START + 41,
6411   EL_CUSTOM_START + 42,
6412   EL_CUSTOM_START + 43,
6413
6414   EL_CUSTOM_START + 44,
6415   EL_CUSTOM_START + 45,
6416   EL_CUSTOM_START + 46,
6417   EL_CUSTOM_START + 47,
6418
6419   EL_CUSTOM_START + 48,
6420   EL_CUSTOM_START + 49,
6421   EL_CUSTOM_START + 50,
6422   EL_CUSTOM_START + 51,
6423
6424   EL_CUSTOM_START + 52,
6425   EL_CUSTOM_START + 53,
6426   EL_CUSTOM_START + 54,
6427   EL_CUSTOM_START + 55,
6428
6429   EL_CUSTOM_START + 56,
6430   EL_CUSTOM_START + 57,
6431   EL_CUSTOM_START + 58,
6432   EL_CUSTOM_START + 59,
6433
6434   EL_CUSTOM_START + 60,
6435   EL_CUSTOM_START + 61,
6436   EL_CUSTOM_START + 62,
6437   EL_CUSTOM_START + 63,
6438
6439   EL_CUSTOM_START + 64,
6440   EL_CUSTOM_START + 65,
6441   EL_CUSTOM_START + 66,
6442   EL_CUSTOM_START + 67,
6443
6444   EL_CUSTOM_START + 68,
6445   EL_CUSTOM_START + 69,
6446   EL_CUSTOM_START + 70,
6447   EL_CUSTOM_START + 71,
6448
6449   EL_CUSTOM_START + 72,
6450   EL_CUSTOM_START + 73,
6451   EL_CUSTOM_START + 74,
6452   EL_CUSTOM_START + 75,
6453
6454   EL_CUSTOM_START + 76,
6455   EL_CUSTOM_START + 77,
6456   EL_CUSTOM_START + 78,
6457   EL_CUSTOM_START + 79,
6458
6459   EL_CUSTOM_START + 80,
6460   EL_CUSTOM_START + 81,
6461   EL_CUSTOM_START + 82,
6462   EL_CUSTOM_START + 83,
6463
6464   EL_CUSTOM_START + 84,
6465   EL_CUSTOM_START + 85,
6466   EL_CUSTOM_START + 86,
6467   EL_CUSTOM_START + 87,
6468
6469   EL_CUSTOM_START + 88,
6470   EL_CUSTOM_START + 89,
6471   EL_CUSTOM_START + 90,
6472   EL_CUSTOM_START + 91,
6473
6474   EL_CUSTOM_START + 92,
6475   EL_CUSTOM_START + 93,
6476   EL_CUSTOM_START + 94,
6477   EL_CUSTOM_START + 95,
6478
6479   EL_CUSTOM_START + 96,
6480   EL_CUSTOM_START + 97,
6481   EL_CUSTOM_START + 98,
6482   EL_CUSTOM_START + 99,
6483
6484   EL_CUSTOM_START + 100,
6485   EL_CUSTOM_START + 101,
6486   EL_CUSTOM_START + 102,
6487   EL_CUSTOM_START + 103,
6488
6489   EL_CUSTOM_START + 104,
6490   EL_CUSTOM_START + 105,
6491   EL_CUSTOM_START + 106,
6492   EL_CUSTOM_START + 107,
6493
6494   EL_CUSTOM_START + 108,
6495   EL_CUSTOM_START + 109,
6496   EL_CUSTOM_START + 110,
6497   EL_CUSTOM_START + 111,
6498
6499   EL_CUSTOM_START + 112,
6500   EL_CUSTOM_START + 113,
6501   EL_CUSTOM_START + 114,
6502   EL_CUSTOM_START + 115,
6503
6504   EL_CUSTOM_START + 116,
6505   EL_CUSTOM_START + 117,
6506   EL_CUSTOM_START + 118,
6507   EL_CUSTOM_START + 119,
6508
6509   EL_CUSTOM_START + 120,
6510   EL_CUSTOM_START + 121,
6511   EL_CUSTOM_START + 122,
6512   EL_CUSTOM_START + 123,
6513
6514   EL_CUSTOM_START + 124,
6515   EL_CUSTOM_START + 125,
6516   EL_CUSTOM_START + 126,
6517   EL_CUSTOM_START + 127,
6518
6519   EL_CUSTOM_START + 128,
6520   EL_CUSTOM_START + 129,
6521   EL_CUSTOM_START + 130,
6522   EL_CUSTOM_START + 131,
6523
6524   EL_CUSTOM_START + 132,
6525   EL_CUSTOM_START + 133,
6526   EL_CUSTOM_START + 134,
6527   EL_CUSTOM_START + 135,
6528
6529   EL_CUSTOM_START + 136,
6530   EL_CUSTOM_START + 137,
6531   EL_CUSTOM_START + 138,
6532   EL_CUSTOM_START + 139,
6533
6534   EL_CUSTOM_START + 140,
6535   EL_CUSTOM_START + 141,
6536   EL_CUSTOM_START + 142,
6537   EL_CUSTOM_START + 143,
6538
6539   EL_CUSTOM_START + 144,
6540   EL_CUSTOM_START + 145,
6541   EL_CUSTOM_START + 146,
6542   EL_CUSTOM_START + 147,
6543
6544   EL_CUSTOM_START + 148,
6545   EL_CUSTOM_START + 149,
6546   EL_CUSTOM_START + 150,
6547   EL_CUSTOM_START + 151,
6548
6549   EL_CUSTOM_START + 152,
6550   EL_CUSTOM_START + 153,
6551   EL_CUSTOM_START + 154,
6552   EL_CUSTOM_START + 155,
6553
6554   EL_CUSTOM_START + 156,
6555   EL_CUSTOM_START + 157,
6556   EL_CUSTOM_START + 158,
6557   EL_CUSTOM_START + 159,
6558
6559   EL_CUSTOM_START + 160,
6560   EL_CUSTOM_START + 161,
6561   EL_CUSTOM_START + 162,
6562   EL_CUSTOM_START + 163,
6563
6564   EL_CUSTOM_START + 164,
6565   EL_CUSTOM_START + 165,
6566   EL_CUSTOM_START + 166,
6567   EL_CUSTOM_START + 167,
6568
6569   EL_CUSTOM_START + 168,
6570   EL_CUSTOM_START + 169,
6571   EL_CUSTOM_START + 170,
6572   EL_CUSTOM_START + 171,
6573
6574   EL_CUSTOM_START + 172,
6575   EL_CUSTOM_START + 173,
6576   EL_CUSTOM_START + 174,
6577   EL_CUSTOM_START + 175,
6578
6579   EL_CUSTOM_START + 176,
6580   EL_CUSTOM_START + 177,
6581   EL_CUSTOM_START + 178,
6582   EL_CUSTOM_START + 179,
6583
6584   EL_CUSTOM_START + 180,
6585   EL_CUSTOM_START + 181,
6586   EL_CUSTOM_START + 182,
6587   EL_CUSTOM_START + 183,
6588
6589   EL_CUSTOM_START + 184,
6590   EL_CUSTOM_START + 185,
6591   EL_CUSTOM_START + 186,
6592   EL_CUSTOM_START + 187,
6593
6594   EL_CUSTOM_START + 188,
6595   EL_CUSTOM_START + 189,
6596   EL_CUSTOM_START + 190,
6597   EL_CUSTOM_START + 191,
6598
6599   EL_CUSTOM_START + 192,
6600   EL_CUSTOM_START + 193,
6601   EL_CUSTOM_START + 194,
6602   EL_CUSTOM_START + 195,
6603
6604   EL_CUSTOM_START + 196,
6605   EL_CUSTOM_START + 197,
6606   EL_CUSTOM_START + 198,
6607   EL_CUSTOM_START + 199,
6608
6609   EL_CUSTOM_START + 200,
6610   EL_CUSTOM_START + 201,
6611   EL_CUSTOM_START + 202,
6612   EL_CUSTOM_START + 203,
6613
6614   EL_CUSTOM_START + 204,
6615   EL_CUSTOM_START + 205,
6616   EL_CUSTOM_START + 206,
6617   EL_CUSTOM_START + 207,
6618
6619   EL_CUSTOM_START + 208,
6620   EL_CUSTOM_START + 209,
6621   EL_CUSTOM_START + 210,
6622   EL_CUSTOM_START + 211,
6623
6624   EL_CUSTOM_START + 212,
6625   EL_CUSTOM_START + 213,
6626   EL_CUSTOM_START + 214,
6627   EL_CUSTOM_START + 215,
6628
6629   EL_CUSTOM_START + 216,
6630   EL_CUSTOM_START + 217,
6631   EL_CUSTOM_START + 218,
6632   EL_CUSTOM_START + 219,
6633
6634   EL_CUSTOM_START + 220,
6635   EL_CUSTOM_START + 221,
6636   EL_CUSTOM_START + 222,
6637   EL_CUSTOM_START + 223,
6638
6639   EL_CUSTOM_START + 224,
6640   EL_CUSTOM_START + 225,
6641   EL_CUSTOM_START + 226,
6642   EL_CUSTOM_START + 227,
6643
6644   EL_CUSTOM_START + 228,
6645   EL_CUSTOM_START + 229,
6646   EL_CUSTOM_START + 230,
6647   EL_CUSTOM_START + 231,
6648
6649   EL_CUSTOM_START + 232,
6650   EL_CUSTOM_START + 233,
6651   EL_CUSTOM_START + 234,
6652   EL_CUSTOM_START + 235,
6653
6654   EL_CUSTOM_START + 236,
6655   EL_CUSTOM_START + 237,
6656   EL_CUSTOM_START + 238,
6657   EL_CUSTOM_START + 239,
6658
6659   EL_CUSTOM_START + 240,
6660   EL_CUSTOM_START + 241,
6661   EL_CUSTOM_START + 242,
6662   EL_CUSTOM_START + 243,
6663
6664   EL_CUSTOM_START + 244,
6665   EL_CUSTOM_START + 245,
6666   EL_CUSTOM_START + 246,
6667   EL_CUSTOM_START + 247,
6668
6669   EL_CUSTOM_START + 248,
6670   EL_CUSTOM_START + 249,
6671   EL_CUSTOM_START + 250,
6672   EL_CUSTOM_START + 251,
6673
6674   EL_CUSTOM_START + 252,
6675   EL_CUSTOM_START + 253,
6676   EL_CUSTOM_START + 254,
6677   EL_CUSTOM_START + 255
6678 };
6679 static int *editor_hl_custom_ptr = editor_hl_custom;
6680 static int *editor_el_custom_ptr = editor_el_custom;
6681 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6682 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6683
6684 static int editor_hl_group[] =
6685 {
6686   EL_INTERNAL_CASCADE_GE_ACTIVE,
6687   EL_CHAR('G'),
6688   EL_CHAR('E'),
6689   EL_EMPTY,
6690 };
6691
6692 static int editor_el_group[] =
6693 {
6694   EL_GROUP_START + 0,
6695   EL_GROUP_START + 1,
6696   EL_GROUP_START + 2,
6697   EL_GROUP_START + 3,
6698
6699   EL_GROUP_START + 4,
6700   EL_GROUP_START + 5,
6701   EL_GROUP_START + 6,
6702   EL_GROUP_START + 7,
6703
6704   EL_GROUP_START + 8,
6705   EL_GROUP_START + 9,
6706   EL_GROUP_START + 10,
6707   EL_GROUP_START + 11,
6708
6709   EL_GROUP_START + 12,
6710   EL_GROUP_START + 13,
6711   EL_GROUP_START + 14,
6712   EL_GROUP_START + 15,
6713
6714   EL_GROUP_START + 16,
6715   EL_GROUP_START + 17,
6716   EL_GROUP_START + 18,
6717   EL_GROUP_START + 19,
6718
6719   EL_GROUP_START + 20,
6720   EL_GROUP_START + 21,
6721   EL_GROUP_START + 22,
6722   EL_GROUP_START + 23,
6723
6724   EL_GROUP_START + 24,
6725   EL_GROUP_START + 25,
6726   EL_GROUP_START + 26,
6727   EL_GROUP_START + 27,
6728
6729   EL_GROUP_START + 28,
6730   EL_GROUP_START + 29,
6731   EL_GROUP_START + 30,
6732   EL_GROUP_START + 31
6733 };
6734 static int *editor_hl_group_ptr = editor_hl_group;
6735 static int *editor_el_group_ptr = editor_el_group;
6736 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6737 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6738
6739 static int editor_hl_empty_space[] =
6740 {
6741   EL_INTERNAL_CASCADE_ES_ACTIVE,
6742   EL_CHAR('E'),
6743   EL_CHAR('S'),
6744   EL_EMPTY,
6745 };
6746
6747 static int editor_el_empty_space[] =
6748 {
6749   EL_EMPTY_SPACE_1,
6750   EL_EMPTY_SPACE_2,
6751   EL_EMPTY_SPACE_3,
6752   EL_EMPTY_SPACE_4,
6753
6754   EL_EMPTY_SPACE_5,
6755   EL_EMPTY_SPACE_6,
6756   EL_EMPTY_SPACE_7,
6757   EL_EMPTY_SPACE_8,
6758
6759   EL_EMPTY_SPACE_9,
6760   EL_EMPTY_SPACE_10,
6761   EL_EMPTY_SPACE_11,
6762   EL_EMPTY_SPACE_12,
6763
6764   EL_EMPTY_SPACE_13,
6765   EL_EMPTY_SPACE_14,
6766   EL_EMPTY_SPACE_15,
6767   EL_EMPTY_SPACE_16
6768 };
6769 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6770 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6771 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6772 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6773
6774 static int editor_hl_reference[] =
6775 {
6776   EL_INTERNAL_CASCADE_REF_ACTIVE,
6777   EL_CHAR('R'),
6778   EL_CHAR('E'),
6779   EL_CHAR('F')
6780 };
6781
6782 static int editor_el_reference[] =
6783 {
6784   EL_TRIGGER_PLAYER,
6785   EL_TRIGGER_ELEMENT,
6786   EL_TRIGGER_CE_VALUE,
6787   EL_TRIGGER_CE_SCORE,
6788
6789   EL_SELF,
6790   EL_ANY_ELEMENT,
6791   EL_CURRENT_CE_VALUE,
6792   EL_CURRENT_CE_SCORE,
6793
6794   EL_PREV_CE_8,
6795   EL_PREV_CE_7,
6796   EL_PREV_CE_6,
6797   EL_PREV_CE_5,
6798
6799   EL_PREV_CE_4,
6800   EL_PREV_CE_3,
6801   EL_PREV_CE_2,
6802   EL_PREV_CE_1,
6803
6804   EL_NEXT_CE_1,
6805   EL_NEXT_CE_2,
6806   EL_NEXT_CE_3,
6807   EL_NEXT_CE_4,
6808
6809   EL_NEXT_CE_5,
6810   EL_NEXT_CE_6,
6811   EL_NEXT_CE_7,
6812   EL_NEXT_CE_8,
6813 };
6814 static int *editor_hl_reference_ptr = editor_hl_reference;
6815 static int *editor_el_reference_ptr = editor_el_reference;
6816 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6817 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6818
6819 static int editor_hl_user_defined[] =
6820 {
6821   EL_INTERNAL_CASCADE_USER_ACTIVE,
6822   EL_CHAR('M'),
6823   EL_CHAR('Y'),
6824   EL_EMPTY,
6825 };
6826
6827 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6828 static int *editor_el_user_defined_ptr = NULL;
6829 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6830 static int num_editor_el_user_defined = 0;
6831
6832 static int editor_hl_dynamic[] =
6833 {
6834   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6835   EL_CHAR('U'),
6836   EL_CHAR('S'),
6837   EL_CHAR('E'),
6838 };
6839
6840 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6841 static int *editor_el_dynamic_ptr = NULL;
6842 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6843 static int num_editor_el_dynamic = 0;
6844
6845 static int editor_hl_empty[] = { EL_EMPTY };
6846 static int *editor_el_empty = NULL;     // dynamically allocated
6847
6848 static int *editor_hl_empty_ptr = editor_hl_empty;
6849 static int *editor_el_empty_ptr = NULL;
6850 static int num_editor_hl_empty = 0;
6851 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6852
6853 static boolean use_el_empty = FALSE;
6854
6855 static int *editor_elements = NULL;     // dynamically allocated
6856 static int num_editor_elements = 0;     // dynamically determined
6857
6858 static boolean setup_editor_cascade_never = FALSE;
6859
6860 static boolean setup_editor_el_players                  = TRUE;
6861 static boolean setup_editor_el_boulderdash              = TRUE;
6862 static boolean setup_editor_el_boulderdash_native       = TRUE;
6863 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6864 static boolean setup_editor_el_emerald_mine             = TRUE;
6865 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6866 static boolean setup_editor_el_more                     = TRUE;
6867 static boolean setup_editor_el_sokoban                  = TRUE;
6868 static boolean setup_editor_el_supaplex                 = TRUE;
6869 static boolean setup_editor_el_diamond_caves            = TRUE;
6870 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6871 static boolean setup_editor_el_mirror_magic             = TRUE;
6872 static boolean setup_editor_el_deflektor                = TRUE;
6873 static boolean setup_editor_el_chars                    = TRUE;
6874 static boolean setup_editor_el_steel_chars              = TRUE;
6875 static boolean setup_editor_el_custom                   = TRUE;
6876 static boolean setup_editor_el_user_defined             = TRUE;
6877 static boolean setup_editor_el_dynamic                  = TRUE;
6878
6879 static int editor_hl_unused[] = { EL_EMPTY };
6880 static int *editor_hl_unused_ptr = editor_hl_unused;
6881 static int num_editor_hl_unused = 0;
6882
6883 static struct
6884 {
6885   boolean *setup_value;
6886   boolean *setup_cascade_value;
6887
6888   int **headline_list;
6889   int *headline_list_size;
6890
6891   int **element_list;
6892   int *element_list_size;
6893
6894   boolean last_setup_value;
6895 }
6896 editor_elements_info[] =
6897 {
6898   {
6899     &setup_editor_el_players,
6900     &setup_editor_cascade_never,
6901     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6902     &editor_el_players_ptr,             &num_editor_el_players
6903   },
6904   {
6905     &setup_editor_el_boulderdash,
6906     &setup.editor_cascade.el_bd,
6907     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6908     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6909   },
6910   {
6911     &setup_editor_el_boulderdash_native,
6912     &setup.editor_cascade.el_bd_native,
6913     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6914     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6915   },
6916   {
6917     &setup_editor_el_boulderdash_effects,
6918     &setup.editor_cascade.el_bd_effects,
6919     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6920     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6921   },
6922   {
6923     &setup_editor_el_emerald_mine,
6924     &setup.editor_cascade.el_em,
6925     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6926     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6927   },
6928   {
6929     &setup_editor_el_emerald_mine_club,
6930     &setup.editor_cascade.el_emc,
6931     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6932     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6933   },
6934   {
6935     &setup_editor_el_more,
6936     &setup.editor_cascade.el_rnd,
6937     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6938     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6939   },
6940   {
6941     &setup_editor_el_sokoban,
6942     &setup.editor_cascade.el_sb,
6943     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6944     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6945   },
6946   {
6947     &setup_editor_el_supaplex,
6948     &setup.editor_cascade.el_sp,
6949     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6950     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6951   },
6952   {
6953     &setup_editor_el_diamond_caves,
6954     &setup.editor_cascade.el_dc,
6955     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6956     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6957   },
6958   {
6959     &setup_editor_el_dx_boulderdash,
6960     &setup.editor_cascade.el_dx,
6961     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6962     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6963   },
6964   {
6965     &setup_editor_el_mirror_magic,
6966     &setup.editor_cascade.el_mm,
6967     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6968     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6969   },
6970   {
6971     &setup_editor_el_deflektor,
6972     &setup.editor_cascade.el_df,
6973     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6974     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6975   },
6976   {
6977     &setup_editor_el_chars,
6978     &setup.editor_cascade.el_chars,
6979     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6980     &editor_el_chars_ptr,               &num_editor_el_chars
6981   },
6982   {
6983     &setup_editor_el_steel_chars,
6984     &setup.editor_cascade.el_steel_chars,
6985     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6986     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6987   },
6988   {
6989     &setup_editor_el_custom,
6990     &setup.editor_cascade.el_ce,
6991     &editor_hl_custom_ptr,              &num_editor_hl_custom,
6992     &editor_el_custom_ptr,              &num_editor_el_custom
6993   },
6994   {
6995     &setup_editor_el_custom,
6996     &setup.editor_cascade.el_ge,
6997     &editor_hl_group_ptr,               &num_editor_hl_group,
6998     &editor_el_group_ptr,               &num_editor_el_group
6999   },
7000   {
7001     &setup_editor_el_custom,
7002     &setup.editor_cascade.el_es,
7003     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
7004     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
7005   },
7006   {
7007     &setup_editor_el_custom,
7008     &setup.editor_cascade.el_ref,
7009     &editor_hl_reference_ptr,           &num_editor_hl_reference,
7010     &editor_el_reference_ptr,           &num_editor_el_reference
7011   },
7012   {
7013     &setup_editor_el_user_defined,
7014     &setup.editor_cascade.el_user,
7015     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
7016     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
7017   },
7018   {
7019     &setup_editor_el_dynamic,
7020     &setup.editor_cascade.el_dynamic,
7021     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
7022     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
7023   },
7024   {
7025     &use_el_empty,
7026     &use_el_empty,
7027     &editor_hl_empty_ptr,               &num_editor_hl_empty,
7028     &editor_el_empty_ptr,               &num_editor_el_empty,
7029   },
7030   {
7031     NULL,
7032     NULL,
7033     NULL,                               NULL,
7034     NULL,                               NULL
7035   }
7036 };
7037
7038 static struct XY xy_directions[] =
7039 {
7040   { -1,  0 },
7041   { +1,  0 },
7042   {  0, -1 },
7043   {  0, +1 }
7044 };
7045
7046
7047 // ----------------------------------------------------------------------------
7048 // functions
7049 // ----------------------------------------------------------------------------
7050
7051 static int getMaxInfoTextLength(void)
7052 {
7053   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
7054 }
7055
7056 static int getTextWidthForGadget(char *text)
7057 {
7058   if (text == NULL)
7059     return 0;
7060
7061   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
7062 }
7063
7064 static int getTextWidthForDrawingArea(char *text)
7065 {
7066   if (text == NULL)
7067     return 0;
7068
7069   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
7070 }
7071
7072 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
7073 {
7074   return (gi->x + gi->width + getTextWidthForGadget(text));
7075 }
7076
7077 static char *getElementInfoText(int element)
7078 {
7079   char *info_text = NULL;
7080
7081   if (element < MAX_NUM_ELEMENTS)
7082   {
7083     if (strlen(element_info[element].description) > 0)
7084       info_text = element_info[element].description;
7085     else if (element_info[element].custom_description != NULL)
7086       info_text = element_info[element].custom_description;
7087     else if (element_info[element].editor_description != NULL)
7088       info_text = element_info[element].editor_description;
7089   }
7090
7091   if (info_text == NULL)
7092     info_text = INFOTEXT_UNKNOWN_ELEMENT;
7093
7094   return info_text;
7095 }
7096
7097 static char *getElementDescriptionFilenameExt(char *basename)
7098 {
7099   char *elements_subdir = ELEMENTS_DIRECTORY;
7100   static char *elements_subdir2 = NULL;
7101   static char *filename = NULL;
7102
7103   if (elements_subdir2 == NULL)
7104     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
7105
7106   checked_free(filename);
7107
7108   // 1st try: look for element description in current level set directory
7109   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
7110   if (fileExists(filename))
7111     return filename;
7112
7113   free(filename);
7114
7115   // 2nd try: look for element description in the game's base directory
7116   filename = getPath3(options.docs_directory, elements_subdir, basename);
7117   if (fileExists(filename))
7118     return filename;
7119
7120   return NULL;
7121 }
7122
7123 static char *getElementDescriptionFilename(int element)
7124 {
7125   char basename[MAX_FILENAME_LEN];
7126   char *filename;
7127
7128   // 1st try: look for element description file for exactly this element
7129   sprintf(basename, "%s.txt", element_info[element].token_name);
7130   filename = getElementDescriptionFilenameExt(basename);
7131   if (filename != NULL)
7132     return filename;
7133
7134   // 2nd try: look for element description file for this element's class
7135   sprintf(basename, "%s.txt", element_info[element].class_name);
7136   filename = getElementDescriptionFilenameExt(basename);
7137   if (filename != NULL)
7138     return filename;
7139
7140   // 3rd try: look for generic fallback text file for any element
7141   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
7142   if (filename != NULL)
7143     return filename;
7144
7145   return NULL;
7146 }
7147
7148 static boolean suppressBorderElement(void)
7149 {
7150   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
7151           lev_fieldx <= MAX_ED_FIELDX &&
7152           lev_fieldy <= MAX_ED_FIELDY);
7153 }
7154
7155 static void InitDynamicEditorElementList(int **elements, int *num_elements)
7156 {
7157   boolean element_found[NUM_FILE_ELEMENTS];
7158   int i, x, y;
7159
7160   // initialize list of used elements to "not used"
7161   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7162     element_found[i] = FALSE;
7163
7164   // find all elements used in current level
7165   for (y = 0; y < lev_fieldy; y++)
7166   {
7167     for (x = 0; x < lev_fieldx; x++)
7168     {
7169       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
7170         continue;
7171
7172       if (IS_MM_WALL(Tile[x][y]))
7173         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
7174       else
7175         element_found[Tile[x][y]] = TRUE;
7176     }
7177   }
7178
7179   *num_elements = 0;
7180
7181   // count number of elements used in current level
7182   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7183     if (element_found[i])
7184       (*num_elements)++;
7185
7186   // add space for up to 3 more elements for padding that may be needed
7187   *num_elements += 3;
7188
7189   // free memory for old list of elements, if needed
7190   checked_free(*elements);
7191
7192   // allocate memory for new list of elements
7193   *elements = checked_malloc(*num_elements * sizeof(int));
7194
7195   *num_elements = 0;
7196
7197   // add all elements used in current level (non-custom/group/empty elements)
7198   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7199     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
7200                               IS_GROUP_ELEMENT(i) ||
7201                               IS_EMPTY_ELEMENT(i)))
7202       (*elements)[(*num_elements)++] = i;
7203
7204   // add all elements used in current level (custom/group/empty elements)
7205   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7206     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
7207                              IS_GROUP_ELEMENT(i) ||
7208                              IS_EMPTY_ELEMENT(i)))
7209       (*elements)[(*num_elements)++] = i;
7210
7211   while (*num_elements % 4)     // pad with empty elements, if needed
7212     (*elements)[(*num_elements)++] = EL_EMPTY;
7213 }
7214
7215 static void ReinitializeElementList_EnableSections(void)
7216 {
7217   // default: enable all element sections
7218
7219   setup_editor_el_players               = TRUE;
7220   setup_editor_el_boulderdash           = TRUE;
7221   setup_editor_el_boulderdash_native    = TRUE;
7222   setup_editor_el_boulderdash_effects   = TRUE;
7223   setup_editor_el_emerald_mine          = TRUE;
7224   setup_editor_el_emerald_mine_club     = TRUE;
7225   setup_editor_el_more                  = TRUE;
7226   setup_editor_el_sokoban               = TRUE;
7227   setup_editor_el_supaplex              = TRUE;
7228   setup_editor_el_diamond_caves         = TRUE;
7229   setup_editor_el_dx_boulderdash        = TRUE;
7230   setup_editor_el_mirror_magic          = TRUE;
7231   setup_editor_el_deflektor             = TRUE;
7232   setup_editor_el_chars                 = TRUE;
7233   setup_editor_el_steel_chars           = TRUE;
7234
7235   setup_editor_el_custom                = TRUE;
7236   setup_editor_el_user_defined          = TRUE;
7237   setup_editor_el_dynamic               = TRUE;
7238
7239   // now disable all element sections not to be displayed
7240
7241   if (!setup.editor.el_classic)
7242   {
7243     setup_editor_el_players             = FALSE;
7244     setup_editor_el_boulderdash         = FALSE;
7245     setup_editor_el_boulderdash_native  = FALSE;
7246     setup_editor_el_boulderdash_effects = FALSE;
7247     setup_editor_el_emerald_mine        = FALSE;
7248     setup_editor_el_emerald_mine_club   = FALSE;
7249     setup_editor_el_more                = FALSE;
7250     setup_editor_el_sokoban             = FALSE;
7251     setup_editor_el_supaplex            = FALSE;
7252     setup_editor_el_diamond_caves       = FALSE;
7253     setup_editor_el_dx_boulderdash      = FALSE;
7254     setup_editor_el_mirror_magic        = FALSE;
7255     setup_editor_el_deflektor           = FALSE;
7256     setup_editor_el_chars               = FALSE;
7257     setup_editor_el_steel_chars         = FALSE;
7258   }
7259
7260   if (!setup.editor.el_custom)
7261   {
7262     setup_editor_el_custom              = FALSE;
7263   }
7264
7265   if (!setup.editor.el_user_defined)
7266   {
7267     setup_editor_el_user_defined        = FALSE;
7268   }
7269
7270   if (!setup.editor.el_dynamic)
7271   {
7272     setup_editor_el_dynamic             = FALSE;
7273   }
7274
7275   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7276   {
7277     setup_editor_el_boulderdash_native  = FALSE;
7278     setup_editor_el_boulderdash_effects = FALSE;
7279     setup_editor_el_mirror_magic        = FALSE;
7280     setup_editor_el_deflektor           = FALSE;
7281   }
7282   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7283   {
7284     setup_editor_el_players             = FALSE;
7285     setup_editor_el_boulderdash         = FALSE;
7286     setup_editor_el_emerald_mine        = FALSE;
7287     setup_editor_el_emerald_mine_club   = FALSE;
7288     setup_editor_el_more                = FALSE;
7289     setup_editor_el_sokoban             = FALSE;
7290     setup_editor_el_supaplex            = FALSE;
7291     setup_editor_el_diamond_caves       = FALSE;
7292     setup_editor_el_dx_boulderdash      = FALSE;
7293     setup_editor_el_mirror_magic        = FALSE;
7294     setup_editor_el_deflektor           = FALSE;
7295     setup_editor_el_chars               = FALSE;
7296     setup_editor_el_steel_chars         = FALSE;
7297
7298     setup_editor_el_custom              = FALSE;
7299   }
7300   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7301   {
7302     setup_editor_el_boulderdash         = FALSE;
7303     setup_editor_el_boulderdash_native  = FALSE;
7304     setup_editor_el_boulderdash_effects = FALSE;
7305     setup_editor_el_more                = FALSE;
7306     setup_editor_el_sokoban             = FALSE;
7307     setup_editor_el_supaplex            = FALSE;
7308     setup_editor_el_diamond_caves       = FALSE;
7309     setup_editor_el_dx_boulderdash      = FALSE;
7310     setup_editor_el_mirror_magic        = FALSE;
7311     setup_editor_el_deflektor           = FALSE;
7312     setup_editor_el_steel_chars         = FALSE;
7313
7314     setup_editor_el_custom              = FALSE;
7315   }
7316   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7317   {
7318     setup_editor_el_players             = FALSE;
7319     setup_editor_el_boulderdash         = FALSE;
7320     setup_editor_el_boulderdash_native  = FALSE;
7321     setup_editor_el_boulderdash_effects = FALSE;
7322     setup_editor_el_emerald_mine        = FALSE;
7323     setup_editor_el_emerald_mine_club   = FALSE;
7324     setup_editor_el_more                = FALSE;
7325     setup_editor_el_sokoban             = FALSE;
7326     setup_editor_el_diamond_caves       = FALSE;
7327     setup_editor_el_dx_boulderdash      = FALSE;
7328     setup_editor_el_mirror_magic        = FALSE;
7329     setup_editor_el_deflektor           = FALSE;
7330     setup_editor_el_chars               = FALSE;
7331     setup_editor_el_steel_chars         = FALSE;
7332
7333     setup_editor_el_custom              = FALSE;
7334   }
7335   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7336   {
7337     setup_editor_el_players             = FALSE;
7338     setup_editor_el_boulderdash         = FALSE;
7339     setup_editor_el_boulderdash_native  = FALSE;
7340     setup_editor_el_boulderdash_effects = FALSE;
7341     setup_editor_el_emerald_mine        = FALSE;
7342     setup_editor_el_emerald_mine_club   = FALSE;
7343     setup_editor_el_more                = FALSE;
7344     setup_editor_el_sokoban             = FALSE;
7345     setup_editor_el_supaplex            = FALSE;
7346     setup_editor_el_diamond_caves       = FALSE;
7347     setup_editor_el_dx_boulderdash      = FALSE;
7348     setup_editor_el_steel_chars         = FALSE;
7349
7350     setup_editor_el_custom              = FALSE;
7351   }
7352 }
7353
7354 static void ReinitializeElementList(void)
7355 {
7356   static boolean initialization_needed = TRUE;
7357   int pos = 0;
7358   int i, j;
7359
7360   ReinitializeElementList_EnableSections();
7361
7362   if (initialization_needed)
7363   {
7364     LoadSetup_EditorCascade();          // load last editor cascade state
7365
7366     // initialize editor cascade element from saved cascade state
7367     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7368     {
7369       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7370       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7371
7372       if (IS_EDITOR_CASCADE(*cascade_element))
7373         *cascade_element =
7374           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7375            EL_CASCADE_INACTIVE(*cascade_element));
7376     }
7377
7378     initialization_needed = FALSE;
7379   }
7380
7381   checked_free(editor_elements);
7382
7383   // reload optional user defined element list for each invocation of editor
7384   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7385                                    &num_editor_el_user_defined);
7386
7387   // initialize dynamic level element list for each invocation of editor
7388   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7389                                &num_editor_el_dynamic);
7390
7391   // initialize list of empty elements (used for padding, if needed)
7392   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7393     editor_el_empty[i] = EL_EMPTY;
7394
7395   // do some sanity checks for each element from element list
7396   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7397   {
7398     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7399     {
7400       int element = (*editor_elements_info[i].element_list)[j];
7401
7402       if (element >= NUM_FILE_ELEMENTS)
7403         Warn("editor element %d is runtime element", element);
7404
7405       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7406         Warn("no element description text for element %d", element);
7407     }
7408   }
7409
7410   num_editor_elements = 0;
7411   use_el_empty = FALSE;
7412
7413   // determine size of element list
7414   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7415   {
7416     if (*editor_elements_info[i].setup_value)
7417     {
7418       boolean found_inactive_cascade = FALSE;
7419
7420       if (setup.editor.el_headlines)
7421       {
7422         // required for correct padding of palette headline buttons
7423         if (*editor_elements_info[i].headline_list_size > 0)
7424           num_editor_elements += ED_ELEMENTLIST_COLS;
7425
7426         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7427         {
7428           int element = (*editor_elements_info[i].headline_list)[j];
7429
7430           if (IS_EDITOR_CASCADE_INACTIVE(element))
7431             found_inactive_cascade = TRUE;
7432         }
7433       }
7434
7435       if (found_inactive_cascade)
7436         continue;
7437
7438       // required for correct padding of palette element buttons
7439       int element_list_size = *editor_elements_info[i].element_list_size;
7440       int element_rows =
7441         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7442       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7443
7444       num_editor_elements += element_buttons;
7445     }
7446   }
7447
7448   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7449   {
7450     // offer at least as many elements as element buttons exist
7451     use_el_empty = TRUE;
7452     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7453
7454     num_editor_elements += num_editor_el_empty;
7455   }
7456   else
7457   {
7458     num_editor_el_empty = 0;
7459   }
7460
7461   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7462
7463   // fill element list
7464   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7465   {
7466     boolean found_inactive_cascade = FALSE;
7467
7468     if (*editor_elements_info[i].setup_value)
7469     {
7470       if (setup.editor.el_headlines)
7471       {
7472         // required for correct padding of palette headline buttons
7473         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7474                              ED_ELEMENTLIST_COLS : 0);
7475
7476         for (j = 0; j < headline_size; j++)
7477         {
7478           // use empty elements for padding of palette headline buttons
7479           int element = (j < *editor_elements_info[i].headline_list_size ?
7480                          (*editor_elements_info[i].headline_list)[j] :
7481                          editor_el_empty[0]);
7482
7483           editor_elements[pos++] = element;
7484
7485           if (IS_EDITOR_CASCADE_INACTIVE(element))
7486             found_inactive_cascade = TRUE;
7487         }
7488       }
7489
7490       if (found_inactive_cascade)
7491         continue;
7492
7493       // required for correct padding of palette element buttons
7494       int element_list_size = *editor_elements_info[i].element_list_size;
7495       int element_rows =
7496         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7497       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7498
7499       // copy all elements from element list
7500       for (j = 0; j < element_list_size; j++)
7501         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7502
7503       // use empty elements for padding of palette element buttons
7504       for (j = 0; j < element_buttons - element_list_size; j++)
7505         editor_elements[pos++] = editor_el_empty[0];
7506     }
7507   }
7508
7509   // (this function is also called before editor gadgets are initialized!)
7510   AdjustElementListScrollbar();
7511 }
7512
7513 void PrintEditorElementList(void)
7514 {
7515   boolean *stop = &setup_editor_el_user_defined;
7516   int i, j;
7517
7518   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7519   {
7520     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7521
7522     if (IS_EDITOR_CASCADE(cascade_element))
7523     {
7524       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7525       char *headline = element_info[cascade_element_show].editor_description;
7526
7527       PrintLineWithPrefix("# ", "-", 77);
7528       Print("# %s\n", headline);
7529       PrintLineWithPrefix("# ", "-", 77);
7530     }
7531
7532     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7533     {
7534       int element = (*editor_elements_info[i].headline_list)[j];
7535
7536       if (IS_EDITOR_CASCADE(element))
7537         element = EL_CHAR_MINUS;
7538
7539       Print("# %s\n", element_info[element].token_name);
7540     }
7541
7542     if (j > 0)
7543       Print("#\n");
7544
7545     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7546     {
7547       int element = (*editor_elements_info[i].element_list)[j];
7548
7549       Print("# %s\n", element_info[element].token_name);
7550     }
7551
7552     if (j > 0)
7553       Print("#\n");
7554   }
7555 }
7556
7557 static void ReinitializeElementListButtons(void)
7558 {
7559   static boolean last_setup_value_headlines = FALSE;
7560   static boolean initialization_needed = TRUE;
7561   int i;
7562
7563   if (!initialization_needed)   // check if editor element setup has changed
7564   {
7565     if (last_setup_value_headlines != setup.editor.el_headlines)
7566       initialization_needed = TRUE;
7567
7568     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7569       if (editor_elements_info[i].last_setup_value !=
7570           *editor_elements_info[i].setup_value)
7571         initialization_needed = TRUE;
7572   }
7573
7574   if (!initialization_needed)
7575     return;
7576
7577   FreeLevelEditorGadgets();
7578   CreateLevelEditorGadgets();
7579
7580   // store current setup values for next invocation of this function
7581   last_setup_value_headlines = setup.editor.el_headlines;
7582   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7583     editor_elements_info[i].last_setup_value =
7584       *editor_elements_info[i].setup_value;
7585
7586   initialization_needed = FALSE;
7587 }
7588
7589 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7590                               boolean input)
7591 {
7592   int border_graphic =
7593     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7594   struct GraphicInfo *g = &graphic_info[border_graphic];
7595   Bitmap *src_bitmap = g->bitmap;
7596   int src_x = g->src_x;
7597   int src_y = g->src_y;
7598   int border_size = g->border_size;
7599   int border_xpos = g->width  - border_size;
7600   int border_ypos = g->height - border_size;
7601   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7602   int i;
7603
7604   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7605              border_size, border_size,
7606              dest_x - border_size, dest_y - border_size);
7607   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7608              border_size, border_size,
7609              dest_x + width, dest_y - border_size);
7610   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7611              border_size, border_size,
7612              dest_x - border_size, dest_y + height);
7613   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7614              border_size, border_size,
7615              dest_x + width, dest_y + height);
7616
7617   for (i = 0; i < width / tilesize; i++)
7618   {
7619     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7620                tilesize, border_size,
7621                dest_x + i * tilesize, dest_y - border_size);
7622     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7623                tilesize, border_size,
7624                dest_x + i * tilesize, dest_y + height);
7625   }
7626
7627   for (i = 0; i < height / tilesize; i++)
7628   {
7629     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7630                border_size, tilesize,
7631                dest_x - border_size, dest_y + i * tilesize);
7632     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7633                border_size, tilesize,
7634                dest_x + width, dest_y + i * tilesize);
7635   }
7636
7637   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7638 }
7639
7640 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7641 {
7642   int xsize_tile = MAX(ed_tilesize, xsize);
7643   int ysize_tile = MAX(ed_tilesize, ysize);
7644   int xsize_full = xsize + 1;
7645   int ysize_full = ysize + 1;
7646   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7647   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7648   Pixel line_color = getTabulatorBarColor();
7649
7650   if (line_color == BLACK_PIXEL)                // black => transparent
7651     return;
7652
7653   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7654   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7655   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7656 }
7657
7658 static void DrawEditorLevelBorderLinesIfNeeded(void)
7659 {
7660   int xsize = lev_fieldx * ed_tilesize;
7661   int ysize = lev_fieldy * ed_tilesize;
7662   int line_size = getTabulatorBarHeight();
7663
7664   if (!suppressBorderElement())
7665     return;
7666
7667   // draw little border line around editable level playfield
7668
7669   if (xsize < SXSIZE)
7670     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7671
7672   if (ysize < SYSIZE)
7673     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7674
7675   if (xsize < SXSIZE && ysize < SYSIZE)
7676     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7677 }
7678
7679 static void DrawEditorElement(int x, int y, int element)
7680 {
7681   DrawSizedElement(x, y, element, ed_tilesize);
7682 }
7683
7684 static void DrawEditorElementThruMask(int x, int y, int element)
7685 {
7686   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7687 }
7688
7689 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7690 {
7691   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7692 }
7693
7694 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7695 {
7696   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7697   DrawEditorLevelBorderLinesIfNeeded();
7698 }
7699
7700 static void DrawDrawingArea(int id)
7701 {
7702   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7703   int x, y;
7704
7705   int *value = drawingarea_info[id].value;
7706   int area_xsize = drawingarea_info[id].area_xsize;
7707   int area_ysize = drawingarea_info[id].area_ysize;
7708   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7709
7710   for (x = 0; x < area_xsize; x++)
7711   {
7712     for (y = 0; y < area_ysize; y++)
7713     {
7714       int element = value[x * area_ysize + y];
7715       int graphic;
7716       int frame;
7717
7718       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7719
7720       DrawSizedGraphicExt(drawto,
7721                           gi->x + x * tilesize,
7722                           gi->y + y * tilesize,
7723                           graphic, frame, tilesize);
7724     }
7725   }
7726 }
7727
7728 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7729 {
7730   int x, y;
7731   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7732   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7733
7734   BlitBitmap(drawto, drawto,
7735              SX + (dx == -1 ? ed_tilesize : 0),
7736              SY + (dy == -1 ? ed_tilesize : 0),
7737              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7738              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7739              SX + (dx == +1 ? ed_tilesize : 0),
7740              SY + (dy == +1 ? ed_tilesize : 0));
7741
7742   if (dx)
7743   {
7744     x = (dx == 1 ? 0 : ed_fieldx - 1);
7745     for (y = 0; y < ed_fieldy; y++)
7746       DrawEditorElementOrWall(x, y, from_x, from_y);
7747   }
7748   else if (dy)
7749   {
7750     y = (dy == 1 ? 0 : ed_fieldy - 1);
7751     for (x = 0; x < ed_fieldx; x++)
7752       DrawEditorElementOrWall(x, y, from_x, from_y);
7753   }
7754
7755   redraw_mask |= REDRAW_FIELD;
7756   BackToFront();
7757 }
7758
7759 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7760 {
7761   if (use_editor_gfx)
7762   {
7763     *graphic = el2edimg(element);
7764     *frame = 0;
7765   }
7766   else
7767   {
7768     *graphic = el2img(element);
7769     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7770               custom_element.ce_value_fixed_initial :
7771               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7772               custom_element.collect_score_initial : FrameCounter);
7773   }
7774
7775   if (*graphic == IMG_UNKNOWN)
7776   {
7777     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7778     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7779     int element_bd = map_element_RND_to_BD_cave(element);
7780
7781     if (element_bd != O_UNKNOWN)
7782     {
7783       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7784
7785       *graphic = g_bd->graphic;
7786       *frame   = g_bd->frame;
7787     }
7788   }
7789 }
7790
7791 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7792                                    int *x, int *y)
7793 {
7794   int graphic;
7795   int frame;
7796
7797   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7798
7799   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7800 }
7801
7802 static void CreateControlButtons(void)
7803 {
7804   struct GadgetInfo *gi;
7805   int i;
7806
7807   // create toolbox buttons
7808   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7809   {
7810     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7811     int id = controlbutton_info[i].gadget_id;
7812     int type = controlbutton_info[i].gadget_type;
7813     int graphic = controlbutton_info[i].graphic;
7814     struct XYTileSize *pos = controlbutton_info[i].pos;
7815     struct GraphicInfo *gd = &graphic_info[graphic];
7816     Bitmap *deco_bitmap = NULL;
7817     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7818     int tile_size = 0, deco_shift = 0;
7819     boolean deco_masked = FALSE;
7820     int gd_x1 = gd->src_x;
7821     int gd_y1 = gd->src_y;
7822     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7823     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7824     int gd_x1a = gd->src_x + gd->active_xoffset;
7825     int gd_y1a = gd->src_y + gd->active_yoffset;
7826     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7827     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7828     int x = pos->x;
7829     int y = pos->y;
7830     unsigned int event_mask;
7831     int radio_button_nr = RADIO_NR_NONE;
7832     boolean checked = FALSE;
7833
7834     if (type_id != i)
7835       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7836
7837     if (type == GD_TYPE_RADIO_BUTTON)
7838     {
7839       event_mask = GD_EVENT_PRESSED;
7840       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7841
7842       if (id == drawing_function)
7843         checked = TRUE;
7844     }
7845     else
7846     {
7847       if (id == GADGET_ID_WRAP_LEFT ||
7848           id == GADGET_ID_WRAP_RIGHT ||
7849           id == GADGET_ID_WRAP_UP ||
7850           id == GADGET_ID_WRAP_DOWN)
7851         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7852       else
7853         event_mask = GD_EVENT_RELEASED;
7854     }
7855
7856     if (id == GADGET_ID_PROPERTIES ||
7857         id == GADGET_ID_PALETTE)
7858     {
7859       x += DX;
7860       y += DY;
7861     }
7862     else if (id == GADGET_ID_ELEMENT_LEFT ||
7863              id == GADGET_ID_ELEMENT_MIDDLE ||
7864              id == GADGET_ID_ELEMENT_RIGHT)
7865     {
7866       x += DX;
7867       y += DY;
7868
7869       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7870                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7871                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7872
7873       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7874                                    editor.button.element_left.tile_size :
7875                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7876                                    editor.button.element_middle.tile_size :
7877                                    id == GADGET_ID_ELEMENT_RIGHT ?
7878                                    editor.button.element_right.tile_size : 0);
7879
7880       // make sure that decoration does not overlap gadget border
7881       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7882
7883       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7884
7885       deco_xpos = (gd->width  - tile_size) / 2;
7886       deco_ypos = (gd->height - tile_size) / 2;
7887       deco_shift = 1;
7888       deco_masked = gd->draw_masked;
7889     }
7890     else
7891     {
7892       x += EX;
7893       y += EY;
7894     }
7895
7896     gi = CreateGadget(GDI_CUSTOM_ID, id,
7897                       GDI_CUSTOM_TYPE_ID, type_id,
7898                       GDI_IMAGE_ID, graphic,
7899                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7900                       GDI_X, x,
7901                       GDI_Y, y,
7902                       GDI_WIDTH, gd->width,
7903                       GDI_HEIGHT, gd->height,
7904                       GDI_TYPE, type,
7905                       GDI_STATE, GD_BUTTON_UNPRESSED,
7906                       GDI_RADIO_NR, radio_button_nr,
7907                       GDI_CHECKED, checked,
7908                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7909                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7910                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7911                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7912                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7913                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7914                       GDI_DECORATION_SIZE, tile_size, tile_size,
7915                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7916                       GDI_DECORATION_MASKED, deco_masked,
7917                       GDI_EVENT_MASK, event_mask,
7918                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7919                       GDI_CALLBACK_ACTION, HandleControlButtons,
7920                       GDI_END);
7921
7922     if (gi == NULL)
7923       Fail("cannot create gadget");
7924
7925     level_editor_gadget[id] = gi;
7926   }
7927
7928   // these values are not constant, but can change at runtime
7929   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7930   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7931   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7932   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7933   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7934   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7935   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7936   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7937   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7938   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7939   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7940   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7941
7942   // create buttons for scrolling of drawing area and element list
7943   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7944   {
7945     int id = scrollbutton_info[i].gadget_id;
7946     int type_id = scrollbutton_info[i].gadget_type_id;
7947     int graphic = scrollbutton_info[i].graphic;
7948     struct GraphicInfo *gd = &graphic_info[graphic];
7949     Bitmap *gd_bitmap = gd->bitmap;
7950     int gd_x1 = gd->src_x;
7951     int gd_y1 = gd->src_y;
7952     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7953     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7954     int width  = gd->width;
7955     int height = gd->height;
7956     int x = scrollbutton_pos[i].x;
7957     int y = scrollbutton_pos[i].y;
7958     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7959
7960     if (type_id != i)
7961       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7962
7963     if (id == GADGET_ID_SCROLL_LIST_UP ||
7964         id == GADGET_ID_SCROLL_LIST_DOWN)
7965     {
7966       x += PX;
7967       y += PY;
7968     }
7969     else
7970     {
7971       x += SX;
7972       y += SY;
7973     }
7974
7975     gi = CreateGadget(GDI_CUSTOM_ID, id,
7976                       GDI_CUSTOM_TYPE_ID, type_id,
7977                       GDI_IMAGE_ID, graphic,
7978                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7979                       GDI_X, x,
7980                       GDI_Y, y,
7981                       GDI_WIDTH, width,
7982                       GDI_HEIGHT, height,
7983                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7984                       GDI_STATE, GD_BUTTON_UNPRESSED,
7985                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7986                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7987                       GDI_EVENT_MASK, event_mask,
7988                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7989                       GDI_CALLBACK_ACTION, HandleControlButtons,
7990                       GDI_END);
7991
7992     if (gi == NULL)
7993       Fail("cannot create gadget");
7994
7995     level_editor_gadget[id] = gi;
7996   }
7997
7998   // create buttons for element list
7999   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8000   {
8001     int type_id = i;
8002     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
8003     int graphic = IMG_EDITOR_PALETTE_BUTTON;
8004     struct GraphicInfo *gd = &graphic_info[graphic];
8005     Bitmap *gd_bitmap = gd->bitmap;
8006     Bitmap *deco_bitmap;
8007     int deco_x, deco_y, deco_xpos, deco_ypos;
8008     int gd_x1 = gd->src_x;
8009     int gd_y1 = gd->src_y;
8010     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8011     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8012     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
8013     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
8014     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
8015     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
8016     int element = editor_elements[i];
8017     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
8018     unsigned int event_mask = GD_EVENT_RELEASED;
8019
8020     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
8021
8022     deco_xpos = (gd->width  - tile_size) / 2;
8023     deco_ypos = (gd->height - tile_size) / 2;
8024
8025     gi = CreateGadget(GDI_CUSTOM_ID, id,
8026                       GDI_CUSTOM_TYPE_ID, type_id,
8027                       GDI_IMAGE_ID, graphic,
8028                       GDI_INFO_TEXT, getElementInfoText(element),
8029                       GDI_X, x,
8030                       GDI_Y, y,
8031                       GDI_WIDTH, gd->width,
8032                       GDI_HEIGHT, gd->height,
8033                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8034                       GDI_STATE, GD_BUTTON_UNPRESSED,
8035                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
8036                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
8037                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
8038                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
8039                       GDI_DECORATION_SIZE, tile_size, tile_size,
8040                       GDI_DECORATION_SHIFTING, 1, 1,
8041                       GDI_EVENT_MASK, event_mask,
8042                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8043                       GDI_CALLBACK_ACTION, HandleControlButtons,
8044                       GDI_END);
8045
8046     if (gi == NULL)
8047       Fail("cannot create gadget");
8048
8049     level_editor_gadget[id] = gi;
8050   }
8051 }
8052
8053 static void CreateCounterButtons(void)
8054 {
8055   int max_infotext_len = getMaxInfoTextLength();
8056   int i;
8057
8058   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
8059   {
8060     int type_id = counterbutton_info[i].gadget_type_id;
8061     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
8062     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
8063     int j;
8064
8065     if (type_id != i)
8066       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
8067
8068     // determine horizontal position to the right of specified gadget
8069     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8070       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
8071            ED_GADGET_TEXT_DISTANCE);
8072
8073     // determine horizontal offset for leading text
8074     if (counterbutton_info[i].text_left != NULL)
8075       x += getTextWidthForGadget(counterbutton_info[i].text_left);
8076
8077     for (j = 0; j < 2; j++)
8078     {
8079       struct GadgetInfo *gi;
8080       int id = (j == 0 ?
8081                 counterbutton_info[i].gadget_id_down :
8082                 counterbutton_info[i].gadget_id_up);
8083       int graphic;
8084       struct GraphicInfo *gd;
8085       int gd_x1, gd_x2, gd_y1, gd_y2;
8086       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
8087       char infotext[max_infotext_len + 1];
8088
8089       if (i == ED_COUNTER_ID_SELECT_LEVEL)
8090       {
8091         graphic = (j == 0 ?
8092                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
8093                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
8094
8095         event_mask |= GD_EVENT_RELEASED;
8096
8097         if (j == 0)
8098         {
8099           x = DX + editor.button.prev_level.x;
8100           y = DY + editor.button.prev_level.y;
8101         }
8102         else
8103         {
8104           x = DX + editor.button.next_level.x;
8105           y = DY + editor.button.next_level.y;
8106         }
8107       }
8108       else
8109       {
8110         graphic = (j == 0 ?
8111                    IMG_EDITOR_COUNTER_DOWN :
8112                    IMG_EDITOR_COUNTER_UP);
8113       }
8114
8115       gd = &graphic_info[graphic];
8116
8117       gd_x1 = gd->src_x;
8118       gd_y1 = gd->src_y;
8119       gd_x2 = gd->src_x + gd->pressed_xoffset;
8120       gd_y2 = gd->src_y + gd->pressed_yoffset;
8121
8122       sprintf(infotext, "%s counter value by 1, 5 or 10",
8123               (j == 0 ? "Decrease" : "Increase"));
8124
8125       gi = CreateGadget(GDI_CUSTOM_ID, id,
8126                         GDI_CUSTOM_TYPE_ID, type_id,
8127                         GDI_IMAGE_ID, graphic,
8128                         GDI_INFO_TEXT, infotext,
8129                         GDI_X, x,
8130                         GDI_Y, y,
8131                         GDI_WIDTH, gd->width,
8132                         GDI_HEIGHT, gd->height,
8133                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8134                         GDI_STATE, GD_BUTTON_UNPRESSED,
8135                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8136                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8137                         GDI_EVENT_MASK, event_mask,
8138                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8139                         GDI_CALLBACK_ACTION, HandleCounterButtons,
8140                         GDI_END);
8141
8142       if (gi == NULL)
8143         Fail("cannot create gadget");
8144
8145       level_editor_gadget[id] = gi;
8146       right_gadget_border[id] =
8147         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8148
8149       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
8150
8151       if (j == 0)
8152       {
8153         int font_type = FONT_INPUT_1;
8154         int font_type_active = FONT_INPUT_1_ACTIVE;
8155
8156         id = counterbutton_info[i].gadget_id_text;
8157
8158         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8159
8160         if (i == ED_COUNTER_ID_SELECT_LEVEL)
8161         {
8162           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
8163
8164           font_type = FONT_LEVEL_NUMBER;
8165           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
8166
8167           x = DX + editor.input.level_number.x;
8168           y = DY + editor.input.level_number.y;
8169         }
8170         else
8171         {
8172           graphic = IMG_EDITOR_COUNTER_INPUT;
8173         }
8174
8175         gd = &graphic_info[graphic];
8176
8177         gd_x1 = gd->src_x;
8178         gd_y1 = gd->src_y;
8179         gd_x2 = gd->src_x + gd->active_xoffset;
8180         gd_y2 = gd->src_y + gd->active_yoffset;
8181
8182         gi = CreateGadget(GDI_CUSTOM_ID, id,
8183                           GDI_CUSTOM_TYPE_ID, type_id,
8184                           GDI_IMAGE_ID, graphic,
8185                           GDI_INFO_TEXT, "Enter counter value",
8186                           GDI_X, x,
8187                           GDI_Y, y,
8188                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
8189                           GDI_NUMBER_VALUE, 0,
8190                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
8191                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
8192                           GDI_TEXT_SIZE, 3,     // minimal counter text size
8193                           GDI_TEXT_FONT, font_type,
8194                           GDI_TEXT_FONT_ACTIVE, font_type_active,
8195                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8196                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8197                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8198                           GDI_DESIGN_WIDTH, gd->width,
8199                           GDI_EVENT_MASK, event_mask,
8200                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8201                           GDI_CALLBACK_ACTION, HandleCounterButtons,
8202                           GDI_END);
8203
8204         if (gi == NULL)
8205           Fail("cannot create gadget");
8206
8207         level_editor_gadget[id] = gi;
8208         right_gadget_border[id] =
8209           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8210
8211         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
8212       }
8213     }
8214   }
8215 }
8216
8217 static void CreateDrawingAreas(void)
8218 {
8219   int i;
8220
8221   // these values are not constant, but can change at runtime
8222   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8223   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8224
8225   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8226   {
8227     struct GadgetInfo *gi;
8228     int id = drawingarea_info[i].gadget_id;
8229     int type_id = drawingarea_info[i].gadget_type_id;
8230     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8231     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8232     int area_xsize = drawingarea_info[i].area_xsize;
8233     int area_ysize = drawingarea_info[i].area_ysize;
8234     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8235                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8236     unsigned int event_mask =
8237       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8238       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8239
8240     if (type_id != i)
8241       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8242
8243     // determine horizontal position to the right of specified gadget
8244     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8245       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8246            ED_DRAWINGAREA_TEXT_DISTANCE);
8247
8248     // determine horizontal offset for leading text
8249     if (drawingarea_info[i].text_left != NULL)
8250       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8251
8252     gi = CreateGadget(GDI_CUSTOM_ID, id,
8253                       GDI_CUSTOM_TYPE_ID, type_id,
8254                       GDI_X, x,
8255                       GDI_Y, y,
8256                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8257                       GDI_AREA_SIZE, area_xsize, area_ysize,
8258                       GDI_ITEM_SIZE, item_size, item_size,
8259                       GDI_EVENT_MASK, event_mask,
8260                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8261                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8262                       GDI_END);
8263
8264     if (gi == NULL)
8265       Fail("cannot create gadget");
8266
8267     level_editor_gadget[id] = gi;
8268     right_gadget_border[id] =
8269       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8270   }
8271 }
8272
8273 static void CreateTextInputGadgets(void)
8274 {
8275   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8276   int max_infotext_len = getMaxInfoTextLength();
8277   int i;
8278
8279   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8280   {
8281     int gd_x1 = gd->src_x;
8282     int gd_y1 = gd->src_y;
8283     int gd_x2 = gd->src_x + gd->active_xoffset;
8284     int gd_y2 = gd->src_y + gd->active_yoffset;
8285     struct GadgetInfo *gi;
8286     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8287     char infotext[MAX_OUTPUT_LINESIZE + 1];
8288     int id = textinput_info[i].gadget_id;
8289     int type_id = textinput_info[i].gadget_type_id;
8290     int x, y;
8291
8292     if (type_id != i)
8293       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8294
8295     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8296     {
8297       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8298       int border_size = gd->border_size;
8299       int font_nr = FONT_INPUT_1;
8300       int font_height = getFontHeight(font_nr);
8301       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8302       int yoffset = element_border + (TILEY - font_height) / 2;
8303
8304       x = (editor.settings.element_name.x != -1 ?
8305            editor.settings.element_name.x :
8306            editor.settings.element_graphic.x + xoffset) - border_size;
8307       y = (editor.settings.element_name.y != -1 ?
8308            editor.settings.element_name.y :
8309            editor.settings.element_graphic.y + yoffset) - border_size;
8310     }
8311     else
8312     {
8313       x = ED_SETTINGS_X(textinput_info[i].x);
8314       y = ED_SETTINGS_Y(textinput_info[i].y);
8315     }
8316
8317     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8318     infotext[max_infotext_len] = '\0';
8319
8320     gi = CreateGadget(GDI_CUSTOM_ID, id,
8321                       GDI_CUSTOM_TYPE_ID, type_id,
8322                       GDI_INFO_TEXT, infotext,
8323                       GDI_X, SX + x,
8324                       GDI_Y, SY + y,
8325                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8326                       GDI_TEXT_VALUE, textinput_info[i].value,
8327                       GDI_TEXT_SIZE, textinput_info[i].size,
8328                       GDI_TEXT_FONT, FONT_INPUT_1,
8329                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8330                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8331                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8332                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8333                       GDI_DESIGN_WIDTH, gd->width,
8334                       GDI_EVENT_MASK, event_mask,
8335                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8336                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
8337                       GDI_END);
8338
8339     if (gi == NULL)
8340       Fail("cannot create gadget");
8341
8342     level_editor_gadget[id] = gi;
8343   }
8344 }
8345
8346 static void CreateTextAreaGadgets(void)
8347 {
8348   int max_infotext_len = getMaxInfoTextLength();
8349   int i;
8350
8351   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8352   {
8353     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8354     int gd_x1 = gd->src_x;
8355     int gd_y1 = gd->src_y;
8356     int gd_x2 = gd->src_x + gd->active_xoffset;
8357     int gd_y2 = gd->src_y + gd->active_yoffset;
8358     struct GadgetInfo *gi;
8359     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8360     char infotext[MAX_OUTPUT_LINESIZE + 1];
8361     int id = textarea_info[i].gadget_id;
8362     int type_id = textarea_info[i].gadget_type_id;
8363     int area_xsize = textarea_info[i].xsize;
8364     int area_ysize = textarea_info[i].ysize;
8365
8366     if (type_id != i)
8367       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8368
8369     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8370     infotext[max_infotext_len] = '\0';
8371
8372     gi = CreateGadget(GDI_CUSTOM_ID, id,
8373                       GDI_CUSTOM_TYPE_ID, type_id,
8374                       GDI_INFO_TEXT, infotext,
8375                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8376                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8377                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8378                       GDI_AREA_SIZE, area_xsize, area_ysize,
8379                       GDI_TEXT_FONT, FONT_INPUT_1,
8380                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8381                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8382                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8383                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8384                       GDI_DESIGN_WIDTH, gd->width,
8385                       GDI_EVENT_MASK, event_mask,
8386                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8387                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8388                       GDI_END);
8389
8390     if (gi == NULL)
8391       Fail("cannot create gadget");
8392
8393     level_editor_gadget[id] = gi;
8394   }
8395 }
8396
8397 static void CreateSelectboxGadgets(void)
8398 {
8399   int max_infotext_len = getMaxInfoTextLength();
8400
8401   int i, j;
8402
8403   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8404   {
8405     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8406     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8407     int gd_x1 = gd->src_x;
8408     int gd_y1 = gd->src_y;
8409     int gd_x2 = gd->src_x + gd->active_xoffset;
8410     int gd_y2 = gd->src_y + gd->active_yoffset;
8411     int selectbox_button_xsize = gd2->width;
8412     struct GadgetInfo *gi;
8413     char infotext[MAX_OUTPUT_LINESIZE + 1];
8414     int id = selectbox_info[i].gadget_id;
8415     int type_id = selectbox_info[i].gadget_type_id;
8416     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8417     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8418     unsigned int event_mask =
8419       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8420
8421     if (type_id != i)
8422       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8423
8424     if (selectbox_info[i].size == -1)   // dynamically determine size
8425     {
8426       // (we cannot use -1 for uninitialized values if we directly compare
8427       // with results from strlen(), because the '<' and '>' operation will
8428       // implicitely cast -1 to an unsigned integer value!)
8429       selectbox_info[i].size = 0;
8430
8431       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8432         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8433           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8434
8435       selectbox_info[i].size++;         // add one character empty space
8436     }
8437
8438     // determine horizontal position to the right of specified gadget
8439     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8440       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8441            ED_GADGET_TEXT_DISTANCE);
8442
8443     // determine horizontal offset for leading text
8444     if (selectbox_info[i].text_left != NULL)
8445       x += getTextWidthForGadget(selectbox_info[i].text_left);
8446
8447     sprintf(infotext, "%s", selectbox_info[i].infotext);
8448     infotext[max_infotext_len] = '\0';
8449
8450     gi = CreateGadget(GDI_CUSTOM_ID, id,
8451                       GDI_CUSTOM_TYPE_ID, type_id,
8452                       GDI_INFO_TEXT, infotext,
8453                       GDI_X, x,
8454                       GDI_Y, y,
8455                       GDI_TYPE, GD_TYPE_SELECTBOX,
8456                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8457                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8458                       GDI_TEXT_SIZE, selectbox_info[i].size,
8459                       GDI_TEXT_FONT, FONT_INPUT_1,
8460                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8461                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8462                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8463                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8464                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8465                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8466                       GDI_DESIGN_WIDTH, gd->width,
8467                       GDI_EVENT_MASK, event_mask,
8468                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8469                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8470                       GDI_END);
8471
8472     if (gi == NULL)
8473       Fail("cannot create gadget");
8474
8475     level_editor_gadget[id] = gi;
8476     right_gadget_border[id] =
8477       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8478   }
8479 }
8480
8481 static void CreateTextbuttonGadgets(void)
8482 {
8483   int max_infotext_len = getMaxInfoTextLength();
8484   int i;
8485
8486   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8487   {
8488     int id = textbutton_info[i].gadget_id;
8489     int type_id = textbutton_info[i].gadget_type_id;
8490     int is_tab_button =
8491       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8492        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8493     int graphic =
8494       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8495     int gadget_distance =
8496       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8497     struct GraphicInfo *gd = &graphic_info[graphic];
8498     int gd_x1 = gd->src_x;
8499     int gd_y1 = gd->src_y;
8500     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8501     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8502     int gd_x1a = gd->src_x + gd->active_xoffset;
8503     int gd_y1a = gd->src_y + gd->active_yoffset;
8504     int border_xsize = gd->border_size + gd->draw_xoffset;
8505     int border_ysize = gd->border_size;
8506     struct GadgetInfo *gi;
8507     unsigned int event_mask = GD_EVENT_RELEASED;
8508     char infotext[MAX_OUTPUT_LINESIZE + 1];
8509     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8510     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8511
8512     if (type_id != i)
8513       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8514
8515     if (textbutton_info[i].size == -1)  // dynamically determine size
8516       textbutton_info[i].size = strlen(textbutton_info[i].text);
8517
8518     sprintf(infotext, "%s", textbutton_info[i].infotext);
8519     infotext[max_infotext_len] = '\0';
8520
8521     // determine horizontal position to the right of specified gadget
8522     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8523     {
8524       int gadget_id_align = textbutton_info[i].gadget_id_align;
8525
8526       x = right_gadget_border[gadget_id_align] + gadget_distance;
8527
8528       if (textbutton_info[i].y == -1)
8529         y = level_editor_gadget[gadget_id_align]->y;
8530     }
8531
8532     // determine horizontal offset for leading text
8533     if (textbutton_info[i].text_left != NULL)
8534       x += getTextWidthForGadget(textbutton_info[i].text_left);
8535
8536     gi = CreateGadget(GDI_CUSTOM_ID, id,
8537                       GDI_CUSTOM_TYPE_ID, type_id,
8538                       GDI_IMAGE_ID, graphic,
8539                       GDI_INFO_TEXT, infotext,
8540                       GDI_X, x,
8541                       GDI_Y, y,
8542                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8543                       GDI_TEXT_VALUE, textbutton_info[i].text,
8544                       GDI_TEXT_SIZE, textbutton_info[i].size,
8545                       GDI_TEXT_FONT, FONT_INPUT_2,
8546                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8547                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8548                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8549                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8550                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8551                       GDI_DESIGN_WIDTH, gd->width,
8552                       GDI_DECORATION_SHIFTING, 1, 1,
8553                       GDI_EVENT_MASK, event_mask,
8554                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8555                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8556                       GDI_END);
8557
8558     if (gi == NULL)
8559       Fail("cannot create gadget");
8560
8561     level_editor_gadget[id] = gi;
8562     right_gadget_border[id] =
8563       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8564   }
8565 }
8566
8567 static void CreateGraphicbuttonGadgets(void)
8568 {
8569   struct GadgetInfo *gi;
8570   int i;
8571
8572   // create buttons for scrolling of drawing area and element list
8573   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8574   {
8575     int id = graphicbutton_info[i].gadget_id;
8576     int type_id = graphicbutton_info[i].gadget_type_id;
8577     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8578     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8579     int graphic = graphicbutton_info[i].graphic;
8580     struct GraphicInfo *gd = &graphic_info[graphic];
8581     int gd_x1 = gd->src_x;
8582     int gd_y1 = gd->src_y;
8583     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8584     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8585     unsigned int event_mask = GD_EVENT_RELEASED;
8586
8587     if (type_id != i)
8588       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8589
8590     // determine horizontal position to the right of specified gadget
8591     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8592       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8593            ED_GADGET_TEXT_DISTANCE);
8594
8595     // determine horizontal offset for leading text
8596     if (graphicbutton_info[i].text_left != NULL)
8597       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8598
8599     gi = CreateGadget(GDI_CUSTOM_ID, id,
8600                       GDI_CUSTOM_TYPE_ID, type_id,
8601                       GDI_IMAGE_ID, graphic,
8602                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8603                       GDI_X, x,
8604                       GDI_Y, y,
8605                       GDI_WIDTH, gd->width,
8606                       GDI_HEIGHT, gd->height,
8607                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8608                       GDI_STATE, GD_BUTTON_UNPRESSED,
8609                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8610                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8611                       GDI_EVENT_MASK, event_mask,
8612                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8613                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8614                       GDI_END);
8615
8616     if (gi == NULL)
8617       Fail("cannot create gadget");
8618
8619     level_editor_gadget[id] = gi;
8620     right_gadget_border[id] =
8621       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8622   }
8623 }
8624
8625 static void CreateScrollbarGadgets(void)
8626 {
8627   int i;
8628
8629   // these values are not constant, but can change at runtime
8630   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8631     SX + ED_SCROLL_HORIZONTAL_XPOS;
8632   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8633     SY + ED_SCROLL_HORIZONTAL_YPOS;
8634   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8635     ED_SCROLL_HORIZONTAL_XSIZE;
8636   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8637     ED_SCROLL_HORIZONTAL_YSIZE;
8638   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8639   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8640   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8641   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8642
8643   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8644     SX + ED_SCROLL_VERTICAL_XPOS;
8645   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8646     SY + ED_SCROLL_VERTICAL_YPOS;
8647   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8648     ED_SCROLL_VERTICAL_XSIZE;
8649   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8650     ED_SCROLL_VERTICAL_YSIZE;
8651   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8652   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8653   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8654   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8655
8656   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8657     PX + ED_SCROLL2_VERTICAL_XPOS;
8658   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8659     PY + ED_SCROLL2_VERTICAL_YPOS;
8660   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8661     ED_SCROLL2_VERTICAL_XSIZE;
8662   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8663     ED_SCROLL2_VERTICAL_YSIZE;
8664   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8665   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8666   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8667   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8668
8669   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8670   {
8671     int id = scrollbar_info[i].gadget_id;
8672     int type_id = scrollbar_info[i].gadget_type_id;
8673     int graphic = scrollbar_info[i].graphic;
8674     struct GraphicInfo *gd = &graphic_info[graphic];
8675     int gd_x1 = gd->src_x;
8676     int gd_y1 = gd->src_y;
8677     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8678     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8679     struct GadgetInfo *gi;
8680     int items_max, items_visible, item_position;
8681     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8682
8683     if (type_id != i)
8684       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8685
8686     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8687     {
8688       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8689       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8690       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8691     }
8692     else        // drawing area scrollbars
8693     {
8694       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8695       {
8696         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8697         items_visible = ed_fieldx;
8698         item_position = 0;
8699       }
8700       else
8701       {
8702         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8703         items_visible = ed_fieldy;
8704         item_position = 0;
8705       }
8706     }
8707
8708     gi = CreateGadget(GDI_CUSTOM_ID, id,
8709                       GDI_CUSTOM_TYPE_ID, type_id,
8710                       GDI_IMAGE_ID, graphic,
8711                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8712                       GDI_X, scrollbar_pos[i].x,
8713                       GDI_Y, scrollbar_pos[i].y,
8714                       GDI_WIDTH, scrollbar_pos[i].width,
8715                       GDI_HEIGHT, scrollbar_pos[i].height,
8716                       GDI_TYPE, scrollbar_info[i].type,
8717                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8718                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8719                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8720                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8721                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8722                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8723                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8724                       GDI_STATE, GD_BUTTON_UNPRESSED,
8725                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8726                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8727                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8728                       GDI_EVENT_MASK, event_mask,
8729                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8730                       GDI_CALLBACK_ACTION, HandleControlButtons,
8731                       GDI_END);
8732
8733     if (gi == NULL)
8734       Fail("cannot create gadget");
8735
8736     level_editor_gadget[id] = gi;
8737   }
8738 }
8739
8740 static void CreateCheckbuttonGadgets(void)
8741 {
8742   struct GadgetInfo *gi;
8743   int i;
8744
8745   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8746   {
8747     int id = checkbutton_info[i].gadget_id;
8748     int type_id = checkbutton_info[i].gadget_type_id;
8749     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8750                    IMG_EDITOR_CHECKBOX);
8751     struct GraphicInfo *gd = &graphic_info[graphic];
8752     int gd_x1 = gd->src_x;
8753     int gd_y1 = gd->src_y;
8754     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8755     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8756     int gd_x1a = gd->src_x + gd->active_xoffset;
8757     int gd_y1a = gd->src_y + gd->active_yoffset;
8758     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8759     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8760     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8761     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8762     unsigned int event_mask = GD_EVENT_PRESSED;
8763
8764     if (type_id != i)
8765       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8766
8767     // determine horizontal position to the right of specified gadget
8768     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8769       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8770            ED_GADGET_TEXT_DISTANCE);
8771
8772     // determine horizontal offset for leading text
8773     if (checkbutton_info[i].text_left != NULL)
8774       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8775
8776     gi = CreateGadget(GDI_CUSTOM_ID, id,
8777                       GDI_CUSTOM_TYPE_ID, type_id,
8778                       GDI_IMAGE_ID, graphic,
8779                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8780                       GDI_X, x,
8781                       GDI_Y, y,
8782                       GDI_WIDTH, gd->width,
8783                       GDI_HEIGHT, gd->height,
8784                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8785                       GDI_CHECKED, *checkbutton_info[i].value,
8786                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8787                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8788                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8789                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8790                       GDI_EVENT_MASK, event_mask,
8791                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8792                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8793                       GDI_END);
8794
8795     if (gi == NULL)
8796       Fail("cannot create gadget");
8797
8798     level_editor_gadget[id] = gi;
8799     right_gadget_border[id] =
8800       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8801   }
8802 }
8803
8804 static void CreateRadiobuttonGadgets(void)
8805 {
8806   int graphic = IMG_EDITOR_RADIOBUTTON;
8807   struct GraphicInfo *gd = &graphic_info[graphic];
8808   int gd_x1 = gd->src_x;
8809   int gd_y1 = gd->src_y;
8810   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8811   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8812   int gd_x1a = gd->src_x + gd->active_xoffset;
8813   int gd_y1a = gd->src_y + gd->active_yoffset;
8814   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8815   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8816   struct GadgetInfo *gi;
8817   int i;
8818
8819   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8820   {
8821     int id = radiobutton_info[i].gadget_id;
8822     int type_id = radiobutton_info[i].gadget_type_id;
8823     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8824     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8825     unsigned int event_mask = GD_EVENT_PRESSED;
8826
8827     if (type_id != i)
8828       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8829
8830     int checked =
8831       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8832
8833     // determine horizontal position to the right of specified gadget
8834     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8835       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8836            ED_GADGET_TEXT_DISTANCE);
8837
8838     // determine horizontal offset for leading text
8839     if (radiobutton_info[i].text_left != NULL)
8840       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8841
8842     gi = CreateGadget(GDI_CUSTOM_ID, id,
8843                       GDI_CUSTOM_TYPE_ID, type_id,
8844                       GDI_IMAGE_ID, graphic,
8845                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8846                       GDI_X, x,
8847                       GDI_Y, y,
8848                       GDI_WIDTH, gd->width,
8849                       GDI_HEIGHT, gd->height,
8850                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8851                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8852                       GDI_CHECKED, checked,
8853                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8854                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8855                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8856                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8857                       GDI_EVENT_MASK, event_mask,
8858                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8859                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8860                       GDI_END);
8861
8862     if (gi == NULL)
8863       Fail("cannot create gadget");
8864
8865     level_editor_gadget[id] = gi;
8866     right_gadget_border[id] =
8867       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8868   }
8869 }
8870
8871 void CreateLevelEditorGadgets(void)
8872 {
8873   // force EDITOR font inside level editor
8874   SetFontStatus(GAME_MODE_EDITOR);
8875
8876   // these values are not constant, but can change at runtime
8877   ed_fieldx = MAX_ED_FIELDX - 1;
8878   ed_fieldy = MAX_ED_FIELDY - 1;
8879
8880   num_editor_gadgets = NUM_EDITOR_GADGETS;
8881
8882   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8883
8884   level_editor_gadget =
8885     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8886   right_gadget_border =
8887     checked_calloc(num_editor_gadgets * sizeof(int));
8888
8889   // set number of empty (padding) element buttons to maximum number of buttons
8890   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8891
8892   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8893   editor_el_empty_ptr = editor_el_empty;
8894
8895   use_permanent_palette = !editor.palette.show_as_separate_screen;
8896
8897   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8898
8899   ReinitializeElementList();
8900
8901   CreateControlButtons();
8902   CreateScrollbarGadgets();
8903
8904   // order of function calls is important because of cross-references
8905   CreateCheckbuttonGadgets();
8906   CreateCounterButtons();
8907   CreateRadiobuttonGadgets();
8908   CreateTextInputGadgets();
8909   CreateTextAreaGadgets();
8910   CreateSelectboxGadgets();
8911   CreateGraphicbuttonGadgets();
8912   CreateTextbuttonGadgets();
8913   CreateDrawingAreas();
8914
8915   ResetFontStatus();
8916 }
8917
8918 void FreeLevelEditorGadgets(void)
8919 {
8920   int i;
8921
8922   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8923
8924   for (i = 0; i < num_editor_gadgets; i++)
8925   {
8926     FreeGadget(level_editor_gadget[i]);
8927
8928     level_editor_gadget[i] = NULL;
8929   }
8930
8931   checked_free(level_editor_gadget);
8932   checked_free(right_gadget_border);
8933
8934   checked_free(editor_el_empty);
8935 }
8936
8937 static void MapCounterButtons(int id)
8938 {
8939   int font_nr = FONT_TEXT_1;
8940   int font_height = getFontHeight(font_nr);
8941   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8942   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8943   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8944   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8945   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8946   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8947   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8948   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8949   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8950   int yoffset = (gi_down->height - font_height) / 2;
8951   int x_left = gi_down->x - xoffset_left;
8952   int x_right;  // set after gadget position was modified
8953   int y_above = gi_down->y - yoffset_above;
8954   int x = gi_down->x;
8955   int y;        // set after gadget position was modified
8956
8957   // counter limits must be changed first to prevent value truncation
8958   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8959                             counterbutton_info[id].max_value);
8960
8961   // right text position might have changed after setting position above
8962   x_right = gi_up->x + gi_up->width + xoffset_right;
8963
8964   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8965
8966   // set position for counter gadgets with dynamically determined position
8967   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8968   {
8969     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8970     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8971     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8972   }
8973
8974   // vertical position might have changed after setting position above
8975   y = gi_up->y + yoffset;
8976
8977   if (counterbutton_info[id].text_above)
8978     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8979
8980   if (counterbutton_info[id].text_left)
8981     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8982
8983   if (counterbutton_info[id].text_right)
8984     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8985
8986   MapGadget(gi_down);
8987   MapGadget(gi_text);
8988   MapGadget(gi_up);
8989 }
8990
8991 static void MapControlButtons(void)
8992 {
8993   int counter_id;
8994   int i;
8995
8996   // map toolbox buttons (excluding special CE toolbox buttons)
8997   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
8998     MapGadget(level_editor_gadget[i]);
8999
9000   // map toolbox buttons (element properties buttons)
9001   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
9002     MapGadget(level_editor_gadget[i]);
9003
9004   if (use_permanent_palette)
9005   {
9006     // map buttons to select elements
9007     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
9008       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
9009     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
9010     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
9011     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
9012   }
9013
9014   // map buttons to select level
9015   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
9016   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
9017   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
9018   MapCounterButtons(counter_id);
9019 }
9020
9021 static void MapDrawingArea(int id)
9022 {
9023   int font_nr = FONT_TEXT_1;
9024   int font_height = getFontHeight(font_nr);
9025   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9026   int area_xsize = gi->drawing.area_xsize;
9027   int area_ysize = gi->drawing.area_ysize;
9028   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9029   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
9030   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
9031   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
9032   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
9033   int x_below = gi->x + (gi->width - xoffset_below) / 2;
9034   int y_side  = gi->y + (gi->height - font_height) / 2;
9035   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
9036   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
9037
9038   if (drawingarea_info[id].text_left)
9039     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
9040
9041   if (drawingarea_info[id].text_right)
9042     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
9043
9044   if (drawingarea_info[id].text_above)
9045     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
9046
9047   if (drawingarea_info[id].text_below)
9048     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
9049
9050   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
9051   {
9052     DrawElementBorder(gi->x, gi->y,
9053                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
9054                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
9055
9056     DrawDrawingArea(id);
9057   }
9058
9059   MapGadget(gi);
9060 }
9061
9062 static void MapTextInputGadget(int id)
9063 {
9064   int font_nr = FONT_TEXT_1;
9065   int font_height = getFontHeight(font_nr);
9066   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
9067   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9068   int x_above = ED_SETTINGS_X(textinput_info[id].x);
9069   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
9070
9071   if (textinput_info[id].text_above)
9072     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
9073
9074   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
9075
9076   MapGadget(gi);
9077 }
9078
9079 static void MapTextAreaGadget(int id)
9080 {
9081   int font_nr = FONT_TEXT_1;
9082   int font_height = getFontHeight(font_nr);
9083   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
9084   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9085   int x_above = ED_SETTINGS_X(textarea_info[id].x);
9086   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
9087   char *text_above = textarea_info[id].text_above;
9088
9089   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
9090     text_above = textarea_info[id].text_above_cropped;
9091
9092   if (text_above)
9093     DrawTextS(x_above, y_above, font_nr, text_above);
9094
9095   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
9096
9097   MapGadget(gi);
9098 }
9099
9100 static void MapSelectboxGadget(int id)
9101 {
9102   int font_nr = FONT_TEXT_1;
9103   int font_height = getFontHeight(font_nr);
9104   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
9105   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
9106   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9107   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9108   int yoffset = (gi->height - font_height) / 2;
9109   int x_left = gi->x - xoffset_left;
9110   int x_right = gi->x + gi->width + xoffset_right;
9111   int y_above = gi->y - yoffset_above;
9112   int x = gi->x;
9113   int y = gi->y + yoffset;
9114
9115   if (selectbox_info[id].text_above)
9116     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
9117
9118   if (selectbox_info[id].text_left)
9119     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
9120
9121   if (selectbox_info[id].text_right)
9122     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
9123
9124   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
9125
9126   MapGadget(gi);
9127 }
9128
9129 static void MapTextbuttonGadget(int id)
9130 {
9131   int font_nr = FONT_TEXT_1;
9132   int font_height = getFontHeight(font_nr);
9133   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
9134   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
9135   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9136   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9137   int yoffset = (gi->height - font_height) / 2;
9138   int x_left = gi->x - xoffset_left;
9139   int x_right = gi->x + gi->width + xoffset_right;
9140   int y_above = gi->y - yoffset_above;
9141   int x = gi->x;
9142   int y = gi->y + yoffset;
9143
9144   // only show button to delete change pages when more than minimum pages
9145   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
9146       custom_element.num_change_pages == MIN_CHANGE_PAGES)
9147     return;
9148
9149   if (textbutton_info[id].text_above)
9150     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
9151
9152   if (textbutton_info[id].text_left)
9153     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
9154
9155   if (textbutton_info[id].text_right)
9156     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
9157
9158   MapGadget(gi);
9159 }
9160
9161 static void MapGraphicbuttonGadget(int id)
9162 {
9163   int font_nr = FONT_TEXT_1;
9164   int font_height = getFontHeight(font_nr);
9165   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
9166   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
9167   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9168   int yoffset = (gi->height - font_height) / 2;
9169   int x_left = gi->x - xoffset_left;
9170   int x_right = gi->x + gi->width + xoffset_right;
9171   int y = gi->y + yoffset;
9172
9173   if (graphicbutton_info[id].text_left)
9174     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
9175
9176   if (graphicbutton_info[id].text_right)
9177     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
9178
9179   MapGadget(gi);
9180 }
9181
9182 static void MapRadiobuttonGadget(int id)
9183 {
9184   int font_nr = FONT_TEXT_1;
9185   int font_height = getFontHeight(font_nr);
9186   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
9187   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9188   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9189   int yoffset = (gi->height - font_height) / 2;
9190   int x_left = gi->x - xoffset_left;
9191   int x_right = gi->x + gi->width + xoffset_right;
9192   int y = gi->y + yoffset;
9193   boolean checked =
9194     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
9195
9196   if (radiobutton_info[id].text_left)
9197     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
9198
9199   if (radiobutton_info[id].text_right)
9200     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
9201
9202   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
9203
9204   MapGadget(gi);
9205 }
9206
9207 static void MapCheckbuttonGadget(int id)
9208 {
9209   int font_nr = FONT_TEXT_1;
9210   int font_height = getFontHeight(font_nr);
9211   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
9212   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9213   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9214   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9215   int yoffset = (gi->height - font_height) / 2;
9216   int y_above = gi->y - yoffset_above;
9217   int x = gi->x;
9218   int x_left, x_right, y;       // set after gadget position was modified
9219
9220   // set position for gadgets with dynamically determined position
9221   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9222     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9223   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9224
9225   x_left = gi->x - xoffset_left;
9226   x_right = gi->x + gi->width + xoffset_right;
9227   y = gi->y + yoffset;
9228
9229   if (checkbutton_info[id].text_above)
9230     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9231
9232   if (checkbutton_info[id].text_left)
9233     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9234
9235   if (checkbutton_info[id].text_right)
9236     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9237
9238   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9239
9240   MapGadget(gi);
9241 }
9242
9243 static void MapMainDrawingArea(void)
9244 {
9245   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9246   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9247   int i;
9248
9249   if (suppressBorderElement())
9250   {
9251     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9252     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9253   }
9254
9255   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9256   {
9257     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9258           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9259          no_horizontal_scrollbar) ||
9260         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9261           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9262          no_vertical_scrollbar))
9263       continue;
9264
9265     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9266   }
9267
9268   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9269   {
9270     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9271         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9272       continue;
9273
9274     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9275   }
9276
9277   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9278 }
9279
9280 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9281 {
9282   int i;
9283
9284   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9285   {
9286     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9287         i == GADGET_ID_CUSTOM_COPY_TO ||
9288         i == GADGET_ID_CUSTOM_EXCHANGE ||
9289         i == GADGET_ID_CUSTOM_COPY ||
9290         i == GADGET_ID_CUSTOM_PASTE)
9291     {
9292       if (map)
9293         MapGadget(level_editor_gadget[i]);
9294       else
9295         UnmapGadget(level_editor_gadget[i]);
9296     }
9297   }
9298 }
9299
9300 static void MapLevelEditorToolboxCustomGadgets(void)
9301 {
9302   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9303 }
9304
9305 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9306 {
9307   if (IS_CUSTOM_ELEMENT(properties_element) ||
9308       IS_GROUP_ELEMENT(properties_element) ||
9309       IS_EMPTY_ELEMENT(properties_element))
9310     MapLevelEditorToolboxCustomGadgets();
9311 }
9312
9313 static void UnmapLevelEditorToolboxCustomGadgets(void)
9314 {
9315   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9316 }
9317
9318 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9319 {
9320   int i;
9321
9322   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9323   {
9324     if (i != GADGET_ID_SINGLE_ITEMS &&
9325         i != GADGET_ID_PICK_ELEMENT)
9326     {
9327       struct GadgetInfo *gi = level_editor_gadget[i];
9328
9329       if (map)
9330       {
9331         MapGadget(gi);
9332       }
9333       else
9334       {
9335         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9336         struct GraphicInfo *gd = &graphic_info[graphic];
9337
9338         UnmapGadget(gi);
9339
9340         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9341                    gi->width, gi->height, gi->x, gi->y);
9342
9343         redraw_mask |= REDRAW_DOOR_3;
9344       }
9345     }
9346   }
9347 }
9348
9349 static void MapLevelEditorToolboxDrawingGadgets(void)
9350 {
9351   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9352 }
9353
9354 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9355 {
9356   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9357 }
9358
9359 static void UnmapDrawingArea(int id)
9360 {
9361   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9362 }
9363
9364 static void UnmapLevelEditorFieldGadgets(void)
9365 {
9366   int i;
9367
9368   for (i = 0; i < num_editor_gadgets; i++)
9369     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9370                           level_editor_gadget[i]->y))
9371       UnmapGadget(level_editor_gadget[i]);
9372 }
9373
9374 void UnmapLevelEditorGadgets(void)
9375 {
9376   int i;
9377
9378   for (i = 0; i < num_editor_gadgets; i++)
9379     UnmapGadget(level_editor_gadget[i]);
9380 }
9381
9382 static void ResetUndoBuffer(void)
9383 {
9384   undo_buffer_position = -1;
9385   undo_buffer_steps = -1;
9386   redo_buffer_steps = 0;
9387
9388   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9389
9390   level.changed = FALSE;
9391 }
9392
9393 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9394 {
9395   if (remap_toolbox_gadgets)
9396   {
9397     ModifyEditorElementList();
9398     RedrawDrawingElements();
9399   }
9400
9401   if (edit_mode == ED_MODE_LEVELCONFIG)
9402     DrawLevelConfigWindow();
9403   else if (edit_mode == ED_MODE_PROPERTIES)
9404     DrawPropertiesWindow();
9405   else if (edit_mode == ED_MODE_PALETTE)
9406     DrawPaletteWindow();
9407   else  // edit_mode == ED_MODE_DRAWING
9408     DrawDrawingWindowExt(remap_toolbox_gadgets);
9409 }
9410
9411 static void DrawEditModeWindow(void)
9412 {
9413   DrawEditModeWindowExt(TRUE);
9414 }
9415
9416 static void DrawEditModeWindow_PlayfieldOnly(void)
9417 {
9418   DrawEditModeWindowExt(FALSE);
9419 }
9420
9421 static void ChangeEditModeWindow(int new_edit_mode)
9422 {
9423   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9424
9425   DrawEditModeWindow();
9426 }
9427
9428 static boolean LevelChanged(void)
9429 {
9430   boolean field_changed = FALSE;
9431   int x, y;
9432
9433   for (y = 0; y < lev_fieldy; y++) 
9434     for (x = 0; x < lev_fieldx; x++)
9435       if (Tile[x][y] != level.field[x][y])
9436         field_changed = TRUE;
9437
9438   return (level.changed || field_changed);
9439 }
9440
9441 static boolean PrepareSavingIntoPersonalLevelSet(void)
9442 {
9443   static LevelDirTree *last_copied_leveldir = NULL;
9444   static LevelDirTree *last_written_leveldir = NULL;
9445   static int last_copied_level_nr = -1;
9446   static int last_written_level_nr = -1;
9447   LevelDirTree *leveldir_former = leveldir_current;
9448   int level_nr_former = level_nr;
9449   int new_level_nr;
9450
9451   // remember last mod/save so that for current session, we write
9452   // back to the same personal copy, asking only about overwrite.
9453   if (leveldir_current == last_copied_leveldir &&
9454       level_nr == last_copied_level_nr)
9455   {
9456     // "cd" to personal level set dir (as used when writing last copy)
9457     leveldir_current = last_written_leveldir;
9458     level_nr = last_written_level_nr;
9459
9460     return TRUE;
9461   }
9462
9463   if (!Request("This level is read-only! "
9464                "Save into personal level set?", REQ_ASK))
9465     return FALSE;
9466
9467   // "cd" to personal level set dir (for writing copy the first time)
9468   leveldir_current =
9469     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9470
9471   // this may happen if "setup.internal.create_user_levelset" is FALSE
9472   // or if file "levelinfo.conf" is missing in personal user level set
9473   if (leveldir_current == NULL)
9474   {
9475     Request("Cannot find personal level set?!", REQ_CONFIRM);
9476
9477     leveldir_current = leveldir_former;
9478
9479     return FALSE;
9480   }
9481
9482   // find unused level number
9483   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9484   {
9485     static char *level_filename = NULL;
9486
9487     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9488
9489     if (!fileExists(level_filename))
9490       break;
9491   }
9492
9493   last_copied_leveldir = leveldir_former;
9494   last_copied_level_nr = level_nr_former;
9495
9496   last_written_leveldir = leveldir_current;
9497   last_written_level_nr = level_nr = new_level_nr;
9498
9499   return TRUE;
9500 }
9501
9502 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9503 {
9504   static char *filename_levelinfo = NULL, *mod_name = NULL;
9505   FILE *file;
9506
9507   // annotate this copy-and-mod in personal levelinfo.conf
9508   setString(&filename_levelinfo,
9509             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9510
9511   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9512   {
9513     fprintf(file, "\n");
9514     fprintf(file, "# level %d was modified from:\n", level_nr);
9515     fprintf(file, "# - previous level set name:    %s\n",
9516             former_name);
9517     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9518             level.file_info.nr, level.name);
9519     fprintf(file, "# - previous author:            %s\n",
9520             level.author);
9521     fprintf(file, "# - previous save date:         ");
9522
9523     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9524     {
9525       fprintf(file, "%04d-%02d-%02d\n",
9526               level.creation_date.year,
9527               level.creation_date.month,
9528               level.creation_date.day);
9529     }
9530     else
9531     {
9532       fprintf(file, "not recorded\n");
9533     }
9534
9535     fclose(file);
9536   }
9537
9538   if (level_nr > leveldir_current->last_level)
9539     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9540
9541   // else: allow the save even if annotation failed
9542
9543   // now... spray graffiti on the old level vital statistics
9544   // user can change these; just trying to set a good baseline
9545
9546   // don't truncate names for fear of making offensive or silly:
9547   // long-named original author only recorded in levelinfo.conf.
9548   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9549   if (!strEqual(level.author, leveldir_current->author))
9550   {
9551     setString(&mod_name, getStringCat3(leveldir_current->author,
9552                                        " after ", level.author));
9553
9554     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9555       setString(&mod_name,
9556                 getStringCat2(leveldir_current->author, " (ed.)"));
9557
9558     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9559       setString(&mod_name, leveldir_current->author);
9560
9561     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9562
9563     // less worried about truncation here
9564     setString(&mod_name, getStringCat2("Mod: ", level.name));
9565     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9566   }
9567 }
9568
9569 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9570                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9571 {
9572   int x, y;
9573
9574   for (x = 0; x < lev_fieldx; x++)
9575     for (y = 0; y < lev_fieldy; y++) 
9576       dst[x][y] = src[x][y];
9577 }
9578
9579 static int setSelectboxValue(int selectbox_id, int new_value)
9580 {
9581   int new_index_value = 0;
9582   int i;
9583
9584   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9585     if (selectbox_info[selectbox_id].options[i].value == new_value)
9586       new_index_value = i;
9587
9588   *selectbox_info[selectbox_id].value =
9589     selectbox_info[selectbox_id].options[new_index_value].value;
9590
9591   return new_index_value;
9592 }
9593
9594 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9595 {
9596   int i;
9597
9598   // change action mode and arg variables according to action type variable
9599   for (i = 0; action_arg_options[i].value != -1; i++)
9600   {
9601     if (action_arg_options[i].value == custom_element_change.action_type)
9602     {
9603       int mode = action_arg_options[i].mode;
9604
9605       // only change if corresponding selectbox has changed
9606       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9607           action_arg_modes[mode])
9608         custom_element_change.action_mode = -1;
9609
9610       // only change if corresponding selectbox has changed
9611       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9612           action_arg_options[i].options)
9613         custom_element_change.action_arg = -1;
9614
9615       break;
9616     }
9617   }
9618 }
9619
9620 static void setSelectboxSpecialActionOptions(void)
9621 {
9622   int i;
9623
9624   // change action mode and arg selectbox according to action type selectbox
9625   for (i = 0; action_arg_options[i].value != -1; i++)
9626   {
9627     if (action_arg_options[i].value == custom_element_change.action_type)
9628     {
9629       int mode = action_arg_options[i].mode;
9630
9631       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9632                                    action_arg_modes[mode]);
9633       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9634                                  custom_element_change.action_mode);
9635
9636       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9637                                    action_arg_options[i].options);
9638       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9639                                  custom_element_change.action_arg);
9640       break;
9641     }
9642   }
9643 }
9644
9645 static void copy_custom_element_settings(int element_from, int element_to)
9646 {
9647   struct ElementInfo *ei_from = &element_info[element_from];
9648   struct ElementInfo *ei_to = &element_info[element_to];
9649
9650   copyElementInfo(ei_from, ei_to);
9651 }
9652
9653 static void replace_custom_element_in_settings(int element_from,
9654                                                int element_to)
9655 {
9656   int i, j, x, y;
9657
9658   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9659   {
9660     struct ElementInfo *ei = &element_info[i];
9661
9662     for (y = 0; y < 3; y++)
9663       for (x = 0; x < 3; x++)
9664         if (ei->content.e[x][y] == element_from)
9665           ei->content.e[x][y] = element_to;
9666
9667     for (j = 0; j < ei->num_change_pages; j++)
9668     {
9669       struct ElementChangeInfo *change = &ei->change_page[j];
9670
9671       if (change->target_element == element_from)
9672         change->target_element = element_to;
9673
9674       if (change->initial_trigger_element == element_from)
9675         change->initial_trigger_element = element_to;
9676
9677       if (change->action_element == element_from)
9678         change->action_element = element_to;
9679
9680       for (y = 0; y < 3; y++)
9681         for (x = 0; x < 3; x++)
9682           if (change->target_content.e[x][y] == element_from)
9683             change->target_content.e[x][y] = element_to;
9684     }
9685
9686     if (ei->group != NULL)                              // group or internal
9687       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9688         if (ei->group->element[j] == element_from)
9689           ei->group->element[j] = element_to;
9690   }
9691 }
9692
9693 static void replace_custom_element_in_playfield(int element_from,
9694                                                 int element_to)
9695 {
9696   int x, y;
9697
9698   for (x = 0; x < lev_fieldx; x++)
9699     for (y = 0; y < lev_fieldy; y++)
9700       if (Tile[x][y] == element_from)
9701         Tile[x][y] = element_to;
9702 }
9703
9704 static boolean CopyCustomElement(int element_old, int element_new,
9705                                  int copy_mode)
9706 {
9707   int copy_mode_orig = copy_mode;
9708
9709   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9710   {
9711     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9712                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9713     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9714   }
9715   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9716   {
9717     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9718                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9719     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9720
9721     level.changed = TRUE;
9722   }
9723   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9724   {
9725     Request("Please choose custom element!", REQ_CONFIRM);
9726
9727     return FALSE;
9728   }
9729   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9730   {
9731     Request("Please choose group element!", REQ_CONFIRM);
9732
9733     return FALSE;
9734   }
9735   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9736   {
9737     Request("Please choose empty element!", REQ_CONFIRM);
9738
9739     return FALSE;
9740   }
9741   else
9742   {
9743     level.changed = TRUE;
9744   }
9745
9746   // when modifying custom/group element, ask for copying level template
9747   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9748   {
9749     if (!AskToCopyAndModifyLevelTemplate())
9750       return FALSE;
9751   }
9752
9753   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9754   {
9755     copy_custom_element_settings(element_new, element_old);
9756   }
9757   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9758   {
9759     copy_custom_element_settings(element_old, element_new);
9760   }
9761   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9762   {
9763     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9764     copy_custom_element_settings(element_new, element_old);
9765     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9766
9767     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9768     replace_custom_element_in_settings(element_new, element_old);
9769     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9770
9771     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9772     replace_custom_element_in_playfield(element_new, element_old);
9773     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9774   }
9775
9776   UpdateCustomElementGraphicGadgets();
9777   DrawPropertiesWindow();
9778
9779   return TRUE;
9780 }
9781
9782 static void CopyCustomElementPropertiesToEditor(int element)
9783 {
9784   int i;
9785   int current_change_page = element_info[element].current_change_page;
9786
9787   // dynamically (re)build selectbox for selecting change page
9788   for (i = 0; i < element_info[element].num_change_pages; i++)
9789   {
9790     sprintf(options_change_page_strings[i], "%d", i + 1);
9791
9792     options_change_page[i].value = i;
9793     options_change_page[i].text = options_change_page_strings[i];
9794   }
9795
9796   options_change_page[i].value = -1;
9797   options_change_page[i].text = NULL;
9798
9799   // needed here to initialize combined element properties
9800   InitElementPropertiesEngine(level.game_version);
9801
9802   element_info[element].change =
9803     &element_info[element].change_page[current_change_page];
9804
9805   custom_element = element_info[element];
9806   custom_element_change = *element_info[element].change;
9807
9808   // needed to initially set selectbox options for special action options
9809   setSelectboxSpecialActionOptions();
9810
9811   // needed to initially set selectbox value variables to reliable defaults
9812   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9813     setSelectboxValue(i, *selectbox_info[i].value);
9814
9815   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9816     custom_element_properties[i] = HAS_PROPERTY(element, i);
9817
9818   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9819     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9820
9821   // ---------- element settings: configure (custom elements) -----------------
9822
9823   // set accessible layer selectbox help value
9824   custom_element.access_type =
9825     (IS_WALKABLE(element) ? EP_WALKABLE :
9826      IS_PASSABLE(element) ? EP_PASSABLE :
9827      custom_element.access_type);
9828   custom_element.access_layer =
9829     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9830      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9831      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9832      custom_element.access_layer);
9833   custom_element.access_protected =
9834     (IS_PROTECTED(element) ? 1 : 0);
9835   custom_element_properties[EP_ACCESSIBLE] =
9836     (IS_ACCESSIBLE_OVER(element) ||
9837      IS_ACCESSIBLE_INSIDE(element) ||
9838      IS_ACCESSIBLE_UNDER(element));
9839
9840   // set walk-to-object action selectbox help value
9841   custom_element.walk_to_action =
9842     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9843      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9844      IS_DROPPABLE(element) ? EP_DROPPABLE :
9845      IS_THROWABLE(element) ? EP_THROWABLE :
9846      IS_PUSHABLE(element) ? EP_PUSHABLE :
9847      custom_element.walk_to_action);
9848   custom_element_properties[EP_WALK_TO_OBJECT] =
9849     (IS_DIGGABLE(element) ||
9850      IS_COLLECTIBLE_ONLY(element) ||
9851      IS_DROPPABLE(element) ||
9852      IS_THROWABLE(element) ||
9853      IS_PUSHABLE(element));
9854
9855   // set smash targets selectbox help value
9856   custom_element.smash_targets =
9857     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9858      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9859      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9860      custom_element.smash_targets);
9861   custom_element_properties[EP_CAN_SMASH] =
9862     (CAN_SMASH_EVERYTHING(element) ||
9863      CAN_SMASH_ENEMIES(element) ||
9864      CAN_SMASH_PLAYER(element));
9865
9866   // set deadliness selectbox help value
9867   custom_element.deadliness =
9868     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9869      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9870      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9871      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9872      custom_element.deadliness);
9873   custom_element_properties[EP_DEADLY] =
9874     (DONT_TOUCH(element) ||
9875      DONT_GET_HIT_BY(element) ||
9876      DONT_COLLIDE_WITH(element) ||
9877      DONT_RUN_INTO(element));
9878
9879   // ---------- element settings: advanced (custom elements) ------------------
9880
9881   // set "change by direct action" selectbox help value
9882   custom_element_change.direct_action =
9883     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9884      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9885      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9886      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9887      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9888      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9889      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9890      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9891      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9892      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9893      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9894      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9895      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9896      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9897      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9898      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9899      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9900      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9901      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9902      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9903      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9904      custom_element_change.direct_action);
9905
9906   // set "change by other element action" selectbox help value
9907   custom_element_change.other_action =
9908     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9909      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9910      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9911      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9912      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9913      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9914      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9915      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9916      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9917      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9918      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9919      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9920      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9921      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9922      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9923      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9924      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9925      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9926      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9927      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9928      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9929      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9930      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9931      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9932      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9933      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9934      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9935      custom_element_change.other_action);
9936 }
9937
9938 static void CopyGroupElementPropertiesToEditor(int element)
9939 {
9940   group_element_info = *element_info[element].group;
9941   custom_element = element_info[element];       // needed for description
9942 }
9943
9944 static void CopyEmptyElementPropertiesToEditor(int element)
9945 {
9946   custom_element = element_info[element];
9947 }
9948
9949 static void CopyClassicElementPropertiesToEditor(int element)
9950 {
9951   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9952     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9953       getMoveIntoAcidProperty(&level, element);
9954
9955   if (MAYBE_DONT_COLLIDE_WITH(element))
9956     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9957       getDontCollideWithProperty(&level, element);
9958 }
9959
9960 static void CopyElementPropertiesToEditor(int element)
9961 {
9962   if (IS_CUSTOM_ELEMENT(element))
9963     CopyCustomElementPropertiesToEditor(element);
9964   else if (IS_GROUP_ELEMENT(element))
9965     CopyGroupElementPropertiesToEditor(element);
9966   else if (IS_EMPTY_ELEMENT(element))
9967     CopyEmptyElementPropertiesToEditor(element);
9968   else
9969     CopyClassicElementPropertiesToEditor(element);
9970 }
9971
9972 static boolean AskToCopyAndModifyLevelTemplate(void)
9973 {
9974   if (Request("Copy and modify settings from level template?", REQ_ASK))
9975   {
9976     level.use_custom_template = FALSE;
9977
9978     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9979                  GDI_CHECKED, FALSE, GDI_END);
9980     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9981                  GDI_CHECKED, FALSE, GDI_END);
9982
9983     return TRUE;
9984   }
9985   else
9986   {
9987     LoadLevelTemplate(-1);      // this resets all element modifications ...
9988
9989     DrawEditModeWindow();       // ... and copies them to 'custom_element'
9990
9991     return FALSE;
9992   }
9993 }
9994
9995 static void CopyCustomElementPropertiesToGame(int element)
9996 {
9997   int i;
9998   int access_type_and_layer;
9999
10000   // mark that this custom element has been modified
10001   custom_element.modified_settings = TRUE;
10002   level.changed = TRUE;
10003
10004   if (level.use_custom_template)
10005     AskToCopyAndModifyLevelTemplate();
10006
10007   element_info[element] = custom_element;
10008   *element_info[element].change = custom_element_change;
10009
10010   // ---------- element settings: configure (custom elements) -----------------
10011
10012   // set accessible property from checkbox and selectbox
10013   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
10014   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
10015   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
10016   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
10017   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
10018   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
10019   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
10020                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
10021                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
10022   custom_element_properties[access_type_and_layer] =
10023     custom_element_properties[EP_ACCESSIBLE];
10024   custom_element_properties[EP_PROTECTED] =
10025     (custom_element.access_protected != 0 &&
10026      custom_element_properties[EP_ACCESSIBLE]);
10027
10028   // set walk-to-object property from checkbox and selectbox
10029   custom_element_properties[EP_DIGGABLE] = FALSE;
10030   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
10031   custom_element_properties[EP_DROPPABLE] = FALSE;
10032   custom_element_properties[EP_THROWABLE] = FALSE;
10033   custom_element_properties[EP_PUSHABLE] = FALSE;
10034   custom_element_properties[custom_element.walk_to_action] =
10035     custom_element_properties[EP_WALK_TO_OBJECT];
10036
10037   // set smash property from checkbox and selectbox
10038   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
10039   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
10040   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
10041   custom_element_properties[custom_element.smash_targets] =
10042     custom_element_properties[EP_CAN_SMASH];
10043
10044   // set deadliness property from checkbox and selectbox
10045   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
10046   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
10047   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
10048   custom_element_properties[EP_DONT_TOUCH] = FALSE;
10049   custom_element_properties[custom_element.deadliness] =
10050     custom_element_properties[EP_DEADLY];
10051
10052   // ---------- element settings: advanced (custom elements) ------------------
10053
10054   // set player change event from checkbox and selectbox
10055   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
10056   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
10057   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
10058   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
10059   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
10060   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
10061   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
10062   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
10063   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
10064   custom_element_change_events[CE_SWITCHED] = FALSE;
10065   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
10066   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
10067   custom_element_change_events[CE_BLOCKED] = FALSE;
10068   custom_element_change_events[CE_IMPACT] = FALSE;
10069   custom_element_change_events[CE_SMASHED] = FALSE;
10070   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
10071   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
10072   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
10073   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
10074   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
10075   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
10076   custom_element_change_events[custom_element_change.direct_action] =
10077     custom_element_change_events[CE_BY_DIRECT_ACTION];
10078
10079   // set other element action change event from checkbox and selectbox
10080   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
10081   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
10082   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
10083   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
10084   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
10085   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
10086   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
10087   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
10088   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
10089   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
10090   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
10091   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
10092   custom_element_change_events[CE_TOUCHING_X] = FALSE;
10093   custom_element_change_events[CE_HITTING_X] = FALSE;
10094   custom_element_change_events[CE_DIGGING_X] = FALSE;
10095   custom_element_change_events[CE_HIT_BY_X] = FALSE;
10096   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
10097   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
10098   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
10099   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
10100   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
10101   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
10102   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
10103   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
10104   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
10105   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
10106   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
10107   custom_element_change_events[custom_element_change.other_action] =
10108     custom_element_change_events[CE_BY_OTHER_ACTION];
10109
10110   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
10111     SET_PROPERTY(element, i, custom_element_properties[i]);
10112
10113   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
10114     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
10115
10116   // copy change events also to special level editor variable
10117   custom_element = element_info[element];
10118   custom_element_change = *element_info[element].change;
10119
10120   // needed here to restore runtime value "element_info[element].gfx_element"
10121   InitElementPropertiesGfxElement();
10122 }
10123
10124 static void CopyGroupElementPropertiesToGame(int element)
10125 {
10126   // mark that this group element has been modified
10127   custom_element.modified_settings = TRUE;
10128   level.changed = TRUE;
10129
10130   if (level.use_custom_template)
10131     AskToCopyAndModifyLevelTemplate();
10132
10133   element_info[element] = custom_element;
10134   *element_info[element].group = group_element_info;
10135
10136   // needed here to restore runtime value "element_info[element].gfx_element"
10137   InitElementPropertiesGfxElement();
10138 }
10139
10140 static void CopyEmptyElementPropertiesToGame(int element)
10141 {
10142   // mark that this empty element has been modified
10143   custom_element.modified_settings = TRUE;
10144   level.changed = TRUE;
10145
10146   if (level.use_custom_template)
10147     AskToCopyAndModifyLevelTemplate();
10148
10149   element_info[element] = custom_element;
10150
10151   // needed here to restore runtime value "element_info[element].gfx_element"
10152   InitElementPropertiesGfxElement();
10153 }
10154
10155 static void CopyClassicElementPropertiesToGame(int element)
10156 {
10157   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
10158     setMoveIntoAcidProperty(&level, element,
10159                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
10160
10161   if (MAYBE_DONT_COLLIDE_WITH(element))
10162     setDontCollideWithProperty(&level, element,
10163                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
10164 }
10165
10166 static void CopyElementPropertiesToGame(int element)
10167 {
10168   if (IS_CUSTOM_ELEMENT(element))
10169     CopyCustomElementPropertiesToGame(element);
10170   else if (IS_GROUP_ELEMENT(element))
10171     CopyGroupElementPropertiesToGame(element);
10172   else if (IS_EMPTY_ELEMENT(element))
10173     CopyEmptyElementPropertiesToGame(element);
10174   else
10175     CopyClassicElementPropertiesToGame(element);
10176 }
10177
10178 #if DEBUG
10179 static void CheckElementDescriptions(void)
10180 {
10181   int i;
10182
10183   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10184     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
10185       Warn("no element description file for element '%s'", EL_NAME(i));
10186 }
10187 #endif
10188
10189 static int getMaxEdFieldX(boolean has_scrollbar)
10190 {
10191   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
10192   int sxsize = SXSIZE - scrollbar_width;
10193   int max_ed_fieldx = sxsize / ed_tilesize;
10194
10195   return max_ed_fieldx;
10196 }
10197
10198 static int getMaxEdFieldY(boolean has_scrollbar)
10199 {
10200   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
10201                          INFOTEXT_YSIZE_FULL : 0);
10202   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
10203   int sysize = SYSIZE - scrollbar_height - infotext_height;
10204   int max_ed_fieldy = sysize / ed_tilesize;
10205
10206   return max_ed_fieldy;
10207 }
10208
10209 static void InitZoomLevelSettings(int zoom_tilesize)
10210 {
10211   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
10212
10213   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
10214   {
10215     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10216     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10217
10218     // make sure that tile size is always a power of 2
10219     ed_tilesize = (1 << log_2(ed_tilesize));
10220
10221     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10222     {
10223       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10224       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10225     }
10226   }
10227
10228   last_game_engine_type = level.game_engine_type;
10229
10230   // limit zoom tilesize by upper and lower bound
10231   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10232
10233   // store zoom tilesize in auto setup file only if it was manually changed
10234   if (zoom_tilesize != -1)
10235     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10236
10237   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10238   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10239 }
10240
10241 static void InitDrawingElements(void)
10242 {
10243   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10244
10245   if (level.game_engine_type == game_engine_type_last)
10246     return;
10247
10248   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10249   {
10250     new_element1 = EL_BD_WALL;
10251     new_element2 = EL_EMPTY;
10252     new_element3 = EL_BD_SAND;
10253   }
10254   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10255   {
10256     new_element1 = EL_SP_CHIP_SINGLE;
10257     new_element2 = EL_EMPTY;
10258     new_element3 = EL_SP_BASE;
10259   }
10260   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10261   {
10262     new_element1 = EL_MM_MIRROR_START;
10263     new_element2 = EL_EMPTY;
10264     new_element3 = EL_MM_WOODEN_WALL;
10265   }
10266   else
10267   {
10268     new_element1 = EL_WALL;
10269     new_element2 = EL_EMPTY;
10270     new_element3 = EL_SAND;
10271   }
10272
10273   game_engine_type_last = level.game_engine_type;
10274 }
10275
10276 static void InitLevelSetInfo(void)
10277 {
10278   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10279            "%s", leveldir_current->name);
10280   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10281            "%s", leveldir_current->author);
10282
10283   levelset_num_levels = leveldir_current->levels;
10284
10285   levelset_use_levelset_artwork = FALSE;
10286   levelset_copy_level_template = FALSE;
10287
10288   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10289 }
10290
10291 static void ChangeEditorToLevelSet(char *levelset_subdir)
10292 {
10293   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10294
10295   // the previous level set might have used custom artwork
10296   ReloadCustomArtwork(0);
10297
10298   LoadLevelSetup_SeriesInfo();
10299
10300   SaveLevelSetup_LastSeries();
10301   SaveLevelSetup_SeriesInfo();
10302
10303   TapeErase();
10304
10305   LoadLevel(level_nr);
10306   LoadScore(level_nr);
10307
10308   DrawLevelEd();
10309 }
10310
10311 static boolean useEditorDoorAnimation(void)
10312 {
10313   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10314   boolean door_1_viewport_unchanged =
10315     (vp_door_1->x      == DX     &&
10316      vp_door_1->y      == DY     &&
10317      vp_door_1->width  == DXSIZE &&
10318      vp_door_1->height == DYSIZE);
10319   boolean door_1_contains_toolbox =
10320     (EX >= DX &&
10321      EY >= DY &&
10322      EX + EXSIZE <= DX + DXSIZE &&
10323      EY + EYSIZE <= DY + DYSIZE);
10324
10325   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10326 }
10327
10328 static void DrawEditorDoorBackground(int graphic, int x, int y,
10329                                      int width, int height)
10330 {
10331   struct GraphicInfo *g = &graphic_info[graphic];
10332
10333   if (g->bitmap != NULL)
10334     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10335                MIN(width, g->width), MIN(height, g->height), x, y);
10336   else
10337     ClearRectangle(drawto, x, y, width, height);
10338 }
10339
10340 static void DrawEditorDoorContent(void)
10341 {
10342   // needed for gadgets drawn on background (like palette scrollbar)
10343   SetDoorBackgroundImage(IMG_UNDEFINED);
10344
10345   // copy default editor door content to main double buffer
10346   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10347
10348   // draw bigger door
10349   DrawSpecialEditorDoor();
10350
10351   // draw new control window
10352   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10353
10354   // draw all toolbox gadgets to editor doors
10355   MapControlButtons();
10356
10357   // when returning from test game to properties page, redraw toolbox gadgets
10358   if (edit_mode == ED_MODE_PROPERTIES)
10359   {
10360     UnmapLevelEditorToolboxDrawingGadgets();
10361     UnmapLevelEditorToolboxCustomGadgets();
10362
10363     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10364   }
10365
10366   // draw all palette gadgets to editor doors
10367   ModifyEditorElementList();
10368   RedrawDrawingElements();
10369
10370   // copy actual editor door content to door double buffer for OpenDoor()
10371   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10372 }
10373
10374 void DrawLevelEd(void)
10375 {
10376   int fade_mask = REDRAW_FIELD;
10377
10378   FadeSoundsAndMusic();
10379
10380   if (CheckFadeAll())
10381     fade_mask = REDRAW_ALL;
10382
10383   FadeOut(fade_mask);
10384
10385   // needed if different viewport properties defined for editor
10386   ChangeViewportPropertiesIfNeeded();
10387
10388   ClearField();
10389
10390   InitZoomLevelSettings(-1);
10391   InitDrawingElements();
10392   InitLevelSetInfo();
10393
10394 #if DEBUG
10395   CheckElementDescriptions();
10396 #endif
10397
10398   if (level_editor_test_game)
10399   {
10400     CopyPlayfield(level.field, Tile);
10401     CopyPlayfield(TileBackup, level.field);
10402
10403     level_editor_test_game = FALSE;
10404   }
10405   else
10406   {
10407     edit_mode = ED_MODE_DRAWING;
10408     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10409     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10410
10411     ResetUndoBuffer();
10412
10413     level_xpos = -1;
10414     level_ypos = -1;
10415   }
10416
10417   // redraw_mask |= REDRAW_ALL;
10418
10419   FreeLevelEditorGadgets();
10420   CreateLevelEditorGadgets();
10421
10422   ReinitializeElementList();            // update dynamic level element list
10423   ReinitializeElementListButtons();     // custom element may look different
10424
10425   InitElementPropertiesGfxElement();
10426
10427   UnmapAllGadgets();
10428
10429   DrawEditModeWindow_PlayfieldOnly();
10430
10431   DrawMaskedBorder(fade_mask);
10432
10433   // use door animation if door 1 viewport is unchanged and contains toolbox
10434   if (useEditorDoorAnimation())
10435   {
10436     FadeIn(fade_mask);
10437
10438     DrawEditorDoorContent();
10439
10440     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10441   }
10442   else
10443   {
10444     DrawEditorDoorContent();
10445
10446     FadeIn(fade_mask);
10447   }
10448
10449   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10450 }
10451
10452 static void AdjustDrawingAreaGadgets(void)
10453 {
10454   int ed_xsize = lev_fieldx + 2;
10455   int ed_ysize = lev_fieldy + 2;
10456   int max_ed_fieldx = MAX_ED_FIELDX;
10457   int max_ed_fieldy = MAX_ED_FIELDY;
10458   boolean horizontal_scrollbar_needed;
10459   boolean vertical_scrollbar_needed;
10460   int x, y, width, height;
10461
10462   if (suppressBorderElement())
10463   {
10464     ed_xsize = lev_fieldx;
10465     ed_ysize = lev_fieldy;
10466   }
10467
10468   // check if we need any scrollbars
10469   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10470   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10471
10472   // check if we have a smaller editor field because of scrollbars
10473   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10474   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10475
10476   // check again if we now need more scrollbars because of less space
10477   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10478   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10479
10480   // check if editor field gets even smaller after adding new scrollbars
10481   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10482   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10483
10484   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10485   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10486
10487   x = SX + ed_fieldx * ed_tilesize;
10488   y = SY + ed_fieldy * ed_tilesize;
10489
10490   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10491   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10492
10493   // adjust drawing area gadget
10494   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10495                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10496                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10497                GDI_END);
10498
10499   // adjust horizontal scrollbar gadgets
10500   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10501                GDI_Y, y,
10502                GDI_END);
10503   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10504                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10505                GDI_Y, y,
10506                GDI_END);
10507   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10508                GDI_Y, y,
10509                GDI_WIDTH, width,
10510                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10511                GDI_END);
10512
10513   // adjust vertical scrollbar gadgets
10514   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10515                GDI_X, x,
10516                GDI_END);
10517   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10518                GDI_X, x,
10519                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10520                GDI_END);
10521   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10522                GDI_X, x,
10523                GDI_HEIGHT, height,
10524                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10525                GDI_END);
10526 }
10527
10528 static void AdjustLevelScrollPosition(void)
10529 {
10530   if (level_xpos < -1)
10531     level_xpos = -1;
10532   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10533     level_xpos = lev_fieldx - ed_fieldx + 1;
10534   if (lev_fieldx < ed_fieldx - 2)
10535     level_xpos = -1;
10536
10537   if (level_ypos < -1)
10538     level_ypos = -1;
10539   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10540     level_ypos = lev_fieldy - ed_fieldy + 1;
10541   if (lev_fieldy < ed_fieldy - 2)
10542     level_ypos = -1;
10543
10544   if (suppressBorderElement())
10545   {
10546     level_xpos = 0;
10547     level_ypos = 0;
10548   }
10549 }
10550
10551 static void AdjustEditorScrollbar(int id)
10552 {
10553   struct GadgetInfo *gi = level_editor_gadget[id];
10554   int items_max, items_visible, item_position;
10555
10556   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10557   {
10558     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10559     items_visible = ed_fieldx;
10560     item_position = level_xpos + 1;
10561   }
10562   else
10563   {
10564     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10565     items_visible = ed_fieldy;
10566     item_position = level_ypos + 1;
10567   }
10568
10569   if (item_position > items_max - items_visible)
10570     item_position = items_max - items_visible;
10571
10572   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10573                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10574 }
10575
10576 static void AdjustElementListScrollbar(void)
10577 {
10578   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10579   int items_max, items_visible, item_position;
10580
10581   // correct position of element list scrollbar
10582   if (element_shift < 0)
10583     element_shift = 0;
10584   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10585     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10586
10587   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10588   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10589   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10590
10591   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10592                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10593                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10594 }
10595
10596 static void ModifyEditorCounterValue(int counter_id, int new_value)
10597 {
10598   int *counter_value = counterbutton_info[counter_id].value;
10599   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10600   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10601
10602   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10603
10604   if (counter_value != NULL)
10605     *counter_value = gi->textinput.number_value;
10606 }
10607
10608 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10609 {
10610   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10611   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10612
10613   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10614
10615   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10616       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10617   {
10618     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10619     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10620
10621     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10622     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10623                  GDI_END);
10624   }
10625 }
10626
10627 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10628 {
10629   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10630   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10631   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10632
10633   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10634 }
10635
10636 static void ModifyEditorSelectboxOptions(int selectbox_id,
10637                                          struct ValueTextInfo *options)
10638 {
10639   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10640   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10641
10642   selectbox_info[selectbox_id].options = options;
10643
10644   // set index to zero -- list may be shorter now (correct later, if needed)
10645   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10646                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10647 }
10648
10649 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10650 {
10651   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10652   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10653
10654   drawingarea_info[drawingarea_id].area_xsize = xsize;
10655   drawingarea_info[drawingarea_id].area_ysize = ysize;
10656
10657   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10658 }
10659
10660 static void ModifyEditorElementList(void)
10661 {
10662   int i;
10663
10664   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10665     return;
10666
10667   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10668   {
10669     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10670     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10671     struct GadgetDesign *gd = &gi->deco.design;
10672     int element = editor_elements[element_shift + i];
10673     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10674
10675     UnmapGadget(gi);
10676
10677     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10678
10679     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10680
10681     MapGadget(gi);
10682   }
10683 }
10684
10685 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10686 {
10687   int graphic = el2edimg(element);
10688   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10689
10690   if (pos->x == -1 &&
10691       pos->y == -1)
10692     return;
10693
10694   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10695 }
10696
10697 static void ModifyDrawingElementButton(int element, int id)
10698 {
10699   struct GadgetInfo *gi = level_editor_gadget[id];
10700   Bitmap *deco_bitmap;
10701   int deco_x, deco_y;
10702   int tile_size = gi->deco.width;
10703
10704   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10705
10706   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10707 }
10708
10709 static void PickDrawingElement(int button, int element)
10710 {
10711   struct
10712   {
10713     int *new_element;
10714     struct XYTileSize *pos;
10715     int id;
10716   } de, drawing_elements[] =
10717   {
10718     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10719     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10720     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10721   };
10722
10723   if (button < 1 || button > 3)
10724     return;
10725
10726   if (IS_MM_WALL(element))
10727     element = map_mm_wall_element(element);
10728
10729   de = drawing_elements[button - 1];
10730
10731   *de.new_element = element;    // update global drawing element variable
10732
10733   DrawDrawingElementGraphic(element, de.pos);
10734   ModifyDrawingElementButton(element, de.id);
10735
10736   redraw_mask |= REDRAW_DOOR_1;
10737 }
10738
10739 static void RedrawDrawingElements(void)
10740 {
10741   PickDrawingElement(1, new_element1);
10742   PickDrawingElement(2, new_element2);
10743   PickDrawingElement(3, new_element3);
10744 }
10745
10746 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10747 {
10748   stick_element_properties_window = FALSE;
10749
10750   SetMainBackgroundImage(IMG_UNDEFINED);
10751   ClearField();
10752
10753   UnmapLevelEditorFieldGadgets();
10754
10755   AdjustDrawingAreaGadgets();
10756   AdjustLevelScrollPosition();
10757   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10758   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10759
10760   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10761
10762   MapMainDrawingArea();
10763
10764   if (remap_toolbox_gadgets)
10765   {
10766     UnmapLevelEditorToolboxCustomGadgets();
10767     MapLevelEditorToolboxDrawingGadgets();
10768   }
10769 }
10770
10771 static void DrawDrawingWindow(void)
10772 {
10773   DrawDrawingWindowExt(TRUE);
10774 }
10775
10776 static int getTabulatorBarWidth(void)
10777 {
10778   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10779   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10780
10781   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10782 }
10783
10784 static int getTabulatorBarHeight(void)
10785 {
10786   return ED_TAB_BAR_HEIGHT;
10787 }
10788
10789 static Pixel getTabulatorBarColor(void)
10790 {
10791   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10792   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10793   int gd_x = gd->x + gd_gi1->border.width / 2;
10794   int gd_y = gd->y + gd_gi1->height - 1;
10795
10796   return GetPixel(gd->bitmap, gd_x, gd_y);
10797 }
10798
10799 static void DrawLevelConfigTabulatorGadgets(void)
10800 {
10801   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10802   Pixel tab_color = getTabulatorBarColor();
10803   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10804   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10805   int i;
10806
10807   // draw additional "engine" tabulator when using native BD engine
10808   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10809     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10810
10811   for (i = id_first; i <= id_last; i++)
10812   {
10813     int gadget_id = textbutton_info[i].gadget_id;
10814     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10815     boolean active = (i != edit_mode_levelconfig);
10816
10817     // draw background line below tabulator button
10818     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10819
10820     // draw solid line below inactive tabulator buttons
10821     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10822       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10823                     ED_GADGET_TINY_DISTANCE, tab_color);
10824
10825     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10826     MapTextbuttonGadget(i);
10827   }
10828
10829   // draw little border line below tabulator buttons
10830   if (tab_color != BLACK_PIXEL)                 // black => transparent
10831     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10832                   ED_GADGET_TINY_DISTANCE,
10833                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10834 }
10835
10836 static void DrawPropertiesTabulatorGadgets(void)
10837 {
10838   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10839   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10840   int gd_x = gd->x + gd_gi1->border.width / 2;
10841   int gd_y = gd->y + gd_gi1->height - 1;
10842   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10843   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10844   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10845   int i;
10846
10847   // draw two config tabulators for player elements
10848   if (IS_PLAYER_ELEMENT(properties_element))
10849     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10850
10851   // draw two config and one "change" tabulator for custom elements
10852   if (IS_CUSTOM_ELEMENT(properties_element))
10853     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10854
10855   for (i = id_first; i <= id_last; i++)
10856   {
10857     int gadget_id = textbutton_info[i].gadget_id;
10858     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10859     boolean active = (i != edit_mode_properties);
10860
10861     // use "config 1" and "config 2" instead of "config" for players and CEs
10862     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10863         (IS_PLAYER_ELEMENT(properties_element) ||
10864          IS_CUSTOM_ELEMENT(properties_element)))
10865       continue;
10866
10867     // draw background line below tabulator button
10868     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10869
10870     // draw solid line below inactive tabulator buttons
10871     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10872       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10873                     ED_GADGET_TINY_DISTANCE, tab_color);
10874
10875     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10876     MapTextbuttonGadget(i);
10877   }
10878
10879   // draw little border line below tabulator buttons
10880   if (tab_color != BLACK_PIXEL)                 // black => transparent
10881     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10882                   ED_GADGET_TINY_DISTANCE,
10883                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10884 }
10885
10886 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10887 {
10888   DrawText(SX + xpos, SY + ypos, text, font_nr);
10889 }
10890
10891 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10892                                            int xpos, int ypos)
10893 {
10894   int font_width = getFontWidth(font_nr);
10895   int font_height = getFontHeight(font_nr);
10896   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10897   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10898
10899   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10900                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10901                       TRUE, FALSE, FALSE);
10902 }
10903
10904 static void DrawLevelConfigLevel(void)
10905 {
10906   int i;
10907
10908   // draw counter gadgets
10909   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10910     MapCounterButtons(i);
10911
10912   // draw checkbutton gadgets
10913   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10914     MapCheckbuttonGadget(i);
10915
10916   // draw selectbox gadgets
10917   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10918     MapSelectboxGadget(i);
10919
10920   // draw text input gadgets
10921   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10922     MapTextInputGadget(i);
10923 }
10924
10925 static char *getLevelSubdirFromSaveMode(int save_mode)
10926 {
10927   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10928     return getNewUserLevelSubdir();
10929
10930   return leveldir_current->subdir;
10931 }
10932
10933 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10934 {
10935   char *directory_text = "Level set directory:";
10936   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10937   int font1_nr = FONT_TEXT_1;
10938   int font2_nr = FONT_TEXT_2;
10939   int font1_height = getFontHeight(font1_nr);
10940   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10941   int x = ED_LEVEL_SETTINGS_X(0);
10942   int y = ED_LEVEL_SETTINGS_Y(6);
10943
10944   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10945   PrintInfoText(directory_name, font2_nr, x, y);
10946 }
10947
10948 static void DrawLevelConfigLevelSet(void)
10949 {
10950   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10951   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10952   int i;
10953
10954   // draw counter gadgets
10955   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10956     MapCounterButtons(i);
10957
10958   // draw checkbutton gadgets
10959   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10960   {
10961     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10962         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10963         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10964       continue;
10965
10966     MapCheckbuttonGadget(i);
10967   }
10968
10969   // draw selectbox gadgets
10970   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10971     MapSelectboxGadget(i);
10972
10973   // draw text input gadgets
10974   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10975     MapTextInputGadget(i);
10976
10977   // draw textbutton gadgets
10978   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10979
10980   // draw info text
10981   DrawLevelConfigLevelSet_DirectoryInfo();
10982 }
10983
10984 static void DrawLevelConfigEditor(void)
10985 {
10986   int i;
10987
10988   // draw counter gadgets
10989   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
10990     MapCounterButtons(i);
10991
10992   // draw checkbutton gadgets
10993   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
10994     MapCheckbuttonGadget(i);
10995
10996   // draw radiobutton gadgets
10997   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
10998     MapRadiobuttonGadget(i);
10999
11000   // draw drawing area
11001   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
11002
11003   // draw textbutton gadgets
11004   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
11005 }
11006
11007 static void DrawLevelConfigEngine(void)
11008 {
11009   int i;
11010
11011   // draw counter gadgets
11012   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
11013   {
11014     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
11015     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
11016   }
11017   else
11018   {
11019     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
11020     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
11021   }
11022
11023   // draw checkbutton gadgets
11024   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
11025     MapCheckbuttonGadget(i);
11026
11027   // draw selectbox gadgets
11028   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
11029     MapSelectboxGadget(i);
11030 }
11031
11032 static void DrawLevelConfigWindow(void)
11033 {
11034   char *text = "Global Settings";
11035   int font_nr = FONT_TITLE_1;
11036   struct MenuPosInfo *pos = &editor.settings.headline;
11037   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
11038   int sy = SY + pos->y;
11039
11040   stick_element_properties_window = FALSE;
11041
11042   SetAutomaticNumberOfGemsNeeded();
11043
11044   UnmapLevelEditorFieldGadgets();
11045
11046   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
11047   ClearField();
11048
11049   DrawText(sx, sy, text, font_nr);
11050
11051   DrawLevelConfigTabulatorGadgets();
11052
11053   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
11054     DrawLevelConfigLevel();
11055   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
11056     DrawLevelConfigLevelSet();
11057   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
11058     DrawLevelConfigEditor();
11059   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
11060     DrawLevelConfigEngine();
11061 }
11062
11063 static void DrawCustomContentArea(void)
11064 {
11065   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
11066   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11067   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
11068   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
11069   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
11070   int xoffset = ED_GADGET_SPACE_DISTANCE;
11071
11072   // add distance for potential left text (without drawing area border)
11073   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
11074
11075   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11076
11077   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
11078 }
11079
11080 static void DrawCustomChangeContentArea(void)
11081 {
11082   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
11083   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11084   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
11085   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
11086   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
11087   int xoffset = ED_GADGET_SPACE_DISTANCE;
11088
11089   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11090
11091   MapDrawingArea(id);
11092 }
11093
11094 static void RemoveElementContentArea(int id, int font_height)
11095 {
11096   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11097
11098   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
11099                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
11100                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11101                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
11102                  ED_GADGET_TEXT_DISTANCE + font_height);
11103 }
11104
11105 static void DrawYamYamContentAreas(void)
11106 {
11107   int font_nr = FONT_TEXT_1;
11108   int font_height = getFontHeight(font_nr);
11109   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11110   int yoffset = (tilesize - font_height) / 2;
11111   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
11112   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
11113   int i;
11114
11115   // display counter to choose number of element content areas
11116   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
11117
11118   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11119   {
11120     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
11121
11122     if (i < level.num_yamyam_contents)
11123     {
11124       MapDrawingArea(id);
11125     }
11126     else
11127     {
11128       UnmapDrawingArea(id);
11129
11130       // delete content areas in case of reducing number of them
11131       RemoveElementContentArea(id, font_height);
11132     }
11133   }
11134
11135   DrawText(x, y + 0 * tilesize, "content", font_nr);
11136   DrawText(x, y + 1 * tilesize, "when",    font_nr);
11137   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
11138 }
11139
11140 static void DrawMagicBallContentAreas(void)
11141 {
11142   int font_nr = FONT_TEXT_1;
11143   int font_height = getFontHeight(font_nr);
11144   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11145   int yoffset = (tilesize - font_height) / 2;
11146   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
11147   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
11148   int i;
11149
11150   // display counter to choose number of element content areas
11151   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
11152
11153   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11154   {
11155     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
11156
11157     if (i < level.num_ball_contents)
11158     {
11159       MapDrawingArea(id);
11160     }
11161     else
11162     {
11163       UnmapDrawingArea(id);
11164
11165       // delete content areas in case of reducing number of them
11166       RemoveElementContentArea(id, font_height);
11167     }
11168   }
11169
11170   DrawText(x, y + 0 * tilesize, "generated", font_nr);
11171   DrawText(x, y + 1 * tilesize, "when",      font_nr);
11172   DrawText(x, y + 2 * tilesize, "active",    font_nr);
11173 }
11174
11175 static void DrawAndroidElementArea(void)
11176 {
11177   int id = ED_DRAWING_ID_ANDROID_CONTENT;
11178   int num_elements = level.num_android_clone_elements;
11179   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11180   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11181   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11182   int xsize = MAX_ANDROID_ELEMENTS;
11183   int ysize = 1;
11184
11185   // display counter to choose number of element areas
11186   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
11187
11188   if (drawingarea_info[id].text_left != NULL)
11189     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11190
11191   UnmapDrawingArea(id);
11192
11193   ModifyEditorDrawingArea(id, num_elements, 1);
11194
11195   // delete content areas in case of reducing number of them
11196   DrawBackground(sx, sy,
11197                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11198                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11199
11200   MapDrawingArea(id);
11201 }
11202
11203 static void DrawGroupElementArea(void)
11204 {
11205   int id = ED_DRAWING_ID_GROUP_CONTENT;
11206   int num_elements = group_element_info.num_elements;
11207   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11208   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11209   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11210   int xsize = MAX_ELEMENTS_IN_GROUP;
11211   int ysize = 1;
11212
11213   if (drawingarea_info[id].text_left != NULL)
11214     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11215
11216   UnmapDrawingArea(id);
11217
11218   ModifyEditorDrawingArea(id, num_elements, 1);
11219
11220   // delete content areas in case of reducing number of them
11221   DrawBackground(sx, sy,
11222                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11223                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11224
11225   MapDrawingArea(id);
11226 }
11227
11228 static void DrawPlayerInitialInventoryArea(int element)
11229 {
11230   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11231   int player_nr = GET_PLAYER_NR(element);
11232   int num_elements = level.initial_inventory_size[player_nr];
11233   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11234   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11235   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11236   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11237   int ysize = 1;
11238
11239   // determine horizontal position to the right of specified gadget
11240   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11241     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11242           ED_DRAWINGAREA_TEXT_DISTANCE);
11243
11244   // determine horizontal offset for leading text
11245   if (drawingarea_info[id].text_left != NULL)
11246     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11247
11248   UnmapDrawingArea(id);
11249
11250   ModifyEditorDrawingArea(id, num_elements, 1);
11251
11252   // delete content areas in case of reducing number of them
11253   DrawBackground(sx, sy,
11254                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11255                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11256
11257   MapDrawingArea(id);
11258 }
11259
11260 static void DrawMMBallContentArea(void)
11261 {
11262   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11263   int num_elements = level.num_mm_ball_contents;
11264   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11265   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11266   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11267   int xsize = MAX_MM_BALL_CONTENTS;
11268   int ysize = 1;
11269
11270   if (drawingarea_info[id].text_left != NULL)
11271     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11272
11273   UnmapDrawingArea(id);
11274
11275   ModifyEditorDrawingArea(id, num_elements, 1);
11276
11277   // delete content areas in case of reducing number of them
11278   DrawBackground(sx, sy,
11279                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11280                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11281
11282   MapDrawingArea(id);
11283 }
11284
11285 static void DrawEnvelopeTextArea(int envelope_nr)
11286 {
11287   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11288   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11289
11290   UnmapGadget(gi);
11291
11292   DrawBackground(gi->x, gi->y,
11293                  gi->textarea.crop_width, gi->textarea.crop_height);
11294
11295   if (envelope_nr != -1)
11296     textarea_info[id].value = level.envelope[envelope_nr].text;
11297
11298   ModifyGadget(gi, GDI_AREA_SIZE,
11299                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11300                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11301                GDI_END);
11302
11303   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11304 }
11305
11306 static void DrawPropertiesInfo(void)
11307 {
11308   static struct
11309   {
11310     int value;
11311     char *text;
11312   }
11313   properties[] =
11314   {
11315     // configurable properties
11316
11317     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11318     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11319     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11320     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11321     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11322     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11323     { EP_PROTECTED,             "- player is protected by it"           },
11324
11325     { EP_DIGGABLE,              "- can be digged away"                  },
11326     { EP_COLLECTIBLE,           "- can be collected"                    },
11327     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11328     { EP_THROWABLE,             "- can be thrown after collecting"      },
11329     { EP_PUSHABLE,              "- can be pushed"                       },
11330
11331     { EP_CAN_FALL,              "- can fall"                            },
11332     { EP_CAN_MOVE,              "- can move"                            },
11333
11334     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11335 #if 0
11336     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11337 #endif
11338     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11339
11340     { EP_SLIPPERY,              "- slippery for falling elements"       },
11341     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11342
11343     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11344     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11345     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11346     { EP_DONT_TOUCH,            "- deadly when touching"                },
11347
11348     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11349
11350     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11351     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11352     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11353
11354     { EP_CAN_CHANGE,            "- can change to other element"         },
11355
11356     // pre-defined properties
11357     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11358     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11359     { EP_SWITCHABLE,            "- can be switched"                     },
11360 #if 0
11361     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11362 #endif
11363
11364     { -1,                       NULL                                    }
11365   };
11366   char *filename = getElementDescriptionFilename(properties_element);
11367   char *num_elements_text = "In this level: ";
11368   char *num_similar_text = "Similar tiles: ";
11369   char *properties_text = "Standard properties: ";
11370   char *description_text = "Description:";
11371   char *no_description_text = "No description available.";
11372   char *none_text = "None";
11373   float percentage;
11374   int num_elements_in_level = 0;
11375   int num_similar_in_level = 0;
11376   int num_hires_tiles_in_level = 0;
11377   int num_standard_properties = 0;
11378   int font1_nr = FONT_TEXT_1;
11379   int font2_nr = FONT_TEXT_2;
11380   int font1_width = getFontWidth(font1_nr);
11381   int font1_height = getFontHeight(font1_nr);
11382   int font2_height = getFontHeight(font2_nr);
11383   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11384   int font2_yoffset = (font1_height - font2_height) / 2;
11385   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11386   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11387   int properties_text_len = strlen(properties_text) * font1_width;
11388   int xpos = ED_ELEMENT_SETTINGS_X(0);
11389   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11390   int i, x, y;
11391
11392   if (setup.editor.show_element_token)
11393   {
11394     int font3_nr = FONT_TEXT_3;
11395     int font3_height = getFontHeight(font3_nr);
11396
11397     DrawTextF(xpos, ypos, font3_nr,
11398               "[%s]", element_info[properties_element].token_name);
11399
11400     ypos += 2 * font3_height;
11401   }
11402
11403   // ----- print number of elements / percentage of this element in level
11404
11405   for (y = 0; y < lev_fieldy; y++)
11406   {
11407     for (x = 0; x < lev_fieldx; x++)
11408     {
11409       if (Tile[x][y] == properties_element)
11410       {
11411         num_elements_in_level++;
11412       }
11413       else if (IS_MM_WALL(Tile[x][y]) &&
11414                map_mm_wall_element(Tile[x][y]) == properties_element)
11415       {
11416         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11417       }
11418     }
11419   }
11420
11421   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11422
11423   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11424
11425   if (num_hires_tiles_in_level > 0)
11426     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11427               "%d wall tiles", num_hires_tiles_in_level);
11428   else if (num_elements_in_level > 0)
11429     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11430               "%d (%.2f %%)", num_elements_in_level, percentage);
11431   else
11432     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11433               none_text);
11434
11435   // ----- print number of similar elements / percentage of them in level
11436
11437   for (y = 0; y < lev_fieldy; y++)
11438   {
11439     for (x = 0; x < lev_fieldx; x++)
11440     {
11441       if (strEqual(element_info[Tile[x][y]].class_name,
11442                    element_info[properties_element].class_name))
11443       {
11444         num_similar_in_level++;
11445       }
11446     }
11447   }
11448
11449   if (num_similar_in_level != num_elements_in_level)
11450   {
11451     ypos += 1 * MAX(font1_height, font2_height);
11452
11453     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11454
11455     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11456
11457     if (num_similar_in_level > 0)
11458       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11459                 "%d (%.2f %%)", num_similar_in_level, percentage);
11460     else
11461       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11462                 none_text);
11463   }
11464
11465   ypos += 2 * MAX(font1_height, font2_height);
11466
11467   // ----- print standard properties of this element
11468
11469   DrawTextS(xpos, ypos, font1_nr, properties_text);
11470
11471   ypos += line1_height;
11472
11473   for (i = 0; properties[i].value != -1; i++)
11474   {
11475     if (!HAS_PROPERTY(properties_element, properties[i].value))
11476       continue;
11477
11478     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11479
11480     ypos += font2_height;
11481
11482     num_standard_properties++;
11483   }
11484
11485   if (num_standard_properties == 0)
11486   {
11487     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11488               font2_nr, none_text);
11489
11490     ypos -= (line1_height - font1_height);
11491   }
11492
11493   ypos += MAX(font1_height, font2_height);
11494
11495   // ----- print special description of this element
11496
11497   PrintInfoText(description_text, font1_nr, xpos, ypos);
11498
11499   ypos += line1_height;
11500
11501   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11502     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11503 }
11504
11505 #define TEXT_COLLECTING                 "Score for collecting"
11506 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11507 #define TEXT_SMASHING                   "Score for smashing"
11508 #define TEXT_SLURPING                   "Score for slurping robot"
11509 #define TEXT_CRACKING                   "Score for cracking"
11510 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11511 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11512 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11513 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11514 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11515 #define TEXT_DURATION                   "Duration when activated"
11516 #define TEXT_DELAY_ON                   "Delay before activating"
11517 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11518 #define TEXT_DELAY_CHANGING             "Delay before changing"
11519 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11520 #define TEXT_DELAY_MOVING               "Delay before moving"
11521 #define TEXT_BALL_DELAY                 "Element generation delay"
11522 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11523 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11524 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11525 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11526 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11527 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11528 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11529 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11530 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11531 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11532 #define TEXT_RANDOM_SEED                "slime random number seed"
11533 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11534 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11535 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11536 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11537 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11538 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11539 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11540 #define TEXT_AUTO_TURN_DELAY            "Creatures auto turn delay"
11541 #define TEXT_GRAVITY_DELAY              "Gravity switch change delay"
11542
11543 static struct
11544 {
11545   int element;
11546   int *value;
11547   char *text;
11548   int min_value;
11549   int max_value;
11550 } elements_with_counter[] =
11551 {
11552   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11553   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11554   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11555   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11556   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11557   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11558   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11559   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11560   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11561   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11562   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11563   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11564   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11565   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11566   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11567   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11568   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11569   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11570   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11571   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11572   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11573   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11574   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11575   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11576   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11577   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11578   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11579   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11580   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11581   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11582   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11583   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11584   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11585   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11586   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11587   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11588   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11589   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11590   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11591   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11592   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11593   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11594   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11595   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11596   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11597   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11598   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11599   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11600   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11601   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11602   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11603   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11604   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11605   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11606   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11607   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11608   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11609   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11610   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11611   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11612   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11613   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11614   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11615   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11616   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11617   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11618   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11619   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11620   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11621   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11622   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11623   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11624   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11625   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11626   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11627   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11628   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11629   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11630   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11631   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11632   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11633   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11634   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11635                                 0, 100                                                          },
11636   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11637                                 0, 100                                                          },
11638   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11639   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11640   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11641                                 0, 100                                                          },
11642   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11643                                 0, 100                                                          },
11644   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11645   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11646   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11647   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11648   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11649   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11650   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11651   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11652   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11653   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11654   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11655                                 -100, 100                                                       },
11656   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11657                                 0, 100                                                          },
11658   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11659                                 0, 100                                                          },
11660   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11661                                 0, 255                                                          },
11662   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11663                                 -1, 65535                                                       },
11664   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11665                                 0, 100                                                          },
11666   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11667                                 0, 3                                                            },
11668   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11669                                 0, 3                                                            },
11670   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11671                                 0, 3                                                            },
11672   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11673                                 0, 3                                                            },
11674   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11675                                 0, 3                                                            },
11676   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11677                                 0, 100                                                          },
11678   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11679                                 1, 100                                                          },
11680   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11681                                 1, 200                                                          },
11682   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11683                                 0, 50                                                           },
11684   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11685                                 0, 50                                                           },
11686   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11687                                 0, 10                                                           },
11688   { EL_BD_CREATURE_SWITCH,      &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
11689   { EL_BD_GRAVITY_SWITCH,       &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
11690                                 1, 60                                                           },
11691   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11692   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11693   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11694   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11695   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11696   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11697   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11698   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11699   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11700   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11701   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11702   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11703   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11704   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11705   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11706   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11707   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11708   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11709   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11710   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11711   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11712   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11713   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11714   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11715   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11716
11717   { -1,                         NULL,                                   NULL                    }
11718 };
11719
11720 static boolean checkPropertiesConfig(int element)
11721 {
11722   int i;
11723
11724   // special case: empty space customization only available in R'n'D game engine
11725   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11726     return FALSE;
11727
11728   // special case: BD style rock customization only available in BD game engine
11729   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11730     return FALSE;
11731
11732   if (IS_GEM(element) ||
11733       IS_CUSTOM_ELEMENT(element) ||
11734       IS_GROUP_ELEMENT(element) ||
11735       IS_EMPTY_ELEMENT(element) ||
11736       IS_BALLOON_ELEMENT(element) ||
11737       IS_ENVELOPE(element) ||
11738       IS_MM_ENVELOPE(element) ||
11739       IS_MM_MCDUFFIN(element) ||
11740       IS_DF_LASER(element) ||
11741       IS_PLAYER_ELEMENT(element) ||
11742       IS_BD_PLAYER_ELEMENT(element) ||
11743       IS_BD_FIREFLY(properties_element) ||
11744       IS_BD_FIREFLY_2(properties_element) ||
11745       IS_BD_BUTTERFLY(properties_element) ||
11746       IS_BD_BUTTERFLY_2(properties_element) ||
11747       IS_BD_STONEFLY(properties_element) ||
11748       IS_BD_DRAGONFLY(properties_element) ||
11749       IS_BD_EXPANDABLE_WALL(properties_element) ||
11750       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11751       IS_BD_CONVEYOR_BELT(properties_element) ||
11752       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11753       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11754       HAS_EDITOR_CONTENT(element) ||
11755       CAN_GROW(element) ||
11756       COULD_MOVE_INTO_ACID(element) ||
11757       MAYBE_DONT_COLLIDE_WITH(element) ||
11758       element == EL_BD_SAND ||
11759       element == EL_BD_ROCK ||
11760       element == EL_BD_MEGA_ROCK ||
11761       element == EL_BD_BOMB ||
11762       element == EL_BD_ROCKET_LAUNCHER ||
11763       element == EL_BD_NITRO_PACK ||
11764       element == EL_BD_SWEET ||
11765       element == EL_BD_VOODOO_DOLL ||
11766       element == EL_BD_WATER ||
11767       element == EL_BD_GRAVITY_SWITCH)
11768   {
11769     return TRUE;
11770   }
11771   else
11772   {
11773     for (i = 0; elements_with_counter[i].element != -1; i++)
11774       if (elements_with_counter[i].element == element)
11775         return TRUE;
11776   }
11777
11778   return FALSE;
11779 }
11780
11781 static void SetAutomaticNumberOfGemsNeeded(void)
11782 {
11783   int x, y;
11784
11785   if (!level.auto_count_gems)
11786     return;
11787
11788   level.gems_needed = 0;
11789
11790   for (x = 0; x < lev_fieldx; x++)
11791   {
11792     for (y = 0; y < lev_fieldy; y++)
11793     {
11794       int element = Tile[x][y];
11795
11796       switch (element)
11797       {
11798         case EL_EMERALD:
11799         case EL_EMERALD_YELLOW:
11800         case EL_EMERALD_RED:
11801         case EL_EMERALD_PURPLE:
11802         case EL_BD_DIAMOND:
11803         case EL_WALL_EMERALD:
11804         case EL_WALL_EMERALD_YELLOW:
11805         case EL_WALL_EMERALD_RED:
11806         case EL_WALL_EMERALD_PURPLE:
11807         case EL_WALL_BD_DIAMOND:
11808         case EL_NUT:
11809         case EL_SP_INFOTRON:
11810         case EL_MM_KETTLE:
11811         case EL_DF_CELL:
11812           level.gems_needed++;
11813           break;
11814
11815         case EL_DIAMOND:
11816         case EL_WALL_DIAMOND:
11817           level.gems_needed += 3;
11818           break;
11819
11820         case EL_PEARL:
11821         case EL_WALL_PEARL:
11822           level.gems_needed += 5;
11823           break;
11824
11825         case EL_CRYSTAL:
11826         case EL_WALL_CRYSTAL:
11827           level.gems_needed += 8;
11828           break;
11829
11830         default:
11831           break;
11832       }
11833     }
11834   }
11835
11836   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11837 }
11838
11839 static void DrawPropertiesConfig(void)
11840 {
11841   boolean draw_footer_line = FALSE;
11842   int max_num_element_counters = 4;
11843   int num_element_counters = 0;
11844   int i;
11845
11846   if (!checkPropertiesConfig(properties_element))
11847   {
11848     int xpos = ED_ELEMENT_SETTINGS_X(0);
11849     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11850
11851     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11852
11853     return;
11854   }
11855
11856   // check if there are elements where a value can be chosen for
11857   for (i = 0; elements_with_counter[i].element != -1; i++)
11858   {
11859     if (elements_with_counter[i].element != properties_element)
11860       continue;
11861
11862     // special case: score for extra diamonds only available in BD game engine
11863     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11864         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11865         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11866       continue;
11867
11868     // special case: some amoeba counters only available in BD game engine
11869     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11870         elements_with_counter[i].value != &level.amoeba_speed &&
11871         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11872       continue;
11873
11874     // special case: score for smashing only available in R'n'D game engine
11875     if ((IS_BD_FIREFLY(elements_with_counter[i].element) ||
11876          IS_BD_BUTTERFLY(elements_with_counter[i].element)) &&
11877         (elements_with_counter[i].value == &level.score[SC_BUG] ||
11878          elements_with_counter[i].value == &level.score[SC_SPACESHIP]) &&
11879         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11880       continue;
11881
11882     // special case: some amoeba counters only available in R'n'D game engine
11883     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11884         elements_with_counter[i].value == &level.amoeba_speed &&
11885         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11886       continue;
11887
11888     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11889
11890     counterbutton_info[counter_id].y =
11891       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11892                                (CAN_GROW(properties_element)                ? 1 : 0) +
11893                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11894                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11895                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11896                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11897                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11898                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11899                                (properties_element == EL_BD_CREATURE_SWITCH ? 1 : 0) +
11900                                (properties_element == EL_BD_GRAVITY_SWITCH  ? 2 : 0) +
11901                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11902                                num_element_counters);
11903
11904     // special case: set magic wall counter for BD game engine separately
11905     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11906       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11907
11908     // special case: set amoeba counters for BD game engine separately
11909     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11910         (properties_element == EL_BD_AMOEBA_2))
11911       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11912
11913     // special case: set position for delay counter for reappearing hammered walls
11914     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11915       counterbutton_info[counter_id].y += 1;
11916
11917     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11918     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11919     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11920     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11921
11922     // default: counter values between 0 and 999
11923     if (counterbutton_info[counter_id].max_value == 0)
11924       counterbutton_info[counter_id].max_value = 999;
11925
11926     MapCounterButtons(counter_id);
11927
11928     num_element_counters++;
11929     if (num_element_counters >= max_num_element_counters)
11930       break;
11931   }
11932
11933   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11934   {
11935     // draw stickybutton gadget
11936     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11937
11938     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE);
11939     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11940     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11941
11942     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11943     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11944     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11945     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11946     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11947     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11948     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11949   }
11950
11951   if (HAS_EDITOR_CONTENT(properties_element))
11952   {
11953     // draw stickybutton gadget
11954     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11955
11956     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11957     {
11958       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11959       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11960
11961       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11962       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11963     }
11964     else if (properties_element == EL_BD_AMOEBA_2)
11965     {
11966       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11967       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11968       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11969
11970       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11971       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11972       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11973       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11974     }
11975     else if (IS_AMOEBOID(properties_element))
11976     {
11977       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11978     }
11979     else if (properties_element == EL_BD_ACID)
11980     {
11981       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11982       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11983     }
11984     else if (IS_BD_BITER(properties_element))
11985     {
11986       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11987     }
11988     else if (properties_element == EL_BD_BLADDER)
11989     {
11990       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11991     }
11992     else if (properties_element == EL_YAMYAM ||
11993              properties_element == EL_YAMYAM_LEFT ||
11994              properties_element == EL_YAMYAM_RIGHT ||
11995              properties_element == EL_YAMYAM_UP ||
11996              properties_element == EL_YAMYAM_DOWN)
11997     {
11998       DrawYamYamContentAreas();
11999     }
12000     else if (properties_element == EL_EMC_MAGIC_BALL)
12001     {
12002       DrawMagicBallContentAreas();
12003
12004       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
12005       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
12006     }
12007     else if (properties_element == EL_EMC_ANDROID)
12008     {
12009       DrawAndroidElementArea();
12010     }
12011     else if (properties_element == EL_MM_GRAY_BALL)
12012     {
12013       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
12014       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
12015       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
12016       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
12017
12018       DrawMMBallContentArea();
12019     }
12020   }
12021
12022   if (IS_PLAYER_ELEMENT(properties_element))
12023   {
12024     int player_nr = GET_PLAYER_NR(properties_element);
12025
12026     // these properties can be set for every player individually
12027
12028     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12029     {
12030       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
12031         &level.start_element[player_nr];
12032       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
12033         &level.artwork_element[player_nr];
12034       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
12035         &level.explosion_element[player_nr];
12036
12037       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
12038         &level.use_start_element[player_nr];
12039       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
12040         &level.use_artwork_element[player_nr];
12041       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
12042         &level.use_explosion_element[player_nr];
12043       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
12044         &level.initial_player_gravity[player_nr];
12045
12046       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
12047         &level.initial_player_stepsize[player_nr];
12048
12049       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
12050       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
12051                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
12052                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
12053       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
12054       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
12055       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
12056       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
12057       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
12058       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
12059       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
12060       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
12061       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
12062       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
12063       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
12064
12065       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
12066       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
12067       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
12068
12069       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
12070     }
12071     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12072     {
12073       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
12074         &level.initial_inventory_content[player_nr][0];
12075
12076       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
12077         &level.initial_inventory_size[player_nr];
12078
12079       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
12080         &level.use_initial_inventory[player_nr];
12081
12082       // draw checkbutton gadgets
12083       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
12084       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
12085       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
12086
12087       // draw counter gadgets
12088       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
12089
12090       // draw drawing area gadgets
12091       DrawPlayerInitialInventoryArea(properties_element);
12092     }
12093   }
12094
12095   if (IS_BD_PLAYER_ELEMENT(properties_element))
12096   {
12097     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12098       ED_ELEMENT_SETTINGS_YPOS(2);
12099     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12100       ED_ELEMENT_SETTINGS_YPOS(3);
12101     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12102       ED_ELEMENT_SETTINGS_YPOS(4);
12103
12104     // draw checkbutton gadgets
12105     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
12106     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
12107     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12108
12109     // draw counter gadgets
12110     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12111     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12112
12113     // draw drawing area gadgets
12114     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
12115   }
12116
12117   if (properties_element == EL_BD_SAND)
12118   {
12119     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
12120   }
12121
12122   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12123   {
12124     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12125       ED_ELEMENT_SETTINGS_YPOS(0);
12126     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12127       ED_ELEMENT_SETTINGS_YPOS(1);
12128
12129     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12130     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12131
12132     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
12133     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
12134   }
12135
12136   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12137   {
12138     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
12139     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
12140   }
12141
12142   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
12143   {
12144     if (IS_BD_FIREFLY(properties_element))
12145     {
12146       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO);
12147       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12148     }
12149     else if (IS_BD_FIREFLY_2(properties_element))
12150     {
12151       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
12152       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12153     }
12154     else if (IS_BD_BUTTERFLY(properties_element))
12155     {
12156       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO);
12157       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12158     }
12159     else if (IS_BD_BUTTERFLY_2(properties_element))
12160     {
12161       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
12162       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12163     }
12164     else if (IS_BD_STONEFLY(properties_element))
12165     {
12166       MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
12167     }
12168     else if (IS_BD_DRAGONFLY(properties_element))
12169     {
12170       MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
12171       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12172     }
12173     else if (properties_element == EL_BD_BOMB)
12174     {
12175       MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
12176     }
12177     else if (properties_element == EL_BD_NITRO_PACK)
12178     {
12179       MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
12180     }
12181   }
12182
12183   if (properties_element == EL_BD_MEGA_ROCK ||
12184       properties_element == EL_BD_SWEET)
12185   {
12186     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12187       ED_ELEMENT_SETTINGS_YPOS(0);
12188     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12189       ED_ELEMENT_SETTINGS_YPOS(1);
12190
12191     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12192     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12193   }
12194
12195   if (properties_element == EL_BD_VOODOO_DOLL)
12196   {
12197     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12198     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12199     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12200     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12201   }
12202
12203   if (properties_element == EL_BD_SLIME)
12204   {
12205     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12206
12207     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12208     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12209     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12210     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12211     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12212     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12213   }
12214
12215   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12216       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12217   {
12218     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12219
12220     if (IS_BD_EXPANDABLE_WALL(properties_element))
12221       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12222   }
12223
12224   if (properties_element == EL_BD_REPLICATOR)
12225   {
12226     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12227   }
12228
12229   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12230       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12231   {
12232     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12233     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12234   }
12235
12236   if (properties_element == EL_BD_WATER)
12237   {
12238     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12239   }
12240
12241   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12242   {
12243     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12244   }
12245
12246   if (properties_element == EL_BD_ROCKET_LAUNCHER)
12247   {
12248     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS);
12249   }
12250
12251   if (properties_element == EL_BD_CREATURE_SWITCH)
12252   {
12253     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12254     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12255   }
12256
12257   if (properties_element == EL_BD_GRAVITY_SWITCH)
12258   {
12259     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12260
12261     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12262     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12263   }
12264
12265   if (properties_element == EL_BD_NUT)
12266   {
12267     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12268   }
12269
12270   // special case: slippery walls option for gems only available in R'n'D game engine
12271   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12272     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12273
12274   if (properties_element == EL_EM_DYNAMITE)
12275     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12276
12277   if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
12278       COULD_MOVE_INTO_ACID(properties_element) &&
12279       !IS_PLAYER_ELEMENT(properties_element) &&
12280       (!IS_CUSTOM_ELEMENT(properties_element) ||
12281        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12282   {
12283     // set position for checkbutton for "can move into acid"
12284     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12285       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12286     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12287       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12288                                IS_BALLOON_ELEMENT(properties_element) ||
12289                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12290
12291     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12292   }
12293
12294   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12295     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12296
12297   if (properties_element == EL_SPRING ||
12298       properties_element == EL_SPRING_LEFT ||
12299       properties_element == EL_SPRING_RIGHT)
12300     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12301
12302   if (properties_element == EL_TIME_ORB_FULL)
12303     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12304
12305   if (properties_element == EL_GAME_OF_LIFE ||
12306       properties_element == EL_BIOMAZE)
12307     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12308
12309   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12310   {
12311     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12312       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12313
12314     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12315   }
12316
12317   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12318     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12319
12320   if (properties_element == EL_SOKOBAN_OBJECT)
12321     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12322
12323   if (properties_element == EL_SOKOBAN_OBJECT ||
12324       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12325       properties_element == EL_SOKOBAN_FIELD_FULL)
12326   {
12327     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12328       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12329                                0 : 1);
12330
12331     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12332   }
12333
12334   if (IS_BALLOON_ELEMENT(properties_element))
12335     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12336
12337   if (IS_ENVELOPE(properties_element) ||
12338       IS_MM_ENVELOPE(properties_element))
12339   {
12340     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12341     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12342     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12343     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12344     int envelope_nr = ENVELOPE_NR(properties_element);
12345
12346     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12347     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12348
12349     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12350     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12351
12352     // display counter to choose size of envelope text area
12353     MapCounterButtons(counter1_id);
12354     MapCounterButtons(counter2_id);
12355
12356     // display checkbuttons to choose auto-wrap and alignment properties
12357     MapCheckbuttonGadget(button1_id);
12358     MapCheckbuttonGadget(button2_id);
12359
12360     DrawEnvelopeTextArea(envelope_nr);
12361   }
12362
12363   if (IS_MM_MCDUFFIN(properties_element))
12364   {
12365     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12366     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12367     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12368   }
12369
12370   if (IS_DF_LASER(properties_element))
12371   {
12372     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12373     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12374     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12375   }
12376
12377   if (IS_CUSTOM_ELEMENT(properties_element))
12378   {
12379     // draw stickybutton gadget
12380     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12381
12382     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12383     {
12384       // draw checkbutton gadgets
12385       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12386            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12387         MapCheckbuttonGadget(i);
12388
12389       // draw counter gadgets
12390       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12391            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12392         MapCounterButtons(i);
12393
12394       // draw selectbox gadgets
12395       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12396            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12397         MapSelectboxGadget(i);
12398
12399       // draw textbutton gadgets
12400       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12401
12402       // draw text input gadgets
12403       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12404
12405       // draw drawing area gadgets
12406       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12407
12408       draw_footer_line = TRUE;
12409     }
12410     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12411     {
12412       // draw checkbutton gadgets
12413       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12414            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12415         MapCheckbuttonGadget(i);
12416
12417       // draw counter gadgets
12418       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12419            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12420         MapCounterButtons(i);
12421
12422       // draw selectbox gadgets
12423       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12424            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12425         MapSelectboxGadget(i);
12426
12427       // draw drawing area gadgets
12428       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12429       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12430       DrawCustomContentArea();
12431     }
12432   }
12433   else if (IS_GROUP_ELEMENT(properties_element))
12434   {
12435     // draw stickybutton gadget
12436     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12437
12438     // draw checkbutton gadgets
12439     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12440     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12441
12442     // draw counter gadgets
12443     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12444
12445     // draw selectbox gadgets
12446     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12447
12448     // draw textbutton gadgets
12449     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12450
12451     // draw drawing area gadgets
12452     DrawGroupElementArea();
12453
12454     // draw text input gadgets
12455     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12456
12457     // draw drawing area gadgets
12458     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12459
12460     draw_footer_line = TRUE;
12461   }
12462   else if (IS_EMPTY_ELEMENT(properties_element))
12463   {
12464     // draw stickybutton gadget
12465     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12466
12467     // draw checkbutton gadgets
12468     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12469     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12470
12471     // draw textbutton gadgets
12472     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12473
12474     // draw drawing area gadgets
12475     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12476
12477     draw_footer_line = TRUE;
12478   }
12479
12480   // draw little footer border line above CE/GE use/save template gadgets
12481   if (draw_footer_line)
12482   {
12483     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12484     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12485     int gd_x = gd->x + gd_gi1->border.width / 2;
12486     int gd_y = gd->y + gd_gi1->height - 1;
12487     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12488
12489     if (tab_color != BLACK_PIXEL)               // black => transparent
12490       FillRectangle(drawto,
12491                     SX + ED_ELEMENT_SETTINGS_X(0),
12492                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12493                     ED_TAB_BAR_HEIGHT,
12494                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12495   }
12496 }
12497
12498 static void DrawPropertiesChangeDrawingAreas(void)
12499 {
12500   if (IS_CUSTOM_ELEMENT(properties_element))
12501   {
12502     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12503     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12504     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12505
12506     DrawCustomChangeContentArea();
12507   }
12508
12509   redraw_mask |= REDRAW_FIELD;
12510 }
12511
12512 static void DrawPropertiesChange(void)
12513 {
12514   int i;
12515
12516   // needed to initially set selectbox options for special action options
12517   setSelectboxSpecialActionOptions();
12518
12519   // draw stickybutton gadget
12520   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12521
12522   // draw checkbutton gadgets
12523   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12524        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12525     MapCheckbuttonGadget(i);
12526
12527   // draw counter gadgets
12528   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12529        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12530     MapCounterButtons(i);
12531
12532   // draw selectbox gadgets
12533   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12534        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12535     MapSelectboxGadget(i);
12536
12537   // draw textbutton gadgets
12538   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12539        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12540     MapTextbuttonGadget(i);
12541
12542   // draw graphicbutton gadgets
12543   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12544        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12545     MapGraphicbuttonGadget(i);
12546
12547   // draw drawing area gadgets
12548   DrawPropertiesChangeDrawingAreas();
12549 }
12550
12551 static void DrawEditorElementAnimation(int x, int y)
12552 {
12553   int graphic;
12554   int frame;
12555
12556   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12557
12558   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12559 }
12560
12561 static void DrawEditorElementName(int x, int y, int font_nr)
12562 {
12563   char *element_name = getElementInfoText(properties_element);
12564   int font_width = getFontWidth(font_nr);
12565   int font_height = getFontHeight(font_nr);
12566   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12567   int max_chars_per_line = max_text_width / font_width;
12568
12569   if (strlen(element_name) <= max_chars_per_line)
12570     DrawTextS(x, y, font_nr, element_name);
12571   else
12572   {
12573     char buffer[max_chars_per_line + 1];
12574     int next_pos = max_chars_per_line;
12575
12576     strncpy(buffer, element_name, max_chars_per_line);
12577     buffer[max_chars_per_line] = '\0';
12578
12579     if (element_name[max_chars_per_line] == ' ')
12580       next_pos++;
12581     else
12582     {
12583       int i;
12584
12585       for (i = max_chars_per_line - 1; i >= 0; i--)
12586         if (buffer[i] == ' ')
12587           break;
12588
12589       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12590       {
12591         buffer[i] = '\0';
12592         next_pos = i + 1;
12593       }
12594     }
12595
12596     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12597
12598     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12599     buffer[max_chars_per_line] = '\0';
12600
12601     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12602   }
12603 }
12604
12605 static void DrawPropertiesWindow(void)
12606 {
12607   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12608   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12609   int border_size = gd->border_size;
12610   int font_nr = FONT_TEXT_1;
12611   int font_height = getFontHeight(font_nr);
12612   int xoffset = TILEX + element_border + 3 * border_size;
12613   int yoffset = (TILEY - font_height) / 2;
12614   int x1 = editor.settings.element_graphic.x + element_border;
12615   int y1 = editor.settings.element_graphic.y + element_border;
12616   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12617             editor.settings.element_name.x);
12618   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12619             editor.settings.element_name.y);
12620   char *text = "Element Settings";
12621   int font2_nr = FONT_TITLE_1;
12622   struct MenuPosInfo *pos = &editor.settings.headline;
12623   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12624   int sy = SY + pos->y;
12625
12626   stick_element_properties_window = FALSE;
12627
12628   // make sure that previous properties edit mode exists for this element
12629   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12630       !IS_CUSTOM_ELEMENT(properties_element))
12631     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12632
12633   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12634       !IS_PLAYER_ELEMENT(properties_element) &&
12635       !IS_CUSTOM_ELEMENT(properties_element))
12636     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12637
12638   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12639       (IS_PLAYER_ELEMENT(properties_element) ||
12640        IS_CUSTOM_ELEMENT(properties_element)))
12641     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12642
12643   CopyElementPropertiesToEditor(properties_element);
12644
12645   UnmapLevelEditorFieldGadgets();
12646   UnmapLevelEditorToolboxDrawingGadgets();
12647   UnmapLevelEditorToolboxCustomGadgets();
12648
12649   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12650
12651   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12652   ClearField();
12653
12654   DrawText(sx, sy, text, font2_nr);
12655
12656   FrameCounter = 0;     // restart animation frame counter
12657
12658   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12659   DrawEditorElementAnimation(SX + x1, SY + y1);
12660   DrawEditorElementName(x2, y2, font_nr);
12661
12662   DrawPropertiesTabulatorGadgets();
12663
12664   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12665     DrawPropertiesInfo();
12666   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12667     DrawPropertiesChange();
12668   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12669     DrawPropertiesConfig();
12670 }
12671
12672 static void DrawPaletteWindow(void)
12673 {
12674   int i;
12675
12676   UnmapLevelEditorFieldGadgets();
12677
12678   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12679   ClearField();
12680
12681   // map buttons to select elements
12682   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12683     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12684   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12685   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12686   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12687 }
12688
12689 static void UpdateCustomElementGraphicGadgets(void)
12690 {
12691   int i;
12692
12693   InitElementPropertiesGfxElement();
12694
12695   ModifyEditorElementList();
12696   RedrawDrawingElements();
12697
12698   // force redraw of all mapped drawing area gadgets
12699   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12700   {
12701     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12702
12703     if (gi->mapped)
12704       MapDrawingArea(i);
12705   }
12706 }
12707
12708 static int getOpenDirectionFromTube(int element)
12709 {
12710   switch (element)
12711   {
12712     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12713     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12714     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12715     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12716     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12717     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12718     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12719     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12720     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12721     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12722     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12723   }
12724
12725   return MV_NONE;
12726 }
12727
12728 static int getTubeFromOpenDirection(int direction)
12729 {
12730   switch (direction)
12731   {
12732     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12733     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12734     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12735     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12736     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12737     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12738     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12739     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12740     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12741     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12742     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12743
12744     // if only one direction, fall back to simple tube with that direction
12745     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12746     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12747     case (MV_UP):                       return EL_TUBE_VERTICAL;
12748     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12749   }
12750
12751   return EL_EMPTY;
12752 }
12753
12754 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12755 {
12756   int element_new = getTubeFromOpenDirection(direction);
12757
12758   return (element_new != EL_EMPTY ? element_new : element_old);
12759 }
12760
12761 static int getOpenDirectionFromBelt(int element)
12762 {
12763   int belt_dir = getBeltDirFromBeltElement(element);
12764
12765   return (belt_dir == MV_LEFT ? MV_RIGHT :
12766           belt_dir == MV_RIGHT ? MV_LEFT :
12767           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12768 }
12769
12770 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12771 {
12772   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12773                   direction == MV_RIGHT ? MV_LEFT :
12774                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12775
12776   if (direction == MV_NONE)
12777     return EL_EMPTY;
12778
12779   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12780 }
12781
12782 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12783                                                  int element_old)
12784 {
12785   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12786
12787   return (element_new != EL_EMPTY ? element_new : element_old);
12788 }
12789
12790 static int getOpenDirectionFromPool(int element)
12791 {
12792   switch (element)
12793   {
12794     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12795     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12796     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12797     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12798     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12799     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12800   }
12801
12802   return MV_NONE;
12803 }
12804
12805 static int getPoolFromOpenDirection(int direction)
12806 {
12807   switch (direction)
12808   {
12809     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12810     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12811     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12812     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12813     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12814     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12815   }
12816
12817   return EL_EMPTY;
12818 }
12819
12820 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12821 {
12822   int element = getPoolFromOpenDirection(direction);
12823   int help_direction = getOpenDirectionFromPool(help_element);
12824
12825   if (element == EL_EMPTY)
12826   {
12827     int help_direction_vertical = help_direction & MV_VERTICAL;
12828
12829     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12830   }
12831
12832   if (element == EL_EMPTY)
12833   {
12834     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12835
12836     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12837   }
12838
12839   return element;
12840 }
12841
12842 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12843 {
12844   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12845
12846   return (element_new != EL_EMPTY ? element_new : element_old);
12847 }
12848
12849 static int getOpenDirectionFromPillar(int element)
12850 {
12851   switch (element)
12852   {
12853     case EL_EMC_WALL_1:                 return (MV_DOWN);
12854     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12855     case EL_EMC_WALL_3:                 return (MV_UP);
12856   }
12857
12858   return MV_NONE;
12859 }
12860
12861 static int getPillarFromOpenDirection(int direction)
12862 {
12863   switch (direction)
12864   {
12865     case (MV_DOWN):                     return EL_EMC_WALL_1;
12866     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12867     case (MV_UP):                       return EL_EMC_WALL_3;
12868   }
12869
12870   return EL_EMPTY;
12871 }
12872
12873 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12874 {
12875   int element_new = getPillarFromOpenDirection(direction);
12876
12877   return (element_new != EL_EMPTY ? element_new : element_old);
12878 }
12879
12880 static int getOpenDirectionFromSteel2(int element)
12881 {
12882   switch (element)
12883   {
12884     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12885     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12886     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12887     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12888     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12889     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12890     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12891     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12892   }
12893
12894   return MV_NONE;
12895 }
12896
12897 static int getSteel2FromOpenDirection(int direction)
12898 {
12899   switch (direction)
12900   {
12901     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12902     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12903     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12904     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12905     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12906     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12907     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12908     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12909   }
12910
12911   return EL_EMPTY;
12912 }
12913
12914 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12915 {
12916   int element_new = getSteel2FromOpenDirection(direction);
12917
12918   return (element_new != EL_EMPTY ? element_new : element_old);
12919 }
12920
12921 static int getOpenDirectionFromChip(int element)
12922 {
12923   switch (element)
12924   {
12925     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12926     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12927     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12928     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12929     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12930   }
12931
12932   return MV_NONE;
12933 }
12934
12935 static int getChipFromOpenDirection(int direction)
12936 {
12937   switch (direction)
12938   {
12939     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12940     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12941     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12942     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12943     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12944   }
12945
12946   return EL_EMPTY;
12947 }
12948
12949 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12950 {
12951   int element_new = getChipFromOpenDirection(direction);
12952
12953   return (element_new != EL_EMPTY ? element_new : element_old);
12954 }
12955
12956 static int getClosedTube(int x, int y)
12957 {
12958   struct XY *xy = xy_directions;
12959   int element_old = IntelliDrawBuffer[x][y];
12960   int direction_old = getOpenDirectionFromTube(element_old);
12961   int direction_new = MV_NONE;
12962   int i;
12963
12964   for (i = 0; i < NUM_DIRECTIONS; i++)
12965   {
12966     int xx = x + xy[i].x;
12967     int yy = y + xy[i].y;
12968     int dir = MV_DIR_FROM_BIT(i);
12969     int dir_opposite = MV_DIR_OPPOSITE(dir);
12970
12971     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12972         (direction_old & dir) &&
12973         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12974       direction_new |= dir;
12975   }
12976
12977   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12978 }
12979
12980 static int getClosedBelt(int x, int y)
12981 {
12982   struct XY *xy = xy_directions;
12983   int element_old = IntelliDrawBuffer[x][y];
12984   int nr = getBeltNrFromBeltElement(element_old);
12985   int direction_old = getOpenDirectionFromBelt(element_old);
12986   int direction_new = MV_NONE;
12987   int i;
12988
12989   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12990   {
12991     int xx = x + xy[i].x;
12992     int yy = y + xy[i].y;
12993     int dir = MV_DIR_FROM_BIT(i);
12994     int dir_opposite = MV_DIR_OPPOSITE(dir);
12995
12996     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12997         (direction_old & dir) &&
12998         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12999       direction_new |= dir;
13000   }
13001
13002   return getBeltFromNrAndOpenDirection(nr, direction_new);
13003 }
13004
13005 static int getClosedPool(int x, int y)
13006 {
13007   struct XY *xy = xy_directions;
13008   int element_old = IntelliDrawBuffer[x][y];
13009   int direction_old = getOpenDirectionFromPool(element_old);
13010   int direction_new = MV_NONE;
13011   int i;
13012
13013   for (i = 0; i < NUM_DIRECTIONS; i++)
13014   {
13015     int xx = x + xy[i].x;
13016     int yy = y + xy[i].y;
13017     int dir = MV_DIR_FROM_BIT(i);
13018     int dir_opposite = MV_DIR_OPPOSITE(dir);
13019
13020     if (IN_LEV_FIELD(xx, yy) &&
13021         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
13022         (direction_old & dir) &&
13023         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13024       direction_new |= dir;
13025   }
13026
13027   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
13028 }
13029
13030 static int getClosedPillar(int x, int y)
13031 {
13032   struct XY *xy = xy_directions;
13033   int element_old = IntelliDrawBuffer[x][y];
13034   int direction_old = getOpenDirectionFromPillar(element_old);
13035   int direction_new = MV_NONE;
13036   int i;
13037
13038   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13039   {
13040     int xx = x + xy[i].x;
13041     int yy = y + xy[i].y;
13042     int dir = MV_DIR_FROM_BIT(i);
13043     int dir_opposite = MV_DIR_OPPOSITE(dir);
13044
13045     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
13046         (direction_old & dir) &&
13047         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13048       direction_new |= dir;
13049   }
13050
13051   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
13052 }
13053
13054 static int getClosedSteel2(int x, int y)
13055 {
13056   struct XY *xy = xy_directions;
13057   int element_old = IntelliDrawBuffer[x][y];
13058   int direction_old = getOpenDirectionFromSteel2(element_old);
13059   int direction_new = MV_NONE;
13060   int i;
13061
13062   for (i = 0; i < NUM_DIRECTIONS; i++)
13063   {
13064     int xx = x + xy[i].x;
13065     int yy = y + xy[i].y;
13066     int dir = MV_DIR_FROM_BIT(i);
13067     int dir_opposite = MV_DIR_OPPOSITE(dir);
13068
13069     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
13070         (direction_old & dir) &&
13071         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13072       direction_new |= dir;
13073   }
13074
13075   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
13076 }
13077
13078 static int getClosedChip(int x, int y)
13079 {
13080   struct XY *xy = xy_directions;
13081   int element_old = IntelliDrawBuffer[x][y];
13082   int direction_old = getOpenDirectionFromChip(element_old);
13083   int direction_new = MV_NONE;
13084   int i;
13085
13086   for (i = 0; i < NUM_DIRECTIONS; i++)
13087   {
13088     int xx = x + xy[i].x;
13089     int yy = y + xy[i].y;
13090     int dir = MV_DIR_FROM_BIT(i);
13091     int dir_opposite = MV_DIR_OPPOSITE(dir);
13092
13093     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
13094         (direction_old & dir) &&
13095         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13096       direction_new |= dir;
13097   }
13098
13099   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
13100 }
13101
13102 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
13103                                 boolean change_level)
13104 {
13105   int sx = x - level_xpos;
13106   int sy = y - level_ypos;
13107   int old_element = Tile[x][y];
13108   int new_element = element;
13109   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
13110   boolean draw_masked = FALSE;
13111
13112   if (IS_MM_WALL_EDITOR(element))
13113   {
13114     element = map_mm_wall_element_editor(element) | new_bitmask;
13115
13116     if (IS_MM_WALL(old_element))
13117       element |= MM_WALL_BITS(old_element);
13118
13119     if (!change_level)
13120       draw_masked = TRUE;
13121   }
13122   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
13123   {
13124     int element_changed = old_element & ~new_bitmask;
13125
13126     if (MM_WALL_BITS(element_changed) != 0)
13127       element = element_changed;
13128   }
13129
13130   IntelliDrawBuffer[x][y] = element;
13131
13132   if (change_level)
13133     Tile[x][y] = element;
13134
13135   if (IN_ED_FIELD(sx, sy))
13136   {
13137     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
13138       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
13139     else if (draw_masked)
13140       DrawEditorElementThruMask(sx, sy, element);
13141     else
13142       DrawEditorElement(sx, sy, element);
13143   }
13144 }
13145
13146 static void SetElementSimple(int x, int y, int element, boolean change_level)
13147 {
13148   SetElementSimpleExt(x, y, 0, 0, element, change_level);
13149 }
13150
13151 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
13152                                            int x2, int y2, int *element2,
13153                                            int (*close_function)(int, int),
13154                                            boolean change_level)
13155 {
13156   // set neighbour elements to newly determined connections
13157   SetElementSimple(x1, y1, *element1, change_level);
13158   SetElementSimple(x2, y2, *element2, change_level);
13159
13160   // remove all open connections of neighbour elements
13161   *element1 = close_function(x1, y1);
13162   *element2 = close_function(x2, y2);
13163
13164   // set neighbour elements to new, minimized connections
13165   SetElementSimple(x1, y1, *element1, change_level);
13166   SetElementSimple(x2, y2, *element2, change_level);
13167 }
13168
13169 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
13170                                   boolean change_level, int button)
13171 {
13172   struct XY *xy = xy_directions;
13173   static int last_x = -1;
13174   static int last_y = -1;
13175
13176   if (new_element == EL_UNDEFINED)
13177   {
13178     last_x = -1;
13179     last_y = -1;
13180
13181     return;
13182   }
13183
13184   int old_element = IntelliDrawBuffer[x][y];
13185
13186   if (IS_TUBE(new_element))
13187   {
13188     int last_element_new = EL_UNDEFINED;
13189     int direction = MV_NONE;
13190     int i;
13191
13192     // if old element is of same kind, keep all existing directions
13193     if (IS_TUBE(old_element))
13194       direction |= getOpenDirectionFromTube(old_element);
13195
13196     for (i = 0; i < NUM_DIRECTIONS; i++)
13197     {
13198       int xx = x + xy[i].x;
13199       int yy = y + xy[i].y;
13200
13201       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13202           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13203       {
13204         int dir = MV_DIR_FROM_BIT(i);
13205         int dir_opposite = MV_DIR_OPPOSITE(dir);
13206         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13207         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13208         int last_direction_new = last_direction_old | dir_opposite;
13209
13210         last_element_new = getTubeFromOpenDirection(last_direction_new);
13211
13212         direction |= dir;
13213       }
13214     }
13215
13216     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13217
13218     if (last_element_new != EL_UNDEFINED)
13219       MergeAndCloseNeighbourElements(x, y, &new_element,
13220                                      last_x, last_y, &last_element_new,
13221                                      getClosedTube, change_level);
13222   }
13223   else if (IS_BELT(new_element))
13224   {
13225     int belt_nr = getBeltNrFromBeltElement(new_element);
13226     int last_element_new = EL_UNDEFINED;
13227     int direction = MV_NONE;
13228     int i;
13229
13230     // if old element is of same kind, keep all existing directions
13231     if (IS_BELT(old_element))
13232       direction |= getOpenDirectionFromBelt(old_element);
13233
13234     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13235     {
13236       int xx = x + xy[i].x;
13237       int yy = y + xy[i].y;
13238
13239       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13240           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
13241       {
13242         int dir = MV_DIR_FROM_BIT(i);
13243         int dir_opposite = MV_DIR_OPPOSITE(dir);
13244         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13245         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
13246         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13247         int last_direction_new = last_direction_old | dir_opposite;
13248
13249         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13250                                                          last_direction_new);
13251         direction |= dir;
13252       }
13253     }
13254
13255     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13256                                                         new_element);
13257     if (last_element_new != EL_UNDEFINED)
13258       MergeAndCloseNeighbourElements(x, y, &new_element,
13259                                      last_x, last_y, &last_element_new,
13260                                      getClosedBelt, change_level);
13261   }
13262   else if (IS_ACID_POOL_OR_ACID(new_element))
13263   {
13264     int last_element_new = EL_UNDEFINED;
13265     int direction = MV_NONE;
13266     int i;
13267
13268     // if old element is of same kind, keep all existing directions
13269     if (IS_ACID_POOL_OR_ACID(old_element))
13270       direction |= getOpenDirectionFromPool(old_element);
13271
13272     for (i = 0; i < NUM_DIRECTIONS; i++)
13273     {
13274       int xx = x + xy[i].x;
13275       int yy = y + xy[i].y;
13276
13277       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13278           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
13279       {
13280         int dir = MV_DIR_FROM_BIT(i);
13281         int dir_opposite = MV_DIR_OPPOSITE(dir);
13282         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13283         int last_direction_old = getOpenDirectionFromPool(last_element_old);
13284         int last_direction_new = last_direction_old | dir_opposite;
13285
13286         last_element_new = getPoolFromOpenDirection(last_direction_new);
13287
13288         direction |= dir;
13289       }
13290     }
13291
13292     // special corrections needed for intuitively correct acid pool drawing
13293     if (last_element_new == EL_EMPTY)
13294       last_element_new = new_element;
13295     else if (last_element_new != EL_UNDEFINED)
13296       new_element = last_element_new;
13297
13298     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13299
13300     if (last_element_new != EL_UNDEFINED)
13301       MergeAndCloseNeighbourElements(x, y, &new_element,
13302                                      last_x, last_y, &last_element_new,
13303                                      getClosedPool, change_level);
13304   }
13305   else if (IS_EMC_PILLAR(new_element))
13306   {
13307     int last_element_new = EL_UNDEFINED;
13308     int direction = MV_NONE;
13309     int i;
13310
13311     // if old element is of same kind, keep all existing directions
13312     if (IS_EMC_PILLAR(old_element))
13313       direction |= getOpenDirectionFromPillar(old_element);
13314
13315     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13316     {
13317       int xx = x + xy[i].x;
13318       int yy = y + xy[i].y;
13319
13320       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13321           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13322       {
13323         int dir = MV_DIR_FROM_BIT(i);
13324         int dir_opposite = MV_DIR_OPPOSITE(dir);
13325         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13326         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13327         int last_direction_new = last_direction_old | dir_opposite;
13328
13329         last_element_new = getPillarFromOpenDirection(last_direction_new);
13330
13331         direction |= dir;
13332       }
13333     }
13334
13335     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13336
13337     if (last_element_new != EL_UNDEFINED)
13338       MergeAndCloseNeighbourElements(x, y, &new_element,
13339                                      last_x, last_y, &last_element_new,
13340                                      getClosedPillar, change_level);
13341   }
13342   else if (IS_DC_STEELWALL_2(new_element))
13343   {
13344     int last_element_new = EL_UNDEFINED;
13345     int direction = MV_NONE;
13346     int i;
13347
13348     // if old element is of same kind, keep all existing directions
13349     if (IS_DC_STEELWALL_2(old_element))
13350       direction |= getOpenDirectionFromSteel2(old_element);
13351
13352     for (i = 0; i < NUM_DIRECTIONS; i++)
13353     {
13354       int xx = x + xy[i].x;
13355       int yy = y + xy[i].y;
13356
13357       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13358           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13359       {
13360         int dir = MV_DIR_FROM_BIT(i);
13361         int dir_opposite = MV_DIR_OPPOSITE(dir);
13362         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13363         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13364         int last_direction_new = last_direction_old | dir_opposite;
13365
13366         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13367
13368         direction |= dir;
13369       }
13370     }
13371
13372     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13373
13374     if (last_element_new != EL_UNDEFINED)
13375       MergeAndCloseNeighbourElements(x, y, &new_element,
13376                                      last_x, last_y, &last_element_new,
13377                                      getClosedSteel2, change_level);
13378   }
13379   else if (IS_SP_CHIP(new_element))
13380   {
13381     int last_element_new = EL_UNDEFINED;
13382     int direction = MV_NONE;
13383     int i;
13384
13385     // (do not keep existing directions, regardless of kind of old element)
13386
13387     for (i = 0; i < NUM_DIRECTIONS; i++)
13388     {
13389       int xx = x + xy[i].x;
13390       int yy = y + xy[i].y;
13391
13392       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13393           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13394       {
13395         int dir = MV_DIR_FROM_BIT(i);
13396         int dir_opposite = MV_DIR_OPPOSITE(dir);
13397         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13398         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13399         int last_direction_new = last_direction_old | dir_opposite;
13400
13401         if (last_direction_old == MV_NONE)
13402         {
13403           last_element_new = getChipFromOpenDirection(last_direction_new);
13404           direction |= dir;
13405         }
13406         else if (last_direction_old & (dir | dir_opposite))
13407         {
13408           direction |= MV_DIR_OPPOSITE(last_direction_old);
13409         }
13410         else
13411         {
13412           direction |= MV_DIR_OPPOSITE(dir);
13413         }
13414       }
13415     }
13416
13417     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13418
13419     if (last_element_new != EL_UNDEFINED)
13420       MergeAndCloseNeighbourElements(x, y, &new_element,
13421                                      last_x, last_y, &last_element_new,
13422                                      getClosedChip, change_level);
13423   }
13424   else if (IS_SP_HARDWARE_BASE(new_element))
13425   {
13426     int nr = GetSimpleRandom(6);
13427
13428     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13429                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13430                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13431                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13432                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13433   }
13434   else if (new_element == EL_SP_HARDWARE_GREEN ||
13435            new_element == EL_SP_HARDWARE_BLUE ||
13436            new_element == EL_SP_HARDWARE_RED)
13437   {
13438     int nr = GetSimpleRandom(3);
13439
13440     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13441                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13442   }
13443   else if (IS_GROUP_ELEMENT(new_element))
13444   {
13445     boolean connected_drawing = FALSE;
13446     int i;
13447
13448     for (i = 0; i < NUM_DIRECTIONS; i++)
13449     {
13450       int xx = x + xy[i].x;
13451       int yy = y + xy[i].y;
13452
13453       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13454           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13455         connected_drawing = TRUE;
13456     }
13457
13458     if (!connected_drawing)
13459       ResolveGroupElement(new_element);
13460
13461     new_element = GetElementFromGroupElement(new_element);
13462   }
13463   else if (IS_BELT_SWITCH(old_element))
13464   {
13465     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13466     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13467
13468     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13469                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13470
13471     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13472   }
13473   else
13474   {
13475     static int swappable_elements[][2] =
13476     {
13477       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13478       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13479       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13480       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13481       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13482       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13483       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13484       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13485       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13486       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13487       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13488       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13489       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13490       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13491       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13492       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13493       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13494       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13495       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13496       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13497       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13498       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13499       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13500       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13501       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13502       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13503       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13504       { EL_PEARL,                       EL_WALL_PEARL                   },
13505       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13506       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13507       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13508       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13509       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13510       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13511       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13512       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13513       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13514       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13515       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13516       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13517       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13518       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13519       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13520       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13521
13522       { -1,                             -1                              },
13523     };
13524     static int rotatable_elements_4[][4] =
13525     {
13526       {
13527         EL_BUG_UP,
13528         EL_BUG_RIGHT,
13529         EL_BUG_DOWN,
13530         EL_BUG_LEFT
13531       },
13532       {
13533         EL_SPACESHIP_UP,
13534         EL_SPACESHIP_RIGHT,
13535         EL_SPACESHIP_DOWN,
13536         EL_SPACESHIP_LEFT
13537       },
13538       {
13539         EL_BD_BUTTERFLY_UP,
13540         EL_BD_BUTTERFLY_RIGHT,
13541         EL_BD_BUTTERFLY_DOWN,
13542         EL_BD_BUTTERFLY_LEFT
13543       },
13544       {
13545         EL_BD_FIREFLY_UP,
13546         EL_BD_FIREFLY_RIGHT,
13547         EL_BD_FIREFLY_DOWN,
13548         EL_BD_FIREFLY_LEFT
13549       },
13550       {
13551         EL_PACMAN_UP,
13552         EL_PACMAN_RIGHT,
13553         EL_PACMAN_DOWN,
13554         EL_PACMAN_LEFT
13555       },
13556       {
13557         EL_YAMYAM_UP,
13558         EL_YAMYAM_RIGHT,
13559         EL_YAMYAM_DOWN,
13560         EL_YAMYAM_LEFT
13561       },
13562       {
13563         EL_ARROW_UP,
13564         EL_ARROW_RIGHT,
13565         EL_ARROW_DOWN,
13566         EL_ARROW_LEFT
13567       },
13568       {
13569         EL_SP_PORT_UP,
13570         EL_SP_PORT_RIGHT,
13571         EL_SP_PORT_DOWN,
13572         EL_SP_PORT_LEFT
13573       },
13574       {
13575         EL_SP_GRAVITY_PORT_UP,
13576         EL_SP_GRAVITY_PORT_RIGHT,
13577         EL_SP_GRAVITY_PORT_DOWN,
13578         EL_SP_GRAVITY_PORT_LEFT
13579       },
13580       {
13581         EL_SP_GRAVITY_ON_PORT_UP,
13582         EL_SP_GRAVITY_ON_PORT_RIGHT,
13583         EL_SP_GRAVITY_ON_PORT_DOWN,
13584         EL_SP_GRAVITY_ON_PORT_LEFT
13585       },
13586       {
13587         EL_SP_GRAVITY_OFF_PORT_UP,
13588         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13589         EL_SP_GRAVITY_OFF_PORT_DOWN,
13590         EL_SP_GRAVITY_OFF_PORT_LEFT
13591       },
13592       {
13593         EL_MOLE_UP,
13594         EL_MOLE_RIGHT,
13595         EL_MOLE_DOWN,
13596         EL_MOLE_LEFT
13597       },
13598       {
13599         EL_BALLOON_SWITCH_UP,
13600         EL_BALLOON_SWITCH_RIGHT,
13601         EL_BALLOON_SWITCH_DOWN,
13602         EL_BALLOON_SWITCH_LEFT
13603       },
13604       {
13605         EL_MM_MCDUFFIN_UP,
13606         EL_MM_MCDUFFIN_RIGHT,
13607         EL_MM_MCDUFFIN_DOWN,
13608         EL_MM_MCDUFFIN_LEFT
13609       },
13610       {
13611         EL_MM_MIRROR_FIXED_1,
13612         EL_MM_MIRROR_FIXED_4,
13613         EL_MM_MIRROR_FIXED_3,
13614         EL_MM_MIRROR_FIXED_2
13615       },
13616       {
13617         EL_MM_STEEL_GRID_FIXED_1,
13618         EL_MM_STEEL_GRID_FIXED_4,
13619         EL_MM_STEEL_GRID_FIXED_2,
13620         EL_MM_STEEL_GRID_FIXED_3
13621       },
13622       {
13623         EL_MM_WOODEN_GRID_FIXED_1,
13624         EL_MM_WOODEN_GRID_FIXED_4,
13625         EL_MM_WOODEN_GRID_FIXED_2,
13626         EL_MM_WOODEN_GRID_FIXED_3
13627       },
13628       {
13629         EL_MM_POLARIZER_CROSS_1,
13630         EL_MM_POLARIZER_CROSS_4,
13631         EL_MM_POLARIZER_CROSS_3,
13632         EL_MM_POLARIZER_CROSS_2
13633       },
13634       {
13635         EL_MM_PACMAN_UP,
13636         EL_MM_PACMAN_RIGHT,
13637         EL_MM_PACMAN_DOWN,
13638         EL_MM_PACMAN_LEFT
13639       },
13640       {
13641         EL_DF_LASER_UP,
13642         EL_DF_LASER_RIGHT,
13643         EL_DF_LASER_DOWN,
13644         EL_DF_LASER_LEFT
13645       },
13646       {
13647         EL_DF_RECEIVER_UP,
13648         EL_DF_RECEIVER_RIGHT,
13649         EL_DF_RECEIVER_DOWN,
13650         EL_DF_RECEIVER_LEFT
13651       },
13652       {
13653         EL_DF_SLOPE_1,
13654         EL_DF_SLOPE_4,
13655         EL_DF_SLOPE_3,
13656         EL_DF_SLOPE_2
13657       },
13658
13659       {
13660         -1,
13661       },
13662     };
13663     static int rotatable_elements_8[][8] =
13664     {
13665       {
13666         EL_DF_STEEL_GRID_FIXED_1,
13667         EL_DF_STEEL_GRID_FIXED_8,
13668         EL_DF_STEEL_GRID_FIXED_7,
13669         EL_DF_STEEL_GRID_FIXED_6,
13670         EL_DF_STEEL_GRID_FIXED_5,
13671         EL_DF_STEEL_GRID_FIXED_4,
13672         EL_DF_STEEL_GRID_FIXED_3,
13673         EL_DF_STEEL_GRID_FIXED_2
13674       },
13675       {
13676         EL_DF_WOODEN_GRID_FIXED_1,
13677         EL_DF_WOODEN_GRID_FIXED_8,
13678         EL_DF_WOODEN_GRID_FIXED_7,
13679         EL_DF_WOODEN_GRID_FIXED_6,
13680         EL_DF_WOODEN_GRID_FIXED_5,
13681         EL_DF_WOODEN_GRID_FIXED_4,
13682         EL_DF_WOODEN_GRID_FIXED_3,
13683         EL_DF_WOODEN_GRID_FIXED_2
13684       },
13685       {
13686         EL_DF_STEEL_GRID_ROTATING_1,
13687         EL_DF_STEEL_GRID_ROTATING_8,
13688         EL_DF_STEEL_GRID_ROTATING_7,
13689         EL_DF_STEEL_GRID_ROTATING_6,
13690         EL_DF_STEEL_GRID_ROTATING_5,
13691         EL_DF_STEEL_GRID_ROTATING_4,
13692         EL_DF_STEEL_GRID_ROTATING_3,
13693         EL_DF_STEEL_GRID_ROTATING_2
13694       },
13695       {
13696         EL_DF_WOODEN_GRID_ROTATING_1,
13697         EL_DF_WOODEN_GRID_ROTATING_8,
13698         EL_DF_WOODEN_GRID_ROTATING_7,
13699         EL_DF_WOODEN_GRID_ROTATING_6,
13700         EL_DF_WOODEN_GRID_ROTATING_5,
13701         EL_DF_WOODEN_GRID_ROTATING_4,
13702         EL_DF_WOODEN_GRID_ROTATING_3,
13703         EL_DF_WOODEN_GRID_ROTATING_2
13704       },
13705
13706       {
13707         -1,
13708       },
13709     };
13710     static int rotatable_elements_16[][16] =
13711     {
13712       {
13713         EL_MM_MIRROR_1,
13714         EL_MM_MIRROR_16,
13715         EL_MM_MIRROR_15,
13716         EL_MM_MIRROR_14,
13717         EL_MM_MIRROR_13,
13718         EL_MM_MIRROR_12,
13719         EL_MM_MIRROR_11,
13720         EL_MM_MIRROR_10,
13721         EL_MM_MIRROR_9,
13722         EL_MM_MIRROR_8,
13723         EL_MM_MIRROR_7,
13724         EL_MM_MIRROR_6,
13725         EL_MM_MIRROR_5,
13726         EL_MM_MIRROR_4,
13727         EL_MM_MIRROR_3,
13728         EL_MM_MIRROR_2
13729       },
13730       {
13731         EL_MM_TELEPORTER_5,
13732         EL_MM_TELEPORTER_4,
13733         EL_MM_TELEPORTER_3,
13734         EL_MM_TELEPORTER_2,
13735         EL_MM_TELEPORTER_1,
13736         EL_MM_TELEPORTER_16,
13737         EL_MM_TELEPORTER_15,
13738         EL_MM_TELEPORTER_14,
13739         EL_MM_TELEPORTER_13,
13740         EL_MM_TELEPORTER_12,
13741         EL_MM_TELEPORTER_11,
13742         EL_MM_TELEPORTER_10,
13743         EL_MM_TELEPORTER_9,
13744         EL_MM_TELEPORTER_8,
13745         EL_MM_TELEPORTER_7,
13746         EL_MM_TELEPORTER_6
13747       },
13748       {
13749         EL_MM_TELEPORTER_RED_5,
13750         EL_MM_TELEPORTER_RED_4,
13751         EL_MM_TELEPORTER_RED_3,
13752         EL_MM_TELEPORTER_RED_2,
13753         EL_MM_TELEPORTER_RED_1,
13754         EL_MM_TELEPORTER_RED_16,
13755         EL_MM_TELEPORTER_RED_15,
13756         EL_MM_TELEPORTER_RED_14,
13757         EL_MM_TELEPORTER_RED_13,
13758         EL_MM_TELEPORTER_RED_12,
13759         EL_MM_TELEPORTER_RED_11,
13760         EL_MM_TELEPORTER_RED_10,
13761         EL_MM_TELEPORTER_RED_9,
13762         EL_MM_TELEPORTER_RED_8,
13763         EL_MM_TELEPORTER_RED_7,
13764         EL_MM_TELEPORTER_RED_6
13765       },
13766       {
13767         EL_MM_TELEPORTER_YELLOW_5,
13768         EL_MM_TELEPORTER_YELLOW_4,
13769         EL_MM_TELEPORTER_YELLOW_3,
13770         EL_MM_TELEPORTER_YELLOW_2,
13771         EL_MM_TELEPORTER_YELLOW_1,
13772         EL_MM_TELEPORTER_YELLOW_16,
13773         EL_MM_TELEPORTER_YELLOW_15,
13774         EL_MM_TELEPORTER_YELLOW_14,
13775         EL_MM_TELEPORTER_YELLOW_13,
13776         EL_MM_TELEPORTER_YELLOW_12,
13777         EL_MM_TELEPORTER_YELLOW_11,
13778         EL_MM_TELEPORTER_YELLOW_10,
13779         EL_MM_TELEPORTER_YELLOW_9,
13780         EL_MM_TELEPORTER_YELLOW_8,
13781         EL_MM_TELEPORTER_YELLOW_7,
13782         EL_MM_TELEPORTER_YELLOW_6
13783       },
13784       {
13785         EL_MM_TELEPORTER_GREEN_5,
13786         EL_MM_TELEPORTER_GREEN_4,
13787         EL_MM_TELEPORTER_GREEN_3,
13788         EL_MM_TELEPORTER_GREEN_2,
13789         EL_MM_TELEPORTER_GREEN_1,
13790         EL_MM_TELEPORTER_GREEN_16,
13791         EL_MM_TELEPORTER_GREEN_15,
13792         EL_MM_TELEPORTER_GREEN_14,
13793         EL_MM_TELEPORTER_GREEN_13,
13794         EL_MM_TELEPORTER_GREEN_12,
13795         EL_MM_TELEPORTER_GREEN_11,
13796         EL_MM_TELEPORTER_GREEN_10,
13797         EL_MM_TELEPORTER_GREEN_9,
13798         EL_MM_TELEPORTER_GREEN_8,
13799         EL_MM_TELEPORTER_GREEN_7,
13800         EL_MM_TELEPORTER_GREEN_6
13801       },
13802       {
13803         EL_MM_TELEPORTER_BLUE_5,
13804         EL_MM_TELEPORTER_BLUE_4,
13805         EL_MM_TELEPORTER_BLUE_3,
13806         EL_MM_TELEPORTER_BLUE_2,
13807         EL_MM_TELEPORTER_BLUE_1,
13808         EL_MM_TELEPORTER_BLUE_16,
13809         EL_MM_TELEPORTER_BLUE_15,
13810         EL_MM_TELEPORTER_BLUE_14,
13811         EL_MM_TELEPORTER_BLUE_13,
13812         EL_MM_TELEPORTER_BLUE_12,
13813         EL_MM_TELEPORTER_BLUE_11,
13814         EL_MM_TELEPORTER_BLUE_10,
13815         EL_MM_TELEPORTER_BLUE_9,
13816         EL_MM_TELEPORTER_BLUE_8,
13817         EL_MM_TELEPORTER_BLUE_7,
13818         EL_MM_TELEPORTER_BLUE_6
13819       },
13820       {
13821         EL_MM_POLARIZER_1,
13822         EL_MM_POLARIZER_16,
13823         EL_MM_POLARIZER_15,
13824         EL_MM_POLARIZER_14,
13825         EL_MM_POLARIZER_13,
13826         EL_MM_POLARIZER_12,
13827         EL_MM_POLARIZER_11,
13828         EL_MM_POLARIZER_10,
13829         EL_MM_POLARIZER_9,
13830         EL_MM_POLARIZER_8,
13831         EL_MM_POLARIZER_7,
13832         EL_MM_POLARIZER_6,
13833         EL_MM_POLARIZER_5,
13834         EL_MM_POLARIZER_4,
13835         EL_MM_POLARIZER_3,
13836         EL_MM_POLARIZER_2
13837       },
13838       {
13839         EL_DF_MIRROR_1,
13840         EL_DF_MIRROR_16,
13841         EL_DF_MIRROR_15,
13842         EL_DF_MIRROR_14,
13843         EL_DF_MIRROR_13,
13844         EL_DF_MIRROR_12,
13845         EL_DF_MIRROR_11,
13846         EL_DF_MIRROR_10,
13847         EL_DF_MIRROR_9,
13848         EL_DF_MIRROR_8,
13849         EL_DF_MIRROR_7,
13850         EL_DF_MIRROR_6,
13851         EL_DF_MIRROR_5,
13852         EL_DF_MIRROR_4,
13853         EL_DF_MIRROR_3,
13854         EL_DF_MIRROR_2
13855       },
13856       {
13857         EL_DF_MIRROR_ROTATING_1,
13858         EL_DF_MIRROR_ROTATING_16,
13859         EL_DF_MIRROR_ROTATING_15,
13860         EL_DF_MIRROR_ROTATING_14,
13861         EL_DF_MIRROR_ROTATING_13,
13862         EL_DF_MIRROR_ROTATING_12,
13863         EL_DF_MIRROR_ROTATING_11,
13864         EL_DF_MIRROR_ROTATING_10,
13865         EL_DF_MIRROR_ROTATING_9,
13866         EL_DF_MIRROR_ROTATING_8,
13867         EL_DF_MIRROR_ROTATING_7,
13868         EL_DF_MIRROR_ROTATING_6,
13869         EL_DF_MIRROR_ROTATING_5,
13870         EL_DF_MIRROR_ROTATING_4,
13871         EL_DF_MIRROR_ROTATING_3,
13872         EL_DF_MIRROR_ROTATING_2
13873       },
13874       {
13875         EL_DF_MIRROR_FIXED_1,
13876         EL_DF_MIRROR_FIXED_16,
13877         EL_DF_MIRROR_FIXED_15,
13878         EL_DF_MIRROR_FIXED_14,
13879         EL_DF_MIRROR_FIXED_13,
13880         EL_DF_MIRROR_FIXED_12,
13881         EL_DF_MIRROR_FIXED_11,
13882         EL_DF_MIRROR_FIXED_10,
13883         EL_DF_MIRROR_FIXED_9,
13884         EL_DF_MIRROR_FIXED_8,
13885         EL_DF_MIRROR_FIXED_7,
13886         EL_DF_MIRROR_FIXED_6,
13887         EL_DF_MIRROR_FIXED_5,
13888         EL_DF_MIRROR_FIXED_4,
13889         EL_DF_MIRROR_FIXED_3,
13890         EL_DF_MIRROR_FIXED_2
13891       },
13892
13893       {
13894         -1,
13895       },
13896     };
13897     int i, j;
13898
13899     for (i = 0; swappable_elements[i][0] != -1; i++)
13900     {
13901       int element1 = swappable_elements[i][0];
13902       int element2 = swappable_elements[i][1];
13903
13904       if (old_element == element1 || old_element == element2)
13905         new_element = (old_element == element1 ? element2 : element1);
13906     }
13907
13908     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13909     {
13910       for (j = 0; j < 4; j++)
13911       {
13912         int element = rotatable_elements_4[i][j];
13913
13914         if (old_element == element)
13915           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13916                          button == 2 ? rotatable_elements_4[i][0]           :
13917                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13918                          old_element);
13919       }
13920     }
13921
13922     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13923     {
13924       for (j = 0; j < 8; j++)
13925       {
13926         int element = rotatable_elements_8[i][j];
13927
13928         if (old_element == element)
13929           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13930                          button == 2 ? rotatable_elements_8[i][0]           :
13931                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13932                          old_element);
13933       }
13934     }
13935
13936     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13937     {
13938       for (j = 0; j < 16; j++)
13939       {
13940         int element = rotatable_elements_16[i][j];
13941
13942         if (old_element == element)
13943           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13944                          button == 2 ? rotatable_elements_16[i][0]             :
13945                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13946                          old_element);
13947       }
13948     }
13949
13950     if (old_element != new_element)
13951     {
13952       int max_infotext_len = getMaxInfoTextLength();
13953       char infotext[MAX_OUTPUT_LINESIZE + 1];
13954
13955       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13956       infotext[max_infotext_len] = '\0';
13957
13958       ClearEditorGadgetInfoText();
13959
13960       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13961                 infotext);
13962     }
13963   }
13964
13965   if (IS_MM_WALL_EDITOR(new_element))
13966     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13967   else
13968     SetElementSimple(x, y, new_element, change_level);
13969
13970   last_x = x;
13971   last_y = y;
13972 }
13973
13974 static void ResetIntelliDraw(void)
13975 {
13976   int x, y;
13977
13978   for (x = 0; x < lev_fieldx; x++)
13979     for (y = 0; y < lev_fieldy; y++)
13980       IntelliDrawBuffer[x][y] = Tile[x][y];
13981
13982   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13983 }
13984
13985 static boolean draw_mode_hires = FALSE;
13986
13987 static boolean isHiresTileElement(int element)
13988 {
13989   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13990 }
13991
13992 static boolean isHiresDrawElement(int element)
13993 {
13994   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13995 }
13996
13997 static int numHiresTiles(int element)
13998 {
13999   if (IS_MM_WALL(element))
14000     return get_number_of_bits(MM_WALL_BITS(element));
14001
14002   return 1;
14003 }
14004
14005 static void SetDrawModeHiRes(int element)
14006 {
14007   draw_mode_hires =
14008     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
14009      isHiresDrawElement(element));
14010 }
14011
14012 static boolean getDrawModeHiRes(void)
14013 {
14014   return draw_mode_hires;
14015 }
14016
14017 static int getLoResScreenPos(int pos)
14018 {
14019   return (getDrawModeHiRes() ? pos / 2 : pos);
14020 }
14021
14022 static int getLoResScreenMod(int pos)
14023 {
14024   return (getDrawModeHiRes() ? pos % 2 : 0);
14025 }
14026
14027 static void SetElementExt(int x, int y, int dx, int dy, int element,
14028                           boolean change_level, int button)
14029 {
14030   if (element < 0)
14031     SetElementSimple(x, y, Tile[x][y], change_level);
14032   else if (GetKeyModState() & KMOD_Shift)
14033     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
14034   else
14035     SetElementSimpleExt(x, y, dx, dy, element, change_level);
14036 }
14037
14038 static void SetElement(int x, int y, int element)
14039 {
14040   SetElementExt(x, y, 0, 0, element, TRUE, -1);
14041 }
14042
14043 static void SetElementButton(int x, int y, int dx, int dy, int element,
14044                              int button)
14045 {
14046   SetElementExt(x, y, dx, dy, element, TRUE, button);
14047 }
14048
14049 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
14050 {
14051   int lx = getLoResScreenPos(sx2) + level_xpos;
14052   int ly = getLoResScreenPos(sy2) + level_ypos;
14053   int dx = getLoResScreenMod(sx2);
14054   int dy = getLoResScreenMod(sy2);
14055
14056   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
14057 }
14058
14059 static void SetLevelElementHiRes(int lx2, int ly2, int element)
14060 {
14061   int lx = lx2 / 2;
14062   int ly = ly2 / 2;
14063   int dx = lx2 % 2;
14064   int dy = ly2 % 2;
14065
14066   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
14067 }
14068
14069 static int getLevelElementHiRes(int lx2, int ly2)
14070 {
14071   int lx = lx2 / 2;
14072   int ly = ly2 / 2;
14073   int dx = lx2 % 2;
14074   int dy = ly2 % 2;
14075   int element = Tile[lx][ly];
14076   unsigned int bitmask = (dx + 1) << (dy * 2);
14077
14078   if (IS_MM_WALL(element))
14079   {
14080     if (element & bitmask)
14081       return map_mm_wall_element(element);
14082     else
14083       return EL_EMPTY;
14084   }
14085
14086   return element;
14087 }
14088
14089 static void DrawLineElement(int x, int y, int element, boolean change_level)
14090 {
14091   SetElementHiRes(x, y, element, change_level);
14092 }
14093
14094 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
14095                      int element, boolean change_level)
14096 {
14097   int xsize = ABS(to_x - from_x);
14098   int ysize = ABS(to_y - from_y);
14099   int dx = (to_x < from_x ? -1 : +1);
14100   int dy = (to_y < from_y ? -1 : +1);
14101   int i;
14102
14103   if (from_y == to_y)                   // horizontal line
14104   {
14105     for (i = 0; i <= xsize; i++)
14106       DrawLineElement(from_x + i * dx, from_y, element, change_level);
14107   }
14108   else if (from_x == to_x)              // vertical line
14109   {
14110     for (i = 0; i <= ysize; i++)
14111       DrawLineElement(from_x, from_y + i * dy, element, change_level);
14112   }
14113   else                                  // diagonal line
14114   {
14115     if (ysize < xsize)                  // a < 1
14116     {
14117       float a = (float)ysize / (float)xsize;
14118
14119       for (i = 0; i <= xsize; i++)
14120       {
14121         int x = dx * i;
14122         int y = dy * (int)(a * i + 0.5);
14123
14124         DrawLineElement(from_x + x, from_y + y, element, change_level);
14125       }
14126     }
14127     else                                // a >= 1
14128     {
14129       float a = (float)xsize / (float)ysize;
14130
14131       for (i = 0; i <= ysize; i++)
14132       {
14133         int x = dx * (int)(a * i + 0.5);
14134         int y = dy * i;
14135
14136         DrawLineElement(from_x + x, from_y + y, element, change_level);
14137       }
14138     }
14139   }
14140 }
14141
14142 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
14143                     int element, boolean change_level)
14144 {
14145   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
14146   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
14147   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
14148   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
14149 }
14150
14151 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
14152                           int element, boolean change_level)
14153 {
14154   int y;
14155
14156   if (from_y > to_y)
14157     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
14158
14159   for (y = from_y; y <= to_y; y++)
14160     DrawLine(from_x, y, to_x, y, element, change_level);
14161 }
14162
14163 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
14164                        int element, boolean change_level)
14165 {
14166   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
14167   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
14168   int len_x = ABS(to_x - from_x);
14169   int len_y = ABS(to_y - from_y);
14170   int radius, x, y;
14171
14172   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
14173
14174   // not optimal (some points get drawn twice) but simple,
14175   // and fast enough for the few points we are drawing
14176
14177   for (x = 0; x <= radius; x++)
14178   {
14179     int sx, sy, sx2, sy2, lx, ly;
14180
14181     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
14182
14183     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14184     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14185     sx = getLoResScreenPos(sx2);
14186     sy = getLoResScreenPos(sy2);
14187     lx = sx + level_xpos;
14188     ly = sy + level_ypos;
14189
14190     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14191       DrawLineElement(sx2, sy2, element, change_level);
14192   }
14193
14194   for (y = 0; y <= radius; y++)
14195   {
14196     int sx, sy, sx2, sy2, lx, ly;
14197
14198     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14199
14200     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14201     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14202     sx = getLoResScreenPos(sx2);
14203     sy = getLoResScreenPos(sy2);
14204     lx = sx + level_xpos;
14205     ly = sy + level_ypos;
14206
14207     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14208       DrawLineElement(sx2, sy2, element, change_level);
14209   }
14210 }
14211
14212 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14213                     int element, boolean change_level)
14214 {
14215   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14216   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14217
14218   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14219 }
14220
14221 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14222
14223 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14224 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14225                        int element, boolean change_level)
14226 {
14227   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14228   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14229   int mirror_to_x2 = from_x - (to_x2 - from_x);
14230   int mirror_to_y2 = from_y - (to_y2 - from_y);
14231
14232   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14233   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14234   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14235   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14236 }
14237 #endif
14238
14239 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14240 {
14241   int from_sx, from_sy;
14242   int to_sx, to_sy;
14243
14244   if (from_x > to_x)
14245     swap_numbers(&from_x, &to_x);
14246
14247   if (from_y > to_y)
14248     swap_numbers(&from_y, &to_y);
14249
14250   from_sx = SX + from_x * ed_tilesize;
14251   from_sy = SY + from_y * ed_tilesize;
14252   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14253   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14254
14255   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14256   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14257   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14258   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14259
14260   if (from_x == to_x && from_y == to_y)
14261     MarkTileDirty(from_x/2, from_y/2);
14262   else
14263     redraw_mask |= REDRAW_FIELD;
14264 }
14265
14266 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14267                         int element, boolean change_level)
14268 {
14269   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14270 }
14271
14272 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14273                        int element, boolean change_level)
14274 {
14275   if (element == -1 || change_level)
14276     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14277   else
14278     DrawAreaBorder(from_x, from_y, to_x, to_y);
14279 }
14280
14281 // values for CopyBrushExt()
14282 #define CB_AREA_TO_BRUSH                0
14283 #define CB_BRUSH_TO_CURSOR              1
14284 #define CB_BRUSH_TO_LEVEL               2
14285 #define CB_DELETE_OLD_CURSOR            3
14286 #define CB_DUMP_BRUSH                   4
14287 #define CB_DUMP_BRUSH_SMALL             5
14288 #define CB_CLIPBOARD_TO_BRUSH           6
14289 #define CB_BRUSH_TO_CLIPBOARD           7
14290 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14291 #define CB_UPDATE_BRUSH_POSITION        9
14292 #define CB_FLIP_BRUSH_X                 10
14293 #define CB_FLIP_BRUSH_Y                 11
14294 #define CB_FLIP_BRUSH_XY                12
14295
14296 #define MAX_CB_PART_SIZE        10
14297 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14298 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14299 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14300                                  MAX_CB_NUM_LINES *     \
14301                                  MAX_CB_PART_SIZE)
14302
14303 static int getFlippedTileExt(int map[], int element)
14304 {
14305   int i;
14306
14307   for (i = 0; map[i] != -1; i++)
14308     if (map[i] == element)
14309       return map[i ^ 1];        // get flipped element by flipping LSB of index
14310
14311   return element;
14312 }
14313
14314 static int getFlippedTileX(int element)
14315 {
14316   int map[] =
14317   {
14318     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14319     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14320     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14321     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14322     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14323     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14324     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14325     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14326     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14327     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14328     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14329     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14330     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14331     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14332     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14333     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14334     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14335     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14336     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14337     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14338     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14339     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14340     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14341     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14342     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14343     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14344     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14345     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14346     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14347     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14348
14349     -1
14350   };
14351
14352   return getFlippedTileExt(map, element);
14353 }
14354
14355 static int getFlippedTileY(int element)
14356 {
14357   int map[] =
14358   {
14359     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14360     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14361     EL_BUG_UP,                          EL_BUG_DOWN,
14362     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14363     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14364     EL_ARROW_UP,                        EL_ARROW_DOWN,
14365     EL_MOLE_UP,                         EL_MOLE_DOWN,
14366     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14367     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14368     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14369     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14370     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14371     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14372     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14373     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14374     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14375     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14376     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14377     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14378     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14379     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14380     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14381     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14382     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14383
14384     -1
14385   };
14386
14387   return getFlippedTileExt(map, element);
14388 }
14389
14390 static int getFlippedTileXY(int element)
14391 {
14392   int map[] =
14393   {
14394     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14395     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14396     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14397     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14398     EL_BUG_LEFT,                        EL_BUG_UP,
14399     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14400     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14401     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14402     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14403     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14404     EL_ARROW_LEFT,                      EL_ARROW_UP,
14405     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14406     EL_MOLE_LEFT,                       EL_MOLE_UP,
14407     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14408     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14409     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14410     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14411     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14412     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14413     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14414     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14415     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14416     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14417     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14418     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14419     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14420     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14421     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14422     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14423     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14424     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14425     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14426     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14427     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14428     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14429     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14430     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14431     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14432     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14433     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14434     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14435     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14436
14437     -1
14438   };
14439
14440   return getFlippedTileExt(map, element);
14441 }
14442
14443 static int getFlippedTile(int element, int mode)
14444 {
14445   if (IS_MM_ELEMENT(element))
14446   {
14447     // get MM game element
14448     element = map_element_RND_to_MM(element);
14449
14450     // get flipped game element
14451     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14452                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14453                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14454                element);
14455
14456     // get RND game element again
14457     element = map_element_MM_to_RND(element);
14458   }
14459   else
14460   {
14461     // get flipped game element
14462     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14463                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14464                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14465                element);
14466   }
14467
14468   return element;
14469 }
14470
14471 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14472 {
14473   // flip tiles
14474   short tile1_flipped = getFlippedTile(*tile1, mode);
14475   short tile2_flipped = getFlippedTile(*tile2, mode);
14476
14477   // swap tiles
14478   *tile1 = tile2_flipped;
14479   *tile2 = tile1_flipped;
14480 }
14481
14482 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14483 {
14484   DrawLineElement(sx, sy, element, change_level);
14485 }
14486
14487 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14488                          int button, int mode)
14489 {
14490   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14491   static int brush_width, brush_height;
14492   static int last_cursor_x = -1, last_cursor_y = -1;
14493   static boolean delete_old_brush = FALSE;
14494   int new_element = BUTTON_ELEMENT(button);
14495   int x, y;
14496
14497   if (mode == CB_DUMP_BRUSH ||
14498       mode == CB_DUMP_BRUSH_SMALL ||
14499       mode == CB_BRUSH_TO_CLIPBOARD ||
14500       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14501   {
14502     if (edit_mode != ED_MODE_DRAWING)
14503       return;
14504
14505     char part[MAX_CB_PART_SIZE + 1] = "";
14506     char text[MAX_CB_TEXT_SIZE + 1] = "";
14507     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14508     int height = (draw_with_brush ? brush_height : lev_fieldy);
14509     char *format = "%s%03d";
14510
14511     for (y = 0; y < height; y++)
14512       for (x = 0; x < width; x++)
14513         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14514           format = "%s%04d";
14515
14516     for (y = 0; y < height; y++)
14517     {
14518       for (x = 0; x < width; x++)
14519       {
14520         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14521         char *prefix = (mode == CB_DUMP_BRUSH ||
14522                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14523
14524         if (element >= NUM_FILE_ELEMENTS)
14525           element = EL_UNKNOWN;
14526
14527         // copy brush to level sketch text buffer for the R'n'D forum:
14528         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14529         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14530         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14531         strcat(text, part);
14532       }
14533
14534       strcat(text, "\n");
14535     }
14536
14537     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14538         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14539       SDL_SetClipboardText(text);
14540     else
14541       Print("%s", text);        // print brush data to console and log file
14542
14543     return;
14544   }
14545
14546   if (mode == CB_CLIPBOARD_TO_BRUSH)
14547   {
14548     if (edit_mode != ED_MODE_DRAWING)
14549       return;
14550
14551     if (!SDL_HasClipboardText())
14552     {
14553       Request("Clipboard is empty!", REQ_CONFIRM);
14554
14555       return;
14556     }
14557
14558     boolean copy_to_brush = (draw_with_brush ||
14559                              drawing_function == GADGET_ID_GRAB_BRUSH);
14560
14561     // this will delete the old brush, if already drawing with a brush
14562     if (copy_to_brush)
14563       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14564
14565     // initialization is required for "odd" (incomplete) clipboard content
14566     for (x = 0; x < MAX_LEV_FIELDX; x++)
14567       for (y = 0; y < MAX_LEV_FIELDY; y++)
14568         brush_buffer[x][y] = EL_EMPTY;
14569
14570     brush_width  = 0;
14571     brush_height = 0;
14572     x = 0;
14573     y = 0;
14574
14575     char *clipboard_text = SDL_GetClipboardText();
14576     char *ptr = clipboard_text;
14577     boolean allow_new_row = FALSE;
14578     boolean stop = FALSE;
14579
14580     while (*ptr && !stop)
14581     {
14582       boolean prefix_found = FALSE;
14583       boolean start_new_row = FALSE;
14584
14585       // level sketch element number prefixes (may be multi-byte characters)
14586       char *prefix_list[] = { "`", "¸" };
14587       int i;
14588
14589       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14590       {
14591         char *prefix = prefix_list[i];
14592
14593         // check if string is large enough for prefix
14594         if (strlen(ptr) < strlen(prefix))
14595         {
14596           stop = TRUE;
14597
14598           break;
14599         }
14600
14601         // check if string starts with prefix
14602         if (strPrefix(ptr, prefix))
14603         {
14604           ptr += strlen(prefix);
14605
14606           prefix_found = TRUE;
14607
14608           break;
14609         }
14610       }
14611
14612       // check if prefix found and followed by (at least) three digits
14613       if (prefix_found &&
14614           strlen(ptr) >= 3 &&
14615           ptr[0] >= '0' && ptr[0] <= '9' &&
14616           ptr[1] >= '0' && ptr[1] <= '9' &&
14617           ptr[2] >= '0' && ptr[2] <= '9')
14618       {
14619         int element = ((ptr[0] - '0') * 100 +
14620                        (ptr[1] - '0') * 10 +
14621                        (ptr[2] - '0'));
14622
14623         ptr += 3;
14624
14625         // level sketch element number might consist of four digits
14626         if (ptr[0] >= '0' && ptr[0] <= '9')
14627         {
14628           element = element * 10 + (ptr[0] - '0');
14629           ptr++;
14630         }
14631
14632         // remap some (historic, now obsolete) elements
14633         element = getMappedElement(element);
14634
14635         if (element >= NUM_FILE_ELEMENTS)
14636           element = EL_UNKNOWN;
14637
14638         brush_buffer[x][y] = element;
14639
14640         brush_width  = MAX(x + 1, brush_width);
14641         brush_height = MAX(y + 1, brush_height);
14642
14643         x++;
14644
14645         if (x >= MAX_LEV_FIELDX)
14646           start_new_row = TRUE;
14647
14648         allow_new_row = TRUE;
14649       }
14650       else
14651       {
14652         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14653           start_new_row = TRUE;
14654
14655         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14656       }
14657
14658       if (start_new_row)
14659       {
14660         x = 0;
14661         y++;
14662
14663         if (y >= MAX_LEV_FIELDY)
14664           stop = TRUE;
14665
14666         allow_new_row = FALSE;
14667       }
14668     }
14669
14670     SDL_free(clipboard_text);
14671
14672     if (brush_width == 0 || brush_height == 0)
14673     {
14674       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14675
14676       return;
14677     }
14678
14679     if (copy_to_brush)
14680     {
14681       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14682       int mx, my;
14683
14684       SDL_GetMouseState(&mx, &my);
14685
14686       // if inside drawing area, activate and draw brush at last mouse position
14687       if (mx >= gi->x && mx < gi->x + gi->width &&
14688           my >= gi->y && my < gi->y + gi->height)
14689         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14690
14691       draw_with_brush = TRUE;
14692     }
14693     else
14694     {
14695       char request[100];
14696
14697       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14698               brush_width, brush_height);
14699
14700       if (!Request(request, REQ_ASK))
14701         return;
14702
14703       for (x = 0; x < MAX_LEV_FIELDX; x++)
14704         for (y = 0; y < MAX_LEV_FIELDY; y++)
14705           Tile[x][y] = brush_buffer[x][y];
14706
14707       lev_fieldx = level.fieldx = brush_width;
14708       lev_fieldy = level.fieldy = brush_height;
14709
14710       boolean use_bd_engine = TRUE;
14711       boolean use_em_engine = TRUE;
14712       boolean use_sp_engine = TRUE;
14713       boolean use_mm_engine = TRUE;
14714
14715       for (x = 0; x < MAX_LEV_FIELDX; x++)
14716       {
14717         for (y = 0; y < MAX_LEV_FIELDY; y++)
14718         {
14719           int element = Tile[x][y];
14720
14721           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14722             use_bd_engine = FALSE;
14723
14724           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14725             use_em_engine = FALSE;
14726
14727           if (!IS_SP_ELEMENT(element))
14728             use_sp_engine = FALSE;
14729
14730           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14731             use_mm_engine = FALSE;
14732         }
14733       }
14734
14735       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14736                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14737                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14738                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14739                                 GAME_ENGINE_TYPE_RND);
14740
14741       // update element selection list
14742       ReinitializeElementList();
14743       ModifyEditorElementList();
14744
14745       SetBorderElement();
14746
14747       DrawEditModeWindow();
14748       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14749     }
14750
14751     return;
14752   }
14753
14754   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14755     return;
14756
14757   if (mode == CB_AREA_TO_BRUSH)
14758   {
14759     int from_lx, from_ly;
14760
14761     if (from_x > to_x)
14762       swap_numbers(&from_x, &to_x);
14763
14764     if (from_y > to_y)
14765       swap_numbers(&from_y, &to_y);
14766
14767     brush_width = to_x - from_x + 1;
14768     brush_height = to_y - from_y + 1;
14769
14770     from_lx = from_x + level_xpos;
14771     from_ly = from_y + level_ypos;
14772
14773     for (y = 0; y < brush_height; y++)
14774     {
14775       for (x = 0; x < brush_width; x++)
14776       {
14777         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14778
14779         if (button != 1)
14780           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14781       }
14782     }
14783
14784     if (button != 1)
14785       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14786
14787     delete_old_brush = FALSE;
14788   }
14789   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14790            mode == CB_BRUSH_TO_LEVEL)
14791   {
14792     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14793     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14794     int cursor_from_x = cursor_x - brush_width / 2;
14795     int cursor_from_y = cursor_y - brush_height / 2;
14796     int border_from_x = cursor_x, border_from_y = cursor_y;
14797     int border_to_x = cursor_x, border_to_y = cursor_y;
14798
14799     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14800       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14801
14802     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14803         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14804     {
14805       delete_old_brush = FALSE;
14806
14807       return;
14808     }
14809
14810     for (y = 0; y < brush_height; y++)
14811     {
14812       for (x = 0; x < brush_width; x++)
14813       {
14814         int sx = cursor_from_x + x;
14815         int sy = cursor_from_y + y;
14816         int lx = sx + level_xpos;
14817         int ly = sy + level_ypos;
14818         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14819         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14820                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14821                        brush_buffer[x][y] : new_element);
14822
14823         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14824         {
14825           if (sx < border_from_x)
14826             border_from_x = sx;
14827           else if (sx > border_to_x)
14828             border_to_x = sx;
14829           if (sy < border_from_y)
14830             border_from_y = sy;
14831           else if (sy > border_to_y)
14832             border_to_y = sy;
14833
14834           DrawBrushElement(sx, sy, element, change_level);
14835         }
14836       }
14837     }
14838
14839     if (mode != CB_DELETE_OLD_CURSOR)
14840       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14841
14842     last_cursor_x = cursor_x;
14843     last_cursor_y = cursor_y;
14844
14845     delete_old_brush = TRUE;
14846   }
14847   else if (mode == CB_FLIP_BRUSH_X)
14848   {
14849     for (y = 0; y < brush_height; y++)
14850       for (x = 0; x < (brush_width + 1) / 2; x++)
14851         SwapFlippedTiles(&brush_buffer[x][y],
14852                          &brush_buffer[brush_width - x - 1][y], mode);
14853
14854     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14855   }
14856   else if (mode == CB_FLIP_BRUSH_Y)
14857   {
14858     for (y = 0; y < (brush_height + 1) / 2; y++)
14859       for (x = 0; x < brush_width; x++)
14860         SwapFlippedTiles(&brush_buffer[x][y],
14861                          &brush_buffer[x][brush_height - y - 1], mode);
14862
14863     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14864   }
14865   else if (mode == CB_FLIP_BRUSH_XY)
14866   {
14867     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14868
14869     for (y = 0; y < MAX(brush_width, brush_height); y++)
14870       for (x = 0; x <= y; x++)
14871         SwapFlippedTiles(&brush_buffer[x][y],
14872                          &brush_buffer[y][x], mode);
14873
14874     swap_numbers(&brush_width, &brush_height);
14875
14876     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14877   }
14878
14879   if (mode == CB_UPDATE_BRUSH_POSITION)
14880   {
14881     last_cursor_x = from_x;
14882     last_cursor_y = from_y;
14883   }
14884 }
14885
14886 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14887                             int button)
14888 {
14889   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14890 }
14891
14892 static void CopyBrushToLevel(int x, int y, int button)
14893 {
14894   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14895 }
14896
14897 static void CopyBrushToCursor(int x, int y)
14898 {
14899   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14900 }
14901
14902 static void UpdateBrushPosition(int x, int y)
14903 {
14904   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14905 }
14906
14907 static void DeleteBrushFromCursor(void)
14908 {
14909   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14910 }
14911
14912 static void FlipBrushX(void)
14913 {
14914   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14915 }
14916
14917 static void FlipBrushY(void)
14918 {
14919   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14920 }
14921
14922 static void RotateBrush(void)
14923 {
14924   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14925   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14926 }
14927
14928 void DumpBrush(void)
14929 {
14930   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14931 }
14932
14933 void DumpBrush_Small(void)
14934 {
14935   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14936 }
14937
14938 void CopyClipboardToBrush(void)
14939 {
14940   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14941 }
14942
14943 void CopyBrushToClipboard(void)
14944 {
14945   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14946 }
14947
14948 void CopyBrushToClipboard_Small(void)
14949 {
14950   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14951 }
14952
14953 void UndoLevelEditorOperation(void)
14954 {
14955   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14956 }
14957
14958 void RedoLevelEditorOperation(void)
14959 {
14960   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14961 }
14962
14963 static void FloodFill(int from_x, int from_y, int fill_element)
14964 {
14965   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14966 }
14967
14968 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14969 {
14970   int from_x = from_sx2 + 2 * level_xpos;
14971   int from_y = from_sy2 + 2 * level_ypos;
14972   int max_fillx = lev_fieldx * 2;
14973   int max_filly = lev_fieldy * 2;
14974   short Fill[max_fillx][max_filly];
14975   int x, y;
14976
14977   for (x = 0; x < max_fillx; x++)
14978     for (y = 0; y < max_filly; y++)
14979       Fill[x][y] = getLevelElementHiRes(x, y);
14980
14981   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14982                     Fill, max_fillx, max_filly);
14983
14984   for (x = 0; x < max_fillx; x++)
14985     for (y = 0; y < max_filly; y++)
14986       if (Fill[x][y] == fill_element)
14987         SetLevelElementHiRes(x, y, Fill[x][y]);
14988 }
14989
14990 // values for DrawLevelText() modes
14991 #define TEXT_INIT               0
14992 #define TEXT_SETCURSOR          1
14993 #define TEXT_WRITECHAR          2
14994 #define TEXT_BACKSPACE          3
14995 #define TEXT_NEWLINE            4
14996 #define TEXT_END                5
14997 #define TEXT_QUERY_TYPING       6
14998
14999 static int DrawLevelText(int sx, int sy, char letter, int mode)
15000 {
15001   static short delete_buffer[MAX_LEV_FIELDX];
15002   static int start_sx;
15003   static int last_sx, last_sy;
15004   static boolean typing = FALSE;
15005   int letter_element;
15006   int lx = 0, ly = 0;
15007
15008   // map lower case letters to upper case and convert special characters
15009   if (letter >= 'a' && letter <= 'z')
15010     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
15011   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
15012     letter_element = EL_CHAR_AUMLAUT;
15013   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
15014     letter_element = EL_CHAR_OUMLAUT;
15015   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
15016     letter_element = EL_CHAR_UUMLAUT;
15017   else if (letter == '^')
15018     letter_element = EL_CHAR_COPYRIGHT;
15019   else
15020     letter_element = EL_CHAR_ASCII0 + letter;
15021
15022   if (mode != TEXT_INIT)
15023   {
15024     if (!typing)
15025       return FALSE;
15026
15027     if (mode != TEXT_SETCURSOR)
15028     {
15029       sx = last_sx;
15030       sy = last_sy;
15031     }
15032
15033     lx = last_sx + level_xpos;
15034     ly = last_sy + level_ypos;
15035   }
15036
15037   switch (mode)
15038   {
15039     case TEXT_INIT:
15040       if (typing)
15041         DrawLevelText(0, 0, 0, TEXT_END);
15042
15043       typing = TRUE;
15044       start_sx = sx;
15045       last_sx = sx;
15046       last_sy = sy;
15047       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
15048       break;
15049
15050     case TEXT_SETCURSOR:
15051       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
15052       DrawAreaBorder(sx, sy, sx, sy);
15053       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
15054                      ed_tilesize, ed_tilesize);
15055       last_sx = sx;
15056       last_sy = sy;
15057       break;
15058
15059     case TEXT_WRITECHAR:
15060       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
15061       {
15062         if (new_element1 >= EL_STEEL_CHAR_START &&
15063             new_element1 <= EL_STEEL_CHAR_END)
15064           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
15065
15066         delete_buffer[sx - start_sx] = Tile[lx][ly];
15067         Tile[lx][ly] = letter_element;
15068
15069         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
15070           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
15071         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15072           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15073         else
15074           DrawLevelText(0, 0, 0, TEXT_END);
15075
15076         level.changed = TRUE;
15077       }
15078       break;
15079
15080     case TEXT_BACKSPACE:
15081       if (sx > start_sx)
15082       {
15083         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
15084         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
15085         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
15086       }
15087       break;
15088
15089     case TEXT_NEWLINE:
15090       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15091         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15092       else
15093         DrawLevelText(0, 0, 0, TEXT_END);
15094       break;
15095
15096     case TEXT_END:
15097       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15098       DrawEditorElement(sx, sy, Tile[lx][ly]);
15099       StopTextInput();
15100       typing = FALSE;
15101       break;
15102
15103     case TEXT_QUERY_TYPING:
15104       break;
15105
15106     default:
15107       break;
15108   }
15109
15110   return typing;
15111 }
15112
15113 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
15114                           int element, boolean change_level)
15115 {
15116   int lx = sx + level_xpos;
15117   int ly = sy + level_ypos;
15118
15119   if (element == -1)
15120     DrawEditorElement(sx, sy, Tile[lx][ly]);
15121   else
15122     DrawAreaBorder(sx, sy, sx, sy);
15123 }
15124
15125 static void CheckLevelBorderElement(boolean redraw_playfield)
15126 {
15127   int last_border_element = BorderElement;
15128
15129   SetBorderElement();
15130
15131   if (redraw_playfield && BorderElement != last_border_element)
15132     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15133 }
15134
15135 static void CopyLevelToUndoBuffer(int mode)
15136 {
15137   static boolean accumulated_undo = FALSE;
15138   boolean new_undo_buffer_position = TRUE;
15139   int x, y;
15140
15141   if (undo_buffer_steps == 0)
15142     accumulated_undo = FALSE;
15143
15144   switch (mode)
15145   {
15146     case UNDO_IMMEDIATE:
15147       accumulated_undo = FALSE;
15148       break;
15149
15150     case UNDO_ACCUMULATE:
15151       if (accumulated_undo)
15152         new_undo_buffer_position = FALSE;
15153       accumulated_undo = TRUE;
15154       break;
15155
15156     default:
15157       break;
15158   }
15159
15160   if (new_undo_buffer_position)
15161   {
15162     // advance position in undo buffer ring
15163     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
15164
15165     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
15166       undo_buffer_steps++;
15167   }
15168
15169   // always reset redo buffer when storing level change into undo buffer
15170   redo_buffer_steps = 0;
15171
15172   for (x = 0; x < lev_fieldx; x++)
15173     for (y = 0; y < lev_fieldy; y++)
15174       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
15175
15176   // check if drawing operation forces change of border style
15177   CheckLevelBorderElement(TRUE);
15178
15179   level.changed = TRUE;
15180 }
15181
15182 static void RandomPlacement(int new_element)
15183 {
15184   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
15185   int num_free_positions = 0;
15186   int num_percentage, num_elements;
15187   int x, y;
15188
15189   ResetIntelliDraw();
15190
15191   // determine number of free positions for randomly placing the new element
15192   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
15193   {
15194     free_position[x][y] =
15195       (random_placement_background_restricted ?
15196        Tile[x][y] == random_placement_background_element :
15197        Tile[x][y] != new_element);
15198
15199     if (free_position[x][y])
15200       num_free_positions++;
15201   }
15202
15203   // determine number of new elements to place there
15204   num_percentage = num_free_positions * random_placement_value / 100;
15205   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15206                   num_percentage : random_placement_value);
15207
15208   // if less free positions than elements to place, fill all these positions
15209   if (num_free_positions < num_elements)
15210   {
15211     for (x = 0; x < lev_fieldx; x++)
15212       for (y = 0; y < lev_fieldy; y++)
15213         if (free_position[x][y])
15214           SetElement(x, y, new_element);
15215   }
15216   else
15217   {
15218     while (num_elements > 0)
15219     {
15220       x = GetSimpleRandom(lev_fieldx);
15221       y = GetSimpleRandom(lev_fieldy);
15222
15223       // don't place element at the same position twice
15224       if (free_position[x][y])
15225       {
15226         free_position[x][y] = FALSE;
15227         SetElement(x, y, new_element);
15228         num_elements--;
15229       }
15230     }
15231   }
15232
15233   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15234   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15235 }
15236
15237 static void WrapLevel(int dx, int dy)
15238 {
15239   int wrap_dx = lev_fieldx - dx;
15240   int wrap_dy = lev_fieldy - dy;
15241   int x, y;
15242
15243   for (x = 0; x < lev_fieldx; x++)
15244     for (y = 0; y < lev_fieldy; y++)
15245       TileBackup[x][y] = Tile[x][y];
15246
15247   for (x = 0; x < lev_fieldx; x++)
15248     for (y = 0; y < lev_fieldy; y++)
15249       Tile[x][y] =
15250         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15251
15252   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15253   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15254 }
15255
15256 static void DrawAreaElementHighlight(boolean highlighted,
15257                                      boolean highlighted_similar)
15258 {
15259   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15260
15261   if (!highlighted)
15262     return;
15263
15264   int x, y;
15265
15266   for (x = 0; x < ed_fieldx; x++)
15267   {
15268     for (y = 0; y < ed_fieldy; y++)
15269     {
15270       boolean highlight = FALSE;
15271       int lx = x + level_xpos;
15272       int ly = y + level_ypos;
15273
15274       if (!IN_LEV_FIELD(lx, ly))
15275         continue;
15276
15277       // check if element is the same
15278       if (Tile[lx][ly] == new_element1)
15279         highlight = TRUE;
15280
15281       // check if element is similar
15282       if (highlighted_similar &&
15283           strEqual(element_info[Tile[lx][ly]].class_name,
15284                    element_info[new_element1].class_name))
15285         highlight = TRUE;
15286
15287       // check if element is matching MM style wall
15288       if (IS_MM_WALL(Tile[lx][ly]) &&
15289           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15290         highlight = TRUE;
15291
15292       if (!highlight)
15293         continue;
15294
15295       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15296       {
15297         int i;
15298
15299         for (i = 0; i < 4; i++)
15300         {
15301           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15302             continue;
15303
15304           int xx = x * 2 + (i % 2);
15305           int yy = y * 2 + (i / 2);
15306           int sx = SX + xx * ed_tilesize / 2;
15307           int sy = SY + yy * ed_tilesize / 2;
15308           int from_sx = sx;
15309           int from_sy = sy;
15310           int to_sx = sx + ed_tilesize / 2 - 1;
15311           int to_sy = sy + ed_tilesize / 2 - 1;
15312
15313           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15314           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15315           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15316           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15317         }
15318       }
15319       else
15320       {
15321         int sx = SX + x * ed_tilesize;
15322         int sy = SY + y * ed_tilesize;
15323         int from_sx = sx;
15324         int from_sy = sy;
15325         int to_sx = sx + ed_tilesize - 1;
15326         int to_sy = sy + ed_tilesize - 1;
15327
15328         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15329         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15330         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15331         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15332       }
15333     }
15334   }
15335 }
15336
15337 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15338 {
15339   char *template_filename_old = getLocalLevelTemplateFilename();
15340   char *template_filename_new =
15341     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15342
15343   if (copyFile(template_filename_old, template_filename_new) != 0)
15344     Request("Cannot copy level template!", REQ_CONFIRM);
15345
15346   free(template_filename_new);
15347 }
15348
15349 static void HandleDrawingAreas(struct GadgetInfo *gi)
15350 {
15351   static boolean started_inside_drawing_area = FALSE;
15352   static int last_sx = -1;
15353   static int last_sy = -1;
15354   static int last_sx2 = -1;
15355   static int last_sy2 = -1;
15356   int id = gi->custom_id;
15357   int type_id = gi->custom_type_id;
15358   boolean button_press_event;
15359   boolean button_release_event;
15360   boolean inside_drawing_area = !gi->event.off_borders;
15361   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15362   int actual_drawing_function;
15363   int button = gi->event.button;
15364   int new_element = BUTTON_ELEMENT(button);
15365   int sx = gi->event.x, sy = gi->event.y;
15366   int min_sx = 0, min_sy = 0;
15367   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15368   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15369   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15370   int sx2 = gi->event.mx / mini_item_xsize;
15371   int sy2 = gi->event.my / mini_item_ysize;
15372   int dx = sx2 % 2;
15373   int dy = sy2 % 2;
15374   int lx = 0, ly = 0;
15375   int x, y;
15376
15377   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15378   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15379
15380   // make sure to stay inside drawing area boundaries
15381   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15382   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15383
15384   if (draw_level)
15385   {
15386     int min_lx = 0, min_ly = 0;
15387     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15388
15389     // get positions inside level field
15390     lx = sx + level_xpos;
15391     ly = sy + level_ypos;
15392
15393     if (!IN_LEV_FIELD(lx, ly))
15394       inside_drawing_area = FALSE;
15395
15396     // make sure to stay inside level field boundaries
15397     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15398     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15399
15400     // correct drawing area positions accordingly
15401     sx = lx - level_xpos;
15402     sy = ly - level_ypos;
15403   }
15404
15405   // also correct MM wall-sized (double) drawing area positions accordingly
15406   if (sx2 / 2 < sx || sx2 / 2 > sx)
15407   {
15408     dx = (sx2 / 2 < sx ? 0 : 1);
15409     sx2 = sx * 2 + dx;
15410   }
15411   if (sy2 / 2 < sy || sy2 / 2 > sy)
15412   {
15413     dy = (sy2 / 2 < sy ? 0 : 1);
15414     sy2 = sy * 2 + dy;
15415   }
15416
15417   if (!button_press_event && !button_release_event)
15418   {
15419     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15420     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15421                              isHiresTileElement(old_element) &&
15422                              isHiresDrawElement(new_element));
15423
15424     // prevent handling events for every pixel position when moving mouse
15425     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15426         (sx2 == last_sx2 && sy2 == last_sy2))
15427       return;
15428   }
15429
15430   last_sx = sx;
15431   last_sy = sy;
15432   last_sx2 = sx2;
15433   last_sy2 = sy2;
15434
15435   if (button_press_event)
15436     started_inside_drawing_area = inside_drawing_area;
15437
15438   if (!started_inside_drawing_area)
15439     return;
15440
15441   if (!IS_VALID_BUTTON(button))
15442     return;
15443
15444   // handle info callback for each invocation of action callback
15445   gi->callback_info(gi);
15446
15447   // automatically switch to 'single item' drawing mode, if needed
15448   actual_drawing_function =
15449     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15450      drawing_function : GADGET_ID_SINGLE_ITEMS);
15451
15452   // clicking into drawing area with pressed Control key picks element
15453   if (GetKeyModState() & KMOD_Control)
15454   {
15455     last_drawing_function = drawing_function;
15456     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15457   }
15458
15459   if (GetKeyModState() & KMOD_Shift)
15460   {
15461     if (button_press_event || button_release_event)
15462       ResetIntelliDraw();
15463   }
15464
15465   SetDrawModeHiRes(-1);         // reset to normal draw mode
15466
15467   switch (actual_drawing_function)
15468   {
15469     case GADGET_ID_SINGLE_ITEMS:
15470       if (draw_level)
15471       {
15472         if (button_release_event)
15473         {
15474           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15475
15476           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15477               !inside_drawing_area)
15478             DeleteBrushFromCursor();
15479
15480           break;
15481         }
15482
15483         if (draw_with_brush)
15484         {
15485           CopyBrushToLevel(sx, sy, button);
15486         }
15487         else
15488         {
15489           SetDrawModeHiRes(new_element);
15490
15491           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15492           {
15493             // remove player at old position
15494             for (y = 0; y < lev_fieldy; y++)
15495             {
15496               for (x = 0; x < lev_fieldx; x++)
15497               {
15498                 int old_element = Tile[x][y];
15499
15500                 if (IS_PLAYER_ELEMENT(old_element) &&
15501                     IS_PLAYER_ELEMENT(new_element))
15502                 {
15503                   int replaced_with_element =
15504                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15505                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15506
15507                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15508                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15509
15510                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15511                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15512
15513                      new_element >= EL_PLAYER_1 &&
15514                      new_element <= EL_PLAYER_4 &&
15515                      new_element == old_element ? EL_EMPTY :
15516
15517                      old_element);
15518
15519                   SetElement(x, y, replaced_with_element);
15520                 }
15521                 else if (IS_MM_MCDUFFIN(old_element) &&
15522                          IS_MM_MCDUFFIN(new_element))
15523                 {
15524                   // remove McDuffin at old position
15525                   SetElement(x, y, EL_EMPTY);
15526                 }
15527               }
15528             }
15529           }
15530
15531           SetElementButton(lx, ly, dx, dy, new_element, button);
15532         }
15533       }
15534       else if (!button_release_event)
15535       {
15536         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15537
15538         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15539           DrawMiniGraphicExt(drawto,
15540                              gi->x + sx * MINI_TILEX,
15541                              gi->y + sy * MINI_TILEY,
15542                              el2edimg(new_element));
15543         else
15544           DrawFixedGraphicExt(drawto,
15545                               gi->x + sx * TILEX,
15546                               gi->y + sy * TILEY,
15547                               el2edimg(new_element), 0);
15548
15549         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15550           new_element = GFX_ELEMENT(new_element);
15551
15552         drawingarea_info[type_id].value[pos] = new_element;
15553
15554         CopyElementPropertiesToGame(properties_element);
15555
15556         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15557         {
15558           UpdateCustomElementGraphicGadgets();
15559
15560           FrameCounter = 0;     // restart animation frame counter
15561         }
15562       }
15563       break;
15564
15565     case GADGET_ID_CONNECTED_ITEMS:
15566       {
15567         static int last_sx = -1;
15568         static int last_sy = -1;
15569
15570         if (button_release_event)
15571           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15572
15573         SetDrawModeHiRes(new_element);
15574
15575         if (getDrawModeHiRes())
15576         {
15577           sx = sx2;
15578           sy = sy2;
15579         }
15580
15581         if (!button_press_event)
15582           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15583
15584         last_sx = sx;
15585         last_sy = sy;
15586       }
15587       break;
15588
15589     case GADGET_ID_LINE:
15590     case GADGET_ID_ARC:
15591     case GADGET_ID_RECTANGLE:
15592     case GADGET_ID_FILLED_BOX:
15593       SetDrawModeHiRes(new_element);
15594
15595       if (getDrawModeHiRes())
15596       {
15597         sx = sx2;
15598         sy = sy2;
15599       }
15600       // FALLTHROUGH
15601     case GADGET_ID_GRAB_BRUSH:
15602     case GADGET_ID_TEXT:
15603       {
15604         static int last_sx = -1;
15605         static int last_sy = -1;
15606         static int start_sx = -1;
15607         static int start_sy = -1;
15608         void (*draw_func)(int, int, int, int, int, boolean);
15609
15610         if (drawing_function == GADGET_ID_LINE)
15611           draw_func = DrawLine;
15612         else if (drawing_function == GADGET_ID_ARC)
15613           draw_func = DrawArc;
15614         else if (drawing_function == GADGET_ID_RECTANGLE)
15615           draw_func = DrawBox;
15616         else if (drawing_function == GADGET_ID_FILLED_BOX)
15617           draw_func = DrawFilledBox;
15618         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15619           draw_func = SelectArea;
15620         else // (drawing_function == GADGET_ID_TEXT)
15621           draw_func = SetTextCursor;
15622
15623         if (button_press_event)
15624         {
15625           draw_func(sx, sy, sx, sy, new_element, FALSE);
15626           start_sx = last_sx = sx;
15627           start_sy = last_sy = sy;
15628
15629           if (drawing_function == GADGET_ID_TEXT)
15630             DrawLevelText(0, 0, 0, TEXT_END);
15631         }
15632         else if (button_release_event)
15633         {
15634           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15635           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15636           {
15637             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15638             CopyBrushToCursor(sx, sy);
15639             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15640                           MB_LEFTBUTTON);
15641             draw_with_brush = TRUE;
15642           }
15643           else if (drawing_function == GADGET_ID_TEXT)
15644             DrawLevelText(sx, sy, 0, TEXT_INIT);
15645           else
15646             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15647         }
15648         else if (last_sx != sx || last_sy != sy)
15649         {
15650           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15651           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15652             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15653           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15654           last_sx = sx;
15655           last_sy = sy;
15656         }
15657       }
15658       break;
15659
15660     case GADGET_ID_FLOOD_FILL:
15661       if (button_press_event && Tile[lx][ly] != new_element)
15662       {
15663         if (IS_MM_WALL_EDITOR(new_element))
15664           FloodFillWall_MM(sx2, sy2, new_element);
15665         else
15666           FloodFill(lx, ly, new_element);
15667
15668         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15669         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15670       }
15671       break;
15672
15673     case GADGET_ID_PICK_ELEMENT:
15674       if (button_release_event)
15675         ClickOnGadget(level_editor_gadget[last_drawing_function],
15676                       MB_LEFTBUTTON);
15677       else if (draw_level)
15678         PickDrawingElement(button, Tile[lx][ly]);
15679       else
15680       {
15681         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15682
15683         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15684       }
15685
15686     default:
15687       break;
15688   }
15689
15690   // do not mark level as modified for certain non-level-changing gadgets
15691   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15692        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15693       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15694       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15695     return;
15696
15697   level.changed = TRUE;
15698 }
15699
15700 static void HandleCounterButtons(struct GadgetInfo *gi)
15701 {
15702   int gadget_id = gi->custom_id;
15703   int counter_id = gi->custom_type_id;
15704   int button = gi->event.button;
15705   int *counter_value = counterbutton_info[counter_id].value;
15706   int step = BUTTON_STEPSIZE(button) *
15707     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15708
15709   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15710   {
15711     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15712     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15713     boolean level_changed = LevelChanged();
15714
15715     if ((level_changed && pressed) || (!level_changed && released))
15716       return;
15717
15718     if (level_changed && !Request("Level has changed! Discard changes?",
15719                                   REQ_ASK))
15720     {
15721       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15722         ModifyEditorCounterValue(counter_id, *counter_value);
15723
15724       return;
15725     }
15726   }
15727
15728   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15729     *counter_value = gi->textinput.number_value;
15730   else
15731     ModifyEditorCounterValue(counter_id, *counter_value + step);
15732
15733   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15734   {
15735     int last_game_engine_type = level.game_engine_type;
15736
15737     LoadLevel(level_nr);
15738     LoadScore(level_nr);
15739
15740     SaveLevelSetup_SeriesInfo();
15741
15742     TapeErase();
15743
15744     ResetUndoBuffer();
15745     DrawEditModeWindow();
15746
15747     if (level.game_engine_type != last_game_engine_type)
15748     {
15749       // update element selection list
15750       ReinitializeElementList();
15751       ModifyEditorElementList();
15752     }
15753
15754     return;
15755   }
15756
15757   switch (counter_id)
15758   {
15759     case ED_COUNTER_ID_YAMYAM_CONTENT:
15760       DrawYamYamContentAreas();
15761       break;
15762
15763     case ED_COUNTER_ID_BALL_CONTENT:
15764       DrawMagicBallContentAreas();
15765       break;
15766
15767     case ED_COUNTER_ID_ANDROID_CONTENT:
15768       DrawAndroidElementArea();
15769       break;
15770
15771     case ED_COUNTER_ID_GROUP_CONTENT:
15772       DrawGroupElementArea();
15773       CopyGroupElementPropertiesToGame(properties_element);
15774       break;
15775
15776     case ED_COUNTER_ID_INVENTORY_SIZE:
15777       DrawPlayerInitialInventoryArea(properties_element);
15778       break;
15779
15780     case ED_COUNTER_ID_MM_BALL_CONTENT:
15781       DrawMMBallContentArea();
15782       break;
15783
15784     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15785     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15786       DrawEnvelopeTextArea(-1);
15787       break;
15788
15789     case ED_COUNTER_ID_LEVEL_XSIZE:
15790     case ED_COUNTER_ID_LEVEL_YSIZE:
15791       lev_fieldx = level.fieldx;
15792       lev_fieldy = level.fieldy;
15793
15794       // check if resizing of level results in change of border border
15795       SetBorderElement();
15796
15797       break;
15798
15799     default:
15800       break;
15801   }
15802
15803   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15804        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15805       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15806        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15807     CopyElementPropertiesToGame(properties_element);
15808
15809   // do not mark level as modified for certain non-level-changing gadgets
15810   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15811        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15812       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15813        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15814     return;
15815
15816   level.changed = TRUE;
15817 }
15818
15819 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15820 {
15821   int type_id = gi->custom_type_id;
15822
15823   strcpy(textinput_info[type_id].value, gi->textinput.value);
15824
15825   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15826   {
15827     CopyElementPropertiesToGame(properties_element);
15828
15829     ModifyEditorElementList();  // update changed button info text
15830   }
15831
15832   // do not mark level as modified for certain non-level-changing gadgets
15833   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15834       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15835     return;
15836
15837   level.changed = TRUE;
15838 }
15839
15840 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15841 {
15842   int type_id = gi->custom_type_id;
15843
15844   strncpy(textarea_info[type_id].value, gi->textarea.value,
15845           MAX_ENVELOPE_TEXT_LEN);
15846   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15847
15848   level.changed = TRUE;
15849 }
15850
15851 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15852 {
15853   int type_id = gi->custom_type_id;
15854   int value_old = *selectbox_info[type_id].value;
15855   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15856
15857   *selectbox_info[type_id].value = value_new;
15858
15859   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15860   {
15861     DrawLevelConfigWindow();
15862   }
15863   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15864   {
15865     element_info[properties_element].current_change_page = gi->selectbox.index;
15866
15867     DrawPropertiesWindow();
15868   }
15869   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15870             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15871            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15872             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15873            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15874   {
15875     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15876     {
15877       // when changing action type, also check action mode and action arg
15878       if (value_old != value_new)
15879         setSelectboxSpecialActionVariablesIfNeeded();
15880
15881       DrawPropertiesChange();
15882     }
15883
15884     CopyElementPropertiesToGame(properties_element);
15885   }
15886   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15887   {
15888     // show or hide "engine" tabulator depending on game engine type
15889     DrawLevelConfigWindow();
15890
15891     // update element selection list depending on game engine type
15892     ReinitializeElementList();
15893     ModifyEditorElementList();
15894   }
15895   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15896   {
15897     // update BD cycle delay counter gadgets depending on BD scheduling type
15898     DrawLevelConfigWindow();
15899   }
15900
15901   // do not mark level as modified for certain non-level-changing gadgets
15902   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15903       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15904     return;
15905
15906   level.changed = TRUE;
15907 }
15908
15909 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15910 {
15911   int type_id = gi->custom_type_id;
15912   int i;
15913
15914   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15915       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15916   {
15917     edit_mode_levelconfig = gi->custom_type_id;
15918
15919     DrawLevelConfigWindow();
15920   }
15921   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15922            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15923   {
15924     edit_mode_properties = gi->custom_type_id;
15925
15926     DrawPropertiesWindow();
15927   }
15928   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15929            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15930   {
15931     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15932
15933     // backup original "level.field" (needed to track playfield changes)
15934     CopyPlayfield(level.field, TileBackup);
15935
15936     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15937     CopyPlayfield(Tile, level.field);
15938
15939     if (new_template ||
15940         Request("Save this template and kill the old?", REQ_ASK))
15941       SaveLevelTemplate();
15942
15943     if (new_template)
15944       Request("Template saved!", REQ_CONFIRM);
15945
15946     // restore original "level.field" (needed to track playfield changes)
15947     CopyPlayfield(TileBackup, level.field);
15948   }
15949   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15950   {
15951     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15952
15953     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15954         leveldir_current->readonly)
15955     {
15956       Request("This level set is read-only!", REQ_CONFIRM);
15957
15958       return;
15959     }
15960
15961     if (strEqual(levelset_name, ""))
15962     {
15963       Request("Please enter level set title!", REQ_CONFIRM);
15964
15965       return;
15966     }
15967
15968     if (strEqual(levelset_author, ""))
15969     {
15970       Request("Please enter level set author!", REQ_CONFIRM);
15971
15972       return;
15973     }
15974
15975     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15976     {
15977       if (UpdateUserLevelSet(levelset_subdir,
15978                              levelset_name,
15979                              levelset_author,
15980                              levelset_num_levels))
15981       {
15982         Request("Level set updated!", REQ_CONFIRM);
15983       }
15984       else
15985       {
15986         Request("Updating level set failed!", REQ_CONFIRM);
15987       }
15988     }
15989     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15990     {
15991       if (level.changed && !Request("Level has changed! Discard changes?",
15992                                      REQ_ASK))
15993         return;
15994
15995       if (CreateUserLevelSet(levelset_subdir,
15996                              levelset_name,
15997                              levelset_author,
15998                              levelset_num_levels,
15999                              levelset_use_levelset_artwork))
16000       {
16001         if (levelset_copy_level_template)
16002           CopyLevelTemplateToUserLevelSet(levelset_subdir);
16003
16004         Request("New level set created!", REQ_CONFIRM);
16005
16006         AddUserLevelSetToLevelInfo(levelset_subdir);
16007         ChangeEditorToLevelSet(levelset_subdir);
16008       }
16009       else
16010       {
16011         Request("Creating new level set failed!", REQ_CONFIRM);
16012       }
16013     }
16014   }
16015   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
16016            custom_element.num_change_pages < MAX_CHANGE_PAGES)
16017   {
16018     struct ElementInfo *ei = &element_info[properties_element];
16019
16020     // when modifying custom element, ask for copying level template
16021     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16022       return;
16023
16024     setElementChangePages(ei, ei->num_change_pages + 1);
16025
16026     // set new change page to be new current change page
16027     ei->current_change_page = ei->num_change_pages - 1;
16028     ei->change = &ei->change_page[ei->current_change_page];
16029
16030     setElementChangeInfoToDefaults(ei->change);
16031
16032     DrawPropertiesWindow();
16033
16034     level.changed = TRUE;
16035   }
16036   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
16037            custom_element.num_change_pages > MIN_CHANGE_PAGES)
16038   {
16039     struct ElementInfo *ei = &element_info[properties_element];
16040
16041     // when modifying custom element, ask for copying level template
16042     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16043       return;
16044
16045     // copy all change pages after change page to be deleted
16046     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
16047       ei->change_page[i] = ei->change_page[i + 1];
16048
16049     setElementChangePages(ei, ei->num_change_pages - 1);
16050
16051     DrawPropertiesWindow();
16052
16053     level.changed = TRUE;
16054   }
16055 }
16056
16057 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
16058 {
16059   int type_id = gi->custom_type_id;
16060
16061   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
16062       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
16063   {
16064     struct ElementInfo *ei = &element_info[properties_element];
16065     int step = BUTTON_STEPSIZE(gi->event.button);
16066
16067     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
16068     ei->current_change_page += step;
16069
16070     if (ei->current_change_page < 0)
16071       ei->current_change_page = 0;
16072     else if (ei->current_change_page >= ei->num_change_pages)
16073       ei->current_change_page = ei->num_change_pages - 1;
16074
16075     DrawPropertiesWindow();
16076   }
16077   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
16078            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16079   {
16080     struct ElementInfo *ei = &element_info[properties_element];
16081     int current_change_page = ei->current_change_page;
16082
16083     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
16084     {
16085       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
16086         ei->change_page[current_change_page];
16087     }
16088     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16089     {
16090       // when modifying custom element, ask for copying level template
16091       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16092         return;
16093
16094       ei->change_page[current_change_page] =
16095         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
16096
16097       level.changed = TRUE;
16098     }
16099
16100     DrawPropertiesWindow();
16101   }
16102 }
16103
16104 static void HandleRadiobuttons(struct GadgetInfo *gi)
16105 {
16106   int type_id = gi->custom_type_id;
16107
16108   *radiobutton_info[type_id].value =
16109     radiobutton_info[type_id].checked_value;
16110
16111   // do not mark level as modified for certain non-level-changing gadgets
16112   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
16113       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
16114     return;
16115
16116   level.changed = TRUE;
16117 }
16118
16119 static void HandleCheckbuttons(struct GadgetInfo *gi)
16120 {
16121   int type_id = gi->custom_type_id;
16122
16123   *checkbutton_info[type_id].value ^= TRUE;
16124
16125   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
16126       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
16127       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
16128       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
16129          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
16130         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
16131          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
16132        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
16133   {
16134     CopyElementPropertiesToGame(properties_element);
16135   }
16136
16137   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
16138   {
16139     UpdateCustomElementGraphicGadgets();
16140   }
16141   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
16142            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
16143   {
16144     boolean template_related_changes_found = FALSE;
16145     int i;
16146
16147     // check if any custom, group or empty elements have been changed
16148     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
16149       if ((IS_CUSTOM_ELEMENT(i) ||
16150            IS_GROUP_ELEMENT(i) ||
16151            IS_EMPTY_ELEMENT(i)) &&
16152           element_info[i].modified_settings)
16153         template_related_changes_found = TRUE;
16154
16155     if (level.use_custom_template &&
16156         !fileExists(getGlobalLevelTemplateFilename()))
16157     {
16158       Request("No level template found!", REQ_CONFIRM);
16159
16160       level.use_custom_template = FALSE;
16161
16162       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16163
16164       return;
16165     }
16166
16167     if (level.use_custom_template &&
16168         template_related_changes_found &&
16169         !Request("Discard changes and use level template?", REQ_ASK))
16170     {
16171       level.use_custom_template = FALSE;
16172
16173       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16174
16175       return;
16176     }
16177
16178     if (!level.use_custom_template &&
16179         Request("Copy settings from level template?", REQ_ASK))
16180     {
16181       return;
16182     }
16183
16184     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
16185
16186     DrawEditModeWindow();
16187   }
16188   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
16189   {
16190     if (setup.editor.use_template_for_new_levels &&
16191         !fileExists(getGlobalLevelTemplateFilename()))
16192     {
16193       Request("No level template found!", REQ_CONFIRM);
16194
16195       return;
16196     }
16197
16198     if (setup.editor.use_template_for_new_levels &&
16199         level.changed &&
16200         !Request("Discard level and load template?", REQ_ASK))
16201     {
16202       return;
16203     }
16204
16205     if (!setup.editor.use_template_for_new_levels &&
16206         level.changed &&
16207         !Request("Discard level and use empty level?", REQ_ASK))
16208     {
16209       return;
16210     }
16211
16212     LoadLevel(level_nr);
16213     LoadScore(level_nr);
16214
16215     TapeErase();
16216
16217     ResetUndoBuffer();
16218     DrawEditModeWindow();
16219   }
16220   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16221   {
16222     SetAutomaticNumberOfGemsNeeded();
16223   }
16224
16225   // do not mark level as modified for certain non-level-changing gadgets
16226   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16227        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16228       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16229        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16230        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16231       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16232     return;
16233
16234   level.changed = TRUE;
16235 }
16236
16237 static void HandleControlButtons(struct GadgetInfo *gi)
16238 {
16239   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16240   static int last_edit_mode = ED_MODE_DRAWING;
16241   static int last_custom_copy_mode = -1;
16242   static int last_button = 0;
16243   int id = gi->custom_id;
16244   int button = gi->event.button;
16245   int step = BUTTON_STEPSIZE(button);
16246   int new_element = BUTTON_ELEMENT(button);
16247   int last_properties_element = properties_element;
16248   int x, y;
16249
16250   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16251     DrawLevelText(0, 0, 0, TEXT_END);
16252
16253   if (id < ED_NUM_CTRL1_BUTTONS &&
16254       id != GADGET_ID_SINGLE_ITEMS &&
16255       id != GADGET_ID_PICK_ELEMENT &&
16256       edit_mode != ED_MODE_DRAWING &&
16257       drawing_function != GADGET_ID_PICK_ELEMENT &&
16258       !(GetKeyModState() & KMOD_Control))
16259     ChangeEditModeWindow(ED_MODE_DRAWING);
16260
16261   // element copy mode active, but no element button pressed => deactivate
16262   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16263     last_custom_copy_mode = -1;
16264
16265   // when showing palette on element buttons, change element of button used
16266   if (editor.palette.show_on_element_buttons &&
16267       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16268   {
16269     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16270
16271     id = GADGET_ID_PALETTE;
16272   }
16273
16274   switch (id)
16275   {
16276     case GADGET_ID_SCROLL_LEFT:
16277       if (level_xpos >= 0)
16278       {
16279         if (lev_fieldx < ed_fieldx - 2)
16280           break;
16281
16282         level_xpos -= step;
16283         if (level_xpos < -1)
16284           level_xpos = -1;
16285         if (button == 1)
16286           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16287         else
16288           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16289
16290         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16291                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16292       }
16293       break;
16294
16295     case GADGET_ID_SCROLL_RIGHT:
16296       if (level_xpos <= lev_fieldx - ed_fieldx)
16297       {
16298         if (lev_fieldx < ed_fieldx - 2)
16299           break;
16300
16301         level_xpos += step;
16302         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16303           level_xpos = lev_fieldx - ed_fieldx + 1;
16304         if (button == 1)
16305           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16306         else
16307           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16308
16309         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16310                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16311       }
16312       break;
16313
16314     case GADGET_ID_SCROLL_UP:
16315       if (level_ypos >= 0)
16316       {
16317         if (lev_fieldy < ed_fieldy - 2)
16318           break;
16319
16320         level_ypos -= step;
16321         if (level_ypos < -1)
16322           level_ypos = -1;
16323         if (button == 1)
16324           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16325         else
16326           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16327
16328         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16329                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16330       }
16331       break;
16332
16333     case GADGET_ID_SCROLL_DOWN:
16334       if (level_ypos <= lev_fieldy - ed_fieldy)
16335       {
16336         if (lev_fieldy < ed_fieldy - 2)
16337           break;
16338
16339         level_ypos += step;
16340         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16341           level_ypos = lev_fieldy - ed_fieldy + 1;
16342         if (button == 1)
16343           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16344         else
16345           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16346
16347         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16348                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16349       }
16350       break;
16351
16352     case GADGET_ID_SCROLL_HORIZONTAL:
16353       level_xpos = gi->event.item_position - 1;
16354
16355       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16356       BackToFront();
16357
16358       break;
16359
16360     case GADGET_ID_SCROLL_VERTICAL:
16361       level_ypos = gi->event.item_position - 1;
16362
16363       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16364       BackToFront();
16365
16366       break;
16367
16368     case GADGET_ID_SCROLL_LIST_UP:
16369     case GADGET_ID_SCROLL_LIST_DOWN:
16370     case GADGET_ID_SCROLL_LIST_VERTICAL:
16371       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16372         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16373       else
16374       {
16375         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16376         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16377
16378         if (element_shift < 0)
16379           element_shift = 0;
16380         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16381           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16382
16383         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16384                      GDI_SCROLLBAR_ITEM_POSITION,
16385                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16386       }
16387
16388       ModifyEditorElementList();
16389
16390       break;
16391
16392     case GADGET_ID_PROPERTIES:
16393       // always switch off element properties when they are already displayed
16394       last_properties_element = new_element;
16395     case GADGET_ID_ELEMENT_LEFT:
16396     case GADGET_ID_ELEMENT_MIDDLE:
16397     case GADGET_ID_ELEMENT_RIGHT:
16398       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16399                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16400                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16401                             new_element);
16402
16403       if (edit_mode != ED_MODE_PROPERTIES)
16404       {
16405         last_edit_mode = edit_mode;
16406
16407         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16408
16409         last_level_drawing_function = drawing_function;
16410         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16411                       MB_LEFTBUTTON);
16412       }
16413       else if (properties_element != last_properties_element)
16414       {
16415         DrawEditModeWindow();
16416       }
16417       else
16418       {
16419         ChangeEditModeWindow(ED_MODE_DRAWING);
16420
16421         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16422                       MB_LEFTBUTTON);
16423       }
16424       break;
16425
16426     case GADGET_ID_PALETTE:
16427       if (edit_mode != ED_MODE_PALETTE)
16428       {
16429         last_edit_mode = edit_mode;
16430
16431         ChangeEditModeWindow(ED_MODE_PALETTE);
16432       }
16433       else
16434       {
16435         ChangeEditModeWindow(last_edit_mode);
16436       }
16437       break;
16438
16439     case GADGET_ID_WRAP_LEFT:
16440       WrapLevel(-step, 0);
16441       break;
16442
16443     case GADGET_ID_WRAP_RIGHT:
16444       WrapLevel(step, 0);
16445       break;
16446
16447     case GADGET_ID_WRAP_UP:
16448       WrapLevel(0, -step);
16449       break;
16450
16451     case GADGET_ID_WRAP_DOWN:
16452       WrapLevel(0, step);
16453       break;
16454
16455     case GADGET_ID_SINGLE_ITEMS:
16456     case GADGET_ID_CONNECTED_ITEMS:
16457     case GADGET_ID_LINE:
16458     case GADGET_ID_ARC:
16459     case GADGET_ID_TEXT:
16460     case GADGET_ID_RECTANGLE:
16461     case GADGET_ID_FILLED_BOX:
16462     case GADGET_ID_FLOOD_FILL:
16463     case GADGET_ID_GRAB_BRUSH:
16464     case GADGET_ID_PICK_ELEMENT:
16465       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16466         last_drawing_function = drawing_function;
16467       drawing_function = id;
16468       draw_with_brush = FALSE;
16469       break;
16470
16471     case GADGET_ID_RANDOM_PLACEMENT:
16472       RandomPlacement(new_element);
16473       break;
16474
16475     case GADGET_ID_ZOOM:
16476       // zoom level editor tile size in or out (or reset to default size)
16477       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16478                      button == 2 ? ed_tilesize_default :
16479                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16480
16481       // when using touch device, cycle through all zoom tilesizes
16482       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16483         ed_tilesize = MICRO_TILESIZE;
16484
16485       // limit zoom level by upper and lower bound
16486       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16487
16488       InitZoomLevelSettings(ed_tilesize);
16489
16490       if (edit_mode == ED_MODE_DRAWING)
16491       {
16492         DrawDrawingWindow();
16493
16494         // redraw zoom gadget info text
16495         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16496       }
16497
16498       // save current editor zoom tilesize
16499       SaveSetup_AutoSetup();
16500
16501       break;
16502
16503     case GADGET_ID_CUSTOM_COPY_FROM:
16504     case GADGET_ID_CUSTOM_COPY_TO:
16505     case GADGET_ID_CUSTOM_EXCHANGE:
16506       last_custom_copy_mode = id;
16507       last_drawing_function = drawing_function;
16508       break;
16509
16510     case GADGET_ID_CUSTOM_COPY:
16511       CopyCustomElement(properties_element, -1, id);
16512       break;
16513
16514     case GADGET_ID_CUSTOM_PASTE:
16515       CopyCustomElement(-1, properties_element, id);
16516       break;
16517
16518     case GADGET_ID_UNDO:
16519       if (button < 0)   // keep button value (even if modifier keys are pressed)
16520         button = -button;
16521       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16522         button = 3;
16523
16524       if (button == 1 && undo_buffer_steps == 0)
16525       {
16526         Request("Undo buffer empty!", REQ_CONFIRM);
16527
16528         break;
16529       }
16530       else if (button == 2)
16531       {
16532         break;
16533       }
16534       else if (button == 3 && redo_buffer_steps == 0)
16535       {
16536         Request("Redo buffer empty!", REQ_CONFIRM);
16537
16538         break;
16539       }
16540
16541       if (edit_mode != ED_MODE_DRAWING)
16542         ChangeEditModeWindow(ED_MODE_DRAWING);
16543
16544       if (button == 1)
16545       {
16546         // undo
16547
16548         undo_buffer_position =
16549           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16550
16551         undo_buffer_steps--;
16552         redo_buffer_steps++;
16553       }
16554       else
16555       {
16556         // redo
16557
16558         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16559
16560         undo_buffer_steps++;
16561         redo_buffer_steps--;
16562       }
16563
16564       for (x = 0; x < lev_fieldx; x++)
16565         for (y = 0; y < lev_fieldy; y++)
16566           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16567
16568       // check if undo operation forces change of border style
16569       CheckLevelBorderElement(FALSE);
16570
16571       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16572
16573       break;
16574
16575     case GADGET_ID_CONF:
16576       if (edit_mode != ED_MODE_LEVELCONFIG)
16577       {
16578         last_edit_mode = edit_mode;
16579
16580         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16581       }
16582       else
16583       {
16584         ChangeEditModeWindow(ED_MODE_DRAWING);
16585       }
16586       break;
16587
16588     case GADGET_ID_CLEAR:
16589       if (edit_mode != ED_MODE_DRAWING)
16590         ChangeEditModeWindow(ED_MODE_DRAWING);
16591
16592       for (x = 0; x < MAX_LEV_FIELDX; x++)
16593         for (y = 0; y < MAX_LEV_FIELDY; y++)
16594           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16595
16596       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16597
16598       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16599       break;
16600
16601     case GADGET_ID_SAVE:
16602     {
16603       // saving read-only levels into personal level set modifies global vars
16604       // "leveldir_current" and "level_nr"; restore them after saving level
16605       LevelDirTree *leveldir_former = leveldir_current;
16606       int level_nr_former = level_nr;
16607       char *level_filename;
16608       boolean new_level;
16609
16610       if (leveldir_current->readonly &&
16611           !PrepareSavingIntoPersonalLevelSet())
16612         break;
16613
16614       level_filename = getDefaultLevelFilename(level_nr);
16615       new_level = !fileExists(level_filename);
16616
16617       if (new_level ||
16618           Request("Save this level and kill the old?", REQ_ASK))
16619       {
16620         if (leveldir_former->readonly)
16621           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16622
16623         SetAutomaticNumberOfGemsNeeded();
16624
16625         CopyPlayfield(Tile, level.field);
16626         SaveLevel(level_nr);
16627
16628         level.changed = FALSE;
16629
16630         if (new_level)
16631         {
16632           char level_saved_msg[64];
16633
16634           if (leveldir_former->readonly)
16635             sprintf(level_saved_msg,
16636                     "Level saved as level %d into personal level set!",
16637                     level_nr);
16638           else
16639             strcpy(level_saved_msg, "Level saved!");
16640
16641           Request(level_saved_msg, REQ_CONFIRM);
16642         }
16643       }
16644
16645       // "cd" back to copied-from levelset (in case of saved read-only level)
16646       leveldir_current = leveldir_former;
16647       level_nr = level_nr_former;
16648
16649       break;
16650     }
16651
16652     case GADGET_ID_TEST:
16653       if (LevelChanged())
16654         level.game_version = GAME_VERSION_ACTUAL;
16655
16656       CopyPlayfield(level.field, TileBackup);
16657       CopyPlayfield(Tile, level.field);
16658
16659       CopyNativeLevel_RND_to_Native(&level);
16660
16661       UnmapLevelEditorGadgets();
16662       UndrawSpecialEditorDoor();
16663
16664       CloseDoor(DOOR_CLOSE_ALL);
16665
16666       // needed before playing if editor playfield area has different size
16667       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16668
16669       // redraw_mask = REDRAW_ALL;
16670
16671       level_editor_test_game = TRUE;
16672
16673       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16674
16675       break;
16676
16677     case GADGET_ID_EXIT:
16678       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16679       break;
16680
16681     default:
16682       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16683           id <= GADGET_ID_ELEMENTLIST_LAST)
16684       {
16685         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16686
16687         new_element = editor_elements[element_position + element_shift];
16688
16689         if (IS_EDITOR_CASCADE(new_element))
16690         {
16691           int i;
16692
16693           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16694           {
16695             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16696             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16697
16698             if (*cascade_element == new_element)
16699             {
16700               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16701               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16702
16703               // update element selection list
16704               ReinitializeElementList();
16705               ModifyEditorElementList();
16706
16707               // update cascading gadget info text
16708               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16709
16710               // save current editor cascading state
16711               SaveSetup_EditorCascade();
16712
16713               break;
16714             }
16715           }
16716
16717           break;
16718         }
16719
16720         if (last_custom_copy_mode != -1)
16721         {
16722           if (CopyCustomElement(properties_element, new_element,
16723                                 last_custom_copy_mode))
16724           {
16725             ClickOnGadget(level_editor_gadget[last_drawing_function],
16726                           MB_LEFTBUTTON);
16727
16728             last_custom_copy_mode = -1;
16729           }
16730
16731           break;
16732         }
16733
16734         // change element of button used to show palette
16735         if (editor.palette.show_on_element_buttons)
16736           button = last_button;
16737
16738         PickDrawingElement(button, new_element);
16739
16740         if (!stick_element_properties_window &&
16741             drawing_function != GADGET_ID_PICK_ELEMENT &&
16742             !(GetKeyModState() & KMOD_Control))
16743         {
16744           properties_element = new_element;
16745           if (edit_mode == ED_MODE_PROPERTIES)
16746             DrawPropertiesWindow();
16747         }
16748
16749         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16750           ClickOnGadget(level_editor_gadget[last_drawing_function],
16751                         MB_LEFTBUTTON);
16752
16753         if (!use_permanent_palette)
16754           ChangeEditModeWindow(last_edit_mode);
16755       }
16756 #ifdef DEBUG
16757       else if (gi->event.type == GD_EVENT_PRESSED)
16758         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16759       else if (gi->event.type == GD_EVENT_RELEASED)
16760         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16761       else if (gi->event.type == GD_EVENT_MOVING)
16762         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16763       else
16764         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16765 #endif
16766       break;
16767   }
16768 }
16769
16770 void HandleLevelEditorKeyInput(Key key)
16771 {
16772   char letter = getCharFromKey(key);
16773
16774   if (drawing_function == GADGET_ID_TEXT &&
16775       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16776   {
16777     if (letter)
16778       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16779     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16780       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16781     else if (key == KSYM_Return)
16782       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16783     else if (key == KSYM_Escape)
16784       DrawLevelText(0, 0, 0, TEXT_END);
16785
16786     return;
16787   }
16788
16789   int id = GADGET_ID_NONE;
16790   int new_element_shift = element_shift;
16791   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16792   int button = MB_LEFTBUTTON;
16793   int i;
16794
16795   switch (key)
16796   {
16797     case KSYM_Left:
16798       id = GADGET_ID_SCROLL_LEFT;
16799       break;
16800     case KSYM_Right:
16801       id = GADGET_ID_SCROLL_RIGHT;
16802       break;
16803     case KSYM_Up:
16804       id = GADGET_ID_SCROLL_UP;
16805       break;
16806     case KSYM_Down:
16807       id = GADGET_ID_SCROLL_DOWN;
16808       break;
16809
16810     case KSYM_Page_Up:
16811     case KSYM_Page_Down:
16812       step *= (key == KSYM_Page_Up ? -1 : +1);
16813       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16814
16815       if (element_shift < 0)
16816         element_shift = 0;
16817       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16818         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16819
16820       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16821                    GDI_SCROLLBAR_ITEM_POSITION,
16822                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16823
16824       ModifyEditorElementList();
16825
16826       break;
16827
16828     case KSYM_Home:
16829     case KSYM_End:
16830       element_shift = (key == KSYM_Home ? 0 :
16831                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16832
16833       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16834                    GDI_SCROLLBAR_ITEM_POSITION,
16835                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16836
16837       ModifyEditorElementList();
16838
16839       break;
16840
16841     case KSYM_Insert:
16842     case KSYM_Delete:
16843
16844       // this is needed to prevent interference with running "True X-Mouse"
16845       if (GetKeyModStateFromEvents() & KMOD_Control)
16846         break;
16847
16848       // check for last or next editor cascade block in element list
16849       for (i = 0; i < num_editor_elements; i++)
16850       {
16851         if ((key == KSYM_Insert && i == element_shift) ||
16852             (key == KSYM_Delete && new_element_shift > element_shift))
16853           break;
16854
16855         // jump to next cascade block (or to start of element list)
16856         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16857           new_element_shift = i;
16858       }
16859
16860       if (i < num_editor_elements)
16861         element_shift = new_element_shift;
16862
16863       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16864         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16865
16866       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16867                    GDI_SCROLLBAR_ITEM_POSITION,
16868                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16869
16870       ModifyEditorElementList();
16871
16872       break;
16873
16874     case KSYM_Escape:
16875       if (edit_mode == ED_MODE_DRAWING)
16876         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16877       else if (edit_mode == ED_MODE_LEVELCONFIG)
16878         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16879       else if (edit_mode == ED_MODE_PROPERTIES)
16880         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16881       else if (edit_mode == ED_MODE_PALETTE)
16882         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16883       else              // should never happen
16884         ChangeEditModeWindow(ED_MODE_DRAWING);
16885
16886       break;
16887
16888     default:
16889       break;
16890   }
16891
16892   if (id != GADGET_ID_NONE)
16893     ClickOnGadget(level_editor_gadget[id], button);
16894   else if (letter == '1' || letter == '?')
16895     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16896   else if (letter == '2')
16897     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16898   else if (letter == '3')
16899     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16900   else if (letter == '.')
16901     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16902   else if (letter == 'U')
16903     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16904   else if (letter == '-' || key == KSYM_KP_Subtract)
16905     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16906   else if (letter == '0' || key == KSYM_KP_0)
16907     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16908   else if (letter == '+' || key == KSYM_KP_Add ||
16909            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16910     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16911   else if (key == KSYM_Return ||
16912            key == KSYM_space ||
16913            key == setup.shortcut.toggle_pause)
16914     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16915   else
16916     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16917       if (letter && letter == controlbutton_info[i].shortcut)
16918         if (!anyTextGadgetActive())
16919           ClickOnGadget(level_editor_gadget[i], button);
16920
16921   if (draw_with_brush)
16922   {
16923     if (letter == 'x')
16924       FlipBrushX();
16925     else if (letter == 'y')
16926       FlipBrushY();
16927     else if (letter == 'z')
16928       RotateBrush();
16929   }
16930 }
16931
16932 static void HandleLevelEditorIdle_Properties(void)
16933 {
16934   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16935   int x = editor.settings.element_graphic.x + element_border;
16936   int y = editor.settings.element_graphic.y + element_border;
16937   static DelayCounter action_delay = { 0 };
16938   int i;
16939
16940   action_delay.value = GameFrameDelay;
16941
16942   if (!DelayReached(&action_delay))
16943     return;
16944
16945   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16946   {
16947     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16948
16949     if (gi->mapped && gi->active && gi->selectbox.open)
16950       return;
16951   }
16952
16953   DrawEditorElementAnimation(SX + x, SY + y);
16954
16955   redraw_mask |= REDRAW_FIELD;
16956
16957   FrameCounter++;       // increase animation frame counter
16958 }
16959
16960 static void HandleLevelEditorIdle_Drawing(void)
16961 {
16962   static boolean last_highlighted = FALSE;
16963   static boolean last_highlighted_similar = FALSE;
16964   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16965   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16966
16967   if (highlighted != last_highlighted ||
16968       (highlighted && highlighted_similar != last_highlighted_similar))
16969   {
16970     DrawAreaElementHighlight(highlighted, highlighted_similar);
16971
16972     redraw_mask |= REDRAW_FIELD;
16973   }
16974
16975   last_highlighted = highlighted;
16976   last_highlighted_similar = highlighted_similar;
16977 }
16978
16979 void HandleLevelEditorIdle(void)
16980 {
16981   if (edit_mode == ED_MODE_PROPERTIES)
16982     HandleLevelEditorIdle_Properties();
16983   else if (edit_mode == ED_MODE_DRAWING)
16984     HandleLevelEditorIdle_Drawing();
16985 }
16986
16987 static void ClearEditorGadgetInfoText(void)
16988 {
16989   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16990 }
16991
16992 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16993 {
16994   char infotext[MAX_OUTPUT_LINESIZE + 1];
16995   int max_infotext_len = getMaxInfoTextLength();
16996
16997   if (gi == NULL || strlen(gi->info_text) == 0)
16998     return;
16999
17000   strncpy(infotext, gi->info_text, max_infotext_len);
17001   infotext[max_infotext_len] = '\0';
17002
17003   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
17004   {
17005     int key = controlbutton_info[gi->custom_id].shortcut;
17006
17007     if (key)
17008     {
17009       char shortcut[MAX_OUTPUT_LINESIZE + 1];
17010
17011       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
17012         sprintf(shortcut, " ('.' or '%c')", key);
17013       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
17014         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
17015       else if (gi->custom_id == GADGET_ID_TEST)
17016         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
17017       else if (gi->custom_id == GADGET_ID_UNDO)
17018         sprintf(shortcut, " ('%c/Shift-U')", key);
17019       else if (gi->custom_id == GADGET_ID_ZOOM)
17020         sprintf(shortcut, " ('%c', '0', '-')", key);
17021       else
17022         sprintf(shortcut, " ('%s%c')",
17023                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
17024
17025       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
17026         strcat(infotext, shortcut);
17027     }
17028   }
17029
17030   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
17031 }
17032
17033 void HandleEditorGadgetInfoText(void *ptr)
17034 {
17035   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
17036
17037   if (game_status != GAME_MODE_EDITOR)
17038     return;
17039
17040   ClearEditorGadgetInfoText();
17041
17042   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
17043     return;
17044
17045   // misuse this function to delete brush cursor, if needed
17046   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
17047     DeleteBrushFromCursor();
17048
17049   PrintEditorGadgetInfoText(gi);
17050 }
17051
17052 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
17053 {
17054   int id = gi->custom_id;
17055   int type_id = gi->custom_type_id;
17056   int sx = gi->event.x;
17057   int sy = gi->event.y;
17058   int lx = sx + level_xpos;
17059   int ly = sy + level_ypos;
17060   int min_sx = 0, min_sy = 0;
17061   int max_sx = gi->drawing.area_xsize - 1;
17062   int max_sy = gi->drawing.area_ysize - 1;
17063   int actual_drawing_function = drawing_function;
17064   int max_infotext_len = getMaxInfoTextLength();
17065   char infotext[MAX_OUTPUT_LINESIZE + 1];
17066
17067   infotext[0] = '\0';           // start with empty info text
17068
17069   // pressed Control key: simulate picking element
17070   if (GetKeyModState() & KMOD_Control)
17071     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
17072
17073   ClearEditorGadgetInfoText();
17074
17075   if (gi->event.type == GD_EVENT_INFO_LEAVING)
17076     return;
17077
17078   // make sure to stay inside drawing area boundaries
17079   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
17080   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
17081
17082   if (id == GADGET_ID_DRAWING_LEVEL)
17083   {
17084     if (button_status)
17085     {
17086       int min_lx = 0, min_ly = 0;
17087       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
17088
17089       // get positions inside level field
17090       lx = sx + level_xpos;
17091       ly = sy + level_ypos;
17092
17093       // make sure to stay inside level field boundaries
17094       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
17095       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
17096
17097       // correct drawing area positions accordingly
17098       sx = lx - level_xpos;
17099       sy = ly - level_ypos;
17100     }
17101
17102     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17103     {
17104       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
17105       {
17106         static int start_lx = 0;
17107         static int start_ly = 0;
17108         char *text;
17109
17110         if (gi->event.type == GD_EVENT_PRESSED)
17111         {
17112           start_lx = lx;
17113           start_ly = ly;
17114         }
17115
17116         switch (actual_drawing_function)
17117         {
17118           case GADGET_ID_SINGLE_ITEMS:
17119             text = "Drawing single items";
17120             break;
17121           case GADGET_ID_CONNECTED_ITEMS:
17122             text = "Drawing connected items";
17123             break;
17124           case GADGET_ID_LINE:
17125             text = "Drawing line";
17126             break;
17127           case GADGET_ID_ARC:
17128             text = "Drawing arc";
17129             break;
17130           case GADGET_ID_TEXT:
17131             text = "Setting text cursor";
17132             break;
17133           case GADGET_ID_RECTANGLE:
17134             text = "Drawing rectangle";
17135             break;
17136           case GADGET_ID_FILLED_BOX:
17137             text = "Drawing filled box";
17138             break;
17139           case GADGET_ID_FLOOD_FILL:
17140             text = "Flood fill";
17141             break;
17142           case GADGET_ID_GRAB_BRUSH:
17143             text = "Grabbing brush";
17144             break;
17145           case GADGET_ID_PICK_ELEMENT:
17146             text = "Picking element";
17147             break;
17148
17149           default:
17150             text = "Drawing position";
17151             break;
17152         }
17153
17154         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17155           sprintf(infotext, "%s: %d, %d", text, lx, ly);
17156         else
17157           sprintf(infotext, "%s: %d, %d", text,
17158                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
17159       }
17160       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17161         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
17162       else
17163         sprintf(infotext, "Level position: %d, %d", lx, ly);
17164     }
17165
17166     // misuse this function to draw brush cursor, if needed
17167     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
17168     {
17169       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17170         CopyBrushToCursor(sx, sy);
17171       else
17172         DeleteBrushFromCursor();
17173     }
17174
17175     if (!draw_with_brush)
17176       UpdateBrushPosition(sx, sy);
17177   }
17178   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17179   {
17180     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
17181     int element = drawingarea_info[type_id].value[pos];
17182
17183     strncpy(infotext, getElementInfoText(element), max_infotext_len);
17184   }
17185   else
17186   {
17187     if (id == GADGET_ID_CUSTOM_CONTENT)
17188       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
17189     else if (id == GADGET_ID_GROUP_CONTENT)
17190       sprintf(infotext, "group element position: %d", sx + 1);
17191     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
17192              id <= GADGET_ID_YAMYAM_CONTENT_7)
17193       sprintf(infotext, "content area %d position: %d, %d",
17194               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
17195     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17196              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17197       sprintf(infotext, "content area %d position: %d, %d",
17198               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17199     else if (id == GADGET_ID_ANDROID_CONTENT)
17200       sprintf(infotext, "android element position: %d", sx + 1);
17201     else if (drawingarea_info[type_id].infotext != NULL)
17202       strcpy(infotext, drawingarea_info[type_id].infotext);
17203   }
17204
17205   infotext[max_infotext_len] = '\0';
17206
17207   if (strlen(infotext) > 0)
17208     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17209 }
17210
17211 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17212                             boolean quick_quit)
17213 {
17214   if (!ask_if_level_has_changed ||
17215       !LevelChanged() ||
17216       Request("Level has changed! Exit without saving?",
17217               REQ_ASK | REQ_STAY_OPEN))
17218   {
17219     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17220     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17221
17222     // draw normal door
17223     UndrawSpecialEditorDoor();
17224
17225     // use door animation if door 1 viewport is unchanged and contains toolbox
17226     if (useEditorDoorAnimation())
17227       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17228
17229     // close editor doors if viewport definition is the same as in main menu
17230     if (vp_door_1->x      == DX     &&
17231         vp_door_1->y      == DY     &&
17232         vp_door_1->width  == DXSIZE &&
17233         vp_door_1->height == DYSIZE &&
17234         vp_door_2->x      == VX     &&
17235         vp_door_2->y      == VY     &&
17236         vp_door_2->width  == VXSIZE &&
17237         vp_door_2->height == VYSIZE)
17238       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17239     else
17240       SetDoorState(DOOR_CLOSE_ALL);
17241
17242     BackToFront();
17243
17244     if (quick_quit)
17245       FadeSkipNextFadeIn();
17246
17247     SetGameStatus(GAME_MODE_MAIN);
17248
17249     DrawMainMenu();
17250   }
17251   else
17252   {
17253     if (!global.use_envelope_request)
17254     {
17255       CloseDoor(DOOR_CLOSE_1);
17256       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17257     }
17258   }
17259 }