extended support for explosion settings in BD engine to level editor
[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_WAIT_HATCHING,
753   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
754   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
755   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
756   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
757   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
758   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
759   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
760   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
761   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
762   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
763   GADGET_ID_BD_REPLICATORS_ACTIVE,
764   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
765   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
766   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
767   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
768   GADGET_ID_BD_CREATURES_START_BACKWARDS,
769   GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
770   GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
771   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
772   GADGET_ID_ENVELOPE_AUTOWRAP,
773   GADGET_ID_ENVELOPE_CENTERED,
774   GADGET_ID_MM_LASER_RED,
775   GADGET_ID_MM_LASER_GREEN,
776   GADGET_ID_MM_LASER_BLUE,
777   GADGET_ID_DF_LASER_RED,
778   GADGET_ID_DF_LASER_GREEN,
779   GADGET_ID_DF_LASER_BLUE,
780   GADGET_ID_ROTATE_MM_BALL_CONTENT,
781   GADGET_ID_EXPLODE_MM_BALL,
782   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
783   GADGET_ID_CUSTOM_CAN_EXPLODE,
784   GADGET_ID_CUSTOM_EXPLODE_FIRE,
785   GADGET_ID_CUSTOM_EXPLODE_SMASH,
786   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
787   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
788   GADGET_ID_CUSTOM_DEADLY,
789   GADGET_ID_CUSTOM_CAN_MOVE,
790   GADGET_ID_CUSTOM_CAN_FALL,
791   GADGET_ID_CUSTOM_CAN_SMASH,
792   GADGET_ID_CUSTOM_SLIPPERY,
793   GADGET_ID_CUSTOM_ACCESSIBLE,
794   GADGET_ID_CUSTOM_GRAV_REACHABLE,
795   GADGET_ID_CUSTOM_USE_LAST_VALUE,
796   GADGET_ID_CUSTOM_USE_GRAPHIC,
797   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
798   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
799   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
800   GADGET_ID_CUSTOM_CAN_CHANGE,
801   GADGET_ID_CHANGE_USE_CONTENT,
802   GADGET_ID_CHANGE_USE_EXPLOSION,
803   GADGET_ID_CHANGE_ONLY_COMPLETE,
804   GADGET_ID_CHANGE_USE_RANDOM,
805   GADGET_ID_CHANGE_HAS_ACTION,
806   GADGET_ID_CHANGE_DELAY,
807   GADGET_ID_CHANGE_BY_DIRECT_ACT,
808   GADGET_ID_CHANGE_BY_OTHER_ACT,
809
810   NUM_STATIC_GADGET_IDS
811 };
812
813 // gadgets for buttons in element list (dynamic)
814 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
815 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
816                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
817
818 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
819
820 // radio button numbers
821 enum
822 {
823   RADIO_NR_NONE,
824   RADIO_NR_DRAWING_TOOLBOX,
825   RADIO_NR_RANDOM_ELEMENTS
826 };
827
828 // values for counter gadgets
829 enum
830 {
831   ED_COUNTER_ID_SELECT_LEVEL,
832   ED_COUNTER_ID_LEVEL_XSIZE,
833   ED_COUNTER_ID_LEVEL_YSIZE,
834   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
835   ED_COUNTER_ID_LEVEL_TIMELIMIT,
836   ED_COUNTER_ID_LEVEL_TIMESCORE,
837   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
838   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
839   ED_COUNTER_ID_LEVEL_RANDOM,
840   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
841   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
842   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
843   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
844   ED_COUNTER_ID_BD_PUSHING_PROB,
845   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
846   ED_COUNTER_ID_ELEMENT_VALUE1,
847   ED_COUNTER_ID_ELEMENT_VALUE2,
848   ED_COUNTER_ID_ELEMENT_VALUE3,
849   ED_COUNTER_ID_ELEMENT_VALUE4,
850   ED_COUNTER_ID_YAMYAM_CONTENT,
851   ED_COUNTER_ID_BALL_CONTENT,
852   ED_COUNTER_ID_ANDROID_CONTENT,
853   ED_COUNTER_ID_ENVELOPE_XSIZE,
854   ED_COUNTER_ID_ENVELOPE_YSIZE,
855   ED_COUNTER_ID_INVENTORY_SIZE,
856   ED_COUNTER_ID_MM_BALL_CONTENT,
857   ED_COUNTER_ID_CUSTOM_SCORE,
858   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
859   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
860   ED_COUNTER_ID_CUSTOM_VALUE_RND,
861   ED_COUNTER_ID_PUSH_DELAY_FIX,
862   ED_COUNTER_ID_PUSH_DELAY_RND,
863   ED_COUNTER_ID_DROP_DELAY_FIX,
864   ED_COUNTER_ID_DROP_DELAY_RND,
865   ED_COUNTER_ID_MOVE_DELAY_FIX,
866   ED_COUNTER_ID_MOVE_DELAY_RND,
867   ED_COUNTER_ID_STEP_DELAY_FIX,
868   ED_COUNTER_ID_STEP_DELAY_RND,
869   ED_COUNTER_ID_EXPLOSION_DELAY,
870   ED_COUNTER_ID_IGNITION_DELAY,
871   ED_COUNTER_ID_GROUP_CONTENT,
872   ED_COUNTER_ID_CHANGE_DELAY_FIX,
873   ED_COUNTER_ID_CHANGE_DELAY_RND,
874   ED_COUNTER_ID_CHANGE_CONT_RND,
875
876   ED_NUM_COUNTERBUTTONS
877 };
878
879 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
880 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
881 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
882 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
883 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
884 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
885
886 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
887 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
888 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
889 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
890 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
891 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
892
893 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
894 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
895
896 // values for scrollbutton gadgets
897 enum
898 {
899   ED_SCROLLBUTTON_ID_AREA_UP,
900   ED_SCROLLBUTTON_ID_AREA_DOWN,
901   ED_SCROLLBUTTON_ID_AREA_LEFT,
902   ED_SCROLLBUTTON_ID_AREA_RIGHT,
903   ED_SCROLLBUTTON_ID_LIST_UP,
904   ED_SCROLLBUTTON_ID_LIST_DOWN,
905
906   ED_NUM_SCROLLBUTTONS
907 };
908
909 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
910 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
911
912 // values for scrollbar gadgets
913 enum
914 {
915   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
916   ED_SCROLLBAR_ID_AREA_VERTICAL,
917   ED_SCROLLBAR_ID_LIST_VERTICAL,
918
919   ED_NUM_SCROLLBARS
920 };
921
922 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
923 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
924
925 // values for text input gadgets
926 enum
927 {
928   ED_TEXTINPUT_ID_LEVEL_NAME,
929   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
930   ED_TEXTINPUT_ID_LEVELSET_NAME,
931   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
932   ED_TEXTINPUT_ID_ELEMENT_NAME,
933
934   ED_NUM_TEXTINPUT
935 };
936
937 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
938 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
939
940 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
941 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
942
943 // values for text area gadgets
944 enum
945 {
946   ED_TEXTAREA_ID_ENVELOPE_INFO,
947
948   ED_NUM_TEXTAREAS
949 };
950
951 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
952 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
953
954 // values for selectbox gadgets
955 enum
956 {
957   ED_SELECTBOX_ID_TIME_OR_STEPS,
958   ED_SELECTBOX_ID_TIME_SCORE_BASE,
959   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
960   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
961   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
962   ED_SELECTBOX_ID_WIND_DIRECTION,
963   ED_SELECTBOX_ID_PLAYER_SPEED,
964   ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
965   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
966   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
967   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
968   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
969   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
970   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
971   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
972   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
973   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
974   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
975   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
976   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
977   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
978   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
979   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
980   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
981   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
982   ED_SELECTBOX_ID_CHANGE_SIDE,
983   ED_SELECTBOX_ID_CHANGE_PLAYER,
984   ED_SELECTBOX_ID_CHANGE_PAGE,
985   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
986   ED_SELECTBOX_ID_ACTION_TYPE,
987   ED_SELECTBOX_ID_ACTION_MODE,
988   ED_SELECTBOX_ID_ACTION_ARG,
989   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
990   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
991
992   ED_NUM_SELECTBOX
993 };
994
995 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
996 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
997
998 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
999 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1000
1001 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1002 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1003
1004 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
1005 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
1006 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
1007 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
1008 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
1009 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
1010
1011 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
1012 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
1013
1014 // values for textbutton gadgets
1015 enum
1016 {
1017   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
1018   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1019   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1020   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1021   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1022   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1023   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1024   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1025   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1026   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1027   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1028   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1029   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1030   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1031
1032   ED_NUM_TEXTBUTTONS
1033 };
1034
1035 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1036 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1037
1038 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1039 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1040
1041 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1042 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1043
1044 // values for graphicbutton gadgets
1045 enum
1046 {
1047   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1048   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1049   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1050   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1051
1052   ED_NUM_GRAPHICBUTTONS
1053 };
1054
1055 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1056 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1057
1058 // values for checkbutton gadgets
1059 enum
1060 {
1061   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1062   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1063   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1064   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1065   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1066   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1067   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1068   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1069   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1070   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1071   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1072   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1073   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1074   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1075   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1076   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1077   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1078   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1079   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1080   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1081   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1082   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1083   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1084   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1085   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1086   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1087   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1088   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1089   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1090   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1091   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1092   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1093   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1094   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1095   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1096   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1097   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1098   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1099   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1100   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1101   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1102   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1103   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1104   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1105   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1106   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1107   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1108   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1109   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1110   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1111   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1112   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1113   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1114   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1115   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1116   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1117   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1118   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1119   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1120   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1121   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1122   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1123   ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
1124   ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
1125   ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
1126   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1127   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1128   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1129   ED_CHECKBUTTON_ID_MM_LASER_RED,
1130   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1131   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1132   ED_CHECKBUTTON_ID_DF_LASER_RED,
1133   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1134   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1135   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1136   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1137   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1138   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1139   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1140   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1141   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1142   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1143   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1144   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1145   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1146   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1147   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1148   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1149   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1150   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1151   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1152   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1153   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1154   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1155   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1156   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1157   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1158   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1159   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1160   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1161   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1162
1163   ED_NUM_CHECKBUTTONS
1164 };
1165
1166 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1167 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1168
1169 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1170 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1171
1172 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1173 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1174
1175 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1176 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
1177
1178 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1179 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1180 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1181 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1182 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1183 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1184
1185 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1186 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1187
1188 // values for radiobutton gadgets
1189 enum
1190 {
1191   ED_RADIOBUTTON_ID_PERCENTAGE,
1192   ED_RADIOBUTTON_ID_QUANTITY,
1193
1194   ED_NUM_RADIOBUTTONS
1195 };
1196
1197 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1198 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1199
1200 // values for drawing area gadgets
1201 enum
1202 {
1203   ED_DRAWING_ID_DRAWING_LEVEL,
1204   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1205   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1206   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1207   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1208   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1209   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1210   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1211   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1212   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1213   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1214   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1215   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1216   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1217   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1218   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1219   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1220   ED_DRAWING_ID_ANDROID_CONTENT,
1221   ED_DRAWING_ID_AMOEBA_CONTENT,
1222   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1223   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1224   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1225   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1226   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1227   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1228   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1229   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1230   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1231   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1232   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1233   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1234   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1235   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1236   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1237   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1238   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1239   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1240   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1241   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1242   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1243   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1244   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1245   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1246   ED_DRAWING_ID_BD_NUT_CONTENT,
1247   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1248   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1249   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
1250   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
1251   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
1252   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
1253   ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
1254   ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
1255   ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
1256   ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
1257   ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
1258   ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
1259   ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
1260   ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
1261   ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
1262   ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
1263   ED_DRAWING_ID_START_ELEMENT,
1264   ED_DRAWING_ID_ARTWORK_ELEMENT,
1265   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1266   ED_DRAWING_ID_INVENTORY_CONTENT,
1267   ED_DRAWING_ID_MM_BALL_CONTENT,
1268   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1269   ED_DRAWING_ID_CUSTOM_CONTENT,
1270   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1271   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1272   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1273   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1274   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1275   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1276   ED_DRAWING_ID_GROUP_CONTENT,
1277   ED_DRAWING_ID_RANDOM_BACKGROUND,
1278
1279   ED_NUM_DRAWING_AREAS
1280 };
1281
1282 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1283 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1284
1285
1286 // ----------------------------------------------------------------------------
1287 // some internally used definitions
1288 // ----------------------------------------------------------------------------
1289
1290 // values for CopyLevelToUndoBuffer()
1291 #define UNDO_IMMEDIATE                  0
1292 #define UNDO_ACCUMULATE                 1
1293
1294 // values for scrollbars
1295 #define ED_SCROLL_NO                    0
1296 #define ED_SCROLL_LEFT                  1
1297 #define ED_SCROLL_RIGHT                 2
1298 #define ED_SCROLL_UP                    4
1299 #define ED_SCROLL_DOWN                  8
1300
1301 // screens in the level editor
1302 #define ED_MODE_DRAWING                 0
1303 #define ED_MODE_LEVELCONFIG             1
1304 #define ED_MODE_PROPERTIES              2
1305 #define ED_MODE_PALETTE                 3
1306
1307 // sub-screens in the global settings section
1308 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1309 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1310 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1311 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1312
1313 // sub-screens in the element properties section
1314 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1315 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1316 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1317 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1318 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1319
1320 // how many steps can be cancelled
1321 #define NUM_UNDO_STEPS                  (64 + 1)
1322
1323 // values for elements with score for certain actions
1324 #define MIN_SCORE                       0
1325 #define MAX_SCORE                       999
1326
1327 // values for elements with count for collecting
1328 #define MIN_COLLECT_COUNT               0
1329 #define MAX_COLLECT_COUNT               999
1330
1331 // values for random placement
1332 #define RANDOM_USE_PERCENTAGE           0
1333 #define RANDOM_USE_QUANTITY             1
1334
1335 // values for level set save mode
1336 #define LEVELSET_SAVE_MODE_UPDATE       0
1337 #define LEVELSET_SAVE_MODE_CREATE       1
1338
1339 // default value for element tile size in drawing area
1340 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1341 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1342
1343
1344 // ----------------------------------------------------------------------------
1345 // some internally used data structure definitions
1346 // ----------------------------------------------------------------------------
1347
1348 static struct
1349 {
1350   int graphic;
1351   int gadget_id;
1352   struct XYTileSize *pos;
1353   int gadget_type;
1354   char *infotext;
1355   char shortcut;
1356 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1357 {
1358   // note: some additional characters are already reserved for "cheat mode"
1359   // shortcuts (":XYZ" style) -- for details, see "events.c"
1360
1361   // ---------- toolbox control buttons ---------------------------------------
1362
1363   {
1364     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1365     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1366     "Draw single items",                        's'
1367   },
1368   {
1369     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1370     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1371     "Draw connected items",                     'd'
1372   },
1373   {
1374     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1375     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1376     "Draw lines",                               'l'
1377   },
1378   {
1379     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1380     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1381     "Draw arcs",                                'a'
1382   },
1383   {
1384     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1385     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1386     "Draw outline rectangles",                  'r'
1387   },
1388   {
1389     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1390     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1391     "Draw filled rectangles",                   'R'
1392   },
1393   {
1394     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1395     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1396     "Wrap (rotate) level up",                   0
1397   },
1398   {
1399     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1400     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1401     "Enter text elements",                      't'
1402   },
1403   {
1404     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1405     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1406     "Flood fill",                               'f'
1407   },
1408   {
1409     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1410     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1411     "Wrap (rotate) level left",                 0
1412   },
1413   {
1414     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1415     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1416     "Zoom level tile size",                     '+'
1417   },
1418   {
1419     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1420     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1421     "Wrap (rotate) level right",                0
1422   },
1423   {
1424     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1425     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1426     "Random element placement",                 0
1427   },
1428   {
1429     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1430     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1431     "Grab brush",                               'b'
1432   },
1433   {
1434     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1435     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1436     "Wrap (rotate) level down",                 0
1437   },
1438   {
1439     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1440     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1441     "Pick drawing element",                     ','
1442   },
1443
1444   // ---------- level control buttons -----------------------------------------
1445
1446   {
1447     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1448     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1449     "Undo/redo last operation",                 'u'
1450   },
1451   {
1452     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1453     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1454     "Level and editor settings",                'I'
1455   },
1456   {
1457     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1458     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1459     "Save level",                               'S'
1460   },
1461   {
1462     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1463     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1464     "Clear level",                              'C'
1465   },
1466   {
1467     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1468     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1469     "Test level",                               'T'
1470   },
1471   {
1472     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1473     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1474     "Exit level editor",                        'E'
1475   },
1476
1477   // ---------- CE and GE control buttons -------------------------------------
1478
1479   {
1480     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1481     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1482     "Copy settings from other element",         0
1483   },
1484   {
1485     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1486     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1487     "Copy settings to other element",           0
1488   },
1489   {
1490     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1491     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1492     "Exchange element with other element",      0
1493   },
1494   {
1495     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1496     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1497     "Copy settings from this element",          0
1498   },
1499   {
1500     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1501     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1502     "Paste settings to this element",           0
1503   },
1504
1505   // ---------- palette control buttons ---------------------------------------
1506
1507   {
1508     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1509     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1510     "Properties of drawing element",            'p'
1511   },
1512   {
1513     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1514     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1515     "Properties of drawing element 1",          '1'
1516   },
1517   {
1518     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1519     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1520     "Properties of drawing element 2",          '2'
1521   },
1522   {
1523     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1524     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1525     "Properties of drawing element 3",          '3'
1526   },
1527   {
1528     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1529     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1530     "Show list of elements",                    'e'
1531   }
1532 };
1533
1534 static int random_placement_value = 10;
1535 static int random_placement_method = RANDOM_USE_QUANTITY;
1536 static int random_placement_background_element = EL_SAND;
1537 static boolean random_placement_background_restricted = FALSE;
1538 static boolean stick_element_properties_window = FALSE;
1539 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1540 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1541 static struct ElementChangeInfo custom_element_change;
1542 static struct ElementGroupInfo group_element_info;
1543 static struct ElementInfo custom_element;
1544
1545 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1546 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1547 static int levelset_num_levels = 100;
1548 static boolean levelset_use_levelset_artwork = FALSE;
1549 static boolean levelset_copy_level_template = FALSE;
1550 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1551
1552 static struct
1553 {
1554   int gadget_type_id;
1555   int x, y;
1556   int min_value, max_value;
1557   int gadget_id_down, gadget_id_up;
1558   int gadget_id_text;
1559   int gadget_id_align;
1560   int *value;
1561   char *text_above, *text_left, *text_right;
1562 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1563 {
1564   // ---------- current level number ------------------------------------------
1565
1566   {
1567     ED_COUNTER_ID_SELECT_LEVEL,
1568     -1, -1,     // these values are not constant, but can change at runtime
1569     1,                                          100,
1570     GADGET_ID_SELECT_LEVEL_DOWN,                GADGET_ID_SELECT_LEVEL_UP,
1571     GADGET_ID_SELECT_LEVEL_TEXT,                GADGET_ID_NONE,
1572     &level_nr,
1573     NULL,                                       NULL, NULL
1574   },
1575
1576   // ---------- level and editor settings -------------------------------------
1577
1578   {
1579     ED_COUNTER_ID_LEVEL_XSIZE,
1580     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1581     MIN_LEV_FIELDX,                             MAX_LEV_FIELDX,
1582     GADGET_ID_LEVEL_XSIZE_DOWN,                 GADGET_ID_LEVEL_XSIZE_UP,
1583     GADGET_ID_LEVEL_XSIZE_TEXT,                 GADGET_ID_NONE,
1584     &level.fieldx,
1585     "Playfield size:",                          NULL, "Width",
1586   },
1587   {
1588     ED_COUNTER_ID_LEVEL_YSIZE,
1589     -1,                                         ED_LEVEL_SETTINGS_YPOS(4),
1590     MIN_LEV_FIELDY,                             MAX_LEV_FIELDY,
1591     GADGET_ID_LEVEL_YSIZE_DOWN,                 GADGET_ID_LEVEL_YSIZE_UP,
1592     GADGET_ID_LEVEL_YSIZE_TEXT,                 GADGET_ID_LEVEL_XSIZE_UP,
1593     &level.fieldy,
1594     NULL,                                       " ", "Height",
1595   },
1596   {
1597     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1598     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
1599     0,                                          999,
1600     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,             GADGET_ID_LEVEL_GEMSLIMIT_UP,
1601     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,             GADGET_ID_NONE,
1602     &level.gems_needed,
1603     NULL,                                       "Number of gems to collect:", NULL
1604   },
1605   {
1606     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1607     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
1608     0,                                          9999,
1609     GADGET_ID_LEVEL_TIMELIMIT_DOWN,             GADGET_ID_LEVEL_TIMELIMIT_UP,
1610     GADGET_ID_LEVEL_TIMELIMIT_TEXT,             GADGET_ID_NONE,
1611     &level.time,
1612     "Time or step limit to solve level:",       NULL, NULL
1613   },
1614   {
1615     ED_COUNTER_ID_LEVEL_TIMESCORE,
1616     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
1617     0,                                          999,
1618     GADGET_ID_LEVEL_TIMESCORE_DOWN,             GADGET_ID_LEVEL_TIMESCORE_UP,
1619     GADGET_ID_LEVEL_TIMESCORE_TEXT,             GADGET_ID_NONE,
1620     &level.score[SC_TIME_BONUS],
1621     "Score for time or steps left:",            NULL, NULL
1622   },
1623   {
1624     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1625     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(13),
1626     0,                                          9999,
1627     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,           GADGET_ID_LEVEL_RANDOM_SEED_UP,
1628     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,           GADGET_ID_NONE,
1629     &level.random_seed,
1630     NULL,                                       "Random seed:", "(0 => random)"
1631   },
1632   {
1633     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1634     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1635     1,                                          MAX_LEVELS,
1636     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,         GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1637     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,         GADGET_ID_NONE,
1638     &levelset_num_levels,
1639     "Number of levels:",                        NULL, NULL,
1640   },
1641   {
1642     ED_COUNTER_ID_LEVEL_RANDOM,
1643     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1644     1,                                          100,
1645     GADGET_ID_LEVEL_RANDOM_DOWN,                GADGET_ID_LEVEL_RANDOM_UP,
1646     GADGET_ID_LEVEL_RANDOM_TEXT,                GADGET_ID_NONE,
1647     &random_placement_value,
1648     "Random element placement:",                NULL, "in"
1649   },
1650   {
1651     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1652     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1653     50,                                         500,
1654     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,           GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1655     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,           GADGET_ID_NONE,
1656     &level.bd_cycle_delay_ms,
1657     NULL,                                       NULL, "Game cycle delay (ms)"
1658   },
1659   {
1660     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1661     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1662     0,                                          32,
1663     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,          GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1664     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,          GADGET_ID_NONE,
1665     &level.bd_cycle_delay_c64,
1666     NULL,                                       NULL, "Game cycle delay (C64-style)"
1667   },
1668   {
1669     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1670     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1671     1,                                          40,
1672     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1673     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1674     &level.bd_hatching_delay_cycles,
1675     NULL,                                       NULL, "Hatching delay (cycles)"
1676   },
1677   {
1678     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1679     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1680     1,                                          40,
1681     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1682     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1683     &level.bd_hatching_delay_seconds,
1684     NULL,                                       NULL, "Hatching delay (seconds)"
1685   },
1686
1687   // ---------- element settings: configure (various elements) ----------------
1688
1689   {
1690     ED_COUNTER_ID_BD_PUSHING_PROB,
1691     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1692     0,                                          100,
1693     GADGET_ID_BD_PUSHING_PROB_DOWN,             GADGET_ID_BD_PUSHING_PROB_UP,
1694     GADGET_ID_BD_PUSHING_PROB_TEXT,             GADGET_ID_NONE,
1695     &level.bd_pushing_prob,
1696     NULL,                                       NULL, "Push probability"
1697   },
1698   {
1699     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1700     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1701     0,                                          100,
1702     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1703     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1704     &level.bd_pushing_prob_with_sweet,
1705     NULL,                                       NULL, "Push probability with sweet"
1706   },
1707   {
1708     ED_COUNTER_ID_ELEMENT_VALUE1,
1709     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1710     MIN_SCORE,                                  MAX_SCORE,
1711     GADGET_ID_ELEMENT_VALUE1_DOWN,              GADGET_ID_ELEMENT_VALUE1_UP,
1712     GADGET_ID_ELEMENT_VALUE1_TEXT,              GADGET_ID_NONE,
1713     NULL,                                       // will be set when used
1714     NULL,                                       NULL, NULL
1715   },
1716   {
1717     ED_COUNTER_ID_ELEMENT_VALUE2,
1718     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
1719     MIN_SCORE,                                  MAX_SCORE,
1720     GADGET_ID_ELEMENT_VALUE2_DOWN,              GADGET_ID_ELEMENT_VALUE2_UP,
1721     GADGET_ID_ELEMENT_VALUE2_TEXT,              GADGET_ID_NONE,
1722     NULL,                                       // will be set when used
1723     NULL,                                       NULL, NULL
1724   },
1725   {
1726     ED_COUNTER_ID_ELEMENT_VALUE3,
1727     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1728     MIN_SCORE,                                  MAX_SCORE,
1729     GADGET_ID_ELEMENT_VALUE3_DOWN,              GADGET_ID_ELEMENT_VALUE3_UP,
1730     GADGET_ID_ELEMENT_VALUE3_TEXT,              GADGET_ID_NONE,
1731     NULL,                                       // will be set when used
1732     NULL,                                       NULL, NULL
1733   },
1734   {
1735     ED_COUNTER_ID_ELEMENT_VALUE4,
1736     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1737     MIN_SCORE,                                  MAX_SCORE,
1738     GADGET_ID_ELEMENT_VALUE4_DOWN,              GADGET_ID_ELEMENT_VALUE4_UP,
1739     GADGET_ID_ELEMENT_VALUE4_TEXT,              GADGET_ID_NONE,
1740     NULL,                                       // will be set when used
1741     NULL,                                       NULL, NULL
1742   },
1743   {
1744     ED_COUNTER_ID_YAMYAM_CONTENT,
1745     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1746     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1747     GADGET_ID_YAMYAM_CONTENT_DOWN,              GADGET_ID_YAMYAM_CONTENT_UP,
1748     GADGET_ID_YAMYAM_CONTENT_TEXT,              GADGET_ID_NONE,
1749     &level.num_yamyam_contents,
1750     NULL,                                       NULL, "Number of content areas"
1751   },
1752   {
1753     ED_COUNTER_ID_BALL_CONTENT,
1754     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1755     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1756     GADGET_ID_BALL_CONTENT_DOWN,                GADGET_ID_BALL_CONTENT_UP,
1757     GADGET_ID_BALL_CONTENT_TEXT,                GADGET_ID_NONE,
1758     &level.num_ball_contents,
1759     NULL,                                       NULL, "Number of content areas"
1760   },
1761   {
1762     ED_COUNTER_ID_ANDROID_CONTENT,
1763     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1764     MIN_ANDROID_ELEMENTS,                       MAX_ANDROID_ELEMENTS,
1765     GADGET_ID_ANDROID_CONTENT_DOWN,             GADGET_ID_ANDROID_CONTENT_UP,
1766     GADGET_ID_ANDROID_CONTENT_TEXT,             GADGET_ID_NONE,
1767     &level.num_android_clone_elements,
1768     NULL,                                       NULL, "Number of clonable elements"
1769   },
1770   {
1771     ED_COUNTER_ID_ENVELOPE_XSIZE,
1772     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1773     MIN_ENVELOPE_XSIZE,                         MAX_ENVELOPE_XSIZE,
1774     GADGET_ID_ENVELOPE_XSIZE_DOWN,              GADGET_ID_ENVELOPE_XSIZE_UP,
1775     GADGET_ID_ENVELOPE_XSIZE_TEXT,              GADGET_ID_NONE,
1776     NULL,                                       // will be set when used
1777     NULL,                                       NULL, "Width",
1778   },
1779   {
1780     ED_COUNTER_ID_ENVELOPE_YSIZE,
1781     -1,                                         ED_ELEMENT_SETTINGS_YPOS(0),
1782     MIN_ENVELOPE_YSIZE,                         MAX_ENVELOPE_YSIZE,
1783     GADGET_ID_ENVELOPE_YSIZE_DOWN,              GADGET_ID_ENVELOPE_YSIZE_UP,
1784     GADGET_ID_ENVELOPE_YSIZE_TEXT,              GADGET_ID_ENVELOPE_XSIZE_UP,
1785     NULL,                                       // will be set when used
1786     NULL,                                       " ", "Height",
1787   },
1788   {
1789     ED_COUNTER_ID_INVENTORY_SIZE,
1790     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1791     MIN_INITIAL_INVENTORY_SIZE,                 MAX_INITIAL_INVENTORY_SIZE,
1792     GADGET_ID_INVENTORY_SIZE_DOWN,              GADGET_ID_INVENTORY_SIZE_UP,
1793     GADGET_ID_INVENTORY_SIZE_TEXT,              GADGET_ID_NONE,
1794     &level.initial_inventory_size[0],
1795     NULL,                                       NULL, "Number of inventory elements"
1796   },
1797   {
1798     ED_COUNTER_ID_MM_BALL_CONTENT,
1799     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1800     MIN_ELEMENTS_IN_GROUP,                      MAX_MM_BALL_CONTENTS,
1801     GADGET_ID_MM_BALL_CONTENT_DOWN,             GADGET_ID_MM_BALL_CONTENT_UP,
1802     GADGET_ID_MM_BALL_CONTENT_TEXT,             GADGET_ID_NONE,
1803     &level.num_mm_ball_contents,
1804     NULL,                                       NULL, "Number of content elements"
1805   },
1806
1807   // ---------- element settings: configure 1 (custom elements) ---------------
1808
1809   {
1810     ED_COUNTER_ID_CUSTOM_SCORE,
1811     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1812     MIN_SCORE,                                  MAX_SCORE,
1813     GADGET_ID_CUSTOM_SCORE_DOWN,                GADGET_ID_CUSTOM_SCORE_UP,
1814     GADGET_ID_CUSTOM_SCORE_TEXT,                GADGET_ID_NONE,
1815     &custom_element.collect_score_initial,
1816     NULL,                                       "CE score", " "
1817   },
1818   {
1819     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1820     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1821     MIN_COLLECT_COUNT,                          MAX_COLLECT_COUNT,
1822     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,             GADGET_ID_CUSTOM_GEMCOUNT_UP,
1823     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,             GADGET_ID_CUSTOM_SCORE_UP,
1824     &custom_element.collect_count_initial,
1825     NULL,                                       "CE count", NULL
1826   },
1827   {
1828     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1829     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1830     0,                                          9999,
1831     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1832     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,            GADGET_ID_NONE,
1833     &custom_element.ce_value_fixed_initial,
1834     NULL,                                       "CE value", NULL
1835   },
1836   {
1837     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1838     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1839     0,                                          9999,
1840     GADGET_ID_CUSTOM_VALUE_RND_DOWN,            GADGET_ID_CUSTOM_VALUE_RND_UP,
1841     GADGET_ID_CUSTOM_VALUE_RND_TEXT,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1842     &custom_element.ce_value_random_initial,
1843     NULL,                                       "+random", NULL
1844   },
1845   {
1846     ED_COUNTER_ID_PUSH_DELAY_FIX,
1847     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1848     0,                                          999,
1849     GADGET_ID_PUSH_DELAY_FIX_DOWN,              GADGET_ID_PUSH_DELAY_FIX_UP,
1850     GADGET_ID_PUSH_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1851     &custom_element.push_delay_fixed,
1852     NULL,                                       "Push delay", NULL
1853   },
1854   {
1855     ED_COUNTER_ID_PUSH_DELAY_RND,
1856     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1857     0,                                          999,
1858     GADGET_ID_PUSH_DELAY_RND_DOWN,              GADGET_ID_PUSH_DELAY_RND_UP,
1859     GADGET_ID_PUSH_DELAY_RND_TEXT,              GADGET_ID_PUSH_DELAY_FIX_UP,
1860     &custom_element.push_delay_random,
1861     NULL,                                       "+random", NULL
1862   },
1863   {
1864     ED_COUNTER_ID_DROP_DELAY_FIX,
1865     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(7),
1866     0,                                          999,
1867     GADGET_ID_DROP_DELAY_FIX_DOWN,              GADGET_ID_DROP_DELAY_FIX_UP,
1868     GADGET_ID_DROP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1869     &custom_element.drop_delay_fixed,
1870     NULL,                                       "Drop delay", NULL
1871   },
1872   {
1873     ED_COUNTER_ID_DROP_DELAY_RND,
1874     -1,                                         ED_ELEMENT_SETTINGS_YPOS(7),
1875     0,                                          999,
1876     GADGET_ID_DROP_DELAY_RND_DOWN,              GADGET_ID_DROP_DELAY_RND_UP,
1877     GADGET_ID_DROP_DELAY_RND_TEXT,              GADGET_ID_DROP_DELAY_FIX_UP,
1878     &custom_element.drop_delay_random,
1879     NULL,                                       "+random", NULL
1880   },
1881
1882   // ---------- element settings: configure 2 (custom elements) ---------------
1883
1884   {
1885     ED_COUNTER_ID_MOVE_DELAY_FIX,
1886     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1887     0,                                          999,
1888     GADGET_ID_MOVE_DELAY_FIX_DOWN,              GADGET_ID_MOVE_DELAY_FIX_UP,
1889     GADGET_ID_MOVE_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1890     &custom_element.move_delay_fixed,
1891     NULL,                                       "Move delay", NULL
1892   },
1893   {
1894     ED_COUNTER_ID_MOVE_DELAY_RND,
1895     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1896     0,                                          999,
1897     GADGET_ID_MOVE_DELAY_RND_DOWN,              GADGET_ID_MOVE_DELAY_RND_UP,
1898     GADGET_ID_MOVE_DELAY_RND_TEXT,              GADGET_ID_MOVE_DELAY_FIX_UP,
1899     &custom_element.move_delay_random,
1900     NULL,                                       "+random", NULL
1901   },
1902   {
1903     ED_COUNTER_ID_STEP_DELAY_FIX,
1904     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1905     0,                                          999,
1906     GADGET_ID_STEP_DELAY_FIX_DOWN,              GADGET_ID_STEP_DELAY_FIX_UP,
1907     GADGET_ID_STEP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1908     &custom_element.step_delay_fixed,
1909     NULL,                                       "Step delay", NULL
1910   },
1911   {
1912     ED_COUNTER_ID_STEP_DELAY_RND,
1913     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1914     0,                                          999,
1915     GADGET_ID_STEP_DELAY_RND_DOWN,              GADGET_ID_STEP_DELAY_RND_UP,
1916     GADGET_ID_STEP_DELAY_RND_TEXT,              GADGET_ID_STEP_DELAY_FIX_UP,
1917     &custom_element.step_delay_random,
1918     NULL,                                       "+random", NULL
1919   },
1920   {
1921     ED_COUNTER_ID_EXPLOSION_DELAY,
1922     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
1923     0,                                          999,
1924     GADGET_ID_EXPLOSION_DELAY_DOWN,             GADGET_ID_EXPLOSION_DELAY_UP,
1925     GADGET_ID_EXPLOSION_DELAY_TEXT,             GADGET_ID_NONE,
1926     &custom_element.explosion_delay,
1927     NULL,                                       "Explosion delay", NULL
1928   },
1929   {
1930     ED_COUNTER_ID_IGNITION_DELAY,
1931     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
1932     0,                                          999,
1933     GADGET_ID_IGNITION_DELAY_DOWN,              GADGET_ID_IGNITION_DELAY_UP,
1934     GADGET_ID_IGNITION_DELAY_TEXT,              GADGET_ID_NONE,
1935     &custom_element.ignition_delay,
1936     NULL,                                       "Ignition delay", "(by fire)"
1937   },
1938
1939   // ---------- element settings: configure (group elements) ------------------
1940
1941   {
1942     ED_COUNTER_ID_GROUP_CONTENT,
1943     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1944     MIN_ELEMENTS_IN_GROUP,                      MAX_ELEMENTS_IN_GROUP,
1945     GADGET_ID_GROUP_CONTENT_DOWN,               GADGET_ID_GROUP_CONTENT_UP,
1946     GADGET_ID_GROUP_CONTENT_TEXT,               GADGET_ID_NONE,
1947     &group_element_info.num_elements,
1948     NULL,                                       NULL, "Number of elements in group"
1949   },
1950
1951   // ---------- element settings: advanced (custom elements) ------------------
1952
1953   {
1954     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1955     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(2),
1956     0,                                          999,
1957     GADGET_ID_CHANGE_DELAY_FIX_DOWN,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1958     GADGET_ID_CHANGE_DELAY_FIX_TEXT,            GADGET_ID_NONE,
1959     &custom_element_change.delay_fixed,
1960     NULL,                                       "CE delay", NULL,
1961   },
1962   {
1963     ED_COUNTER_ID_CHANGE_DELAY_RND,
1964     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
1965     0,                                          999,
1966     GADGET_ID_CHANGE_DELAY_RND_DOWN,            GADGET_ID_CHANGE_DELAY_RND_UP,
1967     GADGET_ID_CHANGE_DELAY_RND_TEXT,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1968     &custom_element_change.delay_random,
1969     NULL,                                       "+random", NULL
1970   },
1971   {
1972     ED_COUNTER_ID_CHANGE_CONT_RND,
1973     ED_ELEMENT_SETTINGS_XPOS(3),                ED_ELEMENT_SETTINGS_YPOS(12),
1974     0,                                          100,
1975     GADGET_ID_CHANGE_CONT_RND_DOWN,             GADGET_ID_CHANGE_CONT_RND_UP,
1976     GADGET_ID_CHANGE_CONT_RND_TEXT,             GADGET_ID_NONE,
1977     &custom_element_change.random_percentage,
1978     NULL,                                       "Use random replace:", "%"
1979   },
1980 };
1981
1982 static struct
1983 {
1984   int gadget_type_id;
1985   int x, y;
1986   int gadget_id;
1987   int size;
1988   char *value;
1989   char *text_above, *infotext;
1990 } textinput_info[ED_NUM_TEXTINPUT] =
1991 {
1992   {
1993     ED_TEXTINPUT_ID_LEVEL_NAME,
1994     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1995     GADGET_ID_LEVEL_NAME,
1996     MAX_LEVEL_NAME_LEN,
1997     level.name,
1998     "Title:", "Title for this level"
1999   },
2000   {
2001     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
2002     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2003     GADGET_ID_LEVEL_AUTHOR,
2004     MAX_LEVEL_AUTHOR_LEN,
2005     level.author,
2006     "Author:", "Author for this level"
2007   },
2008   {
2009     ED_TEXTINPUT_ID_LEVELSET_NAME,
2010     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
2011     GADGET_ID_LEVELSET_NAME,
2012     MAX_LEVEL_NAME_LEN,
2013     levelset_name,
2014     "Title:", "Title for this or new level set"
2015   },
2016   {
2017     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
2018     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2019     GADGET_ID_LEVELSET_AUTHOR,
2020     MAX_LEVEL_AUTHOR_LEN,
2021     levelset_author,
2022     "Author:", "Author for this or new level set"
2023   },
2024   {
2025     ED_TEXTINPUT_ID_ELEMENT_NAME,
2026     -1, -1,     // these values are not constant, but can change at runtime
2027     GADGET_ID_ELEMENT_NAME,
2028     MAX_ELEMENT_NAME_LEN - 2,                   // currently 2 chars less editable
2029     custom_element.description,
2030     NULL, "Element name"
2031   }
2032 };
2033
2034 static struct
2035 {
2036   int gadget_type_id;
2037   int x, y;
2038   int gadget_id;
2039   int xsize, ysize;
2040   char *value;
2041   char *text_above, *text_above_cropped, *infotext;
2042 } textarea_info[ED_NUM_TEXTAREAS] =
2043 {
2044   {
2045     ED_TEXTAREA_ID_ENVELOPE_INFO,
2046     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
2047     GADGET_ID_ENVELOPE_INFO,
2048     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2049     NULL,
2050     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2051   }
2052 };
2053
2054 static struct ValueTextInfo options_time_or_steps[] =
2055 {
2056   { 0,                                  "seconds"                       },
2057   { 1,                                  "steps"                         },
2058
2059   { -1,                                 NULL                            }
2060 };
2061
2062 static struct ValueTextInfo options_time_score_base[] =
2063 {
2064   { 1,                                  "per second/step"               },
2065   { 10,                                 "per 10 seconds/steps"          },
2066
2067   { -1,                                 NULL                            }
2068 };
2069
2070 static struct ValueTextInfo options_game_engine_type[] =
2071 {
2072   { GAME_ENGINE_TYPE_RND,               "Rocks'n'Diamonds"              },
2073   { GAME_ENGINE_TYPE_BD,                "Boulder Dash"                  },
2074   { GAME_ENGINE_TYPE_EM,                "Emerald Mine"                  },
2075   { GAME_ENGINE_TYPE_SP,                "Supaplex"                      },
2076   { GAME_ENGINE_TYPE_MM,                "Mirror Magic"                  },
2077
2078   { -1,                                 NULL                            }
2079 };
2080
2081 static struct ValueTextInfo options_levelset_save_mode[] =
2082 {
2083   { LEVELSET_SAVE_MODE_UPDATE,          "Update this level set"         },
2084   { LEVELSET_SAVE_MODE_CREATE,          "Create new level set"          },
2085
2086   { -1,                                 NULL                            }
2087 };
2088
2089 static struct ValueTextInfo options_bd_gravity_direction[] =
2090 {
2091   { GD_MV_DOWN,                         "down"                          },
2092   { GD_MV_UP,                           "up"                            },
2093   { GD_MV_LEFT,                         "left"                          },
2094   { GD_MV_RIGHT,                        "right"                         },
2095
2096   { -1,                                 NULL                            }
2097 };
2098
2099 static struct ValueTextInfo options_wind_direction[] =
2100 {
2101   { MV_START_NONE,                      "none"                          },
2102   { MV_START_LEFT,                      "left"                          },
2103   { MV_START_RIGHT,                     "right"                         },
2104   { MV_START_UP,                        "up"                            },
2105   { MV_START_DOWN,                      "down"                          },
2106
2107   { -1,                                 NULL                            }
2108 };
2109
2110 static struct ValueTextInfo options_player_speed[] =
2111 {
2112   { 0,                                  "frozen"                        },
2113   { 1,                                  "very slow"                     },
2114   { 2,                                  "slow"                          },
2115   { 4,                                  "normal"                        },
2116   { 8,                                  "fast"                          },
2117   { 16,                                 "very fast"                     },
2118   { 32,                                 "ultrafast"                     },
2119
2120   { -1,                                 NULL                            }
2121 };
2122
2123 static struct ValueTextInfo options_access_type[] =
2124 {
2125   { EP_WALKABLE,                        "walkable"                      },
2126   { EP_PASSABLE,                        "passable"                      },
2127
2128   { -1,                                 NULL                            }
2129 };
2130
2131 static struct ValueTextInfo options_access_layer[] =
2132 {
2133   { EP_ACCESSIBLE_OVER,                 "over"                          },
2134   { EP_ACCESSIBLE_INSIDE,               "inside"                        },
2135   { EP_ACCESSIBLE_UNDER,                "under"                         },
2136
2137   { -1,                                 NULL                            }
2138 };
2139
2140 static struct ValueTextInfo options_access_protected[] =
2141 {
2142   { 0,                                  "unprotected"                   },
2143   { 1,                                  "protected"                     },
2144
2145   { -1,                                 NULL                            }
2146 };
2147
2148 static struct ValueTextInfo options_access_direction[] =
2149 {
2150   { MV_NO_DIRECTION,                    "no direction"                  },
2151   { MV_LEFT,                            "left"                          },
2152   { MV_RIGHT,                           "right"                         },
2153   { MV_UP,                              "up"                            },
2154   { MV_DOWN,                            "down"                          },
2155   { MV_LEFT  | MV_UP,                   "left + up"                     },
2156   { MV_LEFT  | MV_DOWN,                 "left + down"                   },
2157   { MV_RIGHT | MV_UP,                   "right + up"                    },
2158   { MV_RIGHT | MV_DOWN,                 "right + down"                  },
2159   { MV_HORIZONTAL,                      "horizontal"                    },
2160   { MV_VERTICAL,                        "vertical"                      },
2161   { MV_HORIZONTAL | MV_UP,              "horizontal + up"               },
2162   { MV_HORIZONTAL | MV_DOWN,            "horizontal + down"             },
2163   { MV_VERTICAL   | MV_LEFT,            "vertical + left"               },
2164   { MV_VERTICAL   | MV_RIGHT,           "vertical + right"              },
2165   { MV_ALL_DIRECTIONS,                  "all directions"                },
2166
2167   { -1,                                 NULL                            }
2168 };
2169
2170 static struct ValueTextInfo options_walk_to_action[] =
2171 {
2172   { EP_DIGGABLE,                        "diggable"                      },
2173   { EP_COLLECTIBLE_ONLY,                "collectible"                   },
2174   { EP_DROPPABLE,                       "collectible & droppable"       },
2175   { EP_THROWABLE,                       "collectible & throwable"       },
2176   { EP_PUSHABLE,                        "pushable"                      },
2177
2178   { -1,                                 NULL                            }
2179 };
2180
2181 static struct ValueTextInfo options_move_pattern[] =
2182 {
2183   { MV_LEFT,                            "left"                          },
2184   { MV_RIGHT,                           "right"                         },
2185   { MV_UP,                              "up"                            },
2186   { MV_DOWN,                            "down"                          },
2187   { MV_HORIZONTAL,                      "horizontal"                    },
2188   { MV_VERTICAL,                        "vertical"                      },
2189   { MV_ALL_DIRECTIONS,                  "all directions"                },
2190   { MV_WIND_DIRECTION,                  "wind direction"                },
2191   { MV_TOWARDS_PLAYER,                  "towards player"                },
2192   { MV_AWAY_FROM_PLAYER,                "away from player"              },
2193   { MV_ALONG_LEFT_SIDE,                 "along left side"               },
2194   { MV_ALONG_RIGHT_SIDE,                "along right side"              },
2195   { MV_TURNING_LEFT,                    "turning left"                  },
2196   { MV_TURNING_RIGHT,                   "turning right"                 },
2197   { MV_TURNING_LEFT_RIGHT,              "turning left, right"           },
2198   { MV_TURNING_RIGHT_LEFT,              "turning right, left"           },
2199   { MV_TURNING_RANDOM,                  "turning random"                },
2200   { MV_MAZE_RUNNER,                     "maze runner style"             },
2201   { MV_MAZE_HUNTER,                     "maze hunter style"             },
2202   { MV_WHEN_PUSHED,                     "when pushed"                   },
2203   { MV_WHEN_DROPPED,                    "when dropped/thrown"           },
2204
2205   { -1,                                 NULL                            }
2206 };
2207
2208 static struct ValueTextInfo options_move_direction[] =
2209 {
2210   { MV_START_AUTOMATIC,                 "automatic"                     },
2211   { MV_START_LEFT,                      "left"                          },
2212   { MV_START_RIGHT,                     "right"                         },
2213   { MV_START_UP,                        "up"                            },
2214   { MV_START_DOWN,                      "down"                          },
2215   { MV_START_RANDOM,                    "random"                        },
2216   { MV_START_PREVIOUS,                  "previous"                      },
2217
2218   { -1,                                 NULL                            }
2219 };
2220
2221 static struct ValueTextInfo options_move_stepsize[] =
2222 {
2223   { 0,                                  "not moving"                    },
2224   { 1,                                  "very slow"                     },
2225   { 2,                                  "slow"                          },
2226   { 4,                                  "normal"                        },
2227   { 8,                                  "fast"                          },
2228   { 16,                                 "very fast"                     },
2229   { 32,                                 "even faster"                   },
2230
2231   { -1,                                 NULL                            }
2232 };
2233
2234 static struct ValueTextInfo options_move_leave_type[] =
2235 {
2236   { LEAVE_TYPE_UNLIMITED,               "leave behind"                  },
2237   { LEAVE_TYPE_LIMITED,                 "change it to"                  },
2238
2239   { -1,                                 NULL                            }
2240 };
2241
2242 static struct ValueTextInfo options_smash_targets[] =
2243 {
2244   { EP_CAN_SMASH_PLAYER,                "player"                        },
2245 #if 0
2246   { EP_CAN_SMASH_ENEMIES,               "enemies"                       },
2247 #endif
2248   { EP_CAN_SMASH_EVERYTHING,            "everything"                    },
2249
2250   { -1,                                 NULL                            }
2251 };
2252
2253 static struct ValueTextInfo options_slippery_type[] =
2254 {
2255   { SLIPPERY_ANY_RANDOM,                "random"                        },
2256   { SLIPPERY_ANY_LEFT_RIGHT,            "left, right"                   },
2257   { SLIPPERY_ANY_RIGHT_LEFT,            "right, left"                   },
2258   { SLIPPERY_ONLY_LEFT,                 "only left"                     },
2259   { SLIPPERY_ONLY_RIGHT,                "only right"                    },
2260
2261   { -1,                                 NULL                            }
2262 };
2263
2264 static struct ValueTextInfo options_deadliness[] =
2265 {
2266   { EP_DONT_RUN_INTO,                   "running into"                  },
2267   { EP_DONT_COLLIDE_WITH,               "colliding with"                },
2268   { EP_DONT_GET_HIT_BY,                 "getting hit by"                },
2269   { EP_DONT_TOUCH,                      "touching"                      },
2270
2271   { -1,                                 NULL                            }
2272 };
2273
2274 static struct ValueTextInfo options_explosion_type[] =
2275 {
2276   { EXPLODES_3X3,                       "3x3"                           },
2277   { EXPLODES_CROSS,                     "3+3"                           },
2278   { EXPLODES_1X1,                       "1x1"                           },
2279
2280   { -1,                                 NULL                            }
2281 };
2282
2283 static struct ValueTextInfo options_time_units[] =
2284 {
2285   { 1,                                  "frames"                        },
2286   { FRAMES_PER_SECOND,                  "seconds"                       },
2287
2288   { -1,                                 NULL                            }
2289 };
2290
2291 static struct ValueTextInfo options_change_direct_action[] =
2292 {
2293   { CE_TOUCHED_BY_PLAYER,               "touched by player"             },
2294   { CE_PRESSED_BY_PLAYER,               "pressed by player"             },
2295   { CE_SWITCHED_BY_PLAYER,              "switched by player"            },
2296   { CE_SNAPPED_BY_PLAYER,               "snapped by player"             },
2297   { CE_PUSHED_BY_PLAYER,                "pushed by player"              },
2298   { CE_ENTERED_BY_PLAYER,               "entered by player"             },
2299   { CE_LEFT_BY_PLAYER,                  "left by player"                },
2300   { CE_DROPPED_BY_PLAYER,               "dropped/thrown by player"      },
2301   { CE_SWITCHED,                        "switched"                      },
2302   { CE_HITTING_SOMETHING,               "hitting something"             },
2303   { CE_HIT_BY_SOMETHING,                "hit by something"              },
2304 #if 0
2305   { CE_BLOCKED,                         "blocked"                       },
2306 #endif
2307   { CE_IMPACT,                          "impact (on something)"         },
2308   { CE_SMASHED,                         "smashed (from above)"          },
2309 #if 0
2310   { CE_VALUE_CHANGES,                   "CE value changes"              },
2311   { CE_SCORE_CHANGES,                   "CE score changes"              },
2312 #endif
2313   { CE_VALUE_GETS_ZERO,                 "CE value gets 0"               },
2314   { CE_SCORE_GETS_ZERO,                 "CE score gets 0"               },
2315   { CE_UNDEFINED,                       " "                             },
2316   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2317   { CE_CLICKED_BY_MOUSE,                "clicked by mouse"              },
2318   { CE_PRESSED_BY_MOUSE,                "pressed by mouse"              },
2319   { CE_UNDEFINED,                       " "                             },
2320   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2321   { CE_NEXT_TO_PLAYER,                  "next to player"                },
2322
2323   { -1,                                 NULL                            }
2324 };
2325
2326 static struct ValueTextInfo options_change_other_action[] =
2327 {
2328   { CE_PLAYER_TOUCHES_X,                "player touches"                },
2329   { CE_PLAYER_PRESSES_X,                "player presses"                },
2330   { CE_PLAYER_SWITCHES_X,               "player switches"               },
2331   { CE_PLAYER_SNAPS_X,                  "player snaps"                  },
2332   { CE_PLAYER_PUSHES_X,                 "player pushes"                 },
2333   { CE_PLAYER_ENTERS_X,                 "player enters"                 },
2334   { CE_PLAYER_LEAVES_X,                 "player leaves"                 },
2335   { CE_PLAYER_DIGS_X,                   "player digs"                   },
2336   { CE_PLAYER_COLLECTS_X,               "player collects"               },
2337   { CE_PLAYER_DROPS_X,                  "player drops/throws"           },
2338   { CE_TOUCHING_X,                      "touching"                      },
2339   { CE_HITTING_X,                       "hitting"                       },
2340   { CE_DIGGING_X,                       "digging"                       },
2341   { CE_HIT_BY_X,                        "hit by"                        },
2342   { CE_SWITCH_OF_X,                     "switch of"                     },
2343   { CE_CHANGE_OF_X,                     "change by page of"             },
2344   { CE_EXPLOSION_OF_X,                  "explosion of"                  },
2345   { CE_MOVE_OF_X,                       "move of"                       },
2346   { CE_CREATION_OF_X,                   "creation of"                   },
2347   { CE_VALUE_CHANGES_OF_X,              "CE value changes of"           },
2348   { CE_SCORE_CHANGES_OF_X,              "CE score changes of"           },
2349   { CE_VALUE_GETS_ZERO_OF_X,            "CE value gets 0 of"            },
2350   { CE_SCORE_GETS_ZERO_OF_X,            "CE score gets 0 of"            },
2351   { CE_UNDEFINED,                       " "                             },
2352   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2353   { CE_MOUSE_CLICKED_ON_X,              "mouse clicked on"              },
2354   { CE_MOUSE_PRESSED_ON_X,              "mouse pressed on"              },
2355   { CE_UNDEFINED,                       " "                             },
2356   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2357   { CE_PLAYER_NEXT_TO_X,                "player next to"                },
2358   { CE_NEXT_TO_X,                       "next to"                       },
2359
2360   { -1,                                 NULL                            }
2361 };
2362
2363 static struct ValueTextInfo options_change_trigger_side[] =
2364 {
2365   { CH_SIDE_LEFT,                       "left"                          },
2366   { CH_SIDE_RIGHT,                      "right"                         },
2367   { CH_SIDE_TOP,                        "top"                           },
2368   { CH_SIDE_BOTTOM,                     "bottom"                        },
2369   { CH_SIDE_LEFT_RIGHT,                 "left/right"                    },
2370   { CH_SIDE_TOP_BOTTOM,                 "top/bottom"                    },
2371   { CH_SIDE_ANY,                        "any"                           },
2372
2373   { -1,                                 NULL                            }
2374 };
2375
2376 static struct ValueTextInfo options_change_trigger_player[] =
2377 {
2378   { CH_PLAYER_1,                        "1"                             },
2379   { CH_PLAYER_2,                        "2"                             },
2380   { CH_PLAYER_3,                        "3"                             },
2381   { CH_PLAYER_4,                        "4"                             },
2382   { CH_PLAYER_ANY,                      "any"                           },
2383
2384   { -1,                                 NULL                            }
2385 };
2386
2387 static struct ValueTextInfo options_change_trigger_page[] =
2388 {
2389   { (1u << 0),                          "1"                             },
2390   { (1u << 1),                          "2"                             },
2391   { (1u << 2),                          "3"                             },
2392   { (1u << 3),                          "4"                             },
2393   { (1u << 4),                          "5"                             },
2394   { (1u << 5),                          "6"                             },
2395   { (1u << 6),                          "7"                             },
2396   { (1u << 7),                          "8"                             },
2397   { (1u << 8),                          "9"                             },
2398   { (1u << 9),                          "10"                            },
2399   { (1u << 10),                         "11"                            },
2400   { (1u << 11),                         "12"                            },
2401   { (1u << 12),                         "13"                            },
2402   { (1u << 13),                         "14"                            },
2403   { (1u << 14),                         "15"                            },
2404   { (1u << 15),                         "16"                            },
2405   { (1u << 16),                         "17"                            },
2406   { (1u << 17),                         "18"                            },
2407   { (1u << 18),                         "19"                            },
2408   { (1u << 19),                         "20"                            },
2409   { (1u << 20),                         "21"                            },
2410   { (1u << 21),                         "22"                            },
2411   { (1u << 22),                         "23"                            },
2412   { (1u << 23),                         "24"                            },
2413   { (1u << 24),                         "25"                            },
2414   { (1u << 25),                         "26"                            },
2415   { (1u << 26),                         "27"                            },
2416   { (1u << 27),                         "28"                            },
2417   { (1u << 28),                         "29"                            },
2418   { (1u << 29),                         "30"                            },
2419   { (1u << 30),                         "31"                            },
2420   { (1u << 31),                         "32"                            },
2421   { CH_PAGE_ANY,                        "any"                           },
2422
2423   { -1,                                 NULL                            }
2424 };
2425
2426 static struct ValueTextInfo options_change_replace_when[] =
2427 {
2428   { CP_WHEN_EMPTY,                      "empty"                         },
2429   { CP_WHEN_WALKABLE,                   "walkable"                      },
2430   { CP_WHEN_DIGGABLE,                   "diggable"                      },
2431   { CP_WHEN_COLLECTIBLE,                "collectible"                   },
2432   { CP_WHEN_REMOVABLE,                  "removable"                     },
2433   { CP_WHEN_DESTRUCTIBLE,               "destructible"                  },
2434
2435   { -1,                                 NULL                            }
2436 };
2437
2438 static struct ValueTextInfo options_action_type[] =
2439 {
2440   { CA_NO_ACTION,                       "no action"                     },
2441   { CA_UNDEFINED,                       " "                             },
2442   { CA_HEADLINE_LEVEL_ACTIONS,          "[level]"                       },
2443   { CA_RESTART_LEVEL,                   "restart level"                 },
2444   { CA_SHOW_ENVELOPE,                   "show envelope"                 },
2445   { CA_SET_LEVEL_TIME,                  "set time"                      },
2446   { CA_SET_LEVEL_SCORE,                 "set score"                     },
2447   { CA_SET_LEVEL_GEMS,                  "set gems"                      },
2448   { CA_SET_LEVEL_WIND,                  "set wind dir."                 },
2449   { CA_SET_LEVEL_RANDOM_SEED,           "set random seed"               },
2450   { CA_UNDEFINED,                       " "                             },
2451   { CA_HEADLINE_PLAYER_ACTIONS,         "[player]"                      },
2452   { CA_MOVE_PLAYER,                     "move player"                   },
2453   { CA_MOVE_PLAYER_NEW,                 "move player new"               },
2454   { CA_EXIT_PLAYER,                     "exit player"                   },
2455   { CA_KILL_PLAYER,                     "kill player"                   },
2456   { CA_SET_PLAYER_KEYS,                 "set keys"                      },
2457   { CA_SET_PLAYER_SPEED,                "set speed"                     },
2458   { CA_SET_PLAYER_SHIELD,               "set shield"                    },
2459   { CA_SET_PLAYER_GRAVITY,              "set gravity"                   },
2460   { CA_SET_PLAYER_ARTWORK,              "set artwork"                   },
2461   { CA_SET_PLAYER_INVENTORY,            "set inventory"                 },
2462   { CA_UNDEFINED,                       " "                             },
2463   { CA_HEADLINE_CE_ACTIONS,             "[CE]"                          },
2464   { CA_SET_CE_VALUE,                    "set CE value"                  },
2465   { CA_SET_CE_SCORE,                    "set CE score"                  },
2466   { CA_SET_CE_ARTWORK,                  "set CE artwork"                },
2467   { CA_UNDEFINED,                       " "                             },
2468   { CA_HEADLINE_ENGINE_ACTIONS,         "[engine]"                      },
2469   { CA_SET_ENGINE_SCAN_MODE,            "set scan mode"                 },
2470
2471   { -1,                                 NULL                            }
2472 };
2473
2474 static struct ValueTextInfo options_action_mode_none[] =
2475 {
2476   { CA_MODE_UNDEFINED,                  " "                             },
2477
2478   { -1,                                 NULL                            }
2479 };
2480
2481 static struct ValueTextInfo options_action_mode_assign[] =
2482 {
2483   { CA_MODE_SET,                        "="                             },
2484
2485   { -1,                                 NULL                            }
2486 };
2487
2488 static struct ValueTextInfo options_action_mode_add_remove[] =
2489 {
2490   { CA_MODE_ADD,                        "+"                             },
2491   { CA_MODE_SUBTRACT,                   "-"                             },
2492
2493   { -1,                                 NULL                            }
2494 };
2495
2496 static struct ValueTextInfo options_action_mode_calculate[] =
2497 {
2498   { CA_MODE_SET,                        "="                             },
2499   { CA_MODE_ADD,                        "+"                             },
2500   { CA_MODE_SUBTRACT,                   "-"                             },
2501   { CA_MODE_MULTIPLY,                   "*"                             },
2502   { CA_MODE_DIVIDE,                     "/"                             },
2503   { CA_MODE_MODULO,                     "%"                             },
2504
2505   { -1,                                 NULL                            }
2506 };
2507
2508 static struct ValueTextInfo options_action_arg_none[] =
2509 {
2510   { CA_ARG_UNDEFINED,                   "         "                     },
2511
2512   { -1,                                 NULL                            }
2513 };
2514
2515 static struct ValueTextInfo options_action_arg_player[] =
2516 {
2517   { CA_ARG_PLAYER_HEADLINE,             "[player]"                      },
2518   { CA_ARG_PLAYER_1,                    "1"                             },
2519   { CA_ARG_PLAYER_2,                    "2"                             },
2520   { CA_ARG_PLAYER_3,                    "3"                             },
2521   { CA_ARG_PLAYER_4,                    "4"                             },
2522   { CA_ARG_PLAYER_ANY,                  "any"                           },
2523   { CA_ARG_PLAYER_TRIGGER,              "trigger"                       },
2524   { CA_ARG_PLAYER_ACTION,               "action ->"                     },
2525
2526   { -1,                                 NULL                            }
2527 };
2528
2529 static struct ValueTextInfo options_action_arg_number[] =
2530 {
2531   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2532   { CA_ARG_0,                           "0"                             },
2533   { CA_ARG_1,                           "1"                             },
2534   { CA_ARG_2,                           "2"                             },
2535   { CA_ARG_3,                           "3"                             },
2536   { CA_ARG_4,                           "4"                             },
2537   { CA_ARG_5,                           "5"                             },
2538   { CA_ARG_10,                          "10"                            },
2539   { CA_ARG_100,                         "100"                           },
2540   { CA_ARG_1000,                        "1000"                          },
2541   { CA_ARG_UNDEFINED,                   " "                             },
2542   { CA_ARG_NUMBER_MIN,                  "min"                           },
2543   { CA_ARG_NUMBER_MAX,                  "max"                           },
2544   { CA_ARG_UNDEFINED,                   " "                             },
2545   { CA_ARG_NUMBER_RESET,                "reset"                         },
2546   { CA_ARG_UNDEFINED,                   " "                             },
2547   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2548   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2549   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2550   { CA_ARG_UNDEFINED,                   " "                             },
2551   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2552   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2553   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2554   { CA_ARG_UNDEFINED,                   " "                             },
2555   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2556   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2557   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2558   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2559   { CA_ARG_UNDEFINED,                   " "                             },
2560   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2561   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2562   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2563   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2564
2565   { -1,                                 NULL                            }
2566 };
2567
2568 static struct ValueTextInfo options_action_arg_value[] =
2569 {
2570   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2571   { CA_ARG_0,                           "0"                             },
2572   { CA_ARG_1,                           "1"                             },
2573   { CA_ARG_2,                           "2"                             },
2574   { CA_ARG_3,                           "3"                             },
2575   { CA_ARG_4,                           "4"                             },
2576   { CA_ARG_5,                           "5"                             },
2577   { CA_ARG_10,                          "10"                            },
2578   { CA_ARG_100,                         "100"                           },
2579   { CA_ARG_1000,                        "1000"                          },
2580   { CA_ARG_UNDEFINED,                   " "                             },
2581   { CA_ARG_NUMBER_MIN,                  "min"                           },
2582   { CA_ARG_NUMBER_MAX,                  "max"                           },
2583   { CA_ARG_UNDEFINED,                   " "                             },
2584   { CA_ARG_NUMBER_RESET,                "reset"                         },
2585   { CA_ARG_UNDEFINED,                   " "                             },
2586   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2587   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2588   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2589   { CA_ARG_UNDEFINED,                   " "                             },
2590   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2591   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2592   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2593   { CA_ARG_UNDEFINED,                   " "                             },
2594   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2595   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2596   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2597   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2598   { CA_ARG_UNDEFINED,                   " "                             },
2599   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2600   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2601   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2602   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2603   { CA_ARG_UNDEFINED,                   " "                             },
2604   { CA_ARG_ELEMENT_NR_HEADLINE,         "[element]"                     },
2605   { CA_ARG_ELEMENT_NR_TARGET,           "target"                        },
2606   { CA_ARG_ELEMENT_NR_TRIGGER,          "trigger"                       },
2607   { CA_ARG_ELEMENT_NR_ACTION,           "action ->"                     },
2608
2609   { -1,                                 NULL                            }
2610 };
2611
2612 static struct ValueTextInfo options_action_arg_envelope[] =
2613 {
2614   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2615   { CA_ARG_1,                           "1"                             },
2616   { CA_ARG_2,                           "2"                             },
2617   { CA_ARG_3,                           "3"                             },
2618   { CA_ARG_4,                           "4"                             },
2619   { CA_ARG_UNDEFINED,                   " "                             },
2620   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2621   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2622   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2623   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2624
2625   { -1,                                 NULL                            }
2626 };
2627
2628 static struct ValueTextInfo options_action_arg_key[] =
2629 {
2630   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2631   { CA_ARG_1,                           "1"                             },
2632   { CA_ARG_2,                           "2"                             },
2633   { CA_ARG_3,                           "3"                             },
2634   { CA_ARG_4,                           "4"                             },
2635   { CA_ARG_5,                           "5"                             },
2636   { CA_ARG_6,                           "6"                             },
2637   { CA_ARG_7,                           "7"                             },
2638   { CA_ARG_8,                           "8"                             },
2639   { CA_ARG_UNDEFINED,                   " "                             },
2640   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2641   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2642   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2643   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2644
2645   { -1,                                 NULL                            }
2646 };
2647
2648 static struct ValueTextInfo options_action_arg_speed[] =
2649 {
2650   { CA_ARG_SPEED_HEADLINE,              "[speed]"                       },
2651   { CA_ARG_SPEED_NOT_MOVING,            "frozen"                        },
2652   { CA_ARG_SPEED_VERY_SLOW,             "very slow"                     },
2653   { CA_ARG_SPEED_SLOW,                  "slow"                          },
2654   { CA_ARG_SPEED_NORMAL,                "normal"                        },
2655   { CA_ARG_SPEED_FAST,                  "fast"                          },
2656   { CA_ARG_SPEED_VERY_FAST,             "very fast"                     },
2657   { CA_ARG_SPEED_EVEN_FASTER,           "ultrafast"                     },
2658   { CA_ARG_UNDEFINED,                   " "                             },
2659   { CA_ARG_SPEED_SLOWER,                "slower"                        },
2660   { CA_ARG_SPEED_FASTER,                "faster"                        },
2661   { CA_ARG_UNDEFINED,                   " "                             },
2662   { CA_ARG_SPEED_RESET,                 "reset"                         },
2663
2664   { -1,                                 NULL                            }
2665 };
2666
2667 static struct ValueTextInfo options_action_arg_shield[] =
2668 {
2669   { CA_ARG_SHIELD_HEADLINE,             "[shield]"                      },
2670   { CA_ARG_SHIELD_OFF,                  "off"                           },
2671   { CA_ARG_SHIELD_NORMAL,               "normal"                        },
2672   { CA_ARG_SHIELD_DEADLY,               "deadly"                        },
2673
2674   { -1,                                 NULL                            }
2675 };
2676
2677 static struct ValueTextInfo options_action_arg_artwork[] =
2678 {
2679   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2680   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2681   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2682   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2683   { CA_ARG_UNDEFINED,                   " "                             },
2684   { CA_ARG_ELEMENT_RESET,               "reset"                         },
2685
2686   { -1,                                 NULL                            }
2687 };
2688
2689 static struct ValueTextInfo options_action_arg_gravity[] =
2690 {
2691   { CA_ARG_GRAVITY_HEADLINE,            "[gravity]"                     },
2692   { CA_ARG_GRAVITY_ON,                  "on"                            },
2693   { CA_ARG_GRAVITY_OFF,                 "off"                           },
2694   { CA_ARG_GRAVITY_TOGGLE,              "toggle"                        },
2695
2696   { -1,                                 NULL                            }
2697 };
2698
2699 static struct ValueTextInfo options_action_arg_direction[] =
2700 {
2701   { CA_ARG_DIRECTION_HEADLINE,          "[dir.]"                        },
2702   { CA_ARG_DIRECTION_NONE,              "none"                          },
2703   { CA_ARG_DIRECTION_LEFT,              "left"                          },
2704   { CA_ARG_DIRECTION_RIGHT,             "right"                         },
2705   { CA_ARG_DIRECTION_UP,                "up"                            },
2706   { CA_ARG_DIRECTION_DOWN,              "down"                          },
2707   { CA_ARG_DIRECTION_TRIGGER,           "trigger"                       },
2708   { CA_ARG_DIRECTION_TRIGGER_BACK,      "-trigger"                      },
2709
2710   { -1,                                 NULL                            }
2711 };
2712
2713 static struct ValueTextInfo options_action_arg_scan_mode[] =
2714 {
2715   { CA_ARG_SCAN_MODE_HEADLINE,          "[mode]"                        },
2716   { CA_ARG_SCAN_MODE_NORMAL,            "normal"                        },
2717   { CA_ARG_SCAN_MODE_REVERSE,           "reverse"                       },
2718
2719   { -1,                                 NULL                            }
2720 };
2721
2722 static struct ValueTextInfo options_action_arg_inventory[] =
2723 {
2724   { CA_ARG_INVENTORY_HEADLINE,          "[add]"                         },
2725   { CA_ARG_ELEMENT_TARGET,              "+ target"                      },
2726   { CA_ARG_ELEMENT_TRIGGER,             "+ trigger"                     },
2727   { CA_ARG_ELEMENT_ACTION,              "+ action"                      },
2728   { CA_ARG_UNDEFINED,                   " "                             },
2729   { CA_ARG_INVENTORY_RM_HEADLINE,       "[remove]"                      },
2730   { CA_ARG_INVENTORY_RM_TARGET,         "- target"                      },
2731   { CA_ARG_INVENTORY_RM_TRIGGER,        "- trigger"                     },
2732   { CA_ARG_INVENTORY_RM_ACTION,         "- action"                      },
2733   { CA_ARG_INVENTORY_RM_FIRST,          "- first"                       },
2734   { CA_ARG_INVENTORY_RM_LAST,           "- last"                        },
2735   { CA_ARG_INVENTORY_RM_ALL,            "- all"                         },
2736   { CA_ARG_UNDEFINED,                   " "                             },
2737   { CA_ARG_INVENTORY_RESET,             "reset"                         },
2738
2739   { -1,                                 NULL                            }
2740 };
2741
2742 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2743 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2744 {
2745   { -1,                                 NULL                            }
2746 };
2747
2748 static struct ValueTextInfo options_group_choice_mode[] =
2749 {
2750   { ANIM_RANDOM,                        "random"                        },
2751   { ANIM_LOOP,                          "loop"                          },
2752   { ANIM_LINEAR,                        "linear"                        },
2753   { ANIM_PINGPONG,                      "pingpong"                      },
2754   { ANIM_PINGPONG2,                     "pingpong 2"                    },
2755   { ANIM_LEVEL_NR,                      "level number"                  },
2756
2757   { -1,                                 NULL                            }
2758 };
2759
2760 static struct ValueTextInfo options_bd_scheduling_type[] =
2761 {
2762   { GD_SCHEDULING_MILLISECONDS,         "Milliseconds"                  },
2763   { GD_SCHEDULING_BD1,                  "BD1"                           },
2764   { GD_SCHEDULING_BD2,                  "BD2"                           },
2765   { GD_SCHEDULING_PLCK,                 "Construction Kit"              },
2766   { GD_SCHEDULING_CRDR,                 "Crazy Dream 7"                 },
2767   { GD_SCHEDULING_BD1_ATARI,            "Atari BD1"                     },
2768   { GD_SCHEDULING_BD2_PLCK_ATARI,       "Atari BD2 / PLCK"              },
2769
2770   { -1,                                   NULL                          }
2771 };
2772
2773 static struct ValueTextInfo *action_arg_modes[] =
2774 {
2775   options_action_mode_none,
2776   options_action_mode_assign,
2777   options_action_mode_add_remove,
2778   options_action_mode_calculate,
2779 };
2780
2781 static struct
2782 {
2783   int value;
2784   int mode;
2785   struct ValueTextInfo *options;
2786 }
2787 action_arg_options[] =
2788 {
2789   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2790   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2791   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2792   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2793   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2794   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2795   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2796   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2797   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2798   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2799   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2800   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2801   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2802   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2803   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2804   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2805   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2806   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2807   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2808   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2809   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2810   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2811
2812   { -1,                         FALSE,  NULL                            }
2813 };
2814
2815 static struct
2816 {
2817   int gadget_type_id;
2818   int x, y;
2819   int gadget_id;
2820   int gadget_id_align;
2821   int size;     // char size of selectbox or '-1' (dynamically determined)
2822   struct ValueTextInfo *options;
2823   int *value;
2824   char *text_above, *text_left, *text_right, *infotext;
2825 } selectbox_info[ED_NUM_SELECTBOX] =
2826 {
2827   // ---------- level and editor settings -------------------------------------
2828
2829   {
2830     ED_SELECTBOX_ID_TIME_OR_STEPS,
2831     -1,                                         ED_LEVEL_SETTINGS_YPOS(8),
2832     GADGET_ID_TIME_OR_STEPS,                    GADGET_ID_LEVEL_TIMELIMIT_UP,
2833     -1,
2834     options_time_or_steps,
2835     &level.use_step_counter,
2836     NULL, NULL, "(0 => no limit)",              "Select time or step limit"
2837   },
2838   {
2839     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2840     -1,                                         ED_LEVEL_SETTINGS_YPOS(10),
2841     GADGET_ID_TIME_SCORE_BASE,                  GADGET_ID_LEVEL_TIMESCORE_UP,
2842     -1,
2843     options_time_score_base,
2844     &level.time_score_base,
2845     NULL, NULL, NULL,                           "Select time score for 1 or 10 seconds/steps"
2846   },
2847   {
2848     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2849     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(12),
2850     GADGET_ID_GAME_ENGINE_TYPE,                 GADGET_ID_NONE,
2851     -1,
2852     options_game_engine_type,
2853     &level.game_engine_type,
2854     NULL, "Game engine:", NULL,                 "Select game engine"
2855   },
2856   {
2857     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2858     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
2859     GADGET_ID_BD_SCHEDULING_TYPE,               GADGET_ID_NONE,
2860     -1,
2861     options_bd_scheduling_type,
2862     &level.bd_scheduling_type,
2863     NULL, "Scheduling type:", NULL,             "Select level timing"
2864   },
2865   {
2866     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2867     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
2868     GADGET_ID_LEVELSET_SAVE_MODE,               GADGET_ID_NONE,
2869     -1,
2870     options_levelset_save_mode,
2871     &levelset_save_mode,
2872     "Action:", NULL, NULL,                      "Select action when saving level set"
2873   },
2874
2875   // ---------- element settings: configure (several elements) ----------------
2876
2877   {
2878     ED_SELECTBOX_ID_WIND_DIRECTION,
2879     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2880     GADGET_ID_WIND_DIRECTION,                   GADGET_ID_NONE,
2881     -1,
2882     options_wind_direction,
2883     &level.wind_direction_initial,
2884     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2885   },
2886   {
2887     ED_SELECTBOX_ID_PLAYER_SPEED,
2888     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(7),
2889     GADGET_ID_PLAYER_SPEED,                     GADGET_ID_NONE,
2890     -1,
2891     options_player_speed,
2892     &level.initial_player_stepsize[0],
2893     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2894   },
2895   {
2896     ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
2897     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2898     GADGET_ID_BD_GRAVITY_DIRECTION,             GADGET_ID_NONE,
2899     -1,
2900     options_bd_gravity_direction,
2901     &level.bd_gravity_direction,
2902     NULL, "Gravity direction:", NULL,           "Select initial gravity direction"
2903   },
2904   {
2905     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2906     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
2907     GADGET_ID_MM_BALL_CHOICE_MODE,              GADGET_ID_NONE,
2908     -1,
2909     options_group_choice_mode,
2910     &level.mm_ball_choice_mode,
2911     NULL, "Choice type:", NULL,                 "Select type of content choice"
2912   },
2913
2914   // ---------- element settings: configure 1 (custom elements) ---------------
2915
2916   {
2917     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2918     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2919     GADGET_ID_CUSTOM_ACCESS_TYPE,               GADGET_ID_NONE,
2920     -1,
2921     options_access_type,
2922     &custom_element.access_type,
2923     NULL, NULL, NULL,                           "Select type of access to this field"
2924   },
2925   {
2926     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2927     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2928     GADGET_ID_CUSTOM_ACCESS_LAYER,              GADGET_ID_CUSTOM_ACCESS_TYPE,
2929     -1,
2930     options_access_layer,
2931     &custom_element.access_layer,
2932     NULL, NULL, NULL,                           "Select layer of access for this field"
2933   },
2934   {
2935     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2936     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2937     GADGET_ID_CUSTOM_ACCESS_PROTECTED,          GADGET_ID_CUSTOM_ACCESS_LAYER,
2938     -1,
2939     options_access_protected,
2940     &custom_element.access_protected,
2941     NULL, NULL, NULL,                           "Select protected access for this field"
2942   },
2943   {
2944     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2945     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2946     GADGET_ID_CUSTOM_ACCESS_DIRECTION,          GADGET_ID_NONE,
2947     -1,
2948     options_access_direction,
2949     &custom_element.access_direction,
2950     NULL, "from", NULL,                         "Select access direction for this field"
2951   },
2952   {
2953     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2954     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2955     GADGET_ID_CUSTOM_WALK_TO_ACTION,            GADGET_ID_NONE,
2956     -1,
2957     options_walk_to_action,
2958     &custom_element.walk_to_action,
2959     NULL, NULL, NULL,                           "Select diggable/collectible/pushable"
2960   },
2961
2962   // ---------- element settings: configure 2 (custom elements) ---------------
2963
2964   {
2965     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2966     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(1),
2967     GADGET_ID_CUSTOM_MOVE_PATTERN,              GADGET_ID_NONE,
2968     -1,
2969     options_move_pattern,
2970     &custom_element.move_pattern,
2971     NULL, "Can move", NULL,                     "Select element move pattern"
2972   },
2973   {
2974     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2975     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2976     GADGET_ID_CUSTOM_MOVE_DIRECTION,            GADGET_ID_NONE,
2977     -1,
2978     options_move_direction,
2979     &custom_element.move_direction_initial,
2980     NULL, "Starts moving", NULL,                "Select initial element move direction"
2981   },
2982   {
2983     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2984     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2985     GADGET_ID_CUSTOM_MOVE_STEPSIZE,             GADGET_ID_NONE,
2986     -1,
2987     options_move_stepsize,
2988     &custom_element.move_stepsize,
2989     NULL, "Move/fall speed", NULL,              "Select speed of element movement"
2990   },
2991   {
2992     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2993     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2994     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,           GADGET_ID_NONE,
2995     -1,
2996     options_move_leave_type,
2997     &custom_element.move_leave_type,
2998     // left text with leading spaces to place gadget next to "can dig" gadget
2999     // (needed because drawing area gadgets created after selectbox gadgets)
3000     // NULL, "can dig:    can", ":",            "leave behind or change element"
3001     NULL, "            Can", ":",               "Select leave behind or change element"
3002   },
3003   {
3004     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
3005     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
3006     GADGET_ID_CUSTOM_SMASH_TARGETS,             GADGET_ID_CUSTOM_CAN_SMASH,
3007     -1,
3008     options_smash_targets,
3009     &custom_element.smash_targets,
3010     NULL, "Can smash", NULL,                    "Select elements that can be smashed"
3011   },
3012   {
3013     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
3014     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
3015     GADGET_ID_CUSTOM_SLIPPERY_TYPE,             GADGET_ID_NONE,
3016     -1,
3017     options_slippery_type,
3018     &custom_element.slippery_type,
3019     NULL, "Slippery", NULL,                     "Select where other elements fall down"
3020   },
3021   {
3022     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
3023     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(10),
3024     GADGET_ID_CUSTOM_DEADLINESS,                GADGET_ID_NONE,
3025     -1,
3026     options_deadliness,
3027     &custom_element.deadliness,
3028     NULL, "Deadly when", NULL,                  "Select deadliness of element"
3029   },
3030   {
3031     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
3032     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(11),
3033     GADGET_ID_CUSTOM_EXPLOSION_TYPE,            GADGET_ID_NONE,
3034     -1,
3035     options_explosion_type,
3036     &custom_element.explosion_type,
3037     NULL, "Can explode", NULL,                  "Select explosion type"
3038   },
3039
3040   // ---------- element settings: advanced (custom elements) ------------------
3041
3042   {
3043     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
3044     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(3),
3045     GADGET_ID_CHANGE_TIME_UNITS,                GADGET_ID_NONE,
3046     -1,
3047     options_time_units,
3048     &custom_element_change.delay_frames,
3049     NULL, "Delay time given in", NULL,          "Select delay time units for change"
3050   },
3051   {
3052     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
3053     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(4),
3054     GADGET_ID_CHANGE_DIRECT_ACTION,             GADGET_ID_NONE,
3055     -1,
3056     options_change_direct_action,
3057     &custom_element_change.direct_action,
3058     NULL, NULL, NULL,                           "Select type of direct action"
3059   },
3060   {
3061     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3062     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(5),
3063     GADGET_ID_CHANGE_OTHER_ACTION,              GADGET_ID_NONE,
3064     -1,
3065     options_change_other_action,
3066     &custom_element_change.other_action,
3067     NULL, NULL, "element:",                     "Select type of other element action"
3068   },
3069   {
3070     ED_SELECTBOX_ID_CHANGE_SIDE,
3071     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(6),
3072     GADGET_ID_CHANGE_SIDE,                      GADGET_ID_NONE,
3073     -1,
3074     options_change_trigger_side,
3075     &custom_element_change.trigger_side,
3076     NULL, "at", "side",                         "Select element side triggering change"
3077   },
3078   {
3079     ED_SELECTBOX_ID_CHANGE_PLAYER,
3080     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3081     GADGET_ID_CHANGE_PLAYER,                    GADGET_ID_NONE,
3082     -1,
3083     options_change_trigger_player,
3084     &custom_element_change.trigger_player,
3085     NULL, "Player:", " ",                       "Select player that causes change"
3086   },
3087   {
3088     ED_SELECTBOX_ID_CHANGE_PAGE,
3089     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3090     GADGET_ID_CHANGE_PAGE,                      GADGET_ID_CHANGE_PLAYER,
3091     -1,
3092     options_change_trigger_page,
3093     &custom_element_change.trigger_page,
3094     NULL, "Page:", NULL,                        "Select change page that causes change"
3095   },
3096   {
3097     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3098     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(10),
3099     GADGET_ID_CHANGE_REPLACE_WHEN,              GADGET_ID_NONE,
3100     -1,
3101     options_change_replace_when,
3102     &custom_element_change.replace_when,
3103     NULL, "Replace when", NULL,                 "Select which elements can be replaced"
3104   },
3105   {
3106     ED_SELECTBOX_ID_ACTION_TYPE,
3107     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
3108     GADGET_ID_ACTION_TYPE,                      GADGET_ID_NONE,
3109     15,
3110     options_action_type,
3111     &custom_element_change.action_type,
3112     NULL, NULL, NULL,                           "Select action on specified condition"
3113   },
3114   {
3115     ED_SELECTBOX_ID_ACTION_MODE,
3116     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3117     GADGET_ID_ACTION_MODE,                      GADGET_ID_ACTION_TYPE,
3118     -1,
3119     options_action_mode_none,
3120     &custom_element_change.action_mode,
3121     NULL, NULL, NULL,                           "Select action operator"
3122   },
3123   {
3124     ED_SELECTBOX_ID_ACTION_ARG,
3125     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3126     GADGET_ID_ACTION_ARG,                       GADGET_ID_ACTION_MODE,
3127     -1,
3128     options_action_arg_none,
3129     &custom_element_change.action_arg,
3130     NULL, NULL, NULL,                           "Select action parameter"
3131   },
3132   {
3133     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3134     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
3135     GADGET_ID_SELECT_CHANGE_PAGE,               GADGET_ID_NONE,
3136     3,
3137     options_change_page,
3138     &custom_element.current_change_page,
3139     NULL, NULL, NULL,                           "Select element change page"
3140   },
3141
3142   // ---------- element settings: configure (group elements) ------------------
3143
3144   {
3145     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3146     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3147     GADGET_ID_GROUP_CHOICE_MODE,                GADGET_ID_NONE,
3148     -1,
3149     options_group_choice_mode,
3150     &group_element_info.choice_mode,
3151     NULL, "Choice type:", NULL,                 "Select type of group element choice"
3152   },
3153 };
3154
3155 static struct
3156 {
3157   int gadget_type_id;
3158   int x, y;
3159   int gadget_id;
3160   int gadget_id_align;
3161   int size;
3162   char *text;
3163   char *text_above, *text_left, *text_right, *infotext;
3164 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3165 {
3166   // ---------- level and editor settings (tabs) ------------------------------
3167
3168   {
3169     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3170     ED_LEVEL_TABS_XPOS(0),                      ED_LEVEL_TABS_YPOS(0),
3171     GADGET_ID_LEVELCONFIG_LEVEL,                GADGET_ID_NONE,
3172     8,                                          "Level",
3173     NULL, NULL, NULL,                           "Configure level settings"
3174   },
3175   {
3176     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3177     -1,                                         -1,
3178     GADGET_ID_LEVELCONFIG_LEVELSET,             GADGET_ID_LEVELCONFIG_LEVEL,
3179     8,                                          "Levelset",
3180     NULL, NULL, NULL,                           "Update this or create new level set"
3181   },
3182   {
3183     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3184     -1,                                         -1,
3185     GADGET_ID_LEVELCONFIG_EDITOR,               GADGET_ID_LEVELCONFIG_LEVELSET,
3186     8,                                          "Editor",
3187     NULL, NULL, NULL,                           "Configure editor settings"
3188   },
3189   {
3190     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3191     -1,                                         -1,
3192     GADGET_ID_LEVELCONFIG_ENGINE,               GADGET_ID_LEVELCONFIG_EDITOR,
3193     8,                                          "Engine",
3194     NULL, NULL, NULL,                           "Configure engine settings"
3195   },
3196
3197   // ---------- element settings (tabs) ---------------------------------------
3198
3199   {
3200     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3201     ED_ELEMENT_TABS_XPOS(0),                    ED_ELEMENT_TABS_YPOS(0),
3202     GADGET_ID_PROPERTIES_INFO,                  GADGET_ID_NONE,
3203     8,                                          "Info",
3204     NULL, NULL, NULL,                           "Show information about element"
3205   },
3206   {
3207     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3208     -1,                                         -1,
3209     GADGET_ID_PROPERTIES_CONFIG,                GADGET_ID_PROPERTIES_INFO,
3210     8,                                          "Config",
3211     NULL, NULL, NULL,                           "Configure element properties"
3212   },
3213   {
3214     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3215     -1,                                         -1,
3216     GADGET_ID_PROPERTIES_CONFIG_1,              GADGET_ID_PROPERTIES_INFO,
3217     8,                                          "Config 1",
3218     NULL, NULL, NULL,                           "Configure element properties, part 1"
3219   },
3220   {
3221     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3222     -1,                                         -1,
3223     GADGET_ID_PROPERTIES_CONFIG_2,              GADGET_ID_PROPERTIES_CONFIG_1,
3224     8,                                          "Config 2",
3225     NULL, NULL, NULL,                           "Configure element properties, part 2"
3226   },
3227   {
3228     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3229     -1,                                         -1,
3230     GADGET_ID_PROPERTIES_CHANGE,                GADGET_ID_PROPERTIES_CONFIG_2,
3231     8,                                          "Change",
3232     NULL, NULL, NULL,                           "Configure custom element change pages"
3233   },
3234
3235   // ---------- level and editor settings (buttons) ---------------------------
3236
3237   {
3238     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3239     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
3240     GADGET_ID_SAVE_LEVELSET,                    GADGET_ID_LEVELSET_SAVE_MODE,
3241     -1,                                         "Save",
3242     NULL, NULL, NULL,                           "Update or create level set"
3243   },
3244   {
3245     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3246     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3247     GADGET_ID_SAVE_AS_TEMPLATE_2,               GADGET_ID_NONE,
3248     -1,                                         "Save",
3249     NULL, NULL,                                 "this level as level template",
3250     "Save current settings as new template"
3251   },
3252
3253   // ---------- element settings (buttons) ------------------------------------
3254
3255   {
3256     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3257     -1,                                         -1,
3258     GADGET_ID_SAVE_AS_TEMPLATE_1,               GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3259     -1,                                         "Save",
3260     NULL, " ",                                  "As Template",
3261     "Save current settings as new template"
3262   },
3263   {
3264     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3265     -1,                                         -1,
3266     GADGET_ID_ADD_CHANGE_PAGE,                  GADGET_ID_PASTE_CHANGE_PAGE,
3267     -1,                                         "New",
3268     NULL, NULL, NULL,                           "Add new change page"
3269   },
3270   {
3271     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3272     -1,                                         -1,
3273     GADGET_ID_DEL_CHANGE_PAGE,                  GADGET_ID_ADD_CHANGE_PAGE,
3274     -1,                                         "Delete",
3275     NULL, NULL, NULL,                           "Delete current change page"
3276   },
3277 };
3278
3279 static struct
3280 {
3281   int gadget_type_id;
3282   int graphic;
3283   int x, y;
3284   int gadget_id;
3285   int gadget_id_align;
3286   char *text_left, *text_right, *infotext;
3287 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3288 {
3289   {
3290     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3291     IMG_EDITOR_COUNTER_DOWN,
3292     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3293     GADGET_ID_PREV_CHANGE_PAGE,                 GADGET_ID_NONE,
3294     NULL, NULL,                                 "Select previous change page"
3295   },
3296   {
3297     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3298     IMG_EDITOR_COUNTER_UP,
3299     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3300     GADGET_ID_NEXT_CHANGE_PAGE,                 GADGET_ID_SELECT_CHANGE_PAGE,
3301     NULL, "Change page",                        "Select next change page"
3302   },
3303   {
3304     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3305     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3306     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3307     GADGET_ID_COPY_CHANGE_PAGE,                 GADGET_ID_NEXT_CHANGE_PAGE,
3308     " ", NULL,                                  "Copy settings from this change page"
3309   },
3310   {
3311     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3312     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3313     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3314     GADGET_ID_PASTE_CHANGE_PAGE,                GADGET_ID_COPY_CHANGE_PAGE,
3315     NULL, NULL,                                 "Paste settings to this change page"
3316   },
3317 };
3318
3319 static struct
3320 {
3321   int x, y;
3322 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3323
3324 static struct
3325 {
3326   int gadget_type_id;
3327   int graphic;
3328   int gadget_id;
3329   char *infotext;
3330 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3331 {
3332   {
3333     ED_SCROLLBUTTON_ID_AREA_UP,
3334     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3335     GADGET_ID_SCROLL_UP,
3336     "Scroll level editing area up"
3337   },
3338   {
3339     ED_SCROLLBUTTON_ID_AREA_DOWN,
3340     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3341     GADGET_ID_SCROLL_DOWN,
3342     "Scroll level editing area down"
3343   },
3344   {
3345     ED_SCROLLBUTTON_ID_AREA_LEFT,
3346     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3347     GADGET_ID_SCROLL_LEFT,
3348     "Scroll level editing area left"
3349   },
3350   {
3351     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3352     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3353     GADGET_ID_SCROLL_RIGHT,
3354     "Scroll level editing area right"
3355   },
3356   {
3357     ED_SCROLLBUTTON_ID_LIST_UP,
3358     IMG_EDITOR_PALETTE_SCROLL_UP,
3359     GADGET_ID_SCROLL_LIST_UP,
3360     "Scroll element list up ('Page Up')"
3361   },
3362   {
3363     ED_SCROLLBUTTON_ID_LIST_DOWN,
3364     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3365     GADGET_ID_SCROLL_LIST_DOWN,
3366     "Scroll element list down ('Page Down')"
3367   },
3368 };
3369
3370 static struct
3371 {
3372   int x, y;
3373   int width, height;
3374   int wheel_x, wheel_y;
3375   int wheel_width, wheel_height;
3376 } scrollbar_pos[ED_NUM_SCROLLBARS];
3377
3378 static struct
3379 {
3380   int gadget_type_id;
3381   int graphic;
3382   int type;
3383   int gadget_id;
3384   char *infotext;
3385 } scrollbar_info[ED_NUM_SCROLLBARS] =
3386 {
3387   {
3388     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3389     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3390     GD_TYPE_SCROLLBAR_HORIZONTAL,
3391     GADGET_ID_SCROLL_HORIZONTAL,
3392     "Scroll level editing area horizontally"
3393   },
3394   {
3395     ED_SCROLLBAR_ID_AREA_VERTICAL,
3396     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3397     GD_TYPE_SCROLLBAR_VERTICAL,
3398     GADGET_ID_SCROLL_VERTICAL,
3399     "Scroll level editing area vertically"
3400   },
3401   {
3402     ED_SCROLLBAR_ID_LIST_VERTICAL,
3403     IMG_EDITOR_PALETTE_SCROLLBAR,
3404     GD_TYPE_SCROLLBAR_VERTICAL,
3405     GADGET_ID_SCROLL_LIST_VERTICAL,
3406     "Scroll element list vertically"
3407   }
3408 };
3409
3410
3411 static struct
3412 {
3413   int gadget_type_id;
3414   int x, y;
3415   int gadget_id;
3416   int gadget_id_align;
3417   int radio_button_nr;
3418   int *value;
3419   int checked_value;
3420   char *text_left, *text_right, *infotext;
3421 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3422 {
3423   {
3424     ED_RADIOBUTTON_ID_PERCENTAGE,
3425     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3426     GADGET_ID_RANDOM_PERCENTAGE,                GADGET_ID_LEVEL_RANDOM_UP,
3427     RADIO_NR_RANDOM_ELEMENTS,
3428     &random_placement_method,                   RANDOM_USE_PERCENTAGE,
3429     " ", "percentage",                          "Use percentage for random elements"
3430   },
3431   {
3432     ED_RADIOBUTTON_ID_QUANTITY,
3433     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3434     GADGET_ID_RANDOM_QUANTITY,                  GADGET_ID_RANDOM_PERCENTAGE,
3435     RADIO_NR_RANDOM_ELEMENTS,
3436     &random_placement_method,                   RANDOM_USE_QUANTITY,
3437     " ", "quantity",                            "Use quantity for random elements"
3438   }
3439 };
3440
3441 static struct
3442 {
3443   int gadget_type_id;
3444   int x, y;
3445   int gadget_id;
3446   int gadget_id_align;
3447   boolean *value;
3448   char *text_above, *text_left, *text_right, *infotext;
3449 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3450 {
3451   // ---------- level and editor settings -------------------------------------
3452
3453   {
3454     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3455     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3456     GADGET_ID_AUTO_COUNT_GEMS,                  GADGET_ID_NONE,
3457     &level.auto_count_gems,
3458     NULL, NULL,
3459     "Automatically count gems needed",          "Set counter to number of gems"
3460   },
3461   {
3462     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3463     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(11),
3464     GADGET_ID_RATE_TIME_OVER_SCORE,             GADGET_ID_NONE,
3465     &level.rate_time_over_score,
3466     NULL, NULL,
3467     "Rate time/steps used over score",          "Sort high scores by playing time/steps"
3468   },
3469   {
3470     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3471     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3472     GADGET_ID_USE_LEVELSET_ARTWORK,             GADGET_ID_NONE,
3473     &levelset_use_levelset_artwork,
3474     NULL, NULL,
3475     "Use current custom artwork",               "Use custom artwork of this level set"
3476   },
3477   {
3478     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3479     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3480     GADGET_ID_COPY_LEVEL_TEMPLATE,              GADGET_ID_NONE,
3481     &levelset_copy_level_template,
3482     NULL, NULL,
3483     "Copy current level template",              "Copy level template of this level set"
3484   },
3485   {
3486     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3487     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
3488     GADGET_ID_RANDOM_RESTRICTED,                GADGET_ID_NONE,
3489     &random_placement_background_restricted,
3490     NULL, NULL,
3491     "Restrict random placement to:",            "Set random placement restriction"
3492   },
3493   {
3494     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3495     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
3496     GADGET_ID_CUSTOM_USE_TEMPLATE_3,            GADGET_ID_NONE,
3497     &setup.editor.use_template_for_new_levels,
3498     "Template for new levels and CE/GE:", NULL,
3499     "Use template for new levels",              "Use template for level properties"
3500   },
3501   {
3502     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3503     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
3504     GADGET_ID_CUSTOM_USE_TEMPLATE_2,            GADGET_ID_NONE,
3505     &level.use_custom_template,
3506     NULL, NULL,
3507     "Use template for custom elements",         "Use template for custom properties"
3508   },
3509   {
3510     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3511     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
3512     GADGET_ID_BD_INTERMISSION,                  GADGET_ID_NONE,
3513     &level.bd_intermission,
3514     "Boulder Dash game engine settings:", NULL,
3515     "Intermission",                             "Level is an intermission level"
3516   },
3517   {
3518     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3519     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
3520     GADGET_ID_BD_PAL_TIMING,                    GADGET_ID_NONE,
3521     &level.bd_pal_timing,
3522     NULL, NULL,
3523     "PAL timing",                               "Use slower timer (like PAL C64)"
3524   },
3525   {
3526     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3527     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3528     GADGET_ID_BD_LINE_SHIFTING_BORDERS,         GADGET_ID_NONE,
3529     &level.bd_line_shifting_borders,
3530     "Compatibility settings:", NULL,
3531     "Line-shifting borders",                    "Use line-shifting wrap-around"
3532   },
3533   {
3534     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3535     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3536     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,       GADGET_ID_NONE,
3537     &level.bd_scan_first_and_last_row,
3538     NULL, NULL,
3539     "Scan first and last row",                  "Also process top/bottom border rows"
3540   },
3541   {
3542     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3543     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3544     GADGET_ID_BD_SHORT_EXPLOSIONS,              GADGET_ID_NONE,
3545     &level.bd_short_explosions,
3546     NULL, NULL,
3547     "Short explosions",                         "Use four game cycles for explosions"
3548   },
3549
3550   // ---------- element settings: configure (various elements) ----------------
3551
3552   {
3553     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3554     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3555     GADGET_ID_STICK_ELEMENT,                    GADGET_ID_NONE,
3556     &stick_element_properties_window,
3557     NULL, NULL,
3558     "Stick this screen to edit content",        "Stick this screen to edit content"
3559   },
3560   {
3561     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3562     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3563     GADGET_ID_EM_SLIPPERY_GEMS,                 GADGET_ID_NONE,
3564     &level.em_slippery_gems,
3565     NULL, NULL,
3566     "Slip down from certain flat walls",        "Use EM/DC style slipping behaviour"
3567   },
3568   {
3569     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3570     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3571     GADGET_ID_EM_EXPLODES_BY_FIRE,              GADGET_ID_NONE,
3572     &level.em_explodes_by_fire,
3573     NULL, NULL,
3574     "Explodes with chain reaction",             "Use R'n'D style explosion behaviour"
3575   },
3576   {
3577     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3578     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3579     GADGET_ID_USE_SPRING_BUG,                   GADGET_ID_NONE,
3580     &level.use_spring_bug,
3581     NULL, NULL,
3582     "Use spring pushing bug",                   "Use odd spring pushing behaviour"
3583   },
3584   {
3585     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3586     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3587     GADGET_ID_USE_TIME_ORB_BUG,                 GADGET_ID_NONE,
3588     &level.use_time_orb_bug,
3589     NULL, NULL,
3590     "Use time orb bug",                         "Use odd time orb behaviour"
3591   },
3592   {
3593     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3594     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3595     GADGET_ID_USE_LIFE_BUGS,                    GADGET_ID_NONE,
3596     &level.use_life_bugs,
3597     NULL, NULL,
3598     "Use buggy element behaviour",              "Use odd (historic) element behaviour"
3599   },
3600   {
3601     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3602     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3603     GADGET_ID_RANDOM_BALL_CONTENT,              GADGET_ID_NONE,
3604     &level.ball_random,
3605     NULL, NULL,
3606     "Create single random element",             "Only create one element from content"
3607   },
3608   {
3609     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3610     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3611     GADGET_ID_INITIAL_BALL_ACTIVE,              GADGET_ID_NONE,
3612     &level.ball_active_initial,
3613     NULL, NULL,
3614     "Magic ball initially activated",           "Activate magic ball after level start"
3615   },
3616   {
3617     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3618     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3619     GADGET_ID_GROW_INTO_DIGGABLE,               GADGET_ID_NONE,
3620     &level.grow_into_diggable,
3621     NULL, NULL,
3622     "Can grow into anything diggable",          "Grow into more than just sand"
3623   },
3624   {
3625     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3626     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3627     GADGET_ID_SB_FIELDS_NEEDED,                 GADGET_ID_NONE,
3628     &level.sb_fields_needed,
3629     NULL, NULL,
3630     "All fields need to be filled",             "Require all SB fields to be solved"
3631   },
3632   {
3633     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3634     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3635     GADGET_ID_SB_OBJECTS_NEEDED,                GADGET_ID_NONE,
3636     &level.sb_objects_needed,
3637     NULL, NULL,
3638     "All objects need to be placed",            "Require all SB objects to be solved"
3639   },
3640   {
3641     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3642     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3643     GADGET_ID_AUTO_EXIT_SOKOBAN,                GADGET_ID_NONE,
3644     &level.auto_exit_sokoban,
3645     NULL, NULL,
3646     "Exit level if all tasks solved",           "Automatically finish Sokoban levels"
3647   },
3648   {
3649     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3650     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3651     GADGET_ID_SOLVED_BY_ONE_PLAYER,             GADGET_ID_NONE,
3652     &level.solved_by_one_player,
3653     NULL, NULL,
3654     "Only one player must enter exit",          "Level solved by first player in exit"
3655   },
3656   {
3657     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3658     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3659     GADGET_ID_FINISH_DIG_COLLECT,               GADGET_ID_NONE,
3660     &level.finish_dig_collect,
3661     NULL, NULL,
3662     "CE action on finished dig/collect",        "Only finished dig/collect triggers CE"
3663   },
3664   {
3665     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3666     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3667     GADGET_ID_KEEP_WALKABLE_CE,                 GADGET_ID_NONE,
3668     &level.keep_walkable_ce,
3669     NULL, NULL,
3670     "Keep walkable CE changed to player",       "Keep CE changing to player if walkable"
3671   },
3672   {
3673     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3674     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3675     GADGET_ID_CONTINUOUS_SNAPPING,              GADGET_ID_NONE,
3676     &level.continuous_snapping,
3677     NULL, NULL,
3678     "Continuous snapping",                      "Use snapping without releasing key"
3679   },
3680   {
3681     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3682     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
3683     GADGET_ID_BLOCK_SNAP_FIELD,                 GADGET_ID_NONE,
3684     &level.block_snap_field,
3685     NULL, NULL,
3686     "Block snapped field when snapping",        "Use snapping delay to show animation"
3687   },
3688   {
3689     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3690     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3691     GADGET_ID_BLOCK_LAST_FIELD,                 GADGET_ID_NONE,
3692     &level.block_last_field,
3693     NULL, NULL,
3694     "Block last field when moving",             "Player blocks last field when moving"
3695   },
3696   {
3697     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3698     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3699     GADGET_ID_SP_BLOCK_LAST_FIELD,              GADGET_ID_NONE,
3700     &level.sp_block_last_field,
3701     NULL, NULL,
3702     "Block last field when moving",             "Player blocks last field when moving"
3703   },
3704   {
3705     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3706     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3707     GADGET_ID_INSTANT_RELOCATION,               GADGET_ID_NONE,
3708     &level.instant_relocation,
3709     NULL, NULL,
3710     "No scrolling when relocating",             "Player gets relocated without delay"
3711   },
3712   {
3713     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3714     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3715     GADGET_ID_SHIFTED_RELOCATION,               GADGET_ID_NONE,
3716     &level.shifted_relocation,
3717     NULL, NULL,
3718     "No centering when relocating",             "Level not centered after relocation"
3719   },
3720   {
3721     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3722     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3723     GADGET_ID_LAZY_RELOCATION,                  GADGET_ID_NONE,
3724     &level.lazy_relocation,
3725     NULL, NULL,
3726     "Only redraw off-screen relocation",        "No redraw if relocation target visible"
3727   },
3728   {
3729     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3730     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
3731     GADGET_ID_USE_START_ELEMENT,                GADGET_ID_NONE,
3732     &level.use_start_element[0],
3733     NULL, NULL,
3734     "Use level start element:",                "Start level at this element's position"
3735   },
3736   {
3737     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3738     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
3739     GADGET_ID_USE_ARTWORK_ELEMENT,              GADGET_ID_NONE,
3740     &level.use_artwork_element[0],
3741     NULL, NULL,
3742     "Use artwork from element:",                "Use player artwork from other element"
3743   },
3744   {
3745     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3746     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(12),
3747     GADGET_ID_USE_EXPLOSION_ELEMENT,            GADGET_ID_NONE,
3748     &level.use_explosion_element[0],
3749     NULL, NULL,
3750     "Use explosion from element:",              "Use explosion properties from element"
3751   },
3752   {
3753     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3754     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
3755     GADGET_ID_INITIAL_GRAVITY,                  GADGET_ID_NONE,
3756     &level.initial_player_gravity[0],
3757     NULL, NULL,
3758     "Use initial gravity",                      "Set initial player gravity"
3759   },
3760   {
3761     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3762     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3763     GADGET_ID_USE_INITIAL_INVENTORY,            GADGET_ID_NONE,
3764     &level.use_initial_inventory[0],
3765     NULL, NULL,
3766     "Use initial inventory:",                   "Use collected elements on level start"
3767   },
3768   {
3769     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3770     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
3771     GADGET_ID_CAN_PASS_TO_WALKABLE,             GADGET_ID_NONE,
3772     &level.can_pass_to_walkable,
3773     NULL, NULL,
3774     "Can pass to walkable element",             "Player can pass to empty or walkable"
3775   },
3776   {
3777     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3778     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3779     GADGET_ID_CAN_FALL_INTO_ACID,               GADGET_ID_NONE,
3780     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3781     NULL, NULL,
3782     "Can fall into acid (with gravity)",        "Player can fall into acid pool"
3783   },
3784   {
3785     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3786     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3787     GADGET_ID_CAN_MOVE_INTO_ACID,               GADGET_ID_NONE,
3788     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3789     NULL, NULL,
3790     "Can move into acid",                       "Element can move into acid pool"
3791   },
3792   {
3793     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3794     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3795     GADGET_ID_DONT_COLLIDE_WITH,                GADGET_ID_NONE,
3796     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3797     NULL, NULL,
3798     "Deadly when colliding with",               "Element is deadly when hitting player"
3799   },
3800   {
3801     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3802     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3803     GADGET_ID_BD_DIAGONAL_MOVEMENTS,            GADGET_ID_NONE,
3804     &level.bd_diagonal_movements,
3805     NULL, NULL,
3806     "Can move diagonally",                      "Player can move diagonally"
3807   },
3808   {
3809     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3810     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3811     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,         GADGET_ID_NONE,
3812     &level.bd_topmost_player_active,
3813     NULL, NULL,
3814     "Topmost player is active",                 "Use first player found on playfield"
3815   },
3816   {
3817     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3818     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3819     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,     GADGET_ID_NONE,
3820     &level.bd_push_mega_rock_with_sweet,
3821     NULL, NULL,
3822     "Mega rocks pushable with sweet",           "Push mega rocks after eating sweet"
3823   },
3824   {
3825     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3826     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3827     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,      GADGET_ID_NONE,
3828     &level.bd_magic_wall_wait_hatching,
3829     NULL, NULL,
3830     "Wait for player's birth",                  "Timer start waits for player's birth"
3831   },
3832   {
3833     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3834     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3835     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,       GADGET_ID_NONE,
3836     &level.bd_magic_wall_stops_amoeba,
3837     NULL, NULL,
3838     "Turn amoeba to diamonds",                  "Activation changes amoeba to diamonds"
3839   },
3840   {
3841     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3842     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3843     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,      GADGET_ID_NONE,
3844     &level.bd_amoeba_wait_for_hatching,
3845     NULL, NULL,
3846     "Wait for player's birth",                  "Timer start waits for player's birth"
3847   },
3848   {
3849     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3850     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3851     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,      GADGET_ID_NONE,
3852     &level.bd_amoeba_start_immediately,
3853     NULL, NULL,
3854     "Start growing immediately",                "Start slow growth time immediately"
3855   },
3856   {
3857     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3858     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3859     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,    GADGET_ID_NONE,
3860     &level.bd_amoeba_2_explode_by_amoeba,
3861     NULL, NULL,
3862     "Explodes if touched by amoeba",            "Amoeba 2 explodes if touched by amoeba"
3863   },
3864   {
3865     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3866     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3867     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,      GADGET_ID_NONE,
3868     &level.bd_voodoo_collects_diamonds,
3869     NULL, NULL,
3870     "Can collect diamonds",                     "Can collect diamonds for the player"
3871   },
3872   {
3873     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3874     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3875     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,      GADGET_ID_NONE,
3876     &level.bd_voodoo_hurt_kills_player,
3877     NULL, NULL,
3878     "Player is killed if hurt",                 "If hurt in any way, player is killed"
3879   },
3880   {
3881     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3882     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3883     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,           GADGET_ID_NONE,
3884     &level.bd_voodoo_dies_by_rock,
3885     NULL, NULL,
3886     "Killed by falling rock",                   "Can be killed by a falling rock"
3887   },
3888   {
3889     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3890     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3891     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,    GADGET_ID_NONE,
3892     &level.bd_voodoo_vanish_by_explosion,
3893     NULL, NULL,
3894     "Disappears in explosions",                 "Can be destroyed by explosions"
3895   },
3896   {
3897     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3898     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3899     GADGET_ID_BD_SLIME_IS_PREDICTABLE,          GADGET_ID_NONE,
3900     &level.bd_slime_is_predictable,
3901     NULL, NULL,
3902     "Slime is predictable",                     "Use predictable random numbers"
3903   },
3904   {
3905     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3906     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3907     GADGET_ID_BD_CHANGE_EXPANDING_WALL,         GADGET_ID_NONE,
3908     &level.bd_change_expanding_wall,
3909     NULL, NULL,
3910     "Change direction",                         "Switch horizontal/vertical direction"
3911   },
3912   {
3913     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3914     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3915     GADGET_ID_BD_REPLICATORS_ACTIVE,            GADGET_ID_NONE,
3916     &level.bd_replicators_active,
3917     NULL, NULL,
3918     "Active at start",                          "Replicators start in active state"
3919   },
3920   {
3921     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3922     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3923     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,         GADGET_ID_NONE,
3924     &level.bd_conveyor_belts_active,
3925     NULL, NULL,
3926     "Active at start",                          "Conveyor belts start in active state"
3927   },
3928   {
3929     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3930     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3931     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,        GADGET_ID_NONE,
3932     &level.bd_conveyor_belts_changed,
3933     NULL, NULL,
3934     "Change direction",                         "Switch conveyor belt direction"
3935   },
3936   {
3937     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3938     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3939     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,        GADGET_ID_NONE,
3940     &level.bd_water_cannot_flow_down,
3941     NULL, NULL,
3942     "Does not flow downwards",                  "Water can only flow up, left and right"
3943   },
3944   {
3945     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3946     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3947     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,         GADGET_ID_NONE,
3948     &level.bd_hammer_walls_reappear,
3949     NULL, NULL,
3950     "Hammered walls reappear",                  "Hammered walls reappear after delay"
3951   },
3952   {
3953     ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
3954     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3955     GADGET_ID_BD_CREATURES_START_BACKWARDS,     GADGET_ID_NONE,
3956     &level.bd_creatures_start_backwards,
3957     NULL, NULL,
3958     "Creatures start moving backwards",         "Creatures start in opposite direction"
3959   },
3960   {
3961     ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
3962     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3963     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3964     &level.bd_creatures_turn_on_hatching,
3965     NULL, NULL,
3966     "Creatures turn on hatching",               "Creatures change direction on hatching"
3967   },
3968   {
3969     ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
3970     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3971     GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,         GADGET_ID_NONE,
3972     &level.bd_gravity_switch_active,
3973     NULL, NULL,
3974     "Gravity switch active at start",           "Gravity switch starts in active state"
3975   },
3976   {
3977     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
3978     ED_LEVEL_SETTINGS_XPOS(0),                  ED_ELEMENT_SETTINGS_YPOS(3),
3979     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,           GADGET_ID_NONE,
3980     &level.bd_gravity_affects_all,
3981     NULL, NULL,
3982     "Gravity change affects everything",        "Gravity affects all falling objects"
3983   },
3984   {
3985     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
3986     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3987     GADGET_ID_ENVELOPE_AUTOWRAP,                GADGET_ID_NONE,
3988     &level.envelope[0].autowrap,
3989     NULL, NULL,
3990     "Auto-wrap",                                "Automatically wrap envelope text"
3991   },
3992   {
3993     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
3994     -1,                                         ED_ELEMENT_SETTINGS_YPOS(1),
3995     GADGET_ID_ENVELOPE_CENTERED,                GADGET_ID_ENVELOPE_AUTOWRAP,
3996     &level.envelope[0].centered,
3997     NULL, " ",
3998     "Centered",                                 "Automatically center envelope text"
3999   },
4000   {
4001     ED_CHECKBUTTON_ID_MM_LASER_RED,
4002     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4003     GADGET_ID_MM_LASER_RED,                     GADGET_ID_NONE,
4004     &level.mm_laser_red,
4005     "Choose color components for laser:", NULL,
4006     "Red",                                      "Use red color components in laser"
4007   },
4008   {
4009     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
4010     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4011     GADGET_ID_MM_LASER_GREEN,                   GADGET_ID_NONE,
4012     &level.mm_laser_green,
4013     NULL, NULL,
4014     "Green",                                    "Use green color components in laser"
4015   },
4016   {
4017     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
4018     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4019     GADGET_ID_MM_LASER_BLUE,                    GADGET_ID_NONE,
4020     &level.mm_laser_blue,
4021     NULL, NULL,
4022     "Blue",                                     "Use blue color components in laser"
4023   },
4024   {
4025     ED_CHECKBUTTON_ID_DF_LASER_RED,
4026     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4027     GADGET_ID_DF_LASER_RED,                     GADGET_ID_NONE,
4028     &level.df_laser_red,
4029     "Choose color components for laser:", NULL,
4030     "Red",                                      "Use red color components in laser"
4031   },
4032   {
4033     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
4034     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4035     GADGET_ID_DF_LASER_GREEN,                   GADGET_ID_NONE,
4036     &level.df_laser_green,
4037     NULL, NULL,
4038     "Green",                                    "Use green color components in laser"
4039   },
4040   {
4041     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
4042     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4043     GADGET_ID_DF_LASER_BLUE,                    GADGET_ID_NONE,
4044     &level.df_laser_blue,
4045     NULL, NULL,
4046     "Blue",                                     "Use blue color components in laser"
4047   },
4048   {
4049     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
4050     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
4051     GADGET_ID_ROTATE_MM_BALL_CONTENT,           GADGET_ID_NONE,
4052     &level.rotate_mm_ball_content,
4053     NULL, NULL,
4054     "Randomly rotate created content",          "Randomly rotate newly created content"
4055   },
4056   {
4057     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
4058     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
4059     GADGET_ID_EXPLODE_MM_BALL,                  GADGET_ID_NONE,
4060     &level.explode_mm_ball,
4061     NULL, NULL,
4062     "Explode ball instead of melting",          "Use explosion to release ball content"
4063   },
4064
4065   // ---------- element settings: configure 1 (custom elements) ---------------
4066
4067   {
4068     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
4069     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4070     GADGET_ID_CUSTOM_USE_GRAPHIC,               GADGET_ID_NONE,
4071     &custom_element.use_gfx_element,
4072     NULL, NULL,
4073     "Use graphic of element:",                  "Use existing element graphic"
4074   },
4075   {
4076     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
4077     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
4078     GADGET_ID_CUSTOM_USE_TEMPLATE_1,            GADGET_ID_NONE,
4079     &level.use_custom_template,
4080     NULL, NULL,
4081     "Use template",                             "Use template for custom properties"
4082   },
4083   {
4084     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4085     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4086     GADGET_ID_CUSTOM_ACCESSIBLE,                GADGET_ID_NONE,
4087     &custom_element_properties[EP_ACCESSIBLE],
4088     NULL, NULL,
4089     NULL,                                       "Player can walk to or pass this field"
4090   },
4091   {
4092     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4093     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4094     GADGET_ID_CUSTOM_GRAV_REACHABLE,            GADGET_ID_NONE,
4095     &custom_element_properties[EP_GRAVITY_REACHABLE],
4096     NULL, NULL,
4097     "Reachable despite gravity",                "Player can walk/dig despite gravity"
4098   },
4099   {
4100     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4101     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4102     GADGET_ID_CUSTOM_USE_LAST_VALUE,            GADGET_ID_NONE,
4103     &custom_element.use_last_ce_value,
4104     NULL, NULL,
4105     "Use last CE value after change",           "Use last CE value after change"
4106   },
4107   {
4108     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4109     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
4110     GADGET_ID_CUSTOM_WALK_TO_OBJECT,            GADGET_ID_NONE,
4111     &custom_element_properties[EP_WALK_TO_OBJECT],
4112     NULL, NULL,
4113     NULL,                                       "Player can dig/collect/push element"
4114   },
4115   {
4116     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4117     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4118     GADGET_ID_CUSTOM_INDESTRUCTIBLE,            GADGET_ID_NONE,
4119     &custom_element_properties[EP_INDESTRUCTIBLE],
4120     NULL, NULL,
4121     "Indestructible",                           "Element is indestructible"
4122   },
4123
4124   // ---------- element settings: configure 2 (custom elements) ---------------
4125
4126   {
4127     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4128     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4129     GADGET_ID_CUSTOM_CAN_MOVE,                  GADGET_ID_NONE,
4130     &custom_element_properties[EP_CAN_MOVE],
4131     NULL, NULL,
4132     NULL,                                       "Element can move with some pattern"
4133   },
4134   {
4135     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4136     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4137     GADGET_ID_CUSTOM_CAN_FALL,                  GADGET_ID_NONE,
4138     &custom_element_properties[EP_CAN_FALL],
4139     NULL, NULL,
4140     "Can fall",                                 "Element can fall down"
4141   },
4142   {
4143     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4144     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
4145     GADGET_ID_CUSTOM_CAN_SMASH,                 GADGET_ID_CUSTOM_CAN_FALL,
4146     &custom_element_properties[EP_CAN_SMASH],
4147     NULL, " ",
4148     NULL,                                       "Element can smash other elements"
4149   },
4150   {
4151     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4152     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4153     GADGET_ID_CUSTOM_SLIPPERY,                  GADGET_ID_NONE,
4154     &custom_element_properties[EP_SLIPPERY],
4155     NULL, NULL,
4156     NULL,                                       "Other elements can fall down from it"
4157   },
4158   {
4159     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4160     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
4161     GADGET_ID_CUSTOM_DEADLY,                    GADGET_ID_NONE,
4162     &custom_element_properties[EP_DEADLY],
4163     NULL, NULL,
4164     NULL,                                       "Element can kill the player"
4165   },
4166   {
4167     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4168     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4169     GADGET_ID_CUSTOM_CAN_EXPLODE,               GADGET_ID_NONE,
4170     &custom_element_properties[EP_CAN_EXPLODE],
4171     NULL, NULL,
4172     NULL,                                       "Element can explode"
4173   },
4174   {
4175     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4176     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(12),
4177     GADGET_ID_CUSTOM_EXPLODE_FIRE,              GADGET_ID_NONE,
4178     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4179     NULL, NULL,
4180     "By fire",                                  "Element can explode by fire/explosion"
4181   },
4182   {
4183     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4184     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4185     GADGET_ID_CUSTOM_EXPLODE_SMASH,             GADGET_ID_CUSTOM_EXPLODE_FIRE,
4186     &custom_element_properties[EP_EXPLODES_SMASHED],
4187     NULL, " ",
4188     "Smashed",                                  "Element can explode when smashed"
4189   },
4190   {
4191     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4192     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4193     GADGET_ID_CUSTOM_EXPLODE_IMPACT,            GADGET_ID_CUSTOM_EXPLODE_SMASH,
4194     &custom_element_properties[EP_EXPLODES_IMPACT],
4195     NULL, " ",
4196     "Impact",                                   "Element can explode on impact"
4197   },
4198
4199   // ---------- element settings: advanced (custom elements) ------------------
4200
4201   {
4202     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4203     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4204     GADGET_ID_CUSTOM_CAN_CHANGE,                GADGET_ID_NONE,
4205     &custom_element_change.can_change,
4206     NULL, NULL,
4207     "Element changes to:",                      "Change element on specified condition"
4208   },
4209   {
4210     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4211     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
4212     GADGET_ID_CHANGE_DELAY,                     GADGET_ID_NONE,
4213     &custom_element_change_events[CE_DELAY],
4214     NULL, NULL,
4215     NULL,                                       "Element changes after delay"
4216   },
4217   {
4218     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4219     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
4220     GADGET_ID_CHANGE_BY_DIRECT_ACT,             GADGET_ID_NONE,
4221     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4222     NULL, NULL,
4223     NULL,                                       "Element changes by direct action"
4224   },
4225   {
4226     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4227     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
4228     GADGET_ID_CHANGE_BY_OTHER_ACT,              GADGET_ID_NONE,
4229     &custom_element_change_events[CE_BY_OTHER_ACTION],
4230     NULL, NULL,
4231     NULL,                                       "Element changes by other element"
4232   },
4233   {
4234     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4235     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(8),
4236     GADGET_ID_CHANGE_USE_EXPLOSION,             GADGET_ID_NONE,
4237     &custom_element_change.explode,
4238     NULL, NULL,
4239     "Explode instead of change",                "Element explodes instead of change"
4240   },
4241   {
4242     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4243     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
4244     GADGET_ID_CHANGE_USE_CONTENT,               GADGET_ID_NONE,
4245     &custom_element_change.use_target_content,
4246     NULL, NULL,
4247     "Use extended change target:",              "Element changes to more elements"
4248   },
4249   {
4250     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4251     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(11),
4252     GADGET_ID_CHANGE_ONLY_COMPLETE,             GADGET_ID_NONE,
4253     &custom_element_change.only_if_complete,
4254     NULL, NULL,
4255     "Replace all or nothing",                   "Only replace when all can be changed"
4256   },
4257   {
4258     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4259     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(12),
4260     GADGET_ID_CHANGE_USE_RANDOM,                GADGET_ID_NONE,
4261     &custom_element_change.use_random_replace,
4262     NULL, NULL,
4263     NULL,                                       "Use percentage for random replace"
4264   },
4265   {
4266     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4267     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
4268     GADGET_ID_CHANGE_HAS_ACTION,                GADGET_ID_NONE,
4269     &custom_element_change.has_action,
4270     NULL, NULL,
4271     NULL,                                       "Execute action on specified condition"
4272   },
4273 };
4274
4275 static struct
4276 {
4277   int gadget_type_id;
4278   int x, y;
4279   int xoffset, yoffset;
4280   int gadget_id;
4281   int gadget_id_align;
4282   int *value;
4283   int area_xsize, area_ysize;
4284   char *text_left, *text_right, *text_above, *text_below, *infotext;
4285 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4286 {
4287   // ---------- level playfield content ---------------------------------------
4288
4289   {
4290     ED_DRAWING_ID_DRAWING_LEVEL,
4291     0,                                          0,
4292     0,                                          0,
4293     GADGET_ID_DRAWING_LEVEL,                    GADGET_ID_NONE,
4294     NULL,
4295     -1, -1,     // these values are not constant, but can change at runtime
4296     NULL, NULL, NULL, NULL,                     NULL
4297   },
4298
4299   // ---------- yam yam content -----------------------------------------------
4300
4301   {
4302     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4303     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4304     ED_AREA_YAMYAM_CONTENT_XOFF(0),             ED_AREA_YAMYAM_CONTENT_YOFF(0),
4305     GADGET_ID_YAMYAM_CONTENT_0,                 GADGET_ID_NONE,
4306     &level.yamyam_content[0].e[0][0],           3, 3,
4307     NULL, NULL, NULL, "1",                      NULL
4308   },
4309   {
4310     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4311     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4312     ED_AREA_YAMYAM_CONTENT_XOFF(1),             ED_AREA_YAMYAM_CONTENT_YOFF(1),
4313     GADGET_ID_YAMYAM_CONTENT_1,                 GADGET_ID_NONE,
4314     &level.yamyam_content[1].e[0][0],           3, 3,
4315     NULL, NULL, NULL, "2",                      NULL
4316   },
4317   {
4318     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4319     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4320     ED_AREA_YAMYAM_CONTENT_XOFF(2),             ED_AREA_YAMYAM_CONTENT_YOFF(2),
4321     GADGET_ID_YAMYAM_CONTENT_2,                 GADGET_ID_NONE,
4322     &level.yamyam_content[2].e[0][0],           3, 3,
4323     NULL, NULL, NULL, "3",                      NULL
4324   },
4325   {
4326     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4327     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4328     ED_AREA_YAMYAM_CONTENT_XOFF(3),             ED_AREA_YAMYAM_CONTENT_YOFF(3),
4329     GADGET_ID_YAMYAM_CONTENT_3,                 GADGET_ID_NONE,
4330     &level.yamyam_content[3].e[0][0],           3, 3,
4331     NULL, NULL, NULL, "4",                      NULL
4332   },
4333   {
4334     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4335     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4336     ED_AREA_YAMYAM_CONTENT_XOFF(4),             ED_AREA_YAMYAM_CONTENT_YOFF(4),
4337     GADGET_ID_YAMYAM_CONTENT_4,                 GADGET_ID_NONE,
4338     &level.yamyam_content[4].e[0][0],           3, 3,
4339     NULL, NULL, NULL, "5",                      NULL
4340   },
4341   {
4342     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4343     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4344     ED_AREA_YAMYAM_CONTENT_XOFF(5),             ED_AREA_YAMYAM_CONTENT_YOFF(5),
4345     GADGET_ID_YAMYAM_CONTENT_5,                 GADGET_ID_NONE,
4346     &level.yamyam_content[5].e[0][0],           3, 3,
4347     NULL, NULL, NULL, "6",                      NULL
4348   },
4349   {
4350     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4351     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4352     ED_AREA_YAMYAM_CONTENT_XOFF(6),             ED_AREA_YAMYAM_CONTENT_YOFF(6),
4353     GADGET_ID_YAMYAM_CONTENT_6,                 GADGET_ID_NONE,
4354     &level.yamyam_content[6].e[0][0],           3, 3,
4355     NULL, NULL, NULL, "7",                      NULL
4356   },
4357   {
4358     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4359     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4360     ED_AREA_YAMYAM_CONTENT_XOFF(7),             ED_AREA_YAMYAM_CONTENT_YOFF(7),
4361     GADGET_ID_YAMYAM_CONTENT_7,                 GADGET_ID_NONE,
4362     &level.yamyam_content[7].e[0][0],           3, 3,
4363     NULL, NULL, NULL, "8",                      NULL
4364   },
4365
4366   // ---------- magic ball content --------------------------------------------
4367
4368   {
4369     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4370     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4371     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4372     GADGET_ID_MAGIC_BALL_CONTENT_0,             GADGET_ID_NONE,
4373     &level.ball_content[0].e[0][0],             3, 3,
4374     NULL, NULL, NULL, "1",                      NULL
4375   },
4376   {
4377     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4378     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4379     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4380     GADGET_ID_MAGIC_BALL_CONTENT_1,             GADGET_ID_NONE,
4381     &level.ball_content[1].e[0][0],             3, 3,
4382     NULL, NULL, NULL, "2",                      NULL
4383   },
4384   {
4385     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4386     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4387     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4388     GADGET_ID_MAGIC_BALL_CONTENT_2,             GADGET_ID_NONE,
4389     &level.ball_content[2].e[0][0],             3, 3,
4390     NULL, NULL, NULL, "3",                      NULL
4391   },
4392   {
4393     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4394     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4395     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4396     GADGET_ID_MAGIC_BALL_CONTENT_3,             GADGET_ID_NONE,
4397     &level.ball_content[3].e[0][0],             3, 3,
4398     NULL, NULL, NULL, "4",                      NULL
4399   },
4400   {
4401     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4402     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4403     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4404     GADGET_ID_MAGIC_BALL_CONTENT_4,             GADGET_ID_NONE,
4405     &level.ball_content[4].e[0][0],             3, 3,
4406     NULL, NULL, NULL, "5",                      NULL
4407   },
4408   {
4409     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4410     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4411     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4412     GADGET_ID_MAGIC_BALL_CONTENT_5,             GADGET_ID_NONE,
4413     &level.ball_content[5].e[0][0],             3, 3,
4414     NULL, NULL, NULL, "6",                      NULL
4415   },
4416   {
4417     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4418     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4419     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4420     GADGET_ID_MAGIC_BALL_CONTENT_6,             GADGET_ID_NONE,
4421     &level.ball_content[6].e[0][0],             3, 3,
4422     NULL, NULL, NULL, "7",                      NULL
4423   },
4424   {
4425     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4426     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4427     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4428     GADGET_ID_MAGIC_BALL_CONTENT_7,             GADGET_ID_NONE,
4429     &level.ball_content[7].e[0][0],             3, 3,
4430     NULL, NULL, NULL, "8",                      NULL
4431   },
4432
4433   // ---------- android content -----------------------------------------------
4434
4435   {
4436     ED_DRAWING_ID_ANDROID_CONTENT,
4437     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4438     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4439     GADGET_ID_ANDROID_CONTENT,                  GADGET_ID_NONE,
4440     &level.android_clone_element[0],            MAX_ANDROID_ELEMENTS, 1,
4441     NULL, NULL, "Elements:", NULL,              "Elements android can clone"
4442   },
4443
4444   // ---------- amoeba content ------------------------------------------------
4445
4446   {
4447     ED_DRAWING_ID_AMOEBA_CONTENT,
4448     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4449     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4450     GADGET_ID_AMOEBA_CONTENT,                   GADGET_ID_NONE,
4451     &level.amoeba_content,                      1, 1,
4452     "Content:", NULL, NULL, NULL,               "Amoeba content"
4453   },
4454
4455   // ---------- BD snap element -----------------------------------------------
4456
4457   {
4458     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4459     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4460     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4461     GADGET_ID_BD_SNAP_ELEMENT,                  GADGET_ID_NONE,
4462     &level.bd_snap_element,                     1, 1,
4463     "Snap element:", NULL, NULL, NULL,          "Element created when snapping"
4464   },
4465
4466   // ---------- BD magic wall elements ----------------------------------------
4467
4468   {
4469     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4470     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(4),
4471     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4472     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,         GADGET_ID_NONE,
4473     &level.bd_magic_wall_diamond_to,            1, 1,
4474     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4475   },
4476   {
4477     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4478     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4479     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4480     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,            GADGET_ID_NONE,
4481     &level.bd_magic_wall_rock_to,               1, 1,
4482     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4483   },
4484   {
4485     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4486     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4487     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4488     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,       GADGET_ID_NONE,
4489     &level.bd_magic_wall_mega_rock_to,          1, 1,
4490     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4491   },
4492   {
4493     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4494     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4495     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4496     GADGET_ID_BD_MAGIC_WALL_NUT_TO,             GADGET_ID_NONE,
4497     &level.bd_magic_wall_nut_to,                1, 1,
4498     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4499   },
4500   {
4501     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4502     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4503     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4504     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,      GADGET_ID_NONE,
4505     &level.bd_magic_wall_nitro_pack_to,         1, 1,
4506     "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
4507   },
4508   {
4509     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4510     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(9),
4511     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4512     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,  GADGET_ID_NONE,
4513     &level.bd_magic_wall_flying_diamond_to,     1, 1,
4514     "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
4515   },
4516   {
4517     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4518     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4519     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4520     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,     GADGET_ID_NONE,
4521     &level.bd_magic_wall_flying_rock_to,        1, 1,
4522     "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
4523   },
4524
4525   // ---------- BD amoeba content ---------------------------------------------
4526
4527   {
4528     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4529     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4530     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4531     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,        GADGET_ID_NONE,
4532     &level.bd_amoeba_content_too_big,           1, 1,
4533     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba content if too big"
4534   },
4535   {
4536     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4537     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4538     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4539     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,       GADGET_ID_NONE,
4540     &level.bd_amoeba_content_enclosed,          1, 1,
4541     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba content if enclosed"
4542   },
4543
4544   // ---------- BD amoeba 2 content -------------------------------------------
4545
4546   {
4547     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4548     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4549     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4550     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,      GADGET_ID_NONE,
4551     &level.bd_amoeba_2_content_too_big,         1, 1,
4552     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if too big"
4553   },
4554   {
4555     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4556     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4557     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4558     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,     GADGET_ID_NONE,
4559     &level.bd_amoeba_2_content_enclosed,        1, 1,
4560     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if enclosed"
4561   },
4562   {
4563     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4564     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4565     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4566     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,    GADGET_ID_NONE,
4567     &level.bd_amoeba_2_content_exploding,       1, 1,
4568     "If exploding, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if exploding"
4569   },
4570   {
4571     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4572     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4573     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4574     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4575     &level.bd_amoeba_2_content_looks_like,      1, 1,
4576     "Use graphic of element:", NULL, NULL, NULL, "BD amoeba 2 looks like this element"
4577   },
4578   {
4579     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4580     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4581     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4582     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,          GADGET_ID_NONE,
4583     &level.bd_slime_eats_element_1,             1, 1,
4584     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4585   },
4586   {
4587     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4588     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4589     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4590     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4591     &level.bd_slime_converts_to_element_1,      1, 1,
4592     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4593   },
4594   {
4595     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4596     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4597     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4598     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,          GADGET_ID_NONE,
4599     &level.bd_slime_eats_element_2,             1, 1,
4600     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4601   },
4602   {
4603     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4604     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4605     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4606     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4607     &level.bd_slime_converts_to_element_2,      1, 1,
4608     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4609   },
4610   {
4611     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4612     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4613     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4614     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,          GADGET_ID_NONE,
4615     &level.bd_slime_eats_element_3,             1, 1,
4616     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4617   },
4618   {
4619     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4620     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4621     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4622     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4623     &level.bd_slime_converts_to_element_3,      1, 1,
4624     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4625   },
4626   {
4627     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4628     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4629     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4630     GADGET_ID_BD_ACID_EATS_ELEMENT,             GADGET_ID_NONE,
4631     &level.bd_acid_eats_element,                1, 1,
4632     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4633   },
4634   {
4635     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4636     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4637     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4638     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,         GADGET_ID_NONE,
4639     &level.bd_acid_turns_to_element,            1, 1,
4640     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4641   },
4642   {
4643     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4644     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4645     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4646     GADGET_ID_BD_BITER_EATS_ELEMENT,            GADGET_ID_NONE,
4647     &level.bd_biter_eats_element,               1, 1,
4648     "Can eat:", NULL, NULL, NULL,               "Eats this element when moving"
4649   },
4650   {
4651     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4652     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4653     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4654     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
4655     &level.bd_bladder_converts_by_element,      1, 1,
4656     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
4657   },
4658   {
4659     ED_DRAWING_ID_BD_NUT_CONTENT,
4660     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4661     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4662     GADGET_ID_BD_NUT_CONTENT,                   GADGET_ID_NONE,
4663     &level.bd_nut_content,                      1, 1,
4664     "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
4665   },
4666   {
4667     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4668     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4669     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4670     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,     GADGET_ID_NONE,
4671     &level.bd_expanding_wall_looks_like,        1, 1,
4672     "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
4673   },
4674   {
4675     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4676     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4677     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4678     GADGET_ID_BD_SAND_LOOKS_LIKE,               GADGET_ID_NONE,
4679     &level.bd_sand_looks_like,                  1, 1,
4680     "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
4681   },
4682   {
4683     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
4684     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4685     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4686     GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,      GADGET_ID_NONE,
4687     &level.bd_rock_turns_to_on_falling,         1, 1,
4688     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4689   },
4690   {
4691     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
4692     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4693     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4694     GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,       GADGET_ID_NONE,
4695     &level.bd_rock_turns_to_on_impact,          1, 1,
4696     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4697   },
4698   {
4699     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
4700     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4701     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4702     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,   GADGET_ID_NONE,
4703     &level.bd_diamond_turns_to_on_falling,      1, 1,
4704     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4705   },
4706   {
4707     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
4708     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4709     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4710     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,    GADGET_ID_NONE,
4711     &level.bd_diamond_turns_to_on_impact,       1, 1,
4712     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4713   },
4714   {
4715     ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
4716     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4717     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4718     GADGET_ID_BD_FIREFLY_EXPLODES_TO,           GADGET_ID_NONE,
4719     &level.bd_firefly_explodes_to,              1, 1,
4720     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4721   },
4722   {
4723     ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
4724     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4725     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4726     GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,         GADGET_ID_NONE,
4727     &level.bd_firefly_2_explodes_to,            1, 1,
4728     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4729   },
4730   {
4731     ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
4732     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4733     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4734     GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,         GADGET_ID_NONE,
4735     &level.bd_butterfly_explodes_to,            1, 1,
4736     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4737   },
4738   {
4739     ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
4740     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4741     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4742     GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,       GADGET_ID_NONE,
4743     &level.bd_butterfly_2_explodes_to,          1, 1,
4744     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4745   },
4746   {
4747     ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
4748     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4749     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4750     GADGET_ID_BD_STONEFLY_EXPLODES_TO,          GADGET_ID_NONE,
4751     &level.bd_stonefly_explodes_to,             1, 1,
4752     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4753   },
4754   {
4755     ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
4756     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4757     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4758     GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,         GADGET_ID_NONE,
4759     &level.bd_dragonfly_explodes_to,            1, 1,
4760     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4761   },
4762   {
4763     ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
4764     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4765     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4766     GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,        GADGET_ID_NONE,
4767     &level.bd_diamond_birth_turns_to,           1, 1,
4768     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4769   },
4770   {
4771     ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
4772     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4773     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4774     GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,       GADGET_ID_NONE,
4775     &level.bd_bomb_explosion_turns_to,          1, 1,
4776     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4777   },
4778   {
4779     ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
4780     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4781     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4782     GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,      GADGET_ID_NONE,
4783     &level.bd_nitro_explosion_turns_to,         1, 1,
4784     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4785   },
4786   {
4787     ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
4788     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4789     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4790     GADGET_ID_BD_EXPLOSION_TURNS_TO,            GADGET_ID_NONE,
4791     &level.bd_explosion_turns_to,               1, 1,
4792     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4793   },
4794
4795   // ---------- level start element -------------------------------------------
4796
4797   {
4798     ED_DRAWING_ID_START_ELEMENT,
4799     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(10),
4800     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4801     GADGET_ID_START_ELEMENT,                    GADGET_ID_USE_START_ELEMENT,
4802     &level.start_element[0],                    1, 1,
4803     NULL, NULL, NULL, NULL,                     "Level start element"
4804   },
4805
4806   // ---------- player artwork element ----------------------------------------
4807
4808   {
4809     ED_DRAWING_ID_ARTWORK_ELEMENT,
4810     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(11),
4811     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4812     GADGET_ID_ARTWORK_ELEMENT,                  GADGET_ID_USE_ARTWORK_ELEMENT,
4813     &level.artwork_element[0],                  1, 1,
4814     NULL, NULL, NULL, NULL,                     "Element for player artwork"
4815   },
4816
4817   // ---------- player explosion element --------------------------------------
4818
4819   {
4820     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4821     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(12),
4822     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4823     GADGET_ID_EXPLOSION_ELEMENT,                GADGET_ID_USE_EXPLOSION_ELEMENT,
4824     &level.explosion_element[0],                1, 1,
4825     NULL, NULL, NULL, NULL,                     "Element for player explosion"
4826   },
4827
4828   // ---------- player initial inventory --------------------------------------
4829
4830   {
4831     ED_DRAWING_ID_INVENTORY_CONTENT,
4832     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4833     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4834     GADGET_ID_INVENTORY_CONTENT,                GADGET_ID_USE_INITIAL_INVENTORY,
4835     &level.initial_inventory_content[0][0],     MAX_INITIAL_INVENTORY_SIZE, 1,
4836     NULL, NULL, NULL, NULL,                     "Content for initial inventory"
4837   },
4838
4839   // ---------- gray ball content -----------------------------------------
4840
4841   {
4842     ED_DRAWING_ID_MM_BALL_CONTENT,
4843     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4844     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4845     GADGET_ID_MM_BALL_CONTENT,                  GADGET_ID_NONE,
4846     &level.mm_ball_content[0],                  MAX_MM_BALL_CONTENTS, 1,
4847     "Content:", NULL, NULL, NULL,               "Content for gray ball"
4848   },
4849
4850   // ---------- element settings: configure 1 (custom elements) ---------------
4851
4852   // ---------- custom graphic ------------------------------------------------
4853
4854   {
4855     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4856     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4857     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4858     GADGET_ID_CUSTOM_GRAPHIC,                   GADGET_ID_CUSTOM_USE_GRAPHIC,
4859     &custom_element.gfx_element_initial,        1, 1,
4860     NULL, NULL, NULL, NULL,                     "Custom graphic element"
4861   },
4862
4863   // ---------- element settings: configure 2 (custom elements) ---------------
4864
4865   // ---------- custom content (when exploding) -------------------------------
4866
4867   {
4868     ED_DRAWING_ID_CUSTOM_CONTENT,
4869     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(11),
4870     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4871     GADGET_ID_CUSTOM_CONTENT,                   GADGET_ID_NONE,         // align three rows
4872     &custom_element.content.e[0][0],            3, 3,
4873     "Content:", NULL, NULL, NULL,               NULL
4874   },
4875
4876   // ---------- custom enter and leave element (when moving) ------------------
4877
4878   {
4879     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4880     ED_AREA_1X1_SETTINGS_XPOS(1),               ED_AREA_1X1_SETTINGS_YPOS(3),
4881     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4882     GADGET_ID_CUSTOM_MOVE_ENTER,                GADGET_ID_NONE,
4883     &custom_element.move_enter_element,         1, 1,
4884     "Can dig:", " ", NULL, NULL,                "Element that can be digged/collected"
4885   },
4886   {
4887     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4888     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(3),
4889     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4890     GADGET_ID_CUSTOM_MOVE_LEAVE,                GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4891     &custom_element.move_leave_element,         1, 1,
4892     NULL, NULL, NULL, NULL,                     "Element that will be left behind"
4893   },
4894
4895   // ---------- element settings: advanced (custom elements) ------------------
4896
4897   // ---------- custom change target ------------------------------------------
4898
4899   {
4900     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4901     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4902     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4903     GADGET_ID_CUSTOM_CHANGE_TARGET,             GADGET_ID_CUSTOM_CAN_CHANGE,
4904     &custom_element_change.target_element,      1, 1,
4905     NULL, "after/when:", NULL, NULL,            "New target element after change"
4906   },
4907
4908   // ---------- custom change content (extended change target) ----------------
4909
4910   {
4911     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4912     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(9),
4913     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4914     GADGET_ID_CUSTOM_CHANGE_CONTENT,            GADGET_ID_NONE,         // align three rows
4915     &custom_element_change.target_content.e[0][0], 3, 3,
4916     NULL, NULL, NULL, NULL,                     "New extended elements after change"
4917   },
4918
4919   // ---------- custom change trigger (element causing change) ----------------
4920
4921   {
4922     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4923     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(5),
4924     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4925     GADGET_ID_CUSTOM_CHANGE_TRIGGER,            GADGET_ID_CHANGE_OTHER_ACTION,
4926     &custom_element_change.initial_trigger_element, 1, 1,
4927     NULL, NULL, NULL, NULL,                     "Other element triggering change"
4928   },
4929
4930   // ---------- custom change action (element used for action) ----------------
4931
4932   {
4933     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4934     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(13),
4935     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4936     GADGET_ID_CUSTOM_CHANGE_ACTION,             GADGET_ID_ACTION_ARG,
4937     &custom_element_change.action_element,      1, 1,
4938     NULL, NULL, NULL, NULL,                     "Element used as action parameter"
4939   },
4940
4941   // ---------- group element content -----------------------------------------
4942
4943   {
4944     ED_DRAWING_ID_GROUP_CONTENT,
4945     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4946     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4947     GADGET_ID_GROUP_CONTENT,                    GADGET_ID_NONE,
4948     &group_element_info.element[0],             MAX_ELEMENTS_IN_GROUP, 1,
4949     "Content:", NULL, NULL, NULL,               NULL
4950   },
4951
4952   // ---------- random background (for random painting) -----------------------
4953
4954   {
4955     ED_DRAWING_ID_RANDOM_BACKGROUND,
4956     -1,                                         ED_AREA_1X1_LSETTINGS_YPOS(1),
4957     0,                                          ED_AREA_1X1_LSETTINGS_YOFF,
4958     GADGET_ID_RANDOM_BACKGROUND,                GADGET_ID_RANDOM_RESTRICTED,
4959     &random_placement_background_element,       1, 1,
4960     NULL, NULL, NULL, NULL,                     "Random placement background"
4961   },
4962 };
4963
4964
4965 // ----------------------------------------------------------------------------
4966 // some internally used variables
4967 // ----------------------------------------------------------------------------
4968
4969 // maximal size of level editor drawing area
4970 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
4971
4972 // actual size of level editor drawing area
4973 static int ed_fieldx, ed_fieldy;
4974
4975 // actual position of level editor drawing area in level playfield
4976 static int level_xpos = -1, level_ypos = -1;
4977
4978 // actual tile size used to display playfield drawing area
4979 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
4980 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
4981
4982 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
4983
4984 // drawing elements on the three mouse buttons
4985 static int new_element1 = EL_WALL;
4986 static int new_element2 = EL_EMPTY;
4987 static int new_element3 = EL_SAND;
4988
4989 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
4990 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
4991                                 (button) == 2 ? new_element2 : \
4992                                 (button) == 3 ? new_element3 : EL_EMPTY)
4993
4994 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
4995
4996 static int use_permanent_palette = TRUE;
4997
4998 #define PX              (use_permanent_palette ? DX : SX)
4999 #define PY              (use_permanent_palette ? DY : SY)
5000 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
5001 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
5002
5003 // forward declaration for internal use
5004 static void CopyBrushToCursor(int, int);
5005 static void DeleteBrushFromCursor(void);
5006 static void ModifyEditorCounterValue(int, int);
5007 static void ModifyEditorCounterLimits(int, int, int);
5008 static void ModifyEditorSelectboxValue(int, int);
5009 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
5010 static void ModifyEditorDrawingArea(int, int, int);
5011 static void ModifyEditorElementList(void);
5012 static void AdjustElementListScrollbar(void);
5013 static void RedrawDrawingElements(void);
5014 static void DrawDrawingWindowExt(boolean);
5015 static void DrawDrawingWindow(void);
5016 static void DrawLevelConfigWindow(void);
5017 static void DrawPropertiesWindow(void);
5018 static void DrawPaletteWindow(void);
5019 static void UpdateCustomElementGraphicGadgets(void);
5020 static boolean checkPropertiesConfig(int);
5021 static void SetAutomaticNumberOfGemsNeeded(void);
5022 static void ClearEditorGadgetInfoText(void);
5023 static void CopyLevelToUndoBuffer(int);
5024 static void HandleDrawingAreas(struct GadgetInfo *);
5025 static void HandleCounterButtons(struct GadgetInfo *);
5026 static void HandleTextInputGadgets(struct GadgetInfo *);
5027 static void HandleTextAreaGadgets(struct GadgetInfo *);
5028 static void HandleSelectboxGadgets(struct GadgetInfo *);
5029 static void HandleTextbuttonGadgets(struct GadgetInfo *);
5030 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
5031 static void HandleRadiobuttons(struct GadgetInfo *);
5032 static void HandleCheckbuttons(struct GadgetInfo *);
5033 static void HandleControlButtons(struct GadgetInfo *);
5034 static void HandleDrawingAreaInfo(struct GadgetInfo *);
5035 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
5036 static boolean AskToCopyAndModifyLevelTemplate(void);
5037 static boolean getDrawModeHiRes(void);
5038 static int getTabulatorBarWidth(void);
5039 static int getTabulatorBarHeight(void);
5040 static Pixel getTabulatorBarColor(void);
5041 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
5042 static int numHiresTiles(int);
5043
5044 static int num_editor_gadgets = 0;      // dynamically determined
5045
5046 static struct GadgetInfo **level_editor_gadget = NULL;
5047 static int *right_gadget_border = NULL;
5048
5049 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
5050 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
5051 static boolean draw_with_brush = FALSE;
5052 static int properties_element = 0;
5053
5054 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5055 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5056 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5057 static int undo_buffer_position = 0;
5058 static int undo_buffer_steps = 0;
5059 static int redo_buffer_steps = 0;
5060
5061 static int edit_mode;
5062 static int edit_mode_levelconfig;
5063 static int edit_mode_properties;
5064
5065 static int element_shift = 0;
5066
5067 static int editor_el_players[] =
5068 {
5069   EL_PLAYER_1,
5070   EL_PLAYER_2,
5071   EL_PLAYER_3,
5072   EL_PLAYER_4
5073 };
5074 static int *editor_el_players_ptr = editor_el_players;
5075 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
5076
5077 static int editor_hl_boulderdash[] =
5078 {
5079   EL_INTERNAL_CASCADE_BD_ACTIVE,
5080   EL_CHAR('B'),
5081   EL_CHAR('D'),
5082   EL_EMPTY,
5083 };
5084
5085 static int editor_el_boulderdash[] =
5086 {
5087   EL_EMPTY,
5088   EL_SAND,
5089   EL_BD_ROCK,
5090   EL_BD_DIAMOND,
5091
5092   EL_STEELWALL,
5093   EL_BD_WALL,
5094   EL_BD_EXPANDABLE_WALL,
5095   EL_BD_MAGIC_WALL,
5096
5097   EL_BD_AMOEBA,
5098   EL_BD_BUTTERFLY_UP,
5099   EL_BD_FIREFLY_UP,
5100   EL_EXIT_CLOSED,
5101
5102   EL_BD_BUTTERFLY_LEFT,
5103   EL_BD_FIREFLY_LEFT,
5104   EL_BD_BUTTERFLY_RIGHT,
5105   EL_BD_FIREFLY_RIGHT,
5106
5107   EL_EMPTY,
5108   EL_BD_BUTTERFLY_DOWN,
5109   EL_BD_FIREFLY_DOWN,
5110   EL_EXIT_OPEN,
5111 };
5112 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
5113 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
5114 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
5115 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
5116
5117 static int editor_hl_boulderdash_native[] =
5118 {
5119   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
5120   EL_CHAR('B'),
5121   EL_CHAR('D'),
5122   EL_EMPTY,
5123 };
5124
5125 static int editor_el_boulderdash_native[] =
5126 {
5127   EL_EMPTY,
5128   EL_BD_SAND,
5129   EL_BD_ROCK,
5130   EL_BD_DIAMOND,
5131
5132   EL_BD_STEELWALL,
5133   EL_BD_WALL,
5134   EL_BD_SAND_2,
5135   EL_BD_MAGIC_WALL,
5136
5137   EL_BD_AMOEBA,
5138   EL_BD_BUTTERFLY_UP,
5139   EL_BD_FIREFLY_UP,
5140   EL_BD_EXIT_CLOSED,
5141
5142   EL_BD_BUTTERFLY_LEFT,
5143   EL_BD_FIREFLY_LEFT,
5144   EL_BD_BUTTERFLY_RIGHT,
5145   EL_BD_FIREFLY_RIGHT,
5146
5147   EL_BD_INBOX,
5148   EL_BD_BUTTERFLY_DOWN,
5149   EL_BD_FIREFLY_DOWN,
5150   EL_BD_EXIT_OPEN,
5151
5152   EL_BD_AMOEBA_2,
5153   EL_BD_BUTTERFLY_2_UP,
5154   EL_BD_FIREFLY_2_UP,
5155   EL_BD_SLIME,
5156
5157   EL_BD_BUTTERFLY_2_LEFT,
5158   EL_BD_FIREFLY_2_LEFT,
5159   EL_BD_BUTTERFLY_2_RIGHT,
5160   EL_BD_FIREFLY_2_RIGHT,
5161
5162   EL_BD_BOMB,
5163   EL_BD_BUTTERFLY_2_DOWN,
5164   EL_BD_FIREFLY_2_DOWN,
5165   EL_BD_FLYING_DIAMOND,
5166
5167   EL_BD_NITRO_PACK,
5168   EL_BD_DRAGONFLY_UP,
5169   EL_BD_STONEFLY_UP,
5170   EL_BD_DIAMOND_GLUED,
5171
5172   EL_BD_DRAGONFLY_LEFT,
5173   EL_BD_STONEFLY_LEFT,
5174   EL_BD_DRAGONFLY_RIGHT,
5175   EL_BD_STONEFLY_RIGHT,
5176
5177   EL_BD_NUT,
5178   EL_BD_DRAGONFLY_DOWN,
5179   EL_BD_STONEFLY_DOWN,
5180   EL_EMPTY,
5181
5182   EL_BD_BITER_SWITCH_1,
5183   EL_BD_BITER_UP,
5184   EL_BD_COW_UP,
5185   EL_EMPTY,
5186
5187   EL_BD_BITER_LEFT,
5188   EL_BD_COW_LEFT,
5189   EL_BD_BITER_RIGHT,
5190   EL_BD_COW_RIGHT,
5191
5192   EL_BD_VOODOO_DOLL,
5193   EL_BD_BITER_DOWN,
5194   EL_BD_COW_DOWN,
5195   EL_BD_GHOST,
5196
5197   EL_BD_SAND_GLUED,
5198   EL_BD_SAND_BALL,
5199   EL_BD_SAND_LOOSE,
5200   EL_BD_WALL_NON_SLOPED,
5201
5202   EL_BD_SAND_SLOPED_UP_LEFT,
5203   EL_BD_SAND_SLOPED_UP_RIGHT,
5204   EL_BD_WALL_SLOPED_UP_LEFT,
5205   EL_BD_WALL_SLOPED_UP_RIGHT,
5206
5207   EL_BD_SAND_SLOPED_DOWN_LEFT,
5208   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5209   EL_BD_WALL_SLOPED_DOWN_LEFT,
5210   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5211
5212   EL_BD_FLYING_ROCK,
5213   EL_BD_ROCK_GLUED,
5214   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5215   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5216
5217   EL_BD_WAITING_ROCK,
5218   EL_BD_CHASING_ROCK,
5219   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5220   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5221
5222   EL_BD_MEGA_ROCK,
5223   EL_BD_SWEET,
5224   EL_BD_INVISIBLE_EXIT_CLOSED,
5225   EL_BD_INVISIBLE_EXIT_OPEN,
5226
5227   EL_BD_STEELWALL_EXPLODABLE,
5228   EL_BD_STEELWALL_DIGGABLE,
5229   EL_BD_WALL_DIGGABLE,
5230   EL_BD_FALLING_WALL,
5231
5232   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5233   EL_BD_EXPANDABLE_WALL_VERTICAL,
5234   EL_BD_EXPANDABLE_WALL_ANY,
5235   EL_BD_EXPANDABLE_WALL_SWITCH,
5236
5237   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5238   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5239   EL_BD_EXPANDABLE_STEELWALL_ANY,
5240   EL_BD_CREATURE_SWITCH,
5241
5242   EL_BD_BLADDER,
5243   EL_BD_BLADDER_SPENDER,
5244   EL_BD_REPLICATOR,
5245   EL_BD_REPLICATOR_SWITCH,
5246
5247   EL_BD_CONVEYOR_LEFT,
5248   EL_BD_CONVEYOR_RIGHT,
5249   EL_BD_CONVEYOR_SWITCH,
5250   EL_BD_CONVEYOR_DIR_SWITCH,
5251
5252   EL_BD_CLOCK,
5253   EL_BD_TIME_PENALTY,
5254   EL_BD_GRAVESTONE,
5255   EL_BD_SKELETON,
5256
5257   EL_BD_WATER,
5258   EL_BD_ACID,
5259   EL_BD_LAVA,
5260   EL_BD_BOX,
5261
5262   EL_BD_GATE_1,
5263   EL_BD_GATE_2,
5264   EL_BD_GATE_3,
5265   EL_BD_TRAPPED_DIAMOND,
5266
5267   EL_BD_KEY_1,
5268   EL_BD_KEY_2,
5269   EL_BD_KEY_3,
5270   EL_BD_DIAMOND_KEY,
5271
5272   EL_BD_WALL_KEY_1,
5273   EL_BD_WALL_KEY_2,
5274   EL_BD_WALL_KEY_3,
5275   EL_BD_WALL_DIAMOND,
5276
5277   EL_BD_POT,
5278   EL_BD_GRAVITY_SWITCH,
5279   EL_BD_PNEUMATIC_HAMMER,
5280   EL_BD_TELEPORTER,
5281
5282   EL_BD_PLAYER,
5283   EL_BD_PLAYER_WITH_BOMB,
5284   EL_BD_PLAYER_GLUED,
5285   EL_BD_PLAYER_STIRRING,
5286 };
5287 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5288 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5289 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5290 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5291
5292 static int editor_hl_boulderdash_effects[] =
5293 {
5294   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5295   EL_CHAR('B'),
5296   EL_CHAR('D'),
5297   EL_CHAR('E'),
5298 };
5299
5300 static int editor_el_boulderdash_effects[] =
5301 {
5302   EL_BD_DIAMOND_FALLING,
5303   EL_BD_ROCK_FALLING,
5304   EL_BD_MEGA_ROCK_FALLING,
5305   EL_BD_FLYING_DIAMOND_FLYING,
5306
5307   EL_BD_FALLING_WALL_FALLING,
5308   EL_BD_NITRO_PACK_FALLING,
5309   EL_BD_NUT_FALLING,
5310   EL_BD_FLYING_ROCK_FLYING,
5311
5312   EL_BD_PLAYER_GROWING_1,
5313   EL_BD_PLAYER_GROWING_2,
5314   EL_BD_PLAYER_GROWING_3,
5315   EL_BD_PLAYER,
5316
5317   EL_BD_PLAYER_WITH_BOMB,
5318   EL_BD_PLAYER_STIRRING,
5319   EL_BD_EXIT_OPEN,
5320   EL_BD_INVISIBLE_EXIT_OPEN,
5321
5322   EL_BD_BLADDER_1,
5323   EL_BD_BLADDER_2,
5324   EL_BD_BLADDER_3,
5325   EL_BD_BLADDER_4,
5326
5327   EL_BD_BLADDER_5,
5328   EL_BD_BLADDER_6,
5329   EL_BD_BLADDER_7,
5330   EL_BD_BLADDER_8,
5331
5332   EL_BD_SAND_2,
5333   EL_BD_COW_ENCLOSED_1,
5334   EL_BD_COW_ENCLOSED_2,
5335   EL_BD_COW_ENCLOSED_3,
5336
5337   EL_BD_COW_ENCLOSED_4,
5338   EL_BD_COW_ENCLOSED_5,
5339   EL_BD_COW_ENCLOSED_6,
5340   EL_BD_COW_ENCLOSED_7,
5341
5342   EL_BD_WATER_1,
5343   EL_BD_WATER_2,
5344   EL_BD_WATER_3,
5345   EL_BD_WATER_4,
5346
5347   EL_BD_WATER_5,
5348   EL_BD_WATER_6,
5349   EL_BD_WATER_7,
5350   EL_BD_WATER_8,
5351
5352   EL_BD_WATER_9,
5353   EL_BD_WATER_10,
5354   EL_BD_WATER_11,
5355   EL_BD_WATER_12,
5356
5357   EL_BD_WATER_13,
5358   EL_BD_WATER_14,
5359   EL_BD_WATER_15,
5360   EL_BD_WATER_16,
5361
5362   EL_BD_BOMB_TICKING_1,
5363   EL_BD_BOMB_TICKING_2,
5364   EL_BD_BOMB_TICKING_3,
5365   EL_BD_BOMB_TICKING_4,
5366
5367   EL_BD_BOMB_TICKING_5,
5368   EL_BD_BOMB_TICKING_6,
5369   EL_BD_BOMB_TICKING_7,
5370   EL_EMPTY,
5371
5372   EL_BD_BOMB_EXPLODING_1,
5373   EL_BD_BOMB_EXPLODING_2,
5374   EL_BD_BOMB_EXPLODING_3,
5375   EL_BD_BOMB_EXPLODING_4,
5376
5377   EL_BD_NUT_BREAKING_1,
5378   EL_BD_NUT_BREAKING_2,
5379   EL_BD_NUT_BREAKING_3,
5380   EL_BD_NUT_BREAKING_4,
5381
5382   EL_BD_EXPLODING_1,
5383   EL_BD_EXPLODING_2,
5384   EL_BD_EXPLODING_3,
5385   EL_BD_EXPLODING_4,
5386
5387   EL_BD_EXPLODING_5,
5388   EL_BD_TIME_PENALTY,
5389   EL_BD_DIAMOND_GROWING_1,
5390   EL_BD_DIAMOND_GROWING_2,
5391
5392   EL_BD_DIAMOND_GROWING_3,
5393   EL_BD_DIAMOND_GROWING_4,
5394   EL_BD_DIAMOND_GROWING_5,
5395   EL_BD_NITRO_PACK_EXPLODING,
5396
5397   EL_BD_NITRO_PACK_EXPLODING_1,
5398   EL_BD_NITRO_PACK_EXPLODING_2,
5399   EL_BD_NITRO_PACK_EXPLODING_3,
5400   EL_BD_NITRO_PACK_EXPLODING_4,
5401
5402   EL_BD_ROCK_GROWING_1,
5403   EL_BD_ROCK_GROWING_2,
5404   EL_BD_ROCK_GROWING_3,
5405   EL_BD_ROCK_GROWING_4,
5406
5407   EL_BD_STEELWALL_GROWING_1,
5408   EL_BD_STEELWALL_GROWING_2,
5409   EL_BD_STEELWALL_GROWING_3,
5410   EL_BD_STEELWALL_GROWING_4,
5411
5412   EL_BD_CLOCK_GROWING_1,
5413   EL_BD_CLOCK_GROWING_2,
5414   EL_BD_CLOCK_GROWING_3,
5415   EL_BD_CLOCK_GROWING_4,
5416
5417   EL_BD_GHOST_EXPLODING_1,
5418   EL_BD_GHOST_EXPLODING_2,
5419   EL_BD_GHOST_EXPLODING_3,
5420   EL_BD_GHOST_EXPLODING_4,
5421 };
5422 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5423 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5424 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5425 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5426
5427 static int editor_hl_emerald_mine[] =
5428 {
5429   EL_INTERNAL_CASCADE_EM_ACTIVE,
5430   EL_CHAR('E'),
5431   EL_CHAR('M'),
5432   EL_EMPTY,
5433 };
5434
5435 static int editor_el_emerald_mine[] =
5436 {
5437   EL_SAND,
5438   EL_ROCK,
5439   EL_QUICKSAND_EMPTY,
5440   EL_QUICKSAND_FULL,
5441
5442   EL_STEELWALL,
5443   EL_WALL,
5444   EL_WALL_SLIPPERY,
5445   EL_MAGIC_WALL,
5446
5447   EL_EMERALD,
5448   EL_DIAMOND,
5449   EL_NUT,
5450   EL_BOMB,
5451
5452   EL_EM_DYNAMITE,
5453   EL_EM_DYNAMITE_ACTIVE,
5454   EL_EM_EXIT_CLOSED,
5455   EL_EM_EXIT_OPEN,
5456
5457   EL_YAMYAM_UP,
5458   EL_BUG_UP,
5459   EL_SPACESHIP_UP,
5460   EL_ROBOT,
5461
5462   EL_BUG_LEFT,
5463   EL_SPACESHIP_LEFT,
5464   EL_BUG_RIGHT,
5465   EL_SPACESHIP_RIGHT,
5466
5467   EL_ROBOT_WHEEL,
5468   EL_BUG_DOWN,
5469   EL_SPACESHIP_DOWN,
5470   EL_INVISIBLE_WALL,
5471
5472   EL_ACID_POOL_TOPLEFT,
5473   EL_ACID,
5474   EL_ACID_POOL_TOPRIGHT,
5475   EL_AMOEBA_DROP,
5476
5477   EL_ACID_POOL_BOTTOMLEFT,
5478   EL_ACID_POOL_BOTTOM,
5479   EL_ACID_POOL_BOTTOMRIGHT,
5480   EL_AMOEBA_WET,
5481
5482   EL_EM_KEY_1,
5483   EL_EM_KEY_2,
5484   EL_EM_KEY_3,
5485   EL_EM_KEY_4,
5486
5487   EL_EM_GATE_1,
5488   EL_EM_GATE_2,
5489   EL_EM_GATE_3,
5490   EL_EM_GATE_4,
5491
5492   EL_EM_GATE_1_GRAY,
5493   EL_EM_GATE_2_GRAY,
5494   EL_EM_GATE_3_GRAY,
5495   EL_EM_GATE_4_GRAY,
5496 };
5497 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5498 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5499 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5500 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5501
5502 static int editor_hl_emerald_mine_club[] =
5503 {
5504   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5505   EL_CHAR('E'),
5506   EL_CHAR('M'),
5507   EL_CHAR('C'),
5508 };
5509
5510 static int editor_el_emerald_mine_club[] =
5511 {
5512   EL_EMC_KEY_5,
5513   EL_EMC_KEY_6,
5514   EL_EMC_KEY_7,
5515   EL_EMC_KEY_8,
5516
5517   EL_EMC_GATE_5,
5518   EL_EMC_GATE_6,
5519   EL_EMC_GATE_7,
5520   EL_EMC_GATE_8,
5521
5522   EL_EMC_GATE_5_GRAY,
5523   EL_EMC_GATE_6_GRAY,
5524   EL_EMC_GATE_7_GRAY,
5525   EL_EMC_GATE_8_GRAY,
5526
5527   EL_EMC_STEELWALL_1,
5528   EL_EMC_STEELWALL_2,
5529   EL_EMC_STEELWALL_3,
5530   EL_EMC_STEELWALL_4,
5531
5532   EL_EMC_WALL_13,
5533   EL_EMC_WALL_14,
5534   EL_EMC_WALL_15,
5535   EL_EMC_WALL_16,
5536
5537   EL_EMC_WALL_SLIPPERY_1,
5538   EL_EMC_WALL_SLIPPERY_2,
5539   EL_EMC_WALL_SLIPPERY_3,
5540   EL_EMC_WALL_SLIPPERY_4,
5541
5542   EL_EMC_WALL_1,
5543   EL_EMC_WALL_2,
5544   EL_EMC_WALL_3,
5545   EL_EMC_WALL_4,
5546
5547   EL_EMC_WALL_5,
5548   EL_EMC_WALL_6,
5549   EL_EMC_WALL_7,
5550   EL_EMC_WALL_8,
5551
5552   EL_EMC_WALL_9,
5553   EL_EMC_WALL_10,
5554   EL_EMC_WALL_11,
5555   EL_EMC_WALL_12,
5556
5557   EL_EMC_GRASS,
5558   EL_EMC_FAKE_GRASS,
5559   EL_EMC_PLANT,
5560   EL_EMC_DRIPPER,
5561
5562   EL_EMC_MAGIC_BALL,
5563   EL_EMC_MAGIC_BALL_SWITCH,
5564   EL_EMC_LENSES,
5565   EL_EMC_MAGNIFIER,
5566
5567   EL_SPRING_LEFT,
5568   EL_SPRING,
5569   EL_SPRING_RIGHT,
5570   EL_EMC_SPRING_BUMPER,
5571
5572   EL_BALLOON,
5573   EL_YAMYAM_UP,
5574   EL_BALLOON_SWITCH_UP,
5575   EL_BALLOON_SWITCH_ANY,
5576
5577   EL_YAMYAM_LEFT,
5578   EL_BALLOON_SWITCH_LEFT,
5579   EL_YAMYAM_RIGHT,
5580   EL_BALLOON_SWITCH_RIGHT,
5581
5582   EL_EMC_ANDROID,
5583   EL_YAMYAM_DOWN,
5584   EL_BALLOON_SWITCH_DOWN,
5585   EL_BALLOON_SWITCH_NONE,
5586 };
5587 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5588 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5589 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5590 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5591
5592 static int editor_hl_rnd[] =
5593 {
5594   EL_INTERNAL_CASCADE_RND_ACTIVE,
5595   EL_CHAR('R'),
5596   EL_CHAR('N'),
5597   EL_CHAR('D'),
5598 };
5599
5600 static int editor_el_rnd[] =
5601 {
5602   EL_DYNAMITE,                  // RND
5603   EL_DYNAMITE_ACTIVE,           // RND
5604   EL_EMPTY,
5605   EL_EMPTY,
5606
5607   EL_KEY_1,
5608   EL_KEY_2,
5609   EL_KEY_3,
5610   EL_KEY_4,
5611
5612   EL_GATE_1,
5613   EL_GATE_2,
5614   EL_GATE_3,
5615   EL_GATE_4,
5616
5617   EL_GATE_1_GRAY,
5618   EL_GATE_2_GRAY,
5619   EL_GATE_3_GRAY,
5620   EL_GATE_4_GRAY,
5621
5622   EL_ARROW_LEFT,
5623   EL_ARROW_RIGHT,
5624   EL_ARROW_UP,
5625   EL_ARROW_DOWN,
5626
5627   EL_AMOEBA_DEAD,
5628   EL_AMOEBA_DRY,
5629   EL_AMOEBA_FULL,
5630   EL_GAME_OF_LIFE,
5631
5632   EL_EMERALD_YELLOW,
5633   EL_EMERALD_RED,
5634   EL_EMERALD_PURPLE,
5635   EL_BIOMAZE,
5636
5637   EL_WALL_EMERALD_YELLOW,
5638   EL_WALL_EMERALD_RED,
5639   EL_WALL_EMERALD_PURPLE,
5640   EL_WALL_BD_DIAMOND,
5641
5642   EL_SPEED_PILL,
5643   EL_PACMAN_UP,
5644   EL_TIME_ORB_FULL,
5645   EL_TIME_ORB_EMPTY,
5646
5647   EL_PACMAN_LEFT,
5648   EL_DARK_YAMYAM,
5649   EL_PACMAN_RIGHT,
5650   EL_YAMYAM,                    // RND
5651
5652   EL_BLACK_ORB,
5653   EL_PACMAN_DOWN,
5654   EL_LAMP,
5655   EL_LAMP_ACTIVE,
5656
5657   EL_DYNABOMB_INCREASE_NUMBER,
5658   EL_DYNABOMB_INCREASE_SIZE,
5659   EL_DYNABOMB_INCREASE_POWER,
5660   EL_STONEBLOCK,
5661
5662   EL_MOLE,
5663   EL_PENGUIN,
5664   EL_PIG,
5665   EL_DRAGON,
5666
5667   EL_BUG,
5668   EL_MOLE_UP,
5669   EL_BD_BUTTERFLY,
5670   EL_BD_FIREFLY,
5671
5672   EL_MOLE_LEFT,
5673   EL_SATELLITE,
5674   EL_MOLE_RIGHT,
5675   EL_PACMAN,
5676
5677   EL_SPACESHIP,
5678   EL_MOLE_DOWN,
5679   EL_INVISIBLE_STEELWALL,
5680   EL_INVISIBLE_WALL,
5681
5682   EL_EXPANDABLE_WALL,
5683   EL_EXPANDABLE_WALL_HORIZONTAL,
5684   EL_EXPANDABLE_WALL_VERTICAL,
5685   EL_EXPANDABLE_WALL_ANY,
5686 };
5687 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5688 static int *editor_el_rnd_ptr = editor_el_rnd;
5689 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5690 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5691
5692 static int editor_hl_sokoban[] =
5693 {
5694   EL_INTERNAL_CASCADE_SB_ACTIVE,
5695   EL_CHAR('S'),
5696   EL_CHAR('B'),
5697   EL_EMPTY,
5698 };
5699
5700 static int editor_el_sokoban[] =
5701 {
5702   EL_SOKOBAN_OBJECT,
5703   EL_SOKOBAN_FIELD_EMPTY,
5704   EL_SOKOBAN_FIELD_FULL,
5705   EL_SOKOBAN_FIELD_PLAYER,
5706 };
5707 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5708 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5709 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5710 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5711
5712 static int editor_hl_supaplex[] =
5713 {
5714   EL_INTERNAL_CASCADE_SP_ACTIVE,
5715   EL_CHAR('S'),
5716   EL_CHAR('P'),
5717   EL_EMPTY,
5718 };
5719
5720 static int editor_el_supaplex[] =
5721 {
5722   EL_SP_MURPHY,
5723   EL_EMPTY,
5724   EL_SP_BASE,
5725   EL_SP_BUGGY_BASE,
5726
5727   EL_SP_INFOTRON,
5728   EL_SP_ZONK,
5729   EL_SP_SNIKSNAK,
5730   EL_SP_ELECTRON,
5731
5732   EL_SP_DISK_RED,
5733   EL_SP_DISK_ORANGE,
5734   EL_SP_DISK_YELLOW,
5735   EL_SP_TERMINAL,
5736
5737   EL_SP_EXIT_CLOSED,
5738   EL_SP_PORT_HORIZONTAL,
5739   EL_SP_PORT_VERTICAL,
5740   EL_SP_PORT_ANY,
5741
5742   EL_SP_PORT_LEFT,
5743   EL_SP_PORT_RIGHT,
5744   EL_SP_PORT_UP,
5745   EL_SP_PORT_DOWN,
5746
5747   EL_SP_GRAVITY_PORT_LEFT,
5748   EL_SP_GRAVITY_PORT_RIGHT,
5749   EL_SP_GRAVITY_PORT_UP,
5750   EL_SP_GRAVITY_PORT_DOWN,
5751
5752   EL_SP_GRAVITY_ON_PORT_LEFT,
5753   EL_SP_GRAVITY_ON_PORT_RIGHT,
5754   EL_SP_GRAVITY_ON_PORT_UP,
5755   EL_SP_GRAVITY_ON_PORT_DOWN,
5756
5757   EL_SP_GRAVITY_OFF_PORT_LEFT,
5758   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5759   EL_SP_GRAVITY_OFF_PORT_UP,
5760   EL_SP_GRAVITY_OFF_PORT_DOWN,
5761
5762   EL_SP_HARDWARE_GRAY,
5763   EL_SP_HARDWARE_GREEN,
5764   EL_SP_HARDWARE_BLUE,
5765   EL_SP_HARDWARE_RED,
5766
5767   EL_SP_HARDWARE_BASE_1,
5768   EL_SP_HARDWARE_BASE_2,
5769   EL_SP_HARDWARE_BASE_3,
5770   EL_SP_HARDWARE_BASE_4,
5771
5772   EL_SP_HARDWARE_BASE_5,
5773   EL_SP_HARDWARE_BASE_6,
5774   EL_SP_HARDWARE_YELLOW,
5775   EL_SP_CHIP_TOP,
5776
5777   EL_SP_CHIP_SINGLE,
5778   EL_SP_CHIP_LEFT,
5779   EL_SP_CHIP_RIGHT,
5780   EL_SP_CHIP_BOTTOM,
5781 };
5782 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5783 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5784 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5785 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5786
5787 static int editor_hl_diamond_caves[] =
5788 {
5789   EL_INTERNAL_CASCADE_DC_ACTIVE,
5790   EL_CHAR('D'),
5791   EL_CHAR('C'),
5792   EL_CHAR('2'),
5793 };
5794
5795 static int editor_el_diamond_caves[] =
5796 {
5797   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5798   EL_EM_STEEL_EXIT_OPEN,        // DC2
5799   EL_WALL_EMERALD,              // DC2
5800   EL_WALL_DIAMOND,              // DC2
5801
5802   EL_PEARL,
5803   EL_CRYSTAL,
5804   EL_WALL_PEARL,
5805   EL_WALL_CRYSTAL,
5806
5807   EL_CONVEYOR_BELT_1_LEFT,
5808   EL_CONVEYOR_BELT_1_MIDDLE,
5809   EL_CONVEYOR_BELT_1_RIGHT,
5810   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5811
5812   EL_CONVEYOR_BELT_2_LEFT,
5813   EL_CONVEYOR_BELT_2_MIDDLE,
5814   EL_CONVEYOR_BELT_2_RIGHT,
5815   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5816
5817   EL_CONVEYOR_BELT_3_LEFT,
5818   EL_CONVEYOR_BELT_3_MIDDLE,
5819   EL_CONVEYOR_BELT_3_RIGHT,
5820   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5821
5822   EL_CONVEYOR_BELT_4_LEFT,
5823   EL_CONVEYOR_BELT_4_MIDDLE,
5824   EL_CONVEYOR_BELT_4_RIGHT,
5825   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5826
5827   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5828   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5829   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5830   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5831
5832   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5833   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5834   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5835   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5836
5837   EL_TIMEGATE_CLOSED,
5838   EL_TIMEGATE_OPEN,
5839   EL_TIMEGATE_SWITCH,
5840   EL_DC_TIMEGATE_SWITCH,
5841
5842   EL_SWITCHGATE_CLOSED,
5843   EL_SWITCHGATE_OPEN,
5844   EL_SWITCHGATE_SWITCH_UP,
5845   EL_SWITCHGATE_SWITCH_DOWN,
5846
5847   EL_LIGHT_SWITCH,
5848   EL_LIGHT_SWITCH_ACTIVE,
5849   EL_DC_SWITCHGATE_SWITCH_UP,
5850   EL_DC_SWITCHGATE_SWITCH_DOWN,
5851
5852   EL_STEEL_EXIT_CLOSED,
5853   EL_STEEL_EXIT_OPEN,
5854   EL_STEELWALL_SLIPPERY,
5855   EL_INVISIBLE_SAND,
5856
5857   EL_QUICKSAND_FAST_EMPTY,
5858   EL_QUICKSAND_FAST_FULL,
5859   EL_LANDMINE,
5860   EL_DC_LANDMINE,
5861
5862   EL_SHIELD_NORMAL,
5863   EL_SHIELD_DEADLY,
5864   EL_EXTRA_TIME,
5865   EL_DC_MAGIC_WALL,
5866
5867   EL_ENVELOPE_1,
5868   EL_ENVELOPE_2,
5869   EL_ENVELOPE_3,
5870   EL_ENVELOPE_4,
5871
5872   EL_SIGN_RADIOACTIVITY,
5873   EL_SIGN_WHEELCHAIR,
5874   EL_SIGN_PARKING,
5875   EL_SIGN_NO_ENTRY,
5876
5877   EL_SIGN_GIVE_WAY,
5878   EL_SIGN_ENTRY_FORBIDDEN,
5879   EL_SIGN_EMERGENCY_EXIT,
5880   EL_SIGN_YIN_YANG,
5881
5882 #if 0
5883   EL_SIGN_SPERMS,
5884   EL_SIGN_BULLET,
5885   EL_SIGN_HEART,
5886   EL_SIGN_CROSS,
5887
5888   EL_SIGN_FRANKIE,
5889   EL_EMPTY,
5890   EL_EMPTY,
5891   EL_EMPTY,
5892
5893   EL_SPERMS,
5894   EL_BULLET,
5895   EL_HEART,
5896   EL_CROSS,
5897
5898   EL_FRANKIE,
5899   EL_EMPTY,
5900   EL_EMPTY,
5901   EL_EMPTY,
5902 #endif
5903
5904   EL_DC_STEELWALL_2_SINGLE,
5905   EL_DC_STEELWALL_2_TOP,
5906   EL_SIGN_EXCLAMATION,
5907   EL_SIGN_STOP,
5908
5909   EL_DC_STEELWALL_2_LEFT,
5910   EL_DC_STEELWALL_2_MIDDLE,
5911   EL_DC_STEELWALL_2_HORIZONTAL,
5912   EL_DC_STEELWALL_2_RIGHT,
5913
5914   EL_DC_STEELWALL_1_TOPLEFT,
5915   EL_DC_STEELWALL_2_VERTICAL,
5916   EL_DC_STEELWALL_1_TOPRIGHT,
5917   EL_DC_GATE_WHITE,
5918
5919   EL_DC_STEELWALL_1_VERTICAL,
5920   EL_DC_STEELWALL_2_BOTTOM,
5921   EL_DC_KEY_WHITE,
5922   EL_DC_GATE_WHITE_GRAY,
5923
5924   EL_DC_STEELWALL_1_BOTTOMLEFT,
5925   EL_DC_STEELWALL_1_HORIZONTAL,
5926   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5927   EL_DC_GATE_FAKE_GRAY,
5928
5929   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5930   EL_DC_STEELWALL_1_BOTTOM,
5931   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5932   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5933
5934   EL_DC_STEELWALL_1_RIGHT,
5935   EL_EMPTY,
5936   EL_DC_STEELWALL_1_LEFT,
5937   EL_EXPANDABLE_STEELWALL_VERTICAL,
5938
5939   EL_DC_STEELWALL_1_TOPRIGHT_2,
5940   EL_DC_STEELWALL_1_TOP,
5941   EL_DC_STEELWALL_1_TOPLEFT_2,
5942   EL_EXPANDABLE_STEELWALL_ANY,
5943 };
5944 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5945 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5946 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5947 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5948
5949 static int editor_hl_dx_boulderdash[] =
5950 {
5951   EL_INTERNAL_CASCADE_DX_ACTIVE,
5952   EL_CHAR('D'),
5953   EL_CHAR('X'),
5954   EL_EMPTY,
5955 };
5956
5957 static int editor_el_dx_boulderdash[] =
5958 {
5959   EL_EMPTY,
5960   EL_TUBE_RIGHT_DOWN,
5961   EL_TUBE_HORIZONTAL_DOWN,
5962   EL_TUBE_LEFT_DOWN,
5963
5964   EL_TUBE_HORIZONTAL,
5965   EL_TUBE_VERTICAL_RIGHT,
5966   EL_TUBE_ANY,
5967   EL_TUBE_VERTICAL_LEFT,
5968
5969   EL_TUBE_VERTICAL,
5970   EL_TUBE_RIGHT_UP,
5971   EL_TUBE_HORIZONTAL_UP,
5972   EL_TUBE_LEFT_UP,
5973
5974   EL_TRAP,
5975   EL_DX_SUPABOMB,
5976   EL_EMPTY,
5977   EL_EMPTY
5978 };
5979 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
5980 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
5981 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
5982 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
5983
5984 static int editor_hl_mirror_magic[] =
5985 {
5986   EL_INTERNAL_CASCADE_MM_ACTIVE,
5987   EL_CHAR('M'),
5988   EL_CHAR('M'),
5989   EL_EMPTY,
5990 };
5991
5992 static int editor_el_mirror_magic[] =
5993 {
5994   EL_MM_MCDUFFIN_RIGHT,
5995   EL_MM_MCDUFFIN_UP,
5996   EL_MM_MCDUFFIN_LEFT,
5997   EL_MM_MCDUFFIN_DOWN,
5998
5999   EL_MM_MIRROR_START,
6000   EL_MM_MIRROR_FIXED_START,
6001   EL_MM_POLARIZER_START,
6002   EL_MM_POLARIZER_CROSS_START,
6003
6004   EL_MM_TELEPORTER_RED_START,
6005   EL_MM_TELEPORTER_YELLOW_START,
6006   EL_MM_TELEPORTER_GREEN_START,
6007   EL_MM_TELEPORTER_BLUE_START,
6008
6009   EL_MM_PRISM,
6010   EL_MM_FUSE_ACTIVE,
6011   EL_MM_PACMAN_RIGHT,
6012   EL_MM_EXIT_CLOSED,
6013
6014   EL_MM_KETTLE,
6015   EL_MM_BOMB,
6016   EL_MM_KEY,
6017   EL_MM_FUEL_FULL,
6018
6019   EL_MM_LIGHTBULB,
6020   EL_MM_LIGHTBULB_ACTIVE,
6021   EL_MM_GRAY_BALL,
6022   EL_MM_LIGHTBALL,
6023
6024   EL_MM_STEEL_WALL,
6025   EL_MM_WOODEN_WALL,
6026   EL_MM_ICE_WALL,
6027   EL_MM_AMOEBA_WALL,
6028
6029   EL_MM_STEEL_LOCK,
6030   EL_MM_WOODEN_LOCK,
6031   EL_MM_STEEL_BLOCK,
6032   EL_MM_WOODEN_BLOCK,
6033
6034   EL_MM_STEEL_GRID_FIXED_1,
6035   EL_MM_STEEL_GRID_FIXED_2,
6036   EL_MM_STEEL_GRID_FIXED_3,
6037   EL_MM_STEEL_GRID_FIXED_4,
6038
6039   EL_MM_WOODEN_GRID_FIXED_1,
6040   EL_MM_WOODEN_GRID_FIXED_2,
6041   EL_MM_WOODEN_GRID_FIXED_3,
6042   EL_MM_WOODEN_GRID_FIXED_4,
6043
6044   EL_MM_ENVELOPE_1,
6045   EL_MM_ENVELOPE_2,
6046   EL_MM_ENVELOPE_3,
6047   EL_MM_ENVELOPE_4
6048 };
6049 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
6050 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
6051 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
6052 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
6053
6054 static int editor_hl_deflektor[] =
6055 {
6056   EL_INTERNAL_CASCADE_DF_ACTIVE,
6057   EL_CHAR('D'),
6058   EL_CHAR('F'),
6059   EL_EMPTY,
6060 };
6061
6062 static int editor_el_deflektor[] =
6063 {
6064   EL_DF_LASER_RIGHT,
6065   EL_DF_LASER_UP,
6066   EL_DF_LASER_LEFT,
6067   EL_DF_LASER_DOWN,
6068
6069   EL_DF_RECEIVER_RIGHT,
6070   EL_DF_RECEIVER_UP,
6071   EL_DF_RECEIVER_LEFT,
6072   EL_DF_RECEIVER_DOWN,
6073
6074   EL_DF_MIRROR_START,
6075   EL_DF_MIRROR_ROTATING_START,
6076   EL_DF_MIRROR_FIXED_START,
6077   EL_DF_CELL,
6078
6079   EL_DF_FIBRE_OPTIC_RED_1,
6080   EL_DF_FIBRE_OPTIC_YELLOW_1,
6081   EL_DF_FIBRE_OPTIC_GREEN_1,
6082   EL_DF_FIBRE_OPTIC_BLUE_1,
6083
6084   EL_DF_STEEL_GRID_FIXED_START,
6085   EL_DF_STEEL_GRID_ROTATING_START,
6086   EL_DF_WOODEN_GRID_FIXED_START,
6087   EL_DF_WOODEN_GRID_ROTATING_START,
6088
6089   EL_DF_STEEL_WALL,
6090   EL_DF_WOODEN_WALL,
6091   EL_DF_REFRACTOR,
6092   EL_DF_MINE,
6093
6094   EL_DF_SLOPE_1,
6095   EL_DF_SLOPE_2,
6096   EL_DF_SLOPE_3,
6097   EL_DF_SLOPE_4
6098 };
6099 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
6100 static int *editor_el_deflektor_ptr = editor_el_deflektor;
6101 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
6102 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
6103
6104 static int editor_hl_chars[] =
6105 {
6106   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
6107   EL_CHAR('T'),
6108   EL_CHAR('X'),
6109   EL_CHAR('T'),
6110 };
6111
6112 static int editor_el_chars[] =
6113 {
6114   EL_CHAR(' '),
6115   EL_CHAR('!'),
6116   EL_CHAR('"'),
6117   EL_CHAR('#'),
6118
6119   EL_CHAR('$'),
6120   EL_CHAR('%'),
6121   EL_CHAR('&'),
6122   EL_CHAR('\''),
6123
6124   EL_CHAR('('),
6125   EL_CHAR(')'),
6126   EL_CHAR('*'),
6127   EL_CHAR('+'),
6128
6129   EL_CHAR(','),
6130   EL_CHAR('-'),
6131   EL_CHAR('.'),
6132   EL_CHAR('/'),
6133
6134   EL_CHAR('0'),
6135   EL_CHAR('1'),
6136   EL_CHAR('2'),
6137   EL_CHAR('3'),
6138
6139   EL_CHAR('4'),
6140   EL_CHAR('5'),
6141   EL_CHAR('6'),
6142   EL_CHAR('7'),
6143
6144   EL_CHAR('8'),
6145   EL_CHAR('9'),
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('A'),
6156   EL_CHAR('B'),
6157   EL_CHAR('C'),
6158
6159   EL_CHAR('D'),
6160   EL_CHAR('E'),
6161   EL_CHAR('F'),
6162   EL_CHAR('G'),
6163
6164   EL_CHAR('H'),
6165   EL_CHAR('I'),
6166   EL_CHAR('J'),
6167   EL_CHAR('K'),
6168
6169   EL_CHAR('L'),
6170   EL_CHAR('M'),
6171   EL_CHAR('N'),
6172   EL_CHAR('O'),
6173
6174   EL_CHAR('P'),
6175   EL_CHAR('Q'),
6176   EL_CHAR('R'),
6177   EL_CHAR('S'),
6178
6179   EL_CHAR('T'),
6180   EL_CHAR('U'),
6181   EL_CHAR('V'),
6182   EL_CHAR('W'),
6183
6184   EL_CHAR('X'),
6185   EL_CHAR('Y'),
6186   EL_CHAR('Z'),
6187   EL_CHAR('['),
6188
6189   EL_CHAR('\\'),
6190   EL_CHAR(']'),
6191   EL_CHAR('^'),
6192   EL_CHAR('_'),
6193
6194   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6195   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6196   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6197   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6198
6199   EL_CHAR(CHAR_BYTE_DEGREE),
6200   EL_CHAR(CHAR_BYTE_REGISTERED),
6201   EL_CHAR(FONT_ASCII_CURSOR),
6202   EL_CHAR(FONT_ASCII_BUTTON),
6203
6204   EL_CHAR(FONT_ASCII_UP),
6205   EL_CHAR(FONT_ASCII_DOWN),
6206   EL_CHAR(' '),
6207   EL_CHAR(' ')
6208 };
6209 static int *editor_hl_chars_ptr = editor_hl_chars;
6210 static int *editor_el_chars_ptr = editor_el_chars;
6211 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6212 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6213
6214 static int editor_hl_steel_chars[] =
6215 {
6216   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6217   EL_STEEL_CHAR('T'),
6218   EL_STEEL_CHAR('X'),
6219   EL_STEEL_CHAR('T'),
6220 };
6221
6222 static int editor_el_steel_chars[] =
6223 {
6224   EL_STEEL_CHAR(' '),
6225   EL_STEEL_CHAR('!'),
6226   EL_STEEL_CHAR('"'),
6227   EL_STEEL_CHAR('#'),
6228
6229   EL_STEEL_CHAR('$'),
6230   EL_STEEL_CHAR('%'),
6231   EL_STEEL_CHAR('&'),
6232   EL_STEEL_CHAR('\''),
6233
6234   EL_STEEL_CHAR('('),
6235   EL_STEEL_CHAR(')'),
6236   EL_STEEL_CHAR('*'),
6237   EL_STEEL_CHAR('+'),
6238
6239   EL_STEEL_CHAR(','),
6240   EL_STEEL_CHAR('-'),
6241   EL_STEEL_CHAR('.'),
6242   EL_STEEL_CHAR('/'),
6243
6244   EL_STEEL_CHAR('0'),
6245   EL_STEEL_CHAR('1'),
6246   EL_STEEL_CHAR('2'),
6247   EL_STEEL_CHAR('3'),
6248
6249   EL_STEEL_CHAR('4'),
6250   EL_STEEL_CHAR('5'),
6251   EL_STEEL_CHAR('6'),
6252   EL_STEEL_CHAR('7'),
6253
6254   EL_STEEL_CHAR('8'),
6255   EL_STEEL_CHAR('9'),
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('A'),
6266   EL_STEEL_CHAR('B'),
6267   EL_STEEL_CHAR('C'),
6268
6269   EL_STEEL_CHAR('D'),
6270   EL_STEEL_CHAR('E'),
6271   EL_STEEL_CHAR('F'),
6272   EL_STEEL_CHAR('G'),
6273
6274   EL_STEEL_CHAR('H'),
6275   EL_STEEL_CHAR('I'),
6276   EL_STEEL_CHAR('J'),
6277   EL_STEEL_CHAR('K'),
6278
6279   EL_STEEL_CHAR('L'),
6280   EL_STEEL_CHAR('M'),
6281   EL_STEEL_CHAR('N'),
6282   EL_STEEL_CHAR('O'),
6283
6284   EL_STEEL_CHAR('P'),
6285   EL_STEEL_CHAR('Q'),
6286   EL_STEEL_CHAR('R'),
6287   EL_STEEL_CHAR('S'),
6288
6289   EL_STEEL_CHAR('T'),
6290   EL_STEEL_CHAR('U'),
6291   EL_STEEL_CHAR('V'),
6292   EL_STEEL_CHAR('W'),
6293
6294   EL_STEEL_CHAR('X'),
6295   EL_STEEL_CHAR('Y'),
6296   EL_STEEL_CHAR('Z'),
6297   EL_STEEL_CHAR('['),
6298
6299   EL_STEEL_CHAR('\\'),
6300   EL_STEEL_CHAR(']'),
6301   EL_STEEL_CHAR('^'),
6302   EL_STEEL_CHAR('_'),
6303
6304   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6305   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6306   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6307   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6308
6309   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6310   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6311   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6312   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6313
6314   EL_STEEL_CHAR(FONT_ASCII_UP),
6315   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6316   EL_STEEL_CHAR(' '),
6317   EL_STEEL_CHAR(' ')
6318 };
6319 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6320 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6321 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6322 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6323
6324 static int editor_hl_custom[] =
6325 {
6326   EL_INTERNAL_CASCADE_CE_ACTIVE,
6327   EL_CHAR('C'),
6328   EL_CHAR('E'),
6329   EL_EMPTY,
6330 };
6331
6332 static int editor_el_custom[] =
6333 {
6334   EL_CUSTOM_START + 0,
6335   EL_CUSTOM_START + 1,
6336   EL_CUSTOM_START + 2,
6337   EL_CUSTOM_START + 3,
6338
6339   EL_CUSTOM_START + 4,
6340   EL_CUSTOM_START + 5,
6341   EL_CUSTOM_START + 6,
6342   EL_CUSTOM_START + 7,
6343
6344   EL_CUSTOM_START + 8,
6345   EL_CUSTOM_START + 9,
6346   EL_CUSTOM_START + 10,
6347   EL_CUSTOM_START + 11,
6348
6349   EL_CUSTOM_START + 12,
6350   EL_CUSTOM_START + 13,
6351   EL_CUSTOM_START + 14,
6352   EL_CUSTOM_START + 15,
6353
6354   EL_CUSTOM_START + 16,
6355   EL_CUSTOM_START + 17,
6356   EL_CUSTOM_START + 18,
6357   EL_CUSTOM_START + 19,
6358
6359   EL_CUSTOM_START + 20,
6360   EL_CUSTOM_START + 21,
6361   EL_CUSTOM_START + 22,
6362   EL_CUSTOM_START + 23,
6363
6364   EL_CUSTOM_START + 24,
6365   EL_CUSTOM_START + 25,
6366   EL_CUSTOM_START + 26,
6367   EL_CUSTOM_START + 27,
6368
6369   EL_CUSTOM_START + 28,
6370   EL_CUSTOM_START + 29,
6371   EL_CUSTOM_START + 30,
6372   EL_CUSTOM_START + 31,
6373
6374   EL_CUSTOM_START + 32,
6375   EL_CUSTOM_START + 33,
6376   EL_CUSTOM_START + 34,
6377   EL_CUSTOM_START + 35,
6378
6379   EL_CUSTOM_START + 36,
6380   EL_CUSTOM_START + 37,
6381   EL_CUSTOM_START + 38,
6382   EL_CUSTOM_START + 39,
6383
6384   EL_CUSTOM_START + 40,
6385   EL_CUSTOM_START + 41,
6386   EL_CUSTOM_START + 42,
6387   EL_CUSTOM_START + 43,
6388
6389   EL_CUSTOM_START + 44,
6390   EL_CUSTOM_START + 45,
6391   EL_CUSTOM_START + 46,
6392   EL_CUSTOM_START + 47,
6393
6394   EL_CUSTOM_START + 48,
6395   EL_CUSTOM_START + 49,
6396   EL_CUSTOM_START + 50,
6397   EL_CUSTOM_START + 51,
6398
6399   EL_CUSTOM_START + 52,
6400   EL_CUSTOM_START + 53,
6401   EL_CUSTOM_START + 54,
6402   EL_CUSTOM_START + 55,
6403
6404   EL_CUSTOM_START + 56,
6405   EL_CUSTOM_START + 57,
6406   EL_CUSTOM_START + 58,
6407   EL_CUSTOM_START + 59,
6408
6409   EL_CUSTOM_START + 60,
6410   EL_CUSTOM_START + 61,
6411   EL_CUSTOM_START + 62,
6412   EL_CUSTOM_START + 63,
6413
6414   EL_CUSTOM_START + 64,
6415   EL_CUSTOM_START + 65,
6416   EL_CUSTOM_START + 66,
6417   EL_CUSTOM_START + 67,
6418
6419   EL_CUSTOM_START + 68,
6420   EL_CUSTOM_START + 69,
6421   EL_CUSTOM_START + 70,
6422   EL_CUSTOM_START + 71,
6423
6424   EL_CUSTOM_START + 72,
6425   EL_CUSTOM_START + 73,
6426   EL_CUSTOM_START + 74,
6427   EL_CUSTOM_START + 75,
6428
6429   EL_CUSTOM_START + 76,
6430   EL_CUSTOM_START + 77,
6431   EL_CUSTOM_START + 78,
6432   EL_CUSTOM_START + 79,
6433
6434   EL_CUSTOM_START + 80,
6435   EL_CUSTOM_START + 81,
6436   EL_CUSTOM_START + 82,
6437   EL_CUSTOM_START + 83,
6438
6439   EL_CUSTOM_START + 84,
6440   EL_CUSTOM_START + 85,
6441   EL_CUSTOM_START + 86,
6442   EL_CUSTOM_START + 87,
6443
6444   EL_CUSTOM_START + 88,
6445   EL_CUSTOM_START + 89,
6446   EL_CUSTOM_START + 90,
6447   EL_CUSTOM_START + 91,
6448
6449   EL_CUSTOM_START + 92,
6450   EL_CUSTOM_START + 93,
6451   EL_CUSTOM_START + 94,
6452   EL_CUSTOM_START + 95,
6453
6454   EL_CUSTOM_START + 96,
6455   EL_CUSTOM_START + 97,
6456   EL_CUSTOM_START + 98,
6457   EL_CUSTOM_START + 99,
6458
6459   EL_CUSTOM_START + 100,
6460   EL_CUSTOM_START + 101,
6461   EL_CUSTOM_START + 102,
6462   EL_CUSTOM_START + 103,
6463
6464   EL_CUSTOM_START + 104,
6465   EL_CUSTOM_START + 105,
6466   EL_CUSTOM_START + 106,
6467   EL_CUSTOM_START + 107,
6468
6469   EL_CUSTOM_START + 108,
6470   EL_CUSTOM_START + 109,
6471   EL_CUSTOM_START + 110,
6472   EL_CUSTOM_START + 111,
6473
6474   EL_CUSTOM_START + 112,
6475   EL_CUSTOM_START + 113,
6476   EL_CUSTOM_START + 114,
6477   EL_CUSTOM_START + 115,
6478
6479   EL_CUSTOM_START + 116,
6480   EL_CUSTOM_START + 117,
6481   EL_CUSTOM_START + 118,
6482   EL_CUSTOM_START + 119,
6483
6484   EL_CUSTOM_START + 120,
6485   EL_CUSTOM_START + 121,
6486   EL_CUSTOM_START + 122,
6487   EL_CUSTOM_START + 123,
6488
6489   EL_CUSTOM_START + 124,
6490   EL_CUSTOM_START + 125,
6491   EL_CUSTOM_START + 126,
6492   EL_CUSTOM_START + 127,
6493
6494   EL_CUSTOM_START + 128,
6495   EL_CUSTOM_START + 129,
6496   EL_CUSTOM_START + 130,
6497   EL_CUSTOM_START + 131,
6498
6499   EL_CUSTOM_START + 132,
6500   EL_CUSTOM_START + 133,
6501   EL_CUSTOM_START + 134,
6502   EL_CUSTOM_START + 135,
6503
6504   EL_CUSTOM_START + 136,
6505   EL_CUSTOM_START + 137,
6506   EL_CUSTOM_START + 138,
6507   EL_CUSTOM_START + 139,
6508
6509   EL_CUSTOM_START + 140,
6510   EL_CUSTOM_START + 141,
6511   EL_CUSTOM_START + 142,
6512   EL_CUSTOM_START + 143,
6513
6514   EL_CUSTOM_START + 144,
6515   EL_CUSTOM_START + 145,
6516   EL_CUSTOM_START + 146,
6517   EL_CUSTOM_START + 147,
6518
6519   EL_CUSTOM_START + 148,
6520   EL_CUSTOM_START + 149,
6521   EL_CUSTOM_START + 150,
6522   EL_CUSTOM_START + 151,
6523
6524   EL_CUSTOM_START + 152,
6525   EL_CUSTOM_START + 153,
6526   EL_CUSTOM_START + 154,
6527   EL_CUSTOM_START + 155,
6528
6529   EL_CUSTOM_START + 156,
6530   EL_CUSTOM_START + 157,
6531   EL_CUSTOM_START + 158,
6532   EL_CUSTOM_START + 159,
6533
6534   EL_CUSTOM_START + 160,
6535   EL_CUSTOM_START + 161,
6536   EL_CUSTOM_START + 162,
6537   EL_CUSTOM_START + 163,
6538
6539   EL_CUSTOM_START + 164,
6540   EL_CUSTOM_START + 165,
6541   EL_CUSTOM_START + 166,
6542   EL_CUSTOM_START + 167,
6543
6544   EL_CUSTOM_START + 168,
6545   EL_CUSTOM_START + 169,
6546   EL_CUSTOM_START + 170,
6547   EL_CUSTOM_START + 171,
6548
6549   EL_CUSTOM_START + 172,
6550   EL_CUSTOM_START + 173,
6551   EL_CUSTOM_START + 174,
6552   EL_CUSTOM_START + 175,
6553
6554   EL_CUSTOM_START + 176,
6555   EL_CUSTOM_START + 177,
6556   EL_CUSTOM_START + 178,
6557   EL_CUSTOM_START + 179,
6558
6559   EL_CUSTOM_START + 180,
6560   EL_CUSTOM_START + 181,
6561   EL_CUSTOM_START + 182,
6562   EL_CUSTOM_START + 183,
6563
6564   EL_CUSTOM_START + 184,
6565   EL_CUSTOM_START + 185,
6566   EL_CUSTOM_START + 186,
6567   EL_CUSTOM_START + 187,
6568
6569   EL_CUSTOM_START + 188,
6570   EL_CUSTOM_START + 189,
6571   EL_CUSTOM_START + 190,
6572   EL_CUSTOM_START + 191,
6573
6574   EL_CUSTOM_START + 192,
6575   EL_CUSTOM_START + 193,
6576   EL_CUSTOM_START + 194,
6577   EL_CUSTOM_START + 195,
6578
6579   EL_CUSTOM_START + 196,
6580   EL_CUSTOM_START + 197,
6581   EL_CUSTOM_START + 198,
6582   EL_CUSTOM_START + 199,
6583
6584   EL_CUSTOM_START + 200,
6585   EL_CUSTOM_START + 201,
6586   EL_CUSTOM_START + 202,
6587   EL_CUSTOM_START + 203,
6588
6589   EL_CUSTOM_START + 204,
6590   EL_CUSTOM_START + 205,
6591   EL_CUSTOM_START + 206,
6592   EL_CUSTOM_START + 207,
6593
6594   EL_CUSTOM_START + 208,
6595   EL_CUSTOM_START + 209,
6596   EL_CUSTOM_START + 210,
6597   EL_CUSTOM_START + 211,
6598
6599   EL_CUSTOM_START + 212,
6600   EL_CUSTOM_START + 213,
6601   EL_CUSTOM_START + 214,
6602   EL_CUSTOM_START + 215,
6603
6604   EL_CUSTOM_START + 216,
6605   EL_CUSTOM_START + 217,
6606   EL_CUSTOM_START + 218,
6607   EL_CUSTOM_START + 219,
6608
6609   EL_CUSTOM_START + 220,
6610   EL_CUSTOM_START + 221,
6611   EL_CUSTOM_START + 222,
6612   EL_CUSTOM_START + 223,
6613
6614   EL_CUSTOM_START + 224,
6615   EL_CUSTOM_START + 225,
6616   EL_CUSTOM_START + 226,
6617   EL_CUSTOM_START + 227,
6618
6619   EL_CUSTOM_START + 228,
6620   EL_CUSTOM_START + 229,
6621   EL_CUSTOM_START + 230,
6622   EL_CUSTOM_START + 231,
6623
6624   EL_CUSTOM_START + 232,
6625   EL_CUSTOM_START + 233,
6626   EL_CUSTOM_START + 234,
6627   EL_CUSTOM_START + 235,
6628
6629   EL_CUSTOM_START + 236,
6630   EL_CUSTOM_START + 237,
6631   EL_CUSTOM_START + 238,
6632   EL_CUSTOM_START + 239,
6633
6634   EL_CUSTOM_START + 240,
6635   EL_CUSTOM_START + 241,
6636   EL_CUSTOM_START + 242,
6637   EL_CUSTOM_START + 243,
6638
6639   EL_CUSTOM_START + 244,
6640   EL_CUSTOM_START + 245,
6641   EL_CUSTOM_START + 246,
6642   EL_CUSTOM_START + 247,
6643
6644   EL_CUSTOM_START + 248,
6645   EL_CUSTOM_START + 249,
6646   EL_CUSTOM_START + 250,
6647   EL_CUSTOM_START + 251,
6648
6649   EL_CUSTOM_START + 252,
6650   EL_CUSTOM_START + 253,
6651   EL_CUSTOM_START + 254,
6652   EL_CUSTOM_START + 255
6653 };
6654 static int *editor_hl_custom_ptr = editor_hl_custom;
6655 static int *editor_el_custom_ptr = editor_el_custom;
6656 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6657 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6658
6659 static int editor_hl_group[] =
6660 {
6661   EL_INTERNAL_CASCADE_GE_ACTIVE,
6662   EL_CHAR('G'),
6663   EL_CHAR('E'),
6664   EL_EMPTY,
6665 };
6666
6667 static int editor_el_group[] =
6668 {
6669   EL_GROUP_START + 0,
6670   EL_GROUP_START + 1,
6671   EL_GROUP_START + 2,
6672   EL_GROUP_START + 3,
6673
6674   EL_GROUP_START + 4,
6675   EL_GROUP_START + 5,
6676   EL_GROUP_START + 6,
6677   EL_GROUP_START + 7,
6678
6679   EL_GROUP_START + 8,
6680   EL_GROUP_START + 9,
6681   EL_GROUP_START + 10,
6682   EL_GROUP_START + 11,
6683
6684   EL_GROUP_START + 12,
6685   EL_GROUP_START + 13,
6686   EL_GROUP_START + 14,
6687   EL_GROUP_START + 15,
6688
6689   EL_GROUP_START + 16,
6690   EL_GROUP_START + 17,
6691   EL_GROUP_START + 18,
6692   EL_GROUP_START + 19,
6693
6694   EL_GROUP_START + 20,
6695   EL_GROUP_START + 21,
6696   EL_GROUP_START + 22,
6697   EL_GROUP_START + 23,
6698
6699   EL_GROUP_START + 24,
6700   EL_GROUP_START + 25,
6701   EL_GROUP_START + 26,
6702   EL_GROUP_START + 27,
6703
6704   EL_GROUP_START + 28,
6705   EL_GROUP_START + 29,
6706   EL_GROUP_START + 30,
6707   EL_GROUP_START + 31
6708 };
6709 static int *editor_hl_group_ptr = editor_hl_group;
6710 static int *editor_el_group_ptr = editor_el_group;
6711 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6712 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6713
6714 static int editor_hl_empty_space[] =
6715 {
6716   EL_INTERNAL_CASCADE_ES_ACTIVE,
6717   EL_CHAR('E'),
6718   EL_CHAR('S'),
6719   EL_EMPTY,
6720 };
6721
6722 static int editor_el_empty_space[] =
6723 {
6724   EL_EMPTY_SPACE_1,
6725   EL_EMPTY_SPACE_2,
6726   EL_EMPTY_SPACE_3,
6727   EL_EMPTY_SPACE_4,
6728
6729   EL_EMPTY_SPACE_5,
6730   EL_EMPTY_SPACE_6,
6731   EL_EMPTY_SPACE_7,
6732   EL_EMPTY_SPACE_8,
6733
6734   EL_EMPTY_SPACE_9,
6735   EL_EMPTY_SPACE_10,
6736   EL_EMPTY_SPACE_11,
6737   EL_EMPTY_SPACE_12,
6738
6739   EL_EMPTY_SPACE_13,
6740   EL_EMPTY_SPACE_14,
6741   EL_EMPTY_SPACE_15,
6742   EL_EMPTY_SPACE_16
6743 };
6744 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6745 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6746 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6747 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6748
6749 static int editor_hl_reference[] =
6750 {
6751   EL_INTERNAL_CASCADE_REF_ACTIVE,
6752   EL_CHAR('R'),
6753   EL_CHAR('E'),
6754   EL_CHAR('F')
6755 };
6756
6757 static int editor_el_reference[] =
6758 {
6759   EL_TRIGGER_PLAYER,
6760   EL_TRIGGER_ELEMENT,
6761   EL_TRIGGER_CE_VALUE,
6762   EL_TRIGGER_CE_SCORE,
6763
6764   EL_SELF,
6765   EL_ANY_ELEMENT,
6766   EL_CURRENT_CE_VALUE,
6767   EL_CURRENT_CE_SCORE,
6768
6769   EL_PREV_CE_8,
6770   EL_PREV_CE_7,
6771   EL_PREV_CE_6,
6772   EL_PREV_CE_5,
6773
6774   EL_PREV_CE_4,
6775   EL_PREV_CE_3,
6776   EL_PREV_CE_2,
6777   EL_PREV_CE_1,
6778
6779   EL_NEXT_CE_1,
6780   EL_NEXT_CE_2,
6781   EL_NEXT_CE_3,
6782   EL_NEXT_CE_4,
6783
6784   EL_NEXT_CE_5,
6785   EL_NEXT_CE_6,
6786   EL_NEXT_CE_7,
6787   EL_NEXT_CE_8,
6788 };
6789 static int *editor_hl_reference_ptr = editor_hl_reference;
6790 static int *editor_el_reference_ptr = editor_el_reference;
6791 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6792 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6793
6794 static int editor_hl_user_defined[] =
6795 {
6796   EL_INTERNAL_CASCADE_USER_ACTIVE,
6797   EL_CHAR('M'),
6798   EL_CHAR('Y'),
6799   EL_EMPTY,
6800 };
6801
6802 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6803 static int *editor_el_user_defined_ptr = NULL;
6804 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6805 static int num_editor_el_user_defined = 0;
6806
6807 static int editor_hl_dynamic[] =
6808 {
6809   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6810   EL_CHAR('U'),
6811   EL_CHAR('S'),
6812   EL_CHAR('E'),
6813 };
6814
6815 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6816 static int *editor_el_dynamic_ptr = NULL;
6817 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6818 static int num_editor_el_dynamic = 0;
6819
6820 static int editor_hl_empty[] = { EL_EMPTY };
6821 static int *editor_el_empty = NULL;     // dynamically allocated
6822
6823 static int *editor_hl_empty_ptr = editor_hl_empty;
6824 static int *editor_el_empty_ptr = NULL;
6825 static int num_editor_hl_empty = 0;
6826 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6827
6828 static boolean use_el_empty = FALSE;
6829
6830 static int *editor_elements = NULL;     // dynamically allocated
6831 static int num_editor_elements = 0;     // dynamically determined
6832
6833 static boolean setup_editor_cascade_never = FALSE;
6834
6835 static boolean setup_editor_el_players                  = TRUE;
6836 static boolean setup_editor_el_boulderdash              = TRUE;
6837 static boolean setup_editor_el_boulderdash_native       = TRUE;
6838 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6839 static boolean setup_editor_el_emerald_mine             = TRUE;
6840 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6841 static boolean setup_editor_el_more                     = TRUE;
6842 static boolean setup_editor_el_sokoban                  = TRUE;
6843 static boolean setup_editor_el_supaplex                 = TRUE;
6844 static boolean setup_editor_el_diamond_caves            = TRUE;
6845 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6846 static boolean setup_editor_el_mirror_magic             = TRUE;
6847 static boolean setup_editor_el_deflektor                = TRUE;
6848 static boolean setup_editor_el_chars                    = TRUE;
6849 static boolean setup_editor_el_steel_chars              = TRUE;
6850 static boolean setup_editor_el_custom                   = TRUE;
6851 static boolean setup_editor_el_user_defined             = TRUE;
6852 static boolean setup_editor_el_dynamic                  = TRUE;
6853
6854 static int editor_hl_unused[] = { EL_EMPTY };
6855 static int *editor_hl_unused_ptr = editor_hl_unused;
6856 static int num_editor_hl_unused = 0;
6857
6858 static struct
6859 {
6860   boolean *setup_value;
6861   boolean *setup_cascade_value;
6862
6863   int **headline_list;
6864   int *headline_list_size;
6865
6866   int **element_list;
6867   int *element_list_size;
6868
6869   boolean last_setup_value;
6870 }
6871 editor_elements_info[] =
6872 {
6873   {
6874     &setup_editor_el_players,
6875     &setup_editor_cascade_never,
6876     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6877     &editor_el_players_ptr,             &num_editor_el_players
6878   },
6879   {
6880     &setup_editor_el_boulderdash,
6881     &setup.editor_cascade.el_bd,
6882     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6883     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6884   },
6885   {
6886     &setup_editor_el_boulderdash_native,
6887     &setup.editor_cascade.el_bd_native,
6888     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6889     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6890   },
6891   {
6892     &setup_editor_el_boulderdash_effects,
6893     &setup.editor_cascade.el_bd_effects,
6894     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6895     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6896   },
6897   {
6898     &setup_editor_el_emerald_mine,
6899     &setup.editor_cascade.el_em,
6900     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6901     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6902   },
6903   {
6904     &setup_editor_el_emerald_mine_club,
6905     &setup.editor_cascade.el_emc,
6906     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6907     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6908   },
6909   {
6910     &setup_editor_el_more,
6911     &setup.editor_cascade.el_rnd,
6912     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6913     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6914   },
6915   {
6916     &setup_editor_el_sokoban,
6917     &setup.editor_cascade.el_sb,
6918     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6919     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6920   },
6921   {
6922     &setup_editor_el_supaplex,
6923     &setup.editor_cascade.el_sp,
6924     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6925     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6926   },
6927   {
6928     &setup_editor_el_diamond_caves,
6929     &setup.editor_cascade.el_dc,
6930     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6931     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6932   },
6933   {
6934     &setup_editor_el_dx_boulderdash,
6935     &setup.editor_cascade.el_dx,
6936     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6937     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6938   },
6939   {
6940     &setup_editor_el_mirror_magic,
6941     &setup.editor_cascade.el_mm,
6942     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6943     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6944   },
6945   {
6946     &setup_editor_el_deflektor,
6947     &setup.editor_cascade.el_df,
6948     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6949     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6950   },
6951   {
6952     &setup_editor_el_chars,
6953     &setup.editor_cascade.el_chars,
6954     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6955     &editor_el_chars_ptr,               &num_editor_el_chars
6956   },
6957   {
6958     &setup_editor_el_steel_chars,
6959     &setup.editor_cascade.el_steel_chars,
6960     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6961     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6962   },
6963   {
6964     &setup_editor_el_custom,
6965     &setup.editor_cascade.el_ce,
6966     &editor_hl_custom_ptr,              &num_editor_hl_custom,
6967     &editor_el_custom_ptr,              &num_editor_el_custom
6968   },
6969   {
6970     &setup_editor_el_custom,
6971     &setup.editor_cascade.el_ge,
6972     &editor_hl_group_ptr,               &num_editor_hl_group,
6973     &editor_el_group_ptr,               &num_editor_el_group
6974   },
6975   {
6976     &setup_editor_el_custom,
6977     &setup.editor_cascade.el_es,
6978     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
6979     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
6980   },
6981   {
6982     &setup_editor_el_custom,
6983     &setup.editor_cascade.el_ref,
6984     &editor_hl_reference_ptr,           &num_editor_hl_reference,
6985     &editor_el_reference_ptr,           &num_editor_el_reference
6986   },
6987   {
6988     &setup_editor_el_user_defined,
6989     &setup.editor_cascade.el_user,
6990     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
6991     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
6992   },
6993   {
6994     &setup_editor_el_dynamic,
6995     &setup.editor_cascade.el_dynamic,
6996     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
6997     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
6998   },
6999   {
7000     &use_el_empty,
7001     &use_el_empty,
7002     &editor_hl_empty_ptr,               &num_editor_hl_empty,
7003     &editor_el_empty_ptr,               &num_editor_el_empty,
7004   },
7005   {
7006     NULL,
7007     NULL,
7008     NULL,                               NULL,
7009     NULL,                               NULL
7010   }
7011 };
7012
7013 static struct XY xy_directions[] =
7014 {
7015   { -1,  0 },
7016   { +1,  0 },
7017   {  0, -1 },
7018   {  0, +1 }
7019 };
7020
7021
7022 // ----------------------------------------------------------------------------
7023 // functions
7024 // ----------------------------------------------------------------------------
7025
7026 static int getMaxInfoTextLength(void)
7027 {
7028   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
7029 }
7030
7031 static int getTextWidthForGadget(char *text)
7032 {
7033   if (text == NULL)
7034     return 0;
7035
7036   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
7037 }
7038
7039 static int getTextWidthForDrawingArea(char *text)
7040 {
7041   if (text == NULL)
7042     return 0;
7043
7044   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
7045 }
7046
7047 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
7048 {
7049   return (gi->x + gi->width + getTextWidthForGadget(text));
7050 }
7051
7052 static char *getElementInfoText(int element)
7053 {
7054   char *info_text = NULL;
7055
7056   if (element < MAX_NUM_ELEMENTS)
7057   {
7058     if (strlen(element_info[element].description) > 0)
7059       info_text = element_info[element].description;
7060     else if (element_info[element].custom_description != NULL)
7061       info_text = element_info[element].custom_description;
7062     else if (element_info[element].editor_description != NULL)
7063       info_text = element_info[element].editor_description;
7064   }
7065
7066   if (info_text == NULL)
7067     info_text = INFOTEXT_UNKNOWN_ELEMENT;
7068
7069   return info_text;
7070 }
7071
7072 static char *getElementDescriptionFilenameExt(char *basename)
7073 {
7074   char *elements_subdir = ELEMENTS_DIRECTORY;
7075   static char *elements_subdir2 = NULL;
7076   static char *filename = NULL;
7077
7078   if (elements_subdir2 == NULL)
7079     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
7080
7081   checked_free(filename);
7082
7083   // 1st try: look for element description in current level set directory
7084   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
7085   if (fileExists(filename))
7086     return filename;
7087
7088   free(filename);
7089
7090   // 2nd try: look for element description in the game's base directory
7091   filename = getPath3(options.docs_directory, elements_subdir, basename);
7092   if (fileExists(filename))
7093     return filename;
7094
7095   return NULL;
7096 }
7097
7098 static char *getElementDescriptionFilename(int element)
7099 {
7100   char basename[MAX_FILENAME_LEN];
7101   char *filename;
7102
7103   // 1st try: look for element description file for exactly this element
7104   sprintf(basename, "%s.txt", element_info[element].token_name);
7105   filename = getElementDescriptionFilenameExt(basename);
7106   if (filename != NULL)
7107     return filename;
7108
7109   // 2nd try: look for element description file for this element's class
7110   sprintf(basename, "%s.txt", element_info[element].class_name);
7111   filename = getElementDescriptionFilenameExt(basename);
7112   if (filename != NULL)
7113     return filename;
7114
7115   // 3rd try: look for generic fallback text file for any element
7116   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
7117   if (filename != NULL)
7118     return filename;
7119
7120   return NULL;
7121 }
7122
7123 static boolean suppressBorderElement(void)
7124 {
7125   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
7126           lev_fieldx <= MAX_ED_FIELDX &&
7127           lev_fieldy <= MAX_ED_FIELDY);
7128 }
7129
7130 static void InitDynamicEditorElementList(int **elements, int *num_elements)
7131 {
7132   boolean element_found[NUM_FILE_ELEMENTS];
7133   int i, x, y;
7134
7135   // initialize list of used elements to "not used"
7136   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7137     element_found[i] = FALSE;
7138
7139   // find all elements used in current level
7140   for (y = 0; y < lev_fieldy; y++)
7141   {
7142     for (x = 0; x < lev_fieldx; x++)
7143     {
7144       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
7145         continue;
7146
7147       if (IS_MM_WALL(Tile[x][y]))
7148         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
7149       else
7150         element_found[Tile[x][y]] = TRUE;
7151     }
7152   }
7153
7154   *num_elements = 0;
7155
7156   // count number of elements used in current level
7157   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7158     if (element_found[i])
7159       (*num_elements)++;
7160
7161   // add space for up to 3 more elements for padding that may be needed
7162   *num_elements += 3;
7163
7164   // free memory for old list of elements, if needed
7165   checked_free(*elements);
7166
7167   // allocate memory for new list of elements
7168   *elements = checked_malloc(*num_elements * sizeof(int));
7169
7170   *num_elements = 0;
7171
7172   // add all elements used in current level (non-custom/group/empty elements)
7173   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7174     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
7175                               IS_GROUP_ELEMENT(i) ||
7176                               IS_EMPTY_ELEMENT(i)))
7177       (*elements)[(*num_elements)++] = i;
7178
7179   // add all elements used in current level (custom/group/empty elements)
7180   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7181     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
7182                              IS_GROUP_ELEMENT(i) ||
7183                              IS_EMPTY_ELEMENT(i)))
7184       (*elements)[(*num_elements)++] = i;
7185
7186   while (*num_elements % 4)     // pad with empty elements, if needed
7187     (*elements)[(*num_elements)++] = EL_EMPTY;
7188 }
7189
7190 static void ReinitializeElementList_EnableSections(void)
7191 {
7192   // default: enable all element sections
7193
7194   setup_editor_el_players               = TRUE;
7195   setup_editor_el_boulderdash           = TRUE;
7196   setup_editor_el_boulderdash_native    = TRUE;
7197   setup_editor_el_boulderdash_effects   = TRUE;
7198   setup_editor_el_emerald_mine          = TRUE;
7199   setup_editor_el_emerald_mine_club     = TRUE;
7200   setup_editor_el_more                  = TRUE;
7201   setup_editor_el_sokoban               = TRUE;
7202   setup_editor_el_supaplex              = TRUE;
7203   setup_editor_el_diamond_caves         = TRUE;
7204   setup_editor_el_dx_boulderdash        = TRUE;
7205   setup_editor_el_mirror_magic          = TRUE;
7206   setup_editor_el_deflektor             = TRUE;
7207   setup_editor_el_chars                 = TRUE;
7208   setup_editor_el_steel_chars           = TRUE;
7209
7210   setup_editor_el_custom                = TRUE;
7211   setup_editor_el_user_defined          = TRUE;
7212   setup_editor_el_dynamic               = TRUE;
7213
7214   // now disable all element sections not to be displayed
7215
7216   if (!setup.editor.el_classic)
7217   {
7218     setup_editor_el_players             = FALSE;
7219     setup_editor_el_boulderdash         = FALSE;
7220     setup_editor_el_boulderdash_native  = FALSE;
7221     setup_editor_el_boulderdash_effects = FALSE;
7222     setup_editor_el_emerald_mine        = FALSE;
7223     setup_editor_el_emerald_mine_club   = FALSE;
7224     setup_editor_el_more                = FALSE;
7225     setup_editor_el_sokoban             = FALSE;
7226     setup_editor_el_supaplex            = FALSE;
7227     setup_editor_el_diamond_caves       = FALSE;
7228     setup_editor_el_dx_boulderdash      = FALSE;
7229     setup_editor_el_mirror_magic        = FALSE;
7230     setup_editor_el_deflektor           = FALSE;
7231     setup_editor_el_chars               = FALSE;
7232     setup_editor_el_steel_chars         = FALSE;
7233   }
7234
7235   if (!setup.editor.el_custom)
7236   {
7237     setup_editor_el_custom              = FALSE;
7238   }
7239
7240   if (!setup.editor.el_user_defined)
7241   {
7242     setup_editor_el_user_defined        = FALSE;
7243   }
7244
7245   if (!setup.editor.el_dynamic)
7246   {
7247     setup_editor_el_dynamic             = FALSE;
7248   }
7249
7250   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7251   {
7252     setup_editor_el_boulderdash_native  = FALSE;
7253     setup_editor_el_boulderdash_effects = FALSE;
7254     setup_editor_el_mirror_magic        = FALSE;
7255     setup_editor_el_deflektor           = FALSE;
7256   }
7257   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7258   {
7259     setup_editor_el_players             = FALSE;
7260     setup_editor_el_boulderdash         = FALSE;
7261     setup_editor_el_emerald_mine        = FALSE;
7262     setup_editor_el_emerald_mine_club   = FALSE;
7263     setup_editor_el_more                = FALSE;
7264     setup_editor_el_sokoban             = FALSE;
7265     setup_editor_el_supaplex            = FALSE;
7266     setup_editor_el_diamond_caves       = FALSE;
7267     setup_editor_el_dx_boulderdash      = FALSE;
7268     setup_editor_el_mirror_magic        = FALSE;
7269     setup_editor_el_deflektor           = FALSE;
7270     setup_editor_el_chars               = FALSE;
7271     setup_editor_el_steel_chars         = FALSE;
7272
7273     setup_editor_el_custom              = FALSE;
7274   }
7275   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7276   {
7277     setup_editor_el_boulderdash         = FALSE;
7278     setup_editor_el_boulderdash_native  = FALSE;
7279     setup_editor_el_boulderdash_effects = FALSE;
7280     setup_editor_el_more                = FALSE;
7281     setup_editor_el_sokoban             = FALSE;
7282     setup_editor_el_supaplex            = FALSE;
7283     setup_editor_el_diamond_caves       = FALSE;
7284     setup_editor_el_dx_boulderdash      = FALSE;
7285     setup_editor_el_mirror_magic        = FALSE;
7286     setup_editor_el_deflektor           = FALSE;
7287     setup_editor_el_steel_chars         = FALSE;
7288
7289     setup_editor_el_custom              = FALSE;
7290   }
7291   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7292   {
7293     setup_editor_el_players             = FALSE;
7294     setup_editor_el_boulderdash         = FALSE;
7295     setup_editor_el_boulderdash_native  = FALSE;
7296     setup_editor_el_boulderdash_effects = FALSE;
7297     setup_editor_el_emerald_mine        = FALSE;
7298     setup_editor_el_emerald_mine_club   = FALSE;
7299     setup_editor_el_more                = FALSE;
7300     setup_editor_el_sokoban             = FALSE;
7301     setup_editor_el_diamond_caves       = FALSE;
7302     setup_editor_el_dx_boulderdash      = FALSE;
7303     setup_editor_el_mirror_magic        = FALSE;
7304     setup_editor_el_deflektor           = FALSE;
7305     setup_editor_el_chars               = FALSE;
7306     setup_editor_el_steel_chars         = FALSE;
7307
7308     setup_editor_el_custom              = FALSE;
7309   }
7310   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7311   {
7312     setup_editor_el_players             = FALSE;
7313     setup_editor_el_boulderdash         = FALSE;
7314     setup_editor_el_boulderdash_native  = FALSE;
7315     setup_editor_el_boulderdash_effects = FALSE;
7316     setup_editor_el_emerald_mine        = FALSE;
7317     setup_editor_el_emerald_mine_club   = FALSE;
7318     setup_editor_el_more                = FALSE;
7319     setup_editor_el_sokoban             = FALSE;
7320     setup_editor_el_supaplex            = FALSE;
7321     setup_editor_el_diamond_caves       = FALSE;
7322     setup_editor_el_dx_boulderdash      = FALSE;
7323     setup_editor_el_steel_chars         = FALSE;
7324
7325     setup_editor_el_custom              = FALSE;
7326   }
7327 }
7328
7329 static void ReinitializeElementList(void)
7330 {
7331   static boolean initialization_needed = TRUE;
7332   int pos = 0;
7333   int i, j;
7334
7335   ReinitializeElementList_EnableSections();
7336
7337   if (initialization_needed)
7338   {
7339     LoadSetup_EditorCascade();          // load last editor cascade state
7340
7341     // initialize editor cascade element from saved cascade state
7342     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7343     {
7344       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7345       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7346
7347       if (IS_EDITOR_CASCADE(*cascade_element))
7348         *cascade_element =
7349           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7350            EL_CASCADE_INACTIVE(*cascade_element));
7351     }
7352
7353     initialization_needed = FALSE;
7354   }
7355
7356   checked_free(editor_elements);
7357
7358   // reload optional user defined element list for each invocation of editor
7359   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7360                                    &num_editor_el_user_defined);
7361
7362   // initialize dynamic level element list for each invocation of editor
7363   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7364                                &num_editor_el_dynamic);
7365
7366   // initialize list of empty elements (used for padding, if needed)
7367   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7368     editor_el_empty[i] = EL_EMPTY;
7369
7370   // do some sanity checks for each element from element list
7371   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7372   {
7373     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7374     {
7375       int element = (*editor_elements_info[i].element_list)[j];
7376
7377       if (element >= NUM_FILE_ELEMENTS)
7378         Warn("editor element %d is runtime element", element);
7379
7380       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7381         Warn("no element description text for element %d", element);
7382     }
7383   }
7384
7385   num_editor_elements = 0;
7386   use_el_empty = FALSE;
7387
7388   // determine size of element list
7389   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7390   {
7391     if (*editor_elements_info[i].setup_value)
7392     {
7393       boolean found_inactive_cascade = FALSE;
7394
7395       if (setup.editor.el_headlines)
7396       {
7397         // required for correct padding of palette headline buttons
7398         if (*editor_elements_info[i].headline_list_size > 0)
7399           num_editor_elements += ED_ELEMENTLIST_COLS;
7400
7401         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7402         {
7403           int element = (*editor_elements_info[i].headline_list)[j];
7404
7405           if (IS_EDITOR_CASCADE_INACTIVE(element))
7406             found_inactive_cascade = TRUE;
7407         }
7408       }
7409
7410       if (found_inactive_cascade)
7411         continue;
7412
7413       // required for correct padding of palette element buttons
7414       int element_list_size = *editor_elements_info[i].element_list_size;
7415       int element_rows =
7416         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7417       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7418
7419       num_editor_elements += element_buttons;
7420     }
7421   }
7422
7423   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7424   {
7425     // offer at least as many elements as element buttons exist
7426     use_el_empty = TRUE;
7427     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7428
7429     num_editor_elements += num_editor_el_empty;
7430   }
7431   else
7432   {
7433     num_editor_el_empty = 0;
7434   }
7435
7436   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7437
7438   // fill element list
7439   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7440   {
7441     boolean found_inactive_cascade = FALSE;
7442
7443     if (*editor_elements_info[i].setup_value)
7444     {
7445       if (setup.editor.el_headlines)
7446       {
7447         // required for correct padding of palette headline buttons
7448         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7449                              ED_ELEMENTLIST_COLS : 0);
7450
7451         for (j = 0; j < headline_size; j++)
7452         {
7453           // use empty elements for padding of palette headline buttons
7454           int element = (j < *editor_elements_info[i].headline_list_size ?
7455                          (*editor_elements_info[i].headline_list)[j] :
7456                          editor_el_empty[0]);
7457
7458           editor_elements[pos++] = element;
7459
7460           if (IS_EDITOR_CASCADE_INACTIVE(element))
7461             found_inactive_cascade = TRUE;
7462         }
7463       }
7464
7465       if (found_inactive_cascade)
7466         continue;
7467
7468       // required for correct padding of palette element buttons
7469       int element_list_size = *editor_elements_info[i].element_list_size;
7470       int element_rows =
7471         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7472       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7473
7474       // copy all elements from element list
7475       for (j = 0; j < element_list_size; j++)
7476         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7477
7478       // use empty elements for padding of palette element buttons
7479       for (j = 0; j < element_buttons - element_list_size; j++)
7480         editor_elements[pos++] = editor_el_empty[0];
7481     }
7482   }
7483
7484   // (this function is also called before editor gadgets are initialized!)
7485   AdjustElementListScrollbar();
7486 }
7487
7488 void PrintEditorElementList(void)
7489 {
7490   boolean *stop = &setup_editor_el_user_defined;
7491   int i, j;
7492
7493   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7494   {
7495     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7496
7497     if (IS_EDITOR_CASCADE(cascade_element))
7498     {
7499       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7500       char *headline = element_info[cascade_element_show].editor_description;
7501
7502       PrintLineWithPrefix("# ", "-", 77);
7503       Print("# %s\n", headline);
7504       PrintLineWithPrefix("# ", "-", 77);
7505     }
7506
7507     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7508     {
7509       int element = (*editor_elements_info[i].headline_list)[j];
7510
7511       if (IS_EDITOR_CASCADE(element))
7512         element = EL_CHAR_MINUS;
7513
7514       Print("# %s\n", element_info[element].token_name);
7515     }
7516
7517     if (j > 0)
7518       Print("#\n");
7519
7520     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7521     {
7522       int element = (*editor_elements_info[i].element_list)[j];
7523
7524       Print("# %s\n", element_info[element].token_name);
7525     }
7526
7527     if (j > 0)
7528       Print("#\n");
7529   }
7530 }
7531
7532 static void ReinitializeElementListButtons(void)
7533 {
7534   static boolean last_setup_value_headlines = FALSE;
7535   static boolean initialization_needed = TRUE;
7536   int i;
7537
7538   if (!initialization_needed)   // check if editor element setup has changed
7539   {
7540     if (last_setup_value_headlines != setup.editor.el_headlines)
7541       initialization_needed = TRUE;
7542
7543     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7544       if (editor_elements_info[i].last_setup_value !=
7545           *editor_elements_info[i].setup_value)
7546         initialization_needed = TRUE;
7547   }
7548
7549   if (!initialization_needed)
7550     return;
7551
7552   FreeLevelEditorGadgets();
7553   CreateLevelEditorGadgets();
7554
7555   // store current setup values for next invocation of this function
7556   last_setup_value_headlines = setup.editor.el_headlines;
7557   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7558     editor_elements_info[i].last_setup_value =
7559       *editor_elements_info[i].setup_value;
7560
7561   initialization_needed = FALSE;
7562 }
7563
7564 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7565                               boolean input)
7566 {
7567   int border_graphic =
7568     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7569   struct GraphicInfo *g = &graphic_info[border_graphic];
7570   Bitmap *src_bitmap = g->bitmap;
7571   int src_x = g->src_x;
7572   int src_y = g->src_y;
7573   int border_size = g->border_size;
7574   int border_xpos = g->width  - border_size;
7575   int border_ypos = g->height - border_size;
7576   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7577   int i;
7578
7579   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7580              border_size, border_size,
7581              dest_x - border_size, dest_y - border_size);
7582   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7583              border_size, border_size,
7584              dest_x + width, dest_y - border_size);
7585   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7586              border_size, border_size,
7587              dest_x - border_size, dest_y + height);
7588   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7589              border_size, border_size,
7590              dest_x + width, dest_y + height);
7591
7592   for (i = 0; i < width / tilesize; i++)
7593   {
7594     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7595                tilesize, border_size,
7596                dest_x + i * tilesize, dest_y - border_size);
7597     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7598                tilesize, border_size,
7599                dest_x + i * tilesize, dest_y + height);
7600   }
7601
7602   for (i = 0; i < height / tilesize; i++)
7603   {
7604     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7605                border_size, tilesize,
7606                dest_x - border_size, dest_y + i * tilesize);
7607     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7608                border_size, tilesize,
7609                dest_x + width, dest_y + i * tilesize);
7610   }
7611
7612   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7613 }
7614
7615 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7616 {
7617   int xsize_tile = MAX(ed_tilesize, xsize);
7618   int ysize_tile = MAX(ed_tilesize, ysize);
7619   int xsize_full = xsize + 1;
7620   int ysize_full = ysize + 1;
7621   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7622   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7623   Pixel line_color = getTabulatorBarColor();
7624
7625   if (line_color == BLACK_PIXEL)                // black => transparent
7626     return;
7627
7628   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7629   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7630   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7631 }
7632
7633 static void DrawEditorLevelBorderLinesIfNeeded(void)
7634 {
7635   int xsize = lev_fieldx * ed_tilesize;
7636   int ysize = lev_fieldy * ed_tilesize;
7637   int line_size = getTabulatorBarHeight();
7638
7639   if (!suppressBorderElement())
7640     return;
7641
7642   // draw little border line around editable level playfield
7643
7644   if (xsize < SXSIZE)
7645     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7646
7647   if (ysize < SYSIZE)
7648     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7649
7650   if (xsize < SXSIZE && ysize < SYSIZE)
7651     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7652 }
7653
7654 static void DrawEditorElement(int x, int y, int element)
7655 {
7656   DrawSizedElement(x, y, element, ed_tilesize);
7657 }
7658
7659 static void DrawEditorElementThruMask(int x, int y, int element)
7660 {
7661   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7662 }
7663
7664 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7665 {
7666   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7667 }
7668
7669 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7670 {
7671   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7672   DrawEditorLevelBorderLinesIfNeeded();
7673 }
7674
7675 static void DrawDrawingArea(int id)
7676 {
7677   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7678   int x, y;
7679
7680   int *value = drawingarea_info[id].value;
7681   int area_xsize = drawingarea_info[id].area_xsize;
7682   int area_ysize = drawingarea_info[id].area_ysize;
7683   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7684
7685   for (x = 0; x < area_xsize; x++)
7686   {
7687     for (y = 0; y < area_ysize; y++)
7688     {
7689       int element = value[x * area_ysize + y];
7690       int graphic;
7691       int frame;
7692
7693       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7694
7695       DrawSizedGraphicExt(drawto,
7696                           gi->x + x * tilesize,
7697                           gi->y + y * tilesize,
7698                           graphic, frame, tilesize);
7699     }
7700   }
7701 }
7702
7703 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7704 {
7705   int x, y;
7706   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7707   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7708
7709   BlitBitmap(drawto, drawto,
7710              SX + (dx == -1 ? ed_tilesize : 0),
7711              SY + (dy == -1 ? ed_tilesize : 0),
7712              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7713              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7714              SX + (dx == +1 ? ed_tilesize : 0),
7715              SY + (dy == +1 ? ed_tilesize : 0));
7716
7717   if (dx)
7718   {
7719     x = (dx == 1 ? 0 : ed_fieldx - 1);
7720     for (y = 0; y < ed_fieldy; y++)
7721       DrawEditorElementOrWall(x, y, from_x, from_y);
7722   }
7723   else if (dy)
7724   {
7725     y = (dy == 1 ? 0 : ed_fieldy - 1);
7726     for (x = 0; x < ed_fieldx; x++)
7727       DrawEditorElementOrWall(x, y, from_x, from_y);
7728   }
7729
7730   redraw_mask |= REDRAW_FIELD;
7731   BackToFront();
7732 }
7733
7734 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7735 {
7736   if (use_editor_gfx)
7737   {
7738     *graphic = el2edimg(element);
7739     *frame = 0;
7740   }
7741   else
7742   {
7743     *graphic = el2img(element);
7744     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7745               custom_element.ce_value_fixed_initial :
7746               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7747               custom_element.collect_score_initial : FrameCounter);
7748   }
7749
7750   if (*graphic == IMG_UNKNOWN)
7751   {
7752     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7753     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7754     int element_bd = map_element_RND_to_BD_cave(element);
7755
7756     if (element_bd != O_UNKNOWN)
7757     {
7758       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7759
7760       *graphic = g_bd->graphic;
7761       *frame   = g_bd->frame;
7762     }
7763   }
7764 }
7765
7766 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7767                                    int *x, int *y)
7768 {
7769   int graphic;
7770   int frame;
7771
7772   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7773
7774   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7775 }
7776
7777 static void CreateControlButtons(void)
7778 {
7779   struct GadgetInfo *gi;
7780   int i;
7781
7782   // create toolbox buttons
7783   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7784   {
7785     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7786     int id = controlbutton_info[i].gadget_id;
7787     int type = controlbutton_info[i].gadget_type;
7788     int graphic = controlbutton_info[i].graphic;
7789     struct XYTileSize *pos = controlbutton_info[i].pos;
7790     struct GraphicInfo *gd = &graphic_info[graphic];
7791     Bitmap *deco_bitmap = NULL;
7792     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7793     int tile_size = 0, deco_shift = 0;
7794     boolean deco_masked = FALSE;
7795     int gd_x1 = gd->src_x;
7796     int gd_y1 = gd->src_y;
7797     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7798     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7799     int gd_x1a = gd->src_x + gd->active_xoffset;
7800     int gd_y1a = gd->src_y + gd->active_yoffset;
7801     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7802     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7803     int x = pos->x;
7804     int y = pos->y;
7805     unsigned int event_mask;
7806     int radio_button_nr = RADIO_NR_NONE;
7807     boolean checked = FALSE;
7808
7809     if (type_id != i)
7810       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7811
7812     if (type == GD_TYPE_RADIO_BUTTON)
7813     {
7814       event_mask = GD_EVENT_PRESSED;
7815       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7816
7817       if (id == drawing_function)
7818         checked = TRUE;
7819     }
7820     else
7821     {
7822       if (id == GADGET_ID_WRAP_LEFT ||
7823           id == GADGET_ID_WRAP_RIGHT ||
7824           id == GADGET_ID_WRAP_UP ||
7825           id == GADGET_ID_WRAP_DOWN)
7826         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7827       else
7828         event_mask = GD_EVENT_RELEASED;
7829     }
7830
7831     if (id == GADGET_ID_PROPERTIES ||
7832         id == GADGET_ID_PALETTE)
7833     {
7834       x += DX;
7835       y += DY;
7836     }
7837     else if (id == GADGET_ID_ELEMENT_LEFT ||
7838              id == GADGET_ID_ELEMENT_MIDDLE ||
7839              id == GADGET_ID_ELEMENT_RIGHT)
7840     {
7841       x += DX;
7842       y += DY;
7843
7844       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7845                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7846                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7847
7848       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7849                                    editor.button.element_left.tile_size :
7850                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7851                                    editor.button.element_middle.tile_size :
7852                                    id == GADGET_ID_ELEMENT_RIGHT ?
7853                                    editor.button.element_right.tile_size : 0);
7854
7855       // make sure that decoration does not overlap gadget border
7856       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7857
7858       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7859
7860       deco_xpos = (gd->width  - tile_size) / 2;
7861       deco_ypos = (gd->height - tile_size) / 2;
7862       deco_shift = 1;
7863       deco_masked = gd->draw_masked;
7864     }
7865     else
7866     {
7867       x += EX;
7868       y += EY;
7869     }
7870
7871     gi = CreateGadget(GDI_CUSTOM_ID, id,
7872                       GDI_CUSTOM_TYPE_ID, type_id,
7873                       GDI_IMAGE_ID, graphic,
7874                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7875                       GDI_X, x,
7876                       GDI_Y, y,
7877                       GDI_WIDTH, gd->width,
7878                       GDI_HEIGHT, gd->height,
7879                       GDI_TYPE, type,
7880                       GDI_STATE, GD_BUTTON_UNPRESSED,
7881                       GDI_RADIO_NR, radio_button_nr,
7882                       GDI_CHECKED, checked,
7883                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7884                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7885                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7886                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7887                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7888                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7889                       GDI_DECORATION_SIZE, tile_size, tile_size,
7890                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7891                       GDI_DECORATION_MASKED, deco_masked,
7892                       GDI_EVENT_MASK, event_mask,
7893                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7894                       GDI_CALLBACK_ACTION, HandleControlButtons,
7895                       GDI_END);
7896
7897     if (gi == NULL)
7898       Fail("cannot create gadget");
7899
7900     level_editor_gadget[id] = gi;
7901   }
7902
7903   // these values are not constant, but can change at runtime
7904   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7905   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7906   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7907   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7908   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7909   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7910   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7911   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7912   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7913   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7914   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7915   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7916
7917   // create buttons for scrolling of drawing area and element list
7918   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7919   {
7920     int id = scrollbutton_info[i].gadget_id;
7921     int type_id = scrollbutton_info[i].gadget_type_id;
7922     int graphic = scrollbutton_info[i].graphic;
7923     struct GraphicInfo *gd = &graphic_info[graphic];
7924     Bitmap *gd_bitmap = gd->bitmap;
7925     int gd_x1 = gd->src_x;
7926     int gd_y1 = gd->src_y;
7927     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7928     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7929     int width  = gd->width;
7930     int height = gd->height;
7931     int x = scrollbutton_pos[i].x;
7932     int y = scrollbutton_pos[i].y;
7933     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7934
7935     if (type_id != i)
7936       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7937
7938     if (id == GADGET_ID_SCROLL_LIST_UP ||
7939         id == GADGET_ID_SCROLL_LIST_DOWN)
7940     {
7941       x += PX;
7942       y += PY;
7943     }
7944     else
7945     {
7946       x += SX;
7947       y += SY;
7948     }
7949
7950     gi = CreateGadget(GDI_CUSTOM_ID, id,
7951                       GDI_CUSTOM_TYPE_ID, type_id,
7952                       GDI_IMAGE_ID, graphic,
7953                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7954                       GDI_X, x,
7955                       GDI_Y, y,
7956                       GDI_WIDTH, width,
7957                       GDI_HEIGHT, height,
7958                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7959                       GDI_STATE, GD_BUTTON_UNPRESSED,
7960                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7961                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7962                       GDI_EVENT_MASK, event_mask,
7963                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7964                       GDI_CALLBACK_ACTION, HandleControlButtons,
7965                       GDI_END);
7966
7967     if (gi == NULL)
7968       Fail("cannot create gadget");
7969
7970     level_editor_gadget[id] = gi;
7971   }
7972
7973   // create buttons for element list
7974   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7975   {
7976     int type_id = i;
7977     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
7978     int graphic = IMG_EDITOR_PALETTE_BUTTON;
7979     struct GraphicInfo *gd = &graphic_info[graphic];
7980     Bitmap *gd_bitmap = gd->bitmap;
7981     Bitmap *deco_bitmap;
7982     int deco_x, deco_y, deco_xpos, deco_ypos;
7983     int gd_x1 = gd->src_x;
7984     int gd_y1 = gd->src_y;
7985     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7986     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7987     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
7988     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
7989     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
7990     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
7991     int element = editor_elements[i];
7992     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
7993     unsigned int event_mask = GD_EVENT_RELEASED;
7994
7995     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
7996
7997     deco_xpos = (gd->width  - tile_size) / 2;
7998     deco_ypos = (gd->height - tile_size) / 2;
7999
8000     gi = CreateGadget(GDI_CUSTOM_ID, id,
8001                       GDI_CUSTOM_TYPE_ID, type_id,
8002                       GDI_IMAGE_ID, graphic,
8003                       GDI_INFO_TEXT, getElementInfoText(element),
8004                       GDI_X, x,
8005                       GDI_Y, y,
8006                       GDI_WIDTH, gd->width,
8007                       GDI_HEIGHT, gd->height,
8008                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8009                       GDI_STATE, GD_BUTTON_UNPRESSED,
8010                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
8011                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
8012                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
8013                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
8014                       GDI_DECORATION_SIZE, tile_size, tile_size,
8015                       GDI_DECORATION_SHIFTING, 1, 1,
8016                       GDI_EVENT_MASK, event_mask,
8017                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8018                       GDI_CALLBACK_ACTION, HandleControlButtons,
8019                       GDI_END);
8020
8021     if (gi == NULL)
8022       Fail("cannot create gadget");
8023
8024     level_editor_gadget[id] = gi;
8025   }
8026 }
8027
8028 static void CreateCounterButtons(void)
8029 {
8030   int max_infotext_len = getMaxInfoTextLength();
8031   int i;
8032
8033   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
8034   {
8035     int type_id = counterbutton_info[i].gadget_type_id;
8036     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
8037     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
8038     int j;
8039
8040     if (type_id != i)
8041       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
8042
8043     // determine horizontal position to the right of specified gadget
8044     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8045       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
8046            ED_GADGET_TEXT_DISTANCE);
8047
8048     // determine horizontal offset for leading text
8049     if (counterbutton_info[i].text_left != NULL)
8050       x += getTextWidthForGadget(counterbutton_info[i].text_left);
8051
8052     for (j = 0; j < 2; j++)
8053     {
8054       struct GadgetInfo *gi;
8055       int id = (j == 0 ?
8056                 counterbutton_info[i].gadget_id_down :
8057                 counterbutton_info[i].gadget_id_up);
8058       int graphic;
8059       struct GraphicInfo *gd;
8060       int gd_x1, gd_x2, gd_y1, gd_y2;
8061       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
8062       char infotext[max_infotext_len + 1];
8063
8064       if (i == ED_COUNTER_ID_SELECT_LEVEL)
8065       {
8066         graphic = (j == 0 ?
8067                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
8068                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
8069
8070         event_mask |= GD_EVENT_RELEASED;
8071
8072         if (j == 0)
8073         {
8074           x = DX + editor.button.prev_level.x;
8075           y = DY + editor.button.prev_level.y;
8076         }
8077         else
8078         {
8079           x = DX + editor.button.next_level.x;
8080           y = DY + editor.button.next_level.y;
8081         }
8082       }
8083       else
8084       {
8085         graphic = (j == 0 ?
8086                    IMG_EDITOR_COUNTER_DOWN :
8087                    IMG_EDITOR_COUNTER_UP);
8088       }
8089
8090       gd = &graphic_info[graphic];
8091
8092       gd_x1 = gd->src_x;
8093       gd_y1 = gd->src_y;
8094       gd_x2 = gd->src_x + gd->pressed_xoffset;
8095       gd_y2 = gd->src_y + gd->pressed_yoffset;
8096
8097       sprintf(infotext, "%s counter value by 1, 5 or 10",
8098               (j == 0 ? "Decrease" : "Increase"));
8099
8100       gi = CreateGadget(GDI_CUSTOM_ID, id,
8101                         GDI_CUSTOM_TYPE_ID, type_id,
8102                         GDI_IMAGE_ID, graphic,
8103                         GDI_INFO_TEXT, infotext,
8104                         GDI_X, x,
8105                         GDI_Y, y,
8106                         GDI_WIDTH, gd->width,
8107                         GDI_HEIGHT, gd->height,
8108                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8109                         GDI_STATE, GD_BUTTON_UNPRESSED,
8110                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8111                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8112                         GDI_EVENT_MASK, event_mask,
8113                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8114                         GDI_CALLBACK_ACTION, HandleCounterButtons,
8115                         GDI_END);
8116
8117       if (gi == NULL)
8118         Fail("cannot create gadget");
8119
8120       level_editor_gadget[id] = gi;
8121       right_gadget_border[id] =
8122         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8123
8124       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
8125
8126       if (j == 0)
8127       {
8128         int font_type = FONT_INPUT_1;
8129         int font_type_active = FONT_INPUT_1_ACTIVE;
8130
8131         id = counterbutton_info[i].gadget_id_text;
8132
8133         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8134
8135         if (i == ED_COUNTER_ID_SELECT_LEVEL)
8136         {
8137           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
8138
8139           font_type = FONT_LEVEL_NUMBER;
8140           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
8141
8142           x = DX + editor.input.level_number.x;
8143           y = DY + editor.input.level_number.y;
8144         }
8145         else
8146         {
8147           graphic = IMG_EDITOR_COUNTER_INPUT;
8148         }
8149
8150         gd = &graphic_info[graphic];
8151
8152         gd_x1 = gd->src_x;
8153         gd_y1 = gd->src_y;
8154         gd_x2 = gd->src_x + gd->active_xoffset;
8155         gd_y2 = gd->src_y + gd->active_yoffset;
8156
8157         gi = CreateGadget(GDI_CUSTOM_ID, id,
8158                           GDI_CUSTOM_TYPE_ID, type_id,
8159                           GDI_IMAGE_ID, graphic,
8160                           GDI_INFO_TEXT, "Enter counter value",
8161                           GDI_X, x,
8162                           GDI_Y, y,
8163                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
8164                           GDI_NUMBER_VALUE, 0,
8165                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
8166                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
8167                           GDI_TEXT_SIZE, 3,     // minimal counter text size
8168                           GDI_TEXT_FONT, font_type,
8169                           GDI_TEXT_FONT_ACTIVE, font_type_active,
8170                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8171                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8172                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8173                           GDI_DESIGN_WIDTH, gd->width,
8174                           GDI_EVENT_MASK, event_mask,
8175                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8176                           GDI_CALLBACK_ACTION, HandleCounterButtons,
8177                           GDI_END);
8178
8179         if (gi == NULL)
8180           Fail("cannot create gadget");
8181
8182         level_editor_gadget[id] = gi;
8183         right_gadget_border[id] =
8184           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8185
8186         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
8187       }
8188     }
8189   }
8190 }
8191
8192 static void CreateDrawingAreas(void)
8193 {
8194   int i;
8195
8196   // these values are not constant, but can change at runtime
8197   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8198   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8199
8200   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8201   {
8202     struct GadgetInfo *gi;
8203     int id = drawingarea_info[i].gadget_id;
8204     int type_id = drawingarea_info[i].gadget_type_id;
8205     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8206     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8207     int area_xsize = drawingarea_info[i].area_xsize;
8208     int area_ysize = drawingarea_info[i].area_ysize;
8209     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8210                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8211     unsigned int event_mask =
8212       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8213       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8214
8215     if (type_id != i)
8216       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8217
8218     // determine horizontal position to the right of specified gadget
8219     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8220       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8221            ED_DRAWINGAREA_TEXT_DISTANCE);
8222
8223     // determine horizontal offset for leading text
8224     if (drawingarea_info[i].text_left != NULL)
8225       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8226
8227     gi = CreateGadget(GDI_CUSTOM_ID, id,
8228                       GDI_CUSTOM_TYPE_ID, type_id,
8229                       GDI_X, x,
8230                       GDI_Y, y,
8231                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8232                       GDI_AREA_SIZE, area_xsize, area_ysize,
8233                       GDI_ITEM_SIZE, item_size, item_size,
8234                       GDI_EVENT_MASK, event_mask,
8235                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8236                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8237                       GDI_END);
8238
8239     if (gi == NULL)
8240       Fail("cannot create gadget");
8241
8242     level_editor_gadget[id] = gi;
8243     right_gadget_border[id] =
8244       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8245   }
8246 }
8247
8248 static void CreateTextInputGadgets(void)
8249 {
8250   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8251   int max_infotext_len = getMaxInfoTextLength();
8252   int i;
8253
8254   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8255   {
8256     int gd_x1 = gd->src_x;
8257     int gd_y1 = gd->src_y;
8258     int gd_x2 = gd->src_x + gd->active_xoffset;
8259     int gd_y2 = gd->src_y + gd->active_yoffset;
8260     struct GadgetInfo *gi;
8261     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8262     char infotext[MAX_OUTPUT_LINESIZE + 1];
8263     int id = textinput_info[i].gadget_id;
8264     int type_id = textinput_info[i].gadget_type_id;
8265     int x, y;
8266
8267     if (type_id != i)
8268       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8269
8270     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8271     {
8272       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8273       int border_size = gd->border_size;
8274       int font_nr = FONT_INPUT_1;
8275       int font_height = getFontHeight(font_nr);
8276       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8277       int yoffset = element_border + (TILEY - font_height) / 2;
8278
8279       x = (editor.settings.element_name.x != -1 ?
8280            editor.settings.element_name.x :
8281            editor.settings.element_graphic.x + xoffset) - border_size;
8282       y = (editor.settings.element_name.y != -1 ?
8283            editor.settings.element_name.y :
8284            editor.settings.element_graphic.y + yoffset) - border_size;
8285     }
8286     else
8287     {
8288       x = ED_SETTINGS_X(textinput_info[i].x);
8289       y = ED_SETTINGS_Y(textinput_info[i].y);
8290     }
8291
8292     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8293     infotext[max_infotext_len] = '\0';
8294
8295     gi = CreateGadget(GDI_CUSTOM_ID, id,
8296                       GDI_CUSTOM_TYPE_ID, type_id,
8297                       GDI_INFO_TEXT, infotext,
8298                       GDI_X, SX + x,
8299                       GDI_Y, SY + y,
8300                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8301                       GDI_TEXT_VALUE, textinput_info[i].value,
8302                       GDI_TEXT_SIZE, textinput_info[i].size,
8303                       GDI_TEXT_FONT, FONT_INPUT_1,
8304                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8305                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8306                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8307                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8308                       GDI_DESIGN_WIDTH, gd->width,
8309                       GDI_EVENT_MASK, event_mask,
8310                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8311                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
8312                       GDI_END);
8313
8314     if (gi == NULL)
8315       Fail("cannot create gadget");
8316
8317     level_editor_gadget[id] = gi;
8318   }
8319 }
8320
8321 static void CreateTextAreaGadgets(void)
8322 {
8323   int max_infotext_len = getMaxInfoTextLength();
8324   int i;
8325
8326   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8327   {
8328     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8329     int gd_x1 = gd->src_x;
8330     int gd_y1 = gd->src_y;
8331     int gd_x2 = gd->src_x + gd->active_xoffset;
8332     int gd_y2 = gd->src_y + gd->active_yoffset;
8333     struct GadgetInfo *gi;
8334     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8335     char infotext[MAX_OUTPUT_LINESIZE + 1];
8336     int id = textarea_info[i].gadget_id;
8337     int type_id = textarea_info[i].gadget_type_id;
8338     int area_xsize = textarea_info[i].xsize;
8339     int area_ysize = textarea_info[i].ysize;
8340
8341     if (type_id != i)
8342       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8343
8344     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8345     infotext[max_infotext_len] = '\0';
8346
8347     gi = CreateGadget(GDI_CUSTOM_ID, id,
8348                       GDI_CUSTOM_TYPE_ID, type_id,
8349                       GDI_INFO_TEXT, infotext,
8350                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8351                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8352                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8353                       GDI_AREA_SIZE, area_xsize, area_ysize,
8354                       GDI_TEXT_FONT, FONT_INPUT_1,
8355                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8356                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8357                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8358                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8359                       GDI_DESIGN_WIDTH, gd->width,
8360                       GDI_EVENT_MASK, event_mask,
8361                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8362                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8363                       GDI_END);
8364
8365     if (gi == NULL)
8366       Fail("cannot create gadget");
8367
8368     level_editor_gadget[id] = gi;
8369   }
8370 }
8371
8372 static void CreateSelectboxGadgets(void)
8373 {
8374   int max_infotext_len = getMaxInfoTextLength();
8375
8376   int i, j;
8377
8378   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8379   {
8380     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8381     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8382     int gd_x1 = gd->src_x;
8383     int gd_y1 = gd->src_y;
8384     int gd_x2 = gd->src_x + gd->active_xoffset;
8385     int gd_y2 = gd->src_y + gd->active_yoffset;
8386     int selectbox_button_xsize = gd2->width;
8387     struct GadgetInfo *gi;
8388     char infotext[MAX_OUTPUT_LINESIZE + 1];
8389     int id = selectbox_info[i].gadget_id;
8390     int type_id = selectbox_info[i].gadget_type_id;
8391     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8392     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8393     unsigned int event_mask =
8394       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8395
8396     if (type_id != i)
8397       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8398
8399     if (selectbox_info[i].size == -1)   // dynamically determine size
8400     {
8401       // (we cannot use -1 for uninitialized values if we directly compare
8402       // with results from strlen(), because the '<' and '>' operation will
8403       // implicitely cast -1 to an unsigned integer value!)
8404       selectbox_info[i].size = 0;
8405
8406       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8407         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8408           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8409
8410       selectbox_info[i].size++;         // add one character empty space
8411     }
8412
8413     // determine horizontal position to the right of specified gadget
8414     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8415       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8416            ED_GADGET_TEXT_DISTANCE);
8417
8418     // determine horizontal offset for leading text
8419     if (selectbox_info[i].text_left != NULL)
8420       x += getTextWidthForGadget(selectbox_info[i].text_left);
8421
8422     sprintf(infotext, "%s", selectbox_info[i].infotext);
8423     infotext[max_infotext_len] = '\0';
8424
8425     gi = CreateGadget(GDI_CUSTOM_ID, id,
8426                       GDI_CUSTOM_TYPE_ID, type_id,
8427                       GDI_INFO_TEXT, infotext,
8428                       GDI_X, x,
8429                       GDI_Y, y,
8430                       GDI_TYPE, GD_TYPE_SELECTBOX,
8431                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8432                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8433                       GDI_TEXT_SIZE, selectbox_info[i].size,
8434                       GDI_TEXT_FONT, FONT_INPUT_1,
8435                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8436                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8437                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8438                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8439                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8440                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8441                       GDI_DESIGN_WIDTH, gd->width,
8442                       GDI_EVENT_MASK, event_mask,
8443                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8444                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8445                       GDI_END);
8446
8447     if (gi == NULL)
8448       Fail("cannot create gadget");
8449
8450     level_editor_gadget[id] = gi;
8451     right_gadget_border[id] =
8452       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8453   }
8454 }
8455
8456 static void CreateTextbuttonGadgets(void)
8457 {
8458   int max_infotext_len = getMaxInfoTextLength();
8459   int i;
8460
8461   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8462   {
8463     int id = textbutton_info[i].gadget_id;
8464     int type_id = textbutton_info[i].gadget_type_id;
8465     int is_tab_button =
8466       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8467        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8468     int graphic =
8469       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8470     int gadget_distance =
8471       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8472     struct GraphicInfo *gd = &graphic_info[graphic];
8473     int gd_x1 = gd->src_x;
8474     int gd_y1 = gd->src_y;
8475     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8476     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8477     int gd_x1a = gd->src_x + gd->active_xoffset;
8478     int gd_y1a = gd->src_y + gd->active_yoffset;
8479     int border_xsize = gd->border_size + gd->draw_xoffset;
8480     int border_ysize = gd->border_size;
8481     struct GadgetInfo *gi;
8482     unsigned int event_mask = GD_EVENT_RELEASED;
8483     char infotext[MAX_OUTPUT_LINESIZE + 1];
8484     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8485     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8486
8487     if (type_id != i)
8488       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8489
8490     if (textbutton_info[i].size == -1)  // dynamically determine size
8491       textbutton_info[i].size = strlen(textbutton_info[i].text);
8492
8493     sprintf(infotext, "%s", textbutton_info[i].infotext);
8494     infotext[max_infotext_len] = '\0';
8495
8496     // determine horizontal position to the right of specified gadget
8497     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8498     {
8499       int gadget_id_align = textbutton_info[i].gadget_id_align;
8500
8501       x = right_gadget_border[gadget_id_align] + gadget_distance;
8502
8503       if (textbutton_info[i].y == -1)
8504         y = level_editor_gadget[gadget_id_align]->y;
8505     }
8506
8507     // determine horizontal offset for leading text
8508     if (textbutton_info[i].text_left != NULL)
8509       x += getTextWidthForGadget(textbutton_info[i].text_left);
8510
8511     gi = CreateGadget(GDI_CUSTOM_ID, id,
8512                       GDI_CUSTOM_TYPE_ID, type_id,
8513                       GDI_IMAGE_ID, graphic,
8514                       GDI_INFO_TEXT, infotext,
8515                       GDI_X, x,
8516                       GDI_Y, y,
8517                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8518                       GDI_TEXT_VALUE, textbutton_info[i].text,
8519                       GDI_TEXT_SIZE, textbutton_info[i].size,
8520                       GDI_TEXT_FONT, FONT_INPUT_2,
8521                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8522                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8523                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8524                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8525                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8526                       GDI_DESIGN_WIDTH, gd->width,
8527                       GDI_DECORATION_SHIFTING, 1, 1,
8528                       GDI_EVENT_MASK, event_mask,
8529                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8530                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8531                       GDI_END);
8532
8533     if (gi == NULL)
8534       Fail("cannot create gadget");
8535
8536     level_editor_gadget[id] = gi;
8537     right_gadget_border[id] =
8538       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8539   }
8540 }
8541
8542 static void CreateGraphicbuttonGadgets(void)
8543 {
8544   struct GadgetInfo *gi;
8545   int i;
8546
8547   // create buttons for scrolling of drawing area and element list
8548   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8549   {
8550     int id = graphicbutton_info[i].gadget_id;
8551     int type_id = graphicbutton_info[i].gadget_type_id;
8552     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8553     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8554     int graphic = graphicbutton_info[i].graphic;
8555     struct GraphicInfo *gd = &graphic_info[graphic];
8556     int gd_x1 = gd->src_x;
8557     int gd_y1 = gd->src_y;
8558     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8559     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8560     unsigned int event_mask = GD_EVENT_RELEASED;
8561
8562     if (type_id != i)
8563       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8564
8565     // determine horizontal position to the right of specified gadget
8566     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8567       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8568            ED_GADGET_TEXT_DISTANCE);
8569
8570     // determine horizontal offset for leading text
8571     if (graphicbutton_info[i].text_left != NULL)
8572       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8573
8574     gi = CreateGadget(GDI_CUSTOM_ID, id,
8575                       GDI_CUSTOM_TYPE_ID, type_id,
8576                       GDI_IMAGE_ID, graphic,
8577                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8578                       GDI_X, x,
8579                       GDI_Y, y,
8580                       GDI_WIDTH, gd->width,
8581                       GDI_HEIGHT, gd->height,
8582                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8583                       GDI_STATE, GD_BUTTON_UNPRESSED,
8584                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8585                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8586                       GDI_EVENT_MASK, event_mask,
8587                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8588                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8589                       GDI_END);
8590
8591     if (gi == NULL)
8592       Fail("cannot create gadget");
8593
8594     level_editor_gadget[id] = gi;
8595     right_gadget_border[id] =
8596       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8597   }
8598 }
8599
8600 static void CreateScrollbarGadgets(void)
8601 {
8602   int i;
8603
8604   // these values are not constant, but can change at runtime
8605   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8606     SX + ED_SCROLL_HORIZONTAL_XPOS;
8607   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8608     SY + ED_SCROLL_HORIZONTAL_YPOS;
8609   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8610     ED_SCROLL_HORIZONTAL_XSIZE;
8611   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8612     ED_SCROLL_HORIZONTAL_YSIZE;
8613   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8614   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8615   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8616   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8617
8618   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8619     SX + ED_SCROLL_VERTICAL_XPOS;
8620   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8621     SY + ED_SCROLL_VERTICAL_YPOS;
8622   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8623     ED_SCROLL_VERTICAL_XSIZE;
8624   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8625     ED_SCROLL_VERTICAL_YSIZE;
8626   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8627   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8628   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8629   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8630
8631   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8632     PX + ED_SCROLL2_VERTICAL_XPOS;
8633   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8634     PY + ED_SCROLL2_VERTICAL_YPOS;
8635   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8636     ED_SCROLL2_VERTICAL_XSIZE;
8637   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8638     ED_SCROLL2_VERTICAL_YSIZE;
8639   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8640   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8641   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8642   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8643
8644   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8645   {
8646     int id = scrollbar_info[i].gadget_id;
8647     int type_id = scrollbar_info[i].gadget_type_id;
8648     int graphic = scrollbar_info[i].graphic;
8649     struct GraphicInfo *gd = &graphic_info[graphic];
8650     int gd_x1 = gd->src_x;
8651     int gd_y1 = gd->src_y;
8652     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8653     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8654     struct GadgetInfo *gi;
8655     int items_max, items_visible, item_position;
8656     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8657
8658     if (type_id != i)
8659       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8660
8661     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8662     {
8663       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8664       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8665       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8666     }
8667     else        // drawing area scrollbars
8668     {
8669       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8670       {
8671         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8672         items_visible = ed_fieldx;
8673         item_position = 0;
8674       }
8675       else
8676       {
8677         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8678         items_visible = ed_fieldy;
8679         item_position = 0;
8680       }
8681     }
8682
8683     gi = CreateGadget(GDI_CUSTOM_ID, id,
8684                       GDI_CUSTOM_TYPE_ID, type_id,
8685                       GDI_IMAGE_ID, graphic,
8686                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8687                       GDI_X, scrollbar_pos[i].x,
8688                       GDI_Y, scrollbar_pos[i].y,
8689                       GDI_WIDTH, scrollbar_pos[i].width,
8690                       GDI_HEIGHT, scrollbar_pos[i].height,
8691                       GDI_TYPE, scrollbar_info[i].type,
8692                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8693                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8694                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8695                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8696                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8697                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8698                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8699                       GDI_STATE, GD_BUTTON_UNPRESSED,
8700                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8701                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8702                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8703                       GDI_EVENT_MASK, event_mask,
8704                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8705                       GDI_CALLBACK_ACTION, HandleControlButtons,
8706                       GDI_END);
8707
8708     if (gi == NULL)
8709       Fail("cannot create gadget");
8710
8711     level_editor_gadget[id] = gi;
8712   }
8713 }
8714
8715 static void CreateCheckbuttonGadgets(void)
8716 {
8717   struct GadgetInfo *gi;
8718   int i;
8719
8720   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8721   {
8722     int id = checkbutton_info[i].gadget_id;
8723     int type_id = checkbutton_info[i].gadget_type_id;
8724     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8725                    IMG_EDITOR_CHECKBOX);
8726     struct GraphicInfo *gd = &graphic_info[graphic];
8727     int gd_x1 = gd->src_x;
8728     int gd_y1 = gd->src_y;
8729     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8730     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8731     int gd_x1a = gd->src_x + gd->active_xoffset;
8732     int gd_y1a = gd->src_y + gd->active_yoffset;
8733     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8734     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8735     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8736     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8737     unsigned int event_mask = GD_EVENT_PRESSED;
8738
8739     if (type_id != i)
8740       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8741
8742     // determine horizontal position to the right of specified gadget
8743     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8744       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8745            ED_GADGET_TEXT_DISTANCE);
8746
8747     // determine horizontal offset for leading text
8748     if (checkbutton_info[i].text_left != NULL)
8749       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8750
8751     gi = CreateGadget(GDI_CUSTOM_ID, id,
8752                       GDI_CUSTOM_TYPE_ID, type_id,
8753                       GDI_IMAGE_ID, graphic,
8754                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8755                       GDI_X, x,
8756                       GDI_Y, y,
8757                       GDI_WIDTH, gd->width,
8758                       GDI_HEIGHT, gd->height,
8759                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8760                       GDI_CHECKED, *checkbutton_info[i].value,
8761                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8762                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8763                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8764                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8765                       GDI_EVENT_MASK, event_mask,
8766                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8767                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8768                       GDI_END);
8769
8770     if (gi == NULL)
8771       Fail("cannot create gadget");
8772
8773     level_editor_gadget[id] = gi;
8774     right_gadget_border[id] =
8775       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8776   }
8777 }
8778
8779 static void CreateRadiobuttonGadgets(void)
8780 {
8781   int graphic = IMG_EDITOR_RADIOBUTTON;
8782   struct GraphicInfo *gd = &graphic_info[graphic];
8783   int gd_x1 = gd->src_x;
8784   int gd_y1 = gd->src_y;
8785   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8786   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8787   int gd_x1a = gd->src_x + gd->active_xoffset;
8788   int gd_y1a = gd->src_y + gd->active_yoffset;
8789   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8790   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8791   struct GadgetInfo *gi;
8792   int i;
8793
8794   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8795   {
8796     int id = radiobutton_info[i].gadget_id;
8797     int type_id = radiobutton_info[i].gadget_type_id;
8798     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8799     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8800     unsigned int event_mask = GD_EVENT_PRESSED;
8801
8802     if (type_id != i)
8803       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8804
8805     int checked =
8806       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8807
8808     // determine horizontal position to the right of specified gadget
8809     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8810       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8811            ED_GADGET_TEXT_DISTANCE);
8812
8813     // determine horizontal offset for leading text
8814     if (radiobutton_info[i].text_left != NULL)
8815       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8816
8817     gi = CreateGadget(GDI_CUSTOM_ID, id,
8818                       GDI_CUSTOM_TYPE_ID, type_id,
8819                       GDI_IMAGE_ID, graphic,
8820                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8821                       GDI_X, x,
8822                       GDI_Y, y,
8823                       GDI_WIDTH, gd->width,
8824                       GDI_HEIGHT, gd->height,
8825                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8826                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8827                       GDI_CHECKED, checked,
8828                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8829                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8830                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8831                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8832                       GDI_EVENT_MASK, event_mask,
8833                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8834                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8835                       GDI_END);
8836
8837     if (gi == NULL)
8838       Fail("cannot create gadget");
8839
8840     level_editor_gadget[id] = gi;
8841     right_gadget_border[id] =
8842       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8843   }
8844 }
8845
8846 void CreateLevelEditorGadgets(void)
8847 {
8848   // force EDITOR font inside level editor
8849   SetFontStatus(GAME_MODE_EDITOR);
8850
8851   // these values are not constant, but can change at runtime
8852   ed_fieldx = MAX_ED_FIELDX - 1;
8853   ed_fieldy = MAX_ED_FIELDY - 1;
8854
8855   num_editor_gadgets = NUM_EDITOR_GADGETS;
8856
8857   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8858
8859   level_editor_gadget =
8860     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8861   right_gadget_border =
8862     checked_calloc(num_editor_gadgets * sizeof(int));
8863
8864   // set number of empty (padding) element buttons to maximum number of buttons
8865   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8866
8867   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8868   editor_el_empty_ptr = editor_el_empty;
8869
8870   use_permanent_palette = !editor.palette.show_as_separate_screen;
8871
8872   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8873
8874   ReinitializeElementList();
8875
8876   CreateControlButtons();
8877   CreateScrollbarGadgets();
8878
8879   // order of function calls is important because of cross-references
8880   CreateCheckbuttonGadgets();
8881   CreateCounterButtons();
8882   CreateRadiobuttonGadgets();
8883   CreateTextInputGadgets();
8884   CreateTextAreaGadgets();
8885   CreateSelectboxGadgets();
8886   CreateGraphicbuttonGadgets();
8887   CreateTextbuttonGadgets();
8888   CreateDrawingAreas();
8889
8890   ResetFontStatus();
8891 }
8892
8893 void FreeLevelEditorGadgets(void)
8894 {
8895   int i;
8896
8897   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8898
8899   for (i = 0; i < num_editor_gadgets; i++)
8900   {
8901     FreeGadget(level_editor_gadget[i]);
8902
8903     level_editor_gadget[i] = NULL;
8904   }
8905
8906   checked_free(level_editor_gadget);
8907   checked_free(right_gadget_border);
8908
8909   checked_free(editor_el_empty);
8910 }
8911
8912 static void MapCounterButtons(int id)
8913 {
8914   int font_nr = FONT_TEXT_1;
8915   int font_height = getFontHeight(font_nr);
8916   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8917   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8918   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8919   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8920   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8921   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8922   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8923   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8924   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8925   int yoffset = (gi_down->height - font_height) / 2;
8926   int x_left = gi_down->x - xoffset_left;
8927   int x_right;  // set after gadget position was modified
8928   int y_above = gi_down->y - yoffset_above;
8929   int x = gi_down->x;
8930   int y;        // set after gadget position was modified
8931
8932   // counter limits must be changed first to prevent value truncation
8933   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8934                             counterbutton_info[id].max_value);
8935
8936   // right text position might have changed after setting position above
8937   x_right = gi_up->x + gi_up->width + xoffset_right;
8938
8939   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8940
8941   // set position for counter gadgets with dynamically determined position
8942   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8943   {
8944     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8945     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8946     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8947   }
8948
8949   // vertical position might have changed after setting position above
8950   y = gi_up->y + yoffset;
8951
8952   if (counterbutton_info[id].text_above)
8953     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8954
8955   if (counterbutton_info[id].text_left)
8956     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8957
8958   if (counterbutton_info[id].text_right)
8959     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8960
8961   MapGadget(gi_down);
8962   MapGadget(gi_text);
8963   MapGadget(gi_up);
8964 }
8965
8966 static void MapControlButtons(void)
8967 {
8968   int counter_id;
8969   int i;
8970
8971   // map toolbox buttons (excluding special CE toolbox buttons)
8972   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
8973     MapGadget(level_editor_gadget[i]);
8974
8975   // map toolbox buttons (element properties buttons)
8976   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
8977     MapGadget(level_editor_gadget[i]);
8978
8979   if (use_permanent_palette)
8980   {
8981     // map buttons to select elements
8982     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8983       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
8984     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
8985     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
8986     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
8987   }
8988
8989   // map buttons to select level
8990   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
8991   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
8992   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
8993   MapCounterButtons(counter_id);
8994 }
8995
8996 static void MapDrawingArea(int id)
8997 {
8998   int font_nr = FONT_TEXT_1;
8999   int font_height = getFontHeight(font_nr);
9000   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9001   int area_xsize = gi->drawing.area_xsize;
9002   int area_ysize = gi->drawing.area_ysize;
9003   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9004   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
9005   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
9006   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
9007   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
9008   int x_below = gi->x + (gi->width - xoffset_below) / 2;
9009   int y_side  = gi->y + (gi->height - font_height) / 2;
9010   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
9011   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
9012
9013   if (drawingarea_info[id].text_left)
9014     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
9015
9016   if (drawingarea_info[id].text_right)
9017     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
9018
9019   if (drawingarea_info[id].text_above)
9020     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
9021
9022   if (drawingarea_info[id].text_below)
9023     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
9024
9025   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
9026   {
9027     DrawElementBorder(gi->x, gi->y,
9028                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
9029                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
9030
9031     DrawDrawingArea(id);
9032   }
9033
9034   MapGadget(gi);
9035 }
9036
9037 static void MapTextInputGadget(int id)
9038 {
9039   int font_nr = FONT_TEXT_1;
9040   int font_height = getFontHeight(font_nr);
9041   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
9042   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9043   int x_above = ED_SETTINGS_X(textinput_info[id].x);
9044   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
9045
9046   if (textinput_info[id].text_above)
9047     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
9048
9049   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
9050
9051   MapGadget(gi);
9052 }
9053
9054 static void MapTextAreaGadget(int id)
9055 {
9056   int font_nr = FONT_TEXT_1;
9057   int font_height = getFontHeight(font_nr);
9058   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
9059   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9060   int x_above = ED_SETTINGS_X(textarea_info[id].x);
9061   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
9062   char *text_above = textarea_info[id].text_above;
9063
9064   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
9065     text_above = textarea_info[id].text_above_cropped;
9066
9067   if (text_above)
9068     DrawTextS(x_above, y_above, font_nr, text_above);
9069
9070   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
9071
9072   MapGadget(gi);
9073 }
9074
9075 static void MapSelectboxGadget(int id)
9076 {
9077   int font_nr = FONT_TEXT_1;
9078   int font_height = getFontHeight(font_nr);
9079   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
9080   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
9081   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9082   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9083   int yoffset = (gi->height - font_height) / 2;
9084   int x_left = gi->x - xoffset_left;
9085   int x_right = gi->x + gi->width + xoffset_right;
9086   int y_above = gi->y - yoffset_above;
9087   int x = gi->x;
9088   int y = gi->y + yoffset;
9089
9090   if (selectbox_info[id].text_above)
9091     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
9092
9093   if (selectbox_info[id].text_left)
9094     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
9095
9096   if (selectbox_info[id].text_right)
9097     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
9098
9099   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
9100
9101   MapGadget(gi);
9102 }
9103
9104 static void MapTextbuttonGadget(int id)
9105 {
9106   int font_nr = FONT_TEXT_1;
9107   int font_height = getFontHeight(font_nr);
9108   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
9109   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
9110   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9111   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9112   int yoffset = (gi->height - font_height) / 2;
9113   int x_left = gi->x - xoffset_left;
9114   int x_right = gi->x + gi->width + xoffset_right;
9115   int y_above = gi->y - yoffset_above;
9116   int x = gi->x;
9117   int y = gi->y + yoffset;
9118
9119   // only show button to delete change pages when more than minimum pages
9120   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
9121       custom_element.num_change_pages == MIN_CHANGE_PAGES)
9122     return;
9123
9124   if (textbutton_info[id].text_above)
9125     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
9126
9127   if (textbutton_info[id].text_left)
9128     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
9129
9130   if (textbutton_info[id].text_right)
9131     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
9132
9133   MapGadget(gi);
9134 }
9135
9136 static void MapGraphicbuttonGadget(int id)
9137 {
9138   int font_nr = FONT_TEXT_1;
9139   int font_height = getFontHeight(font_nr);
9140   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
9141   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
9142   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9143   int yoffset = (gi->height - font_height) / 2;
9144   int x_left = gi->x - xoffset_left;
9145   int x_right = gi->x + gi->width + xoffset_right;
9146   int y = gi->y + yoffset;
9147
9148   if (graphicbutton_info[id].text_left)
9149     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
9150
9151   if (graphicbutton_info[id].text_right)
9152     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
9153
9154   MapGadget(gi);
9155 }
9156
9157 static void MapRadiobuttonGadget(int id)
9158 {
9159   int font_nr = FONT_TEXT_1;
9160   int font_height = getFontHeight(font_nr);
9161   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
9162   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9163   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9164   int yoffset = (gi->height - font_height) / 2;
9165   int x_left = gi->x - xoffset_left;
9166   int x_right = gi->x + gi->width + xoffset_right;
9167   int y = gi->y + yoffset;
9168   boolean checked =
9169     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
9170
9171   if (radiobutton_info[id].text_left)
9172     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
9173
9174   if (radiobutton_info[id].text_right)
9175     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
9176
9177   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
9178
9179   MapGadget(gi);
9180 }
9181
9182 static void MapCheckbuttonGadget(int id)
9183 {
9184   int font_nr = FONT_TEXT_1;
9185   int font_height = getFontHeight(font_nr);
9186   struct GadgetInfo *gi = level_editor_gadget[checkbutton_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_above = font_height + ED_GADGET_LINE_DISTANCE;
9190   int yoffset = (gi->height - font_height) / 2;
9191   int y_above = gi->y - yoffset_above;
9192   int x = gi->x;
9193   int x_left, x_right, y;       // set after gadget position was modified
9194
9195   // set position for gadgets with dynamically determined position
9196   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9197     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9198   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9199
9200   x_left = gi->x - xoffset_left;
9201   x_right = gi->x + gi->width + xoffset_right;
9202   y = gi->y + yoffset;
9203
9204   if (checkbutton_info[id].text_above)
9205     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9206
9207   if (checkbutton_info[id].text_left)
9208     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9209
9210   if (checkbutton_info[id].text_right)
9211     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9212
9213   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9214
9215   MapGadget(gi);
9216 }
9217
9218 static void MapMainDrawingArea(void)
9219 {
9220   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9221   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9222   int i;
9223
9224   if (suppressBorderElement())
9225   {
9226     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9227     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9228   }
9229
9230   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9231   {
9232     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9233           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9234          no_horizontal_scrollbar) ||
9235         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9236           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9237          no_vertical_scrollbar))
9238       continue;
9239
9240     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9241   }
9242
9243   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9244   {
9245     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9246         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9247       continue;
9248
9249     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9250   }
9251
9252   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9253 }
9254
9255 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9256 {
9257   int i;
9258
9259   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9260   {
9261     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9262         i == GADGET_ID_CUSTOM_COPY_TO ||
9263         i == GADGET_ID_CUSTOM_EXCHANGE ||
9264         i == GADGET_ID_CUSTOM_COPY ||
9265         i == GADGET_ID_CUSTOM_PASTE)
9266     {
9267       if (map)
9268         MapGadget(level_editor_gadget[i]);
9269       else
9270         UnmapGadget(level_editor_gadget[i]);
9271     }
9272   }
9273 }
9274
9275 static void MapLevelEditorToolboxCustomGadgets(void)
9276 {
9277   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9278 }
9279
9280 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9281 {
9282   if (IS_CUSTOM_ELEMENT(properties_element) ||
9283       IS_GROUP_ELEMENT(properties_element) ||
9284       IS_EMPTY_ELEMENT(properties_element))
9285     MapLevelEditorToolboxCustomGadgets();
9286 }
9287
9288 static void UnmapLevelEditorToolboxCustomGadgets(void)
9289 {
9290   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9291 }
9292
9293 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9294 {
9295   int i;
9296
9297   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9298   {
9299     if (i != GADGET_ID_SINGLE_ITEMS &&
9300         i != GADGET_ID_PICK_ELEMENT)
9301     {
9302       struct GadgetInfo *gi = level_editor_gadget[i];
9303
9304       if (map)
9305       {
9306         MapGadget(gi);
9307       }
9308       else
9309       {
9310         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9311         struct GraphicInfo *gd = &graphic_info[graphic];
9312
9313         UnmapGadget(gi);
9314
9315         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9316                    gi->width, gi->height, gi->x, gi->y);
9317
9318         redraw_mask |= REDRAW_DOOR_3;
9319       }
9320     }
9321   }
9322 }
9323
9324 static void MapLevelEditorToolboxDrawingGadgets(void)
9325 {
9326   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9327 }
9328
9329 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9330 {
9331   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9332 }
9333
9334 static void UnmapDrawingArea(int id)
9335 {
9336   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9337 }
9338
9339 static void UnmapLevelEditorFieldGadgets(void)
9340 {
9341   int i;
9342
9343   for (i = 0; i < num_editor_gadgets; i++)
9344     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9345                           level_editor_gadget[i]->y))
9346       UnmapGadget(level_editor_gadget[i]);
9347 }
9348
9349 void UnmapLevelEditorGadgets(void)
9350 {
9351   int i;
9352
9353   for (i = 0; i < num_editor_gadgets; i++)
9354     UnmapGadget(level_editor_gadget[i]);
9355 }
9356
9357 static void ResetUndoBuffer(void)
9358 {
9359   undo_buffer_position = -1;
9360   undo_buffer_steps = -1;
9361   redo_buffer_steps = 0;
9362
9363   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9364
9365   level.changed = FALSE;
9366 }
9367
9368 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9369 {
9370   if (remap_toolbox_gadgets)
9371   {
9372     ModifyEditorElementList();
9373     RedrawDrawingElements();
9374   }
9375
9376   if (edit_mode == ED_MODE_LEVELCONFIG)
9377     DrawLevelConfigWindow();
9378   else if (edit_mode == ED_MODE_PROPERTIES)
9379     DrawPropertiesWindow();
9380   else if (edit_mode == ED_MODE_PALETTE)
9381     DrawPaletteWindow();
9382   else  // edit_mode == ED_MODE_DRAWING
9383     DrawDrawingWindowExt(remap_toolbox_gadgets);
9384 }
9385
9386 static void DrawEditModeWindow(void)
9387 {
9388   DrawEditModeWindowExt(TRUE);
9389 }
9390
9391 static void DrawEditModeWindow_PlayfieldOnly(void)
9392 {
9393   DrawEditModeWindowExt(FALSE);
9394 }
9395
9396 static void ChangeEditModeWindow(int new_edit_mode)
9397 {
9398   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9399
9400   DrawEditModeWindow();
9401 }
9402
9403 static boolean LevelChanged(void)
9404 {
9405   boolean field_changed = FALSE;
9406   int x, y;
9407
9408   for (y = 0; y < lev_fieldy; y++) 
9409     for (x = 0; x < lev_fieldx; x++)
9410       if (Tile[x][y] != level.field[x][y])
9411         field_changed = TRUE;
9412
9413   return (level.changed || field_changed);
9414 }
9415
9416 static boolean PrepareSavingIntoPersonalLevelSet(void)
9417 {
9418   static LevelDirTree *last_copied_leveldir = NULL;
9419   static LevelDirTree *last_written_leveldir = NULL;
9420   static int last_copied_level_nr = -1;
9421   static int last_written_level_nr = -1;
9422   LevelDirTree *leveldir_former = leveldir_current;
9423   int level_nr_former = level_nr;
9424   int new_level_nr;
9425
9426   // remember last mod/save so that for current session, we write
9427   // back to the same personal copy, asking only about overwrite.
9428   if (leveldir_current == last_copied_leveldir &&
9429       level_nr == last_copied_level_nr)
9430   {
9431     // "cd" to personal level set dir (as used when writing last copy)
9432     leveldir_current = last_written_leveldir;
9433     level_nr = last_written_level_nr;
9434
9435     return TRUE;
9436   }
9437
9438   if (!Request("This level is read-only! "
9439                "Save into personal level set?", REQ_ASK))
9440     return FALSE;
9441
9442   // "cd" to personal level set dir (for writing copy the first time)
9443   leveldir_current =
9444     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9445
9446   // this may happen if "setup.internal.create_user_levelset" is FALSE
9447   // or if file "levelinfo.conf" is missing in personal user level set
9448   if (leveldir_current == NULL)
9449   {
9450     Request("Cannot find personal level set?!", REQ_CONFIRM);
9451
9452     leveldir_current = leveldir_former;
9453
9454     return FALSE;
9455   }
9456
9457   // find unused level number
9458   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9459   {
9460     static char *level_filename = NULL;
9461
9462     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9463
9464     if (!fileExists(level_filename))
9465       break;
9466   }
9467
9468   last_copied_leveldir = leveldir_former;
9469   last_copied_level_nr = level_nr_former;
9470
9471   last_written_leveldir = leveldir_current;
9472   last_written_level_nr = level_nr = new_level_nr;
9473
9474   return TRUE;
9475 }
9476
9477 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9478 {
9479   static char *filename_levelinfo = NULL, *mod_name = NULL;
9480   FILE *file;
9481
9482   // annotate this copy-and-mod in personal levelinfo.conf
9483   setString(&filename_levelinfo,
9484             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9485
9486   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9487   {
9488     fprintf(file, "\n");
9489     fprintf(file, "# level %d was modified from:\n", level_nr);
9490     fprintf(file, "# - previous level set name:    %s\n",
9491             former_name);
9492     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9493             level.file_info.nr, level.name);
9494     fprintf(file, "# - previous author:            %s\n",
9495             level.author);
9496     fprintf(file, "# - previous save date:         ");
9497
9498     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9499     {
9500       fprintf(file, "%04d-%02d-%02d\n",
9501               level.creation_date.year,
9502               level.creation_date.month,
9503               level.creation_date.day);
9504     }
9505     else
9506     {
9507       fprintf(file, "not recorded\n");
9508     }
9509
9510     fclose(file);
9511   }
9512
9513   if (level_nr > leveldir_current->last_level)
9514     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9515
9516   // else: allow the save even if annotation failed
9517
9518   // now... spray graffiti on the old level vital statistics
9519   // user can change these; just trying to set a good baseline
9520
9521   // don't truncate names for fear of making offensive or silly:
9522   // long-named original author only recorded in levelinfo.conf.
9523   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9524   if (!strEqual(level.author, leveldir_current->author))
9525   {
9526     setString(&mod_name, getStringCat3(leveldir_current->author,
9527                                        " after ", level.author));
9528
9529     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9530       setString(&mod_name,
9531                 getStringCat2(leveldir_current->author, " (ed.)"));
9532
9533     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9534       setString(&mod_name, leveldir_current->author);
9535
9536     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9537
9538     // less worried about truncation here
9539     setString(&mod_name, getStringCat2("Mod: ", level.name));
9540     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9541   }
9542 }
9543
9544 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9545                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9546 {
9547   int x, y;
9548
9549   for (x = 0; x < lev_fieldx; x++)
9550     for (y = 0; y < lev_fieldy; y++) 
9551       dst[x][y] = src[x][y];
9552 }
9553
9554 static int setSelectboxValue(int selectbox_id, int new_value)
9555 {
9556   int new_index_value = 0;
9557   int i;
9558
9559   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9560     if (selectbox_info[selectbox_id].options[i].value == new_value)
9561       new_index_value = i;
9562
9563   *selectbox_info[selectbox_id].value =
9564     selectbox_info[selectbox_id].options[new_index_value].value;
9565
9566   return new_index_value;
9567 }
9568
9569 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9570 {
9571   int i;
9572
9573   // change action mode and arg variables according to action type variable
9574   for (i = 0; action_arg_options[i].value != -1; i++)
9575   {
9576     if (action_arg_options[i].value == custom_element_change.action_type)
9577     {
9578       int mode = action_arg_options[i].mode;
9579
9580       // only change if corresponding selectbox has changed
9581       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9582           action_arg_modes[mode])
9583         custom_element_change.action_mode = -1;
9584
9585       // only change if corresponding selectbox has changed
9586       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9587           action_arg_options[i].options)
9588         custom_element_change.action_arg = -1;
9589
9590       break;
9591     }
9592   }
9593 }
9594
9595 static void setSelectboxSpecialActionOptions(void)
9596 {
9597   int i;
9598
9599   // change action mode and arg selectbox according to action type selectbox
9600   for (i = 0; action_arg_options[i].value != -1; i++)
9601   {
9602     if (action_arg_options[i].value == custom_element_change.action_type)
9603     {
9604       int mode = action_arg_options[i].mode;
9605
9606       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9607                                    action_arg_modes[mode]);
9608       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9609                                  custom_element_change.action_mode);
9610
9611       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9612                                    action_arg_options[i].options);
9613       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9614                                  custom_element_change.action_arg);
9615       break;
9616     }
9617   }
9618 }
9619
9620 static void copy_custom_element_settings(int element_from, int element_to)
9621 {
9622   struct ElementInfo *ei_from = &element_info[element_from];
9623   struct ElementInfo *ei_to = &element_info[element_to];
9624
9625   copyElementInfo(ei_from, ei_to);
9626 }
9627
9628 static void replace_custom_element_in_settings(int element_from,
9629                                                int element_to)
9630 {
9631   int i, j, x, y;
9632
9633   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9634   {
9635     struct ElementInfo *ei = &element_info[i];
9636
9637     for (y = 0; y < 3; y++)
9638       for (x = 0; x < 3; x++)
9639         if (ei->content.e[x][y] == element_from)
9640           ei->content.e[x][y] = element_to;
9641
9642     for (j = 0; j < ei->num_change_pages; j++)
9643     {
9644       struct ElementChangeInfo *change = &ei->change_page[j];
9645
9646       if (change->target_element == element_from)
9647         change->target_element = element_to;
9648
9649       if (change->initial_trigger_element == element_from)
9650         change->initial_trigger_element = element_to;
9651
9652       if (change->action_element == element_from)
9653         change->action_element = element_to;
9654
9655       for (y = 0; y < 3; y++)
9656         for (x = 0; x < 3; x++)
9657           if (change->target_content.e[x][y] == element_from)
9658             change->target_content.e[x][y] = element_to;
9659     }
9660
9661     if (ei->group != NULL)                              // group or internal
9662       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9663         if (ei->group->element[j] == element_from)
9664           ei->group->element[j] = element_to;
9665   }
9666 }
9667
9668 static void replace_custom_element_in_playfield(int element_from,
9669                                                 int element_to)
9670 {
9671   int x, y;
9672
9673   for (x = 0; x < lev_fieldx; x++)
9674     for (y = 0; y < lev_fieldy; y++)
9675       if (Tile[x][y] == element_from)
9676         Tile[x][y] = element_to;
9677 }
9678
9679 static boolean CopyCustomElement(int element_old, int element_new,
9680                                  int copy_mode)
9681 {
9682   int copy_mode_orig = copy_mode;
9683
9684   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9685   {
9686     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9687                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9688     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9689   }
9690   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9691   {
9692     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9693                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9694     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9695
9696     level.changed = TRUE;
9697   }
9698   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9699   {
9700     Request("Please choose custom element!", REQ_CONFIRM);
9701
9702     return FALSE;
9703   }
9704   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9705   {
9706     Request("Please choose group element!", REQ_CONFIRM);
9707
9708     return FALSE;
9709   }
9710   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9711   {
9712     Request("Please choose empty element!", REQ_CONFIRM);
9713
9714     return FALSE;
9715   }
9716   else
9717   {
9718     level.changed = TRUE;
9719   }
9720
9721   // when modifying custom/group element, ask for copying level template
9722   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9723   {
9724     if (!AskToCopyAndModifyLevelTemplate())
9725       return FALSE;
9726   }
9727
9728   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9729   {
9730     copy_custom_element_settings(element_new, element_old);
9731   }
9732   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9733   {
9734     copy_custom_element_settings(element_old, element_new);
9735   }
9736   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9737   {
9738     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9739     copy_custom_element_settings(element_new, element_old);
9740     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9741
9742     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9743     replace_custom_element_in_settings(element_new, element_old);
9744     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9745
9746     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9747     replace_custom_element_in_playfield(element_new, element_old);
9748     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9749   }
9750
9751   UpdateCustomElementGraphicGadgets();
9752   DrawPropertiesWindow();
9753
9754   return TRUE;
9755 }
9756
9757 static void CopyCustomElementPropertiesToEditor(int element)
9758 {
9759   int i;
9760   int current_change_page = element_info[element].current_change_page;
9761
9762   // dynamically (re)build selectbox for selecting change page
9763   for (i = 0; i < element_info[element].num_change_pages; i++)
9764   {
9765     sprintf(options_change_page_strings[i], "%d", i + 1);
9766
9767     options_change_page[i].value = i;
9768     options_change_page[i].text = options_change_page_strings[i];
9769   }
9770
9771   options_change_page[i].value = -1;
9772   options_change_page[i].text = NULL;
9773
9774   // needed here to initialize combined element properties
9775   InitElementPropertiesEngine(level.game_version);
9776
9777   element_info[element].change =
9778     &element_info[element].change_page[current_change_page];
9779
9780   custom_element = element_info[element];
9781   custom_element_change = *element_info[element].change;
9782
9783   // needed to initially set selectbox options for special action options
9784   setSelectboxSpecialActionOptions();
9785
9786   // needed to initially set selectbox value variables to reliable defaults
9787   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9788     setSelectboxValue(i, *selectbox_info[i].value);
9789
9790   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9791     custom_element_properties[i] = HAS_PROPERTY(element, i);
9792
9793   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9794     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9795
9796   // ---------- element settings: configure (custom elements) -----------------
9797
9798   // set accessible layer selectbox help value
9799   custom_element.access_type =
9800     (IS_WALKABLE(element) ? EP_WALKABLE :
9801      IS_PASSABLE(element) ? EP_PASSABLE :
9802      custom_element.access_type);
9803   custom_element.access_layer =
9804     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9805      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9806      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9807      custom_element.access_layer);
9808   custom_element.access_protected =
9809     (IS_PROTECTED(element) ? 1 : 0);
9810   custom_element_properties[EP_ACCESSIBLE] =
9811     (IS_ACCESSIBLE_OVER(element) ||
9812      IS_ACCESSIBLE_INSIDE(element) ||
9813      IS_ACCESSIBLE_UNDER(element));
9814
9815   // set walk-to-object action selectbox help value
9816   custom_element.walk_to_action =
9817     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9818      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9819      IS_DROPPABLE(element) ? EP_DROPPABLE :
9820      IS_THROWABLE(element) ? EP_THROWABLE :
9821      IS_PUSHABLE(element) ? EP_PUSHABLE :
9822      custom_element.walk_to_action);
9823   custom_element_properties[EP_WALK_TO_OBJECT] =
9824     (IS_DIGGABLE(element) ||
9825      IS_COLLECTIBLE_ONLY(element) ||
9826      IS_DROPPABLE(element) ||
9827      IS_THROWABLE(element) ||
9828      IS_PUSHABLE(element));
9829
9830   // set smash targets selectbox help value
9831   custom_element.smash_targets =
9832     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9833      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9834      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9835      custom_element.smash_targets);
9836   custom_element_properties[EP_CAN_SMASH] =
9837     (CAN_SMASH_EVERYTHING(element) ||
9838      CAN_SMASH_ENEMIES(element) ||
9839      CAN_SMASH_PLAYER(element));
9840
9841   // set deadliness selectbox help value
9842   custom_element.deadliness =
9843     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9844      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9845      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9846      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9847      custom_element.deadliness);
9848   custom_element_properties[EP_DEADLY] =
9849     (DONT_TOUCH(element) ||
9850      DONT_GET_HIT_BY(element) ||
9851      DONT_COLLIDE_WITH(element) ||
9852      DONT_RUN_INTO(element));
9853
9854   // ---------- element settings: advanced (custom elements) ------------------
9855
9856   // set "change by direct action" selectbox help value
9857   custom_element_change.direct_action =
9858     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9859      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9860      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9861      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9862      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9863      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9864      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9865      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9866      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9867      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9868      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9869      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9870      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9871      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9872      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9873      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9874      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9875      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9876      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9877      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9878      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9879      custom_element_change.direct_action);
9880
9881   // set "change by other element action" selectbox help value
9882   custom_element_change.other_action =
9883     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9884      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9885      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9886      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9887      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9888      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9889      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9890      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9891      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9892      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9893      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9894      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9895      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9896      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9897      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9898      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9899      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9900      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9901      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9902      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9903      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9904      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9905      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9906      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9907      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9908      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9909      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9910      custom_element_change.other_action);
9911 }
9912
9913 static void CopyGroupElementPropertiesToEditor(int element)
9914 {
9915   group_element_info = *element_info[element].group;
9916   custom_element = element_info[element];       // needed for description
9917 }
9918
9919 static void CopyEmptyElementPropertiesToEditor(int element)
9920 {
9921   custom_element = element_info[element];
9922 }
9923
9924 static void CopyClassicElementPropertiesToEditor(int element)
9925 {
9926   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9927     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9928       getMoveIntoAcidProperty(&level, element);
9929
9930   if (MAYBE_DONT_COLLIDE_WITH(element))
9931     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9932       getDontCollideWithProperty(&level, element);
9933 }
9934
9935 static void CopyElementPropertiesToEditor(int element)
9936 {
9937   if (IS_CUSTOM_ELEMENT(element))
9938     CopyCustomElementPropertiesToEditor(element);
9939   else if (IS_GROUP_ELEMENT(element))
9940     CopyGroupElementPropertiesToEditor(element);
9941   else if (IS_EMPTY_ELEMENT(element))
9942     CopyEmptyElementPropertiesToEditor(element);
9943   else
9944     CopyClassicElementPropertiesToEditor(element);
9945 }
9946
9947 static boolean AskToCopyAndModifyLevelTemplate(void)
9948 {
9949   if (Request("Copy and modify settings from level template?", REQ_ASK))
9950   {
9951     level.use_custom_template = FALSE;
9952
9953     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9954                  GDI_CHECKED, FALSE, GDI_END);
9955     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9956                  GDI_CHECKED, FALSE, GDI_END);
9957
9958     return TRUE;
9959   }
9960   else
9961   {
9962     LoadLevelTemplate(-1);      // this resets all element modifications ...
9963
9964     DrawEditModeWindow();       // ... and copies them to 'custom_element'
9965
9966     return FALSE;
9967   }
9968 }
9969
9970 static void CopyCustomElementPropertiesToGame(int element)
9971 {
9972   int i;
9973   int access_type_and_layer;
9974
9975   // mark that this custom element has been modified
9976   custom_element.modified_settings = TRUE;
9977   level.changed = TRUE;
9978
9979   if (level.use_custom_template)
9980     AskToCopyAndModifyLevelTemplate();
9981
9982   element_info[element] = custom_element;
9983   *element_info[element].change = custom_element_change;
9984
9985   // ---------- element settings: configure (custom elements) -----------------
9986
9987   // set accessible property from checkbox and selectbox
9988   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
9989   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
9990   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
9991   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
9992   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
9993   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
9994   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
9995                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
9996                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
9997   custom_element_properties[access_type_and_layer] =
9998     custom_element_properties[EP_ACCESSIBLE];
9999   custom_element_properties[EP_PROTECTED] =
10000     (custom_element.access_protected != 0 &&
10001      custom_element_properties[EP_ACCESSIBLE]);
10002
10003   // set walk-to-object property from checkbox and selectbox
10004   custom_element_properties[EP_DIGGABLE] = FALSE;
10005   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
10006   custom_element_properties[EP_DROPPABLE] = FALSE;
10007   custom_element_properties[EP_THROWABLE] = FALSE;
10008   custom_element_properties[EP_PUSHABLE] = FALSE;
10009   custom_element_properties[custom_element.walk_to_action] =
10010     custom_element_properties[EP_WALK_TO_OBJECT];
10011
10012   // set smash property from checkbox and selectbox
10013   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
10014   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
10015   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
10016   custom_element_properties[custom_element.smash_targets] =
10017     custom_element_properties[EP_CAN_SMASH];
10018
10019   // set deadliness property from checkbox and selectbox
10020   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
10021   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
10022   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
10023   custom_element_properties[EP_DONT_TOUCH] = FALSE;
10024   custom_element_properties[custom_element.deadliness] =
10025     custom_element_properties[EP_DEADLY];
10026
10027   // ---------- element settings: advanced (custom elements) ------------------
10028
10029   // set player change event from checkbox and selectbox
10030   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
10031   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
10032   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
10033   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
10034   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
10035   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
10036   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
10037   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
10038   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
10039   custom_element_change_events[CE_SWITCHED] = FALSE;
10040   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
10041   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
10042   custom_element_change_events[CE_BLOCKED] = FALSE;
10043   custom_element_change_events[CE_IMPACT] = FALSE;
10044   custom_element_change_events[CE_SMASHED] = FALSE;
10045   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
10046   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
10047   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
10048   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
10049   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
10050   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
10051   custom_element_change_events[custom_element_change.direct_action] =
10052     custom_element_change_events[CE_BY_DIRECT_ACTION];
10053
10054   // set other element action change event from checkbox and selectbox
10055   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
10056   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
10057   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
10058   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
10059   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
10060   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
10061   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
10062   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
10063   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
10064   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
10065   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
10066   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
10067   custom_element_change_events[CE_TOUCHING_X] = FALSE;
10068   custom_element_change_events[CE_HITTING_X] = FALSE;
10069   custom_element_change_events[CE_DIGGING_X] = FALSE;
10070   custom_element_change_events[CE_HIT_BY_X] = FALSE;
10071   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
10072   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
10073   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
10074   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
10075   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
10076   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
10077   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
10078   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
10079   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
10080   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
10081   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
10082   custom_element_change_events[custom_element_change.other_action] =
10083     custom_element_change_events[CE_BY_OTHER_ACTION];
10084
10085   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
10086     SET_PROPERTY(element, i, custom_element_properties[i]);
10087
10088   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
10089     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
10090
10091   // copy change events also to special level editor variable
10092   custom_element = element_info[element];
10093   custom_element_change = *element_info[element].change;
10094
10095   // needed here to restore runtime value "element_info[element].gfx_element"
10096   InitElementPropertiesGfxElement();
10097 }
10098
10099 static void CopyGroupElementPropertiesToGame(int element)
10100 {
10101   // mark that this group element has been modified
10102   custom_element.modified_settings = TRUE;
10103   level.changed = TRUE;
10104
10105   if (level.use_custom_template)
10106     AskToCopyAndModifyLevelTemplate();
10107
10108   element_info[element] = custom_element;
10109   *element_info[element].group = group_element_info;
10110
10111   // needed here to restore runtime value "element_info[element].gfx_element"
10112   InitElementPropertiesGfxElement();
10113 }
10114
10115 static void CopyEmptyElementPropertiesToGame(int element)
10116 {
10117   // mark that this empty element has been modified
10118   custom_element.modified_settings = TRUE;
10119   level.changed = TRUE;
10120
10121   if (level.use_custom_template)
10122     AskToCopyAndModifyLevelTemplate();
10123
10124   element_info[element] = custom_element;
10125
10126   // needed here to restore runtime value "element_info[element].gfx_element"
10127   InitElementPropertiesGfxElement();
10128 }
10129
10130 static void CopyClassicElementPropertiesToGame(int element)
10131 {
10132   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
10133     setMoveIntoAcidProperty(&level, element,
10134                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
10135
10136   if (MAYBE_DONT_COLLIDE_WITH(element))
10137     setDontCollideWithProperty(&level, element,
10138                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
10139 }
10140
10141 static void CopyElementPropertiesToGame(int element)
10142 {
10143   if (IS_CUSTOM_ELEMENT(element))
10144     CopyCustomElementPropertiesToGame(element);
10145   else if (IS_GROUP_ELEMENT(element))
10146     CopyGroupElementPropertiesToGame(element);
10147   else if (IS_EMPTY_ELEMENT(element))
10148     CopyEmptyElementPropertiesToGame(element);
10149   else
10150     CopyClassicElementPropertiesToGame(element);
10151 }
10152
10153 #if DEBUG
10154 static void CheckElementDescriptions(void)
10155 {
10156   int i;
10157
10158   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10159     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
10160       Warn("no element description file for element '%s'", EL_NAME(i));
10161 }
10162 #endif
10163
10164 static int getMaxEdFieldX(boolean has_scrollbar)
10165 {
10166   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
10167   int sxsize = SXSIZE - scrollbar_width;
10168   int max_ed_fieldx = sxsize / ed_tilesize;
10169
10170   return max_ed_fieldx;
10171 }
10172
10173 static int getMaxEdFieldY(boolean has_scrollbar)
10174 {
10175   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
10176                          INFOTEXT_YSIZE_FULL : 0);
10177   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
10178   int sysize = SYSIZE - scrollbar_height - infotext_height;
10179   int max_ed_fieldy = sysize / ed_tilesize;
10180
10181   return max_ed_fieldy;
10182 }
10183
10184 static void InitZoomLevelSettings(int zoom_tilesize)
10185 {
10186   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
10187
10188   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
10189   {
10190     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10191     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10192
10193     // make sure that tile size is always a power of 2
10194     ed_tilesize = (1 << log_2(ed_tilesize));
10195
10196     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10197     {
10198       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10199       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10200     }
10201   }
10202
10203   last_game_engine_type = level.game_engine_type;
10204
10205   // limit zoom tilesize by upper and lower bound
10206   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10207
10208   // store zoom tilesize in auto setup file only if it was manually changed
10209   if (zoom_tilesize != -1)
10210     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10211
10212   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10213   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10214 }
10215
10216 static void InitDrawingElements(void)
10217 {
10218   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10219
10220   if (level.game_engine_type == game_engine_type_last)
10221     return;
10222
10223   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10224   {
10225     new_element1 = EL_BD_WALL;
10226     new_element2 = EL_EMPTY;
10227     new_element3 = EL_BD_SAND;
10228   }
10229   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10230   {
10231     new_element1 = EL_SP_CHIP_SINGLE;
10232     new_element2 = EL_EMPTY;
10233     new_element3 = EL_SP_BASE;
10234   }
10235   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10236   {
10237     new_element1 = EL_MM_MIRROR_START;
10238     new_element2 = EL_EMPTY;
10239     new_element3 = EL_MM_WOODEN_WALL;
10240   }
10241   else
10242   {
10243     new_element1 = EL_WALL;
10244     new_element2 = EL_EMPTY;
10245     new_element3 = EL_SAND;
10246   }
10247
10248   game_engine_type_last = level.game_engine_type;
10249 }
10250
10251 static void InitLevelSetInfo(void)
10252 {
10253   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10254            "%s", leveldir_current->name);
10255   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10256            "%s", leveldir_current->author);
10257
10258   levelset_num_levels = leveldir_current->levels;
10259
10260   levelset_use_levelset_artwork = FALSE;
10261   levelset_copy_level_template = FALSE;
10262
10263   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10264 }
10265
10266 static void ChangeEditorToLevelSet(char *levelset_subdir)
10267 {
10268   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10269
10270   // the previous level set might have used custom artwork
10271   ReloadCustomArtwork(0);
10272
10273   LoadLevelSetup_SeriesInfo();
10274
10275   SaveLevelSetup_LastSeries();
10276   SaveLevelSetup_SeriesInfo();
10277
10278   TapeErase();
10279
10280   LoadLevel(level_nr);
10281   LoadScore(level_nr);
10282
10283   DrawLevelEd();
10284 }
10285
10286 static boolean useEditorDoorAnimation(void)
10287 {
10288   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10289   boolean door_1_viewport_unchanged =
10290     (vp_door_1->x      == DX     &&
10291      vp_door_1->y      == DY     &&
10292      vp_door_1->width  == DXSIZE &&
10293      vp_door_1->height == DYSIZE);
10294   boolean door_1_contains_toolbox =
10295     (EX >= DX &&
10296      EY >= DY &&
10297      EX + EXSIZE <= DX + DXSIZE &&
10298      EY + EYSIZE <= DY + DYSIZE);
10299
10300   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10301 }
10302
10303 static void DrawEditorDoorBackground(int graphic, int x, int y,
10304                                      int width, int height)
10305 {
10306   struct GraphicInfo *g = &graphic_info[graphic];
10307
10308   if (g->bitmap != NULL)
10309     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10310                MIN(width, g->width), MIN(height, g->height), x, y);
10311   else
10312     ClearRectangle(drawto, x, y, width, height);
10313 }
10314
10315 static void DrawEditorDoorContent(void)
10316 {
10317   // needed for gadgets drawn on background (like palette scrollbar)
10318   SetDoorBackgroundImage(IMG_UNDEFINED);
10319
10320   // copy default editor door content to main double buffer
10321   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10322
10323   // draw bigger door
10324   DrawSpecialEditorDoor();
10325
10326   // draw new control window
10327   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10328
10329   // draw all toolbox gadgets to editor doors
10330   MapControlButtons();
10331
10332   // when returning from test game to properties page, redraw toolbox gadgets
10333   if (edit_mode == ED_MODE_PROPERTIES)
10334   {
10335     UnmapLevelEditorToolboxDrawingGadgets();
10336     UnmapLevelEditorToolboxCustomGadgets();
10337
10338     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10339   }
10340
10341   // draw all palette gadgets to editor doors
10342   ModifyEditorElementList();
10343   RedrawDrawingElements();
10344
10345   // copy actual editor door content to door double buffer for OpenDoor()
10346   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10347 }
10348
10349 void DrawLevelEd(void)
10350 {
10351   int fade_mask = REDRAW_FIELD;
10352
10353   FadeSoundsAndMusic();
10354
10355   if (CheckFadeAll())
10356     fade_mask = REDRAW_ALL;
10357
10358   FadeOut(fade_mask);
10359
10360   // needed if different viewport properties defined for editor
10361   ChangeViewportPropertiesIfNeeded();
10362
10363   ClearField();
10364
10365   InitZoomLevelSettings(-1);
10366   InitDrawingElements();
10367   InitLevelSetInfo();
10368
10369 #if DEBUG
10370   CheckElementDescriptions();
10371 #endif
10372
10373   if (level_editor_test_game)
10374   {
10375     CopyPlayfield(level.field, Tile);
10376     CopyPlayfield(TileBackup, level.field);
10377
10378     level_editor_test_game = FALSE;
10379   }
10380   else
10381   {
10382     edit_mode = ED_MODE_DRAWING;
10383     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10384     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10385
10386     ResetUndoBuffer();
10387
10388     level_xpos = -1;
10389     level_ypos = -1;
10390   }
10391
10392   // redraw_mask |= REDRAW_ALL;
10393
10394   FreeLevelEditorGadgets();
10395   CreateLevelEditorGadgets();
10396
10397   ReinitializeElementList();            // update dynamic level element list
10398   ReinitializeElementListButtons();     // custom element may look different
10399
10400   InitElementPropertiesGfxElement();
10401
10402   UnmapAllGadgets();
10403
10404   DrawEditModeWindow_PlayfieldOnly();
10405
10406   DrawMaskedBorder(fade_mask);
10407
10408   // use door animation if door 1 viewport is unchanged and contains toolbox
10409   if (useEditorDoorAnimation())
10410   {
10411     FadeIn(fade_mask);
10412
10413     DrawEditorDoorContent();
10414
10415     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10416   }
10417   else
10418   {
10419     DrawEditorDoorContent();
10420
10421     FadeIn(fade_mask);
10422   }
10423
10424   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10425 }
10426
10427 static void AdjustDrawingAreaGadgets(void)
10428 {
10429   int ed_xsize = lev_fieldx + 2;
10430   int ed_ysize = lev_fieldy + 2;
10431   int max_ed_fieldx = MAX_ED_FIELDX;
10432   int max_ed_fieldy = MAX_ED_FIELDY;
10433   boolean horizontal_scrollbar_needed;
10434   boolean vertical_scrollbar_needed;
10435   int x, y, width, height;
10436
10437   if (suppressBorderElement())
10438   {
10439     ed_xsize = lev_fieldx;
10440     ed_ysize = lev_fieldy;
10441   }
10442
10443   // check if we need any scrollbars
10444   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10445   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10446
10447   // check if we have a smaller editor field because of scrollbars
10448   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10449   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10450
10451   // check again if we now need more scrollbars because of less space
10452   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10453   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10454
10455   // check if editor field gets even smaller after adding new scrollbars
10456   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10457   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10458
10459   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10460   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10461
10462   x = SX + ed_fieldx * ed_tilesize;
10463   y = SY + ed_fieldy * ed_tilesize;
10464
10465   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10466   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10467
10468   // adjust drawing area gadget
10469   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10470                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10471                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10472                GDI_END);
10473
10474   // adjust horizontal scrollbar gadgets
10475   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10476                GDI_Y, y,
10477                GDI_END);
10478   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10479                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10480                GDI_Y, y,
10481                GDI_END);
10482   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10483                GDI_Y, y,
10484                GDI_WIDTH, width,
10485                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10486                GDI_END);
10487
10488   // adjust vertical scrollbar gadgets
10489   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10490                GDI_X, x,
10491                GDI_END);
10492   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10493                GDI_X, x,
10494                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10495                GDI_END);
10496   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10497                GDI_X, x,
10498                GDI_HEIGHT, height,
10499                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10500                GDI_END);
10501 }
10502
10503 static void AdjustLevelScrollPosition(void)
10504 {
10505   if (level_xpos < -1)
10506     level_xpos = -1;
10507   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10508     level_xpos = lev_fieldx - ed_fieldx + 1;
10509   if (lev_fieldx < ed_fieldx - 2)
10510     level_xpos = -1;
10511
10512   if (level_ypos < -1)
10513     level_ypos = -1;
10514   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10515     level_ypos = lev_fieldy - ed_fieldy + 1;
10516   if (lev_fieldy < ed_fieldy - 2)
10517     level_ypos = -1;
10518
10519   if (suppressBorderElement())
10520   {
10521     level_xpos = 0;
10522     level_ypos = 0;
10523   }
10524 }
10525
10526 static void AdjustEditorScrollbar(int id)
10527 {
10528   struct GadgetInfo *gi = level_editor_gadget[id];
10529   int items_max, items_visible, item_position;
10530
10531   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10532   {
10533     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10534     items_visible = ed_fieldx;
10535     item_position = level_xpos + 1;
10536   }
10537   else
10538   {
10539     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10540     items_visible = ed_fieldy;
10541     item_position = level_ypos + 1;
10542   }
10543
10544   if (item_position > items_max - items_visible)
10545     item_position = items_max - items_visible;
10546
10547   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10548                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10549 }
10550
10551 static void AdjustElementListScrollbar(void)
10552 {
10553   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10554   int items_max, items_visible, item_position;
10555
10556   // correct position of element list scrollbar
10557   if (element_shift < 0)
10558     element_shift = 0;
10559   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10560     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10561
10562   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10563   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10564   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10565
10566   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10567                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10568                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10569 }
10570
10571 static void ModifyEditorCounterValue(int counter_id, int new_value)
10572 {
10573   int *counter_value = counterbutton_info[counter_id].value;
10574   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10575   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10576
10577   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10578
10579   if (counter_value != NULL)
10580     *counter_value = gi->textinput.number_value;
10581 }
10582
10583 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10584 {
10585   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10586   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10587
10588   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10589
10590   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10591       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10592   {
10593     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10594     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10595
10596     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10597     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10598                  GDI_END);
10599   }
10600 }
10601
10602 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10603 {
10604   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10605   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10606   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10607
10608   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10609 }
10610
10611 static void ModifyEditorSelectboxOptions(int selectbox_id,
10612                                          struct ValueTextInfo *options)
10613 {
10614   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10615   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10616
10617   selectbox_info[selectbox_id].options = options;
10618
10619   // set index to zero -- list may be shorter now (correct later, if needed)
10620   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10621                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10622 }
10623
10624 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10625 {
10626   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10627   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10628
10629   drawingarea_info[drawingarea_id].area_xsize = xsize;
10630   drawingarea_info[drawingarea_id].area_ysize = ysize;
10631
10632   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10633 }
10634
10635 static void ModifyEditorElementList(void)
10636 {
10637   int i;
10638
10639   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10640     return;
10641
10642   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10643   {
10644     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10645     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10646     struct GadgetDesign *gd = &gi->deco.design;
10647     int element = editor_elements[element_shift + i];
10648     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10649
10650     UnmapGadget(gi);
10651
10652     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10653
10654     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10655
10656     MapGadget(gi);
10657   }
10658 }
10659
10660 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10661 {
10662   int graphic = el2edimg(element);
10663   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10664
10665   if (pos->x == -1 &&
10666       pos->y == -1)
10667     return;
10668
10669   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10670 }
10671
10672 static void ModifyDrawingElementButton(int element, int id)
10673 {
10674   struct GadgetInfo *gi = level_editor_gadget[id];
10675   Bitmap *deco_bitmap;
10676   int deco_x, deco_y;
10677   int tile_size = gi->deco.width;
10678
10679   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10680
10681   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10682 }
10683
10684 static void PickDrawingElement(int button, int element)
10685 {
10686   struct
10687   {
10688     int *new_element;
10689     struct XYTileSize *pos;
10690     int id;
10691   } de, drawing_elements[] =
10692   {
10693     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10694     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10695     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10696   };
10697
10698   if (button < 1 || button > 3)
10699     return;
10700
10701   if (IS_MM_WALL(element))
10702     element = map_mm_wall_element(element);
10703
10704   de = drawing_elements[button - 1];
10705
10706   *de.new_element = element;    // update global drawing element variable
10707
10708   DrawDrawingElementGraphic(element, de.pos);
10709   ModifyDrawingElementButton(element, de.id);
10710
10711   redraw_mask |= REDRAW_DOOR_1;
10712 }
10713
10714 static void RedrawDrawingElements(void)
10715 {
10716   PickDrawingElement(1, new_element1);
10717   PickDrawingElement(2, new_element2);
10718   PickDrawingElement(3, new_element3);
10719 }
10720
10721 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10722 {
10723   stick_element_properties_window = FALSE;
10724
10725   SetMainBackgroundImage(IMG_UNDEFINED);
10726   ClearField();
10727
10728   UnmapLevelEditorFieldGadgets();
10729
10730   AdjustDrawingAreaGadgets();
10731   AdjustLevelScrollPosition();
10732   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10733   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10734
10735   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10736
10737   MapMainDrawingArea();
10738
10739   if (remap_toolbox_gadgets)
10740   {
10741     UnmapLevelEditorToolboxCustomGadgets();
10742     MapLevelEditorToolboxDrawingGadgets();
10743   }
10744 }
10745
10746 static void DrawDrawingWindow(void)
10747 {
10748   DrawDrawingWindowExt(TRUE);
10749 }
10750
10751 static int getTabulatorBarWidth(void)
10752 {
10753   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10754   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10755
10756   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10757 }
10758
10759 static int getTabulatorBarHeight(void)
10760 {
10761   return ED_TAB_BAR_HEIGHT;
10762 }
10763
10764 static Pixel getTabulatorBarColor(void)
10765 {
10766   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10767   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10768   int gd_x = gd->x + gd_gi1->border.width / 2;
10769   int gd_y = gd->y + gd_gi1->height - 1;
10770
10771   return GetPixel(gd->bitmap, gd_x, gd_y);
10772 }
10773
10774 static void DrawLevelConfigTabulatorGadgets(void)
10775 {
10776   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10777   Pixel tab_color = getTabulatorBarColor();
10778   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10779   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10780   int i;
10781
10782   // draw additional "engine" tabulator when using native BD engine
10783   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10784     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10785
10786   for (i = id_first; i <= id_last; i++)
10787   {
10788     int gadget_id = textbutton_info[i].gadget_id;
10789     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10790     boolean active = (i != edit_mode_levelconfig);
10791
10792     // draw background line below tabulator button
10793     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10794
10795     // draw solid line below inactive tabulator buttons
10796     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10797       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10798                     ED_GADGET_TINY_DISTANCE, tab_color);
10799
10800     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10801     MapTextbuttonGadget(i);
10802   }
10803
10804   // draw little border line below tabulator buttons
10805   if (tab_color != BLACK_PIXEL)                 // black => transparent
10806     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10807                   ED_GADGET_TINY_DISTANCE,
10808                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10809 }
10810
10811 static void DrawPropertiesTabulatorGadgets(void)
10812 {
10813   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10814   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10815   int gd_x = gd->x + gd_gi1->border.width / 2;
10816   int gd_y = gd->y + gd_gi1->height - 1;
10817   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10818   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10819   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10820   int i;
10821
10822   // draw two config tabulators for player elements
10823   if (IS_PLAYER_ELEMENT(properties_element))
10824     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10825
10826   // draw two config and one "change" tabulator for custom elements
10827   if (IS_CUSTOM_ELEMENT(properties_element))
10828     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10829
10830   for (i = id_first; i <= id_last; i++)
10831   {
10832     int gadget_id = textbutton_info[i].gadget_id;
10833     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10834     boolean active = (i != edit_mode_properties);
10835
10836     // use "config 1" and "config 2" instead of "config" for players and CEs
10837     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10838         (IS_PLAYER_ELEMENT(properties_element) ||
10839          IS_CUSTOM_ELEMENT(properties_element)))
10840       continue;
10841
10842     // draw background line below tabulator button
10843     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10844
10845     // draw solid line below inactive tabulator buttons
10846     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10847       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10848                     ED_GADGET_TINY_DISTANCE, tab_color);
10849
10850     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10851     MapTextbuttonGadget(i);
10852   }
10853
10854   // draw little border line below tabulator buttons
10855   if (tab_color != BLACK_PIXEL)                 // black => transparent
10856     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10857                   ED_GADGET_TINY_DISTANCE,
10858                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10859 }
10860
10861 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10862 {
10863   DrawText(SX + xpos, SY + ypos, text, font_nr);
10864 }
10865
10866 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10867                                            int xpos, int ypos)
10868 {
10869   int font_width = getFontWidth(font_nr);
10870   int font_height = getFontHeight(font_nr);
10871   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10872   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10873
10874   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10875                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10876                       TRUE, FALSE, FALSE);
10877 }
10878
10879 static void DrawLevelConfigLevel(void)
10880 {
10881   int i;
10882
10883   // draw counter gadgets
10884   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10885     MapCounterButtons(i);
10886
10887   // draw checkbutton gadgets
10888   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10889     MapCheckbuttonGadget(i);
10890
10891   // draw selectbox gadgets
10892   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10893     MapSelectboxGadget(i);
10894
10895   // draw text input gadgets
10896   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10897     MapTextInputGadget(i);
10898 }
10899
10900 static char *getLevelSubdirFromSaveMode(int save_mode)
10901 {
10902   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10903     return getNewUserLevelSubdir();
10904
10905   return leveldir_current->subdir;
10906 }
10907
10908 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10909 {
10910   char *directory_text = "Level set directory:";
10911   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10912   int font1_nr = FONT_TEXT_1;
10913   int font2_nr = FONT_TEXT_2;
10914   int font1_height = getFontHeight(font1_nr);
10915   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10916   int x = ED_LEVEL_SETTINGS_X(0);
10917   int y = ED_LEVEL_SETTINGS_Y(6);
10918
10919   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10920   PrintInfoText(directory_name, font2_nr, x, y);
10921 }
10922
10923 static void DrawLevelConfigLevelSet(void)
10924 {
10925   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10926   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10927   int i;
10928
10929   // draw counter gadgets
10930   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10931     MapCounterButtons(i);
10932
10933   // draw checkbutton gadgets
10934   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10935   {
10936     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10937         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10938         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10939       continue;
10940
10941     MapCheckbuttonGadget(i);
10942   }
10943
10944   // draw selectbox gadgets
10945   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10946     MapSelectboxGadget(i);
10947
10948   // draw text input gadgets
10949   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10950     MapTextInputGadget(i);
10951
10952   // draw textbutton gadgets
10953   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10954
10955   // draw info text
10956   DrawLevelConfigLevelSet_DirectoryInfo();
10957 }
10958
10959 static void DrawLevelConfigEditor(void)
10960 {
10961   int i;
10962
10963   // draw counter gadgets
10964   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
10965     MapCounterButtons(i);
10966
10967   // draw checkbutton gadgets
10968   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
10969     MapCheckbuttonGadget(i);
10970
10971   // draw radiobutton gadgets
10972   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
10973     MapRadiobuttonGadget(i);
10974
10975   // draw drawing area
10976   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
10977
10978   // draw textbutton gadgets
10979   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
10980 }
10981
10982 static void DrawLevelConfigEngine(void)
10983 {
10984   int i;
10985
10986   // draw counter gadgets
10987   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
10988   {
10989     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
10990     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
10991   }
10992   else
10993   {
10994     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
10995     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
10996   }
10997
10998   // draw checkbutton gadgets
10999   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
11000     MapCheckbuttonGadget(i);
11001
11002   // draw selectbox gadgets
11003   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
11004     MapSelectboxGadget(i);
11005 }
11006
11007 static void DrawLevelConfigWindow(void)
11008 {
11009   char *text = "Global Settings";
11010   int font_nr = FONT_TITLE_1;
11011   struct MenuPosInfo *pos = &editor.settings.headline;
11012   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
11013   int sy = SY + pos->y;
11014
11015   stick_element_properties_window = FALSE;
11016
11017   SetAutomaticNumberOfGemsNeeded();
11018
11019   UnmapLevelEditorFieldGadgets();
11020
11021   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
11022   ClearField();
11023
11024   DrawText(sx, sy, text, font_nr);
11025
11026   DrawLevelConfigTabulatorGadgets();
11027
11028   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
11029     DrawLevelConfigLevel();
11030   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
11031     DrawLevelConfigLevelSet();
11032   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
11033     DrawLevelConfigEditor();
11034   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
11035     DrawLevelConfigEngine();
11036 }
11037
11038 static void DrawCustomContentArea(void)
11039 {
11040   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
11041   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11042   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
11043   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
11044   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
11045   int xoffset = ED_GADGET_SPACE_DISTANCE;
11046
11047   // add distance for potential left text (without drawing area border)
11048   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
11049
11050   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11051
11052   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
11053 }
11054
11055 static void DrawCustomChangeContentArea(void)
11056 {
11057   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
11058   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11059   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
11060   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
11061   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
11062   int xoffset = ED_GADGET_SPACE_DISTANCE;
11063
11064   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11065
11066   MapDrawingArea(id);
11067 }
11068
11069 static void RemoveElementContentArea(int id, int font_height)
11070 {
11071   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11072
11073   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
11074                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
11075                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11076                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
11077                  ED_GADGET_TEXT_DISTANCE + font_height);
11078 }
11079
11080 static void DrawYamYamContentAreas(void)
11081 {
11082   int font_nr = FONT_TEXT_1;
11083   int font_height = getFontHeight(font_nr);
11084   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11085   int yoffset = (tilesize - font_height) / 2;
11086   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
11087   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
11088   int i;
11089
11090   // display counter to choose number of element content areas
11091   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
11092
11093   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11094   {
11095     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
11096
11097     if (i < level.num_yamyam_contents)
11098     {
11099       MapDrawingArea(id);
11100     }
11101     else
11102     {
11103       UnmapDrawingArea(id);
11104
11105       // delete content areas in case of reducing number of them
11106       RemoveElementContentArea(id, font_height);
11107     }
11108   }
11109
11110   DrawText(x, y + 0 * tilesize, "content", font_nr);
11111   DrawText(x, y + 1 * tilesize, "when",    font_nr);
11112   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
11113 }
11114
11115 static void DrawMagicBallContentAreas(void)
11116 {
11117   int font_nr = FONT_TEXT_1;
11118   int font_height = getFontHeight(font_nr);
11119   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11120   int yoffset = (tilesize - font_height) / 2;
11121   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
11122   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
11123   int i;
11124
11125   // display counter to choose number of element content areas
11126   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
11127
11128   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11129   {
11130     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
11131
11132     if (i < level.num_ball_contents)
11133     {
11134       MapDrawingArea(id);
11135     }
11136     else
11137     {
11138       UnmapDrawingArea(id);
11139
11140       // delete content areas in case of reducing number of them
11141       RemoveElementContentArea(id, font_height);
11142     }
11143   }
11144
11145   DrawText(x, y + 0 * tilesize, "generated", font_nr);
11146   DrawText(x, y + 1 * tilesize, "when",      font_nr);
11147   DrawText(x, y + 2 * tilesize, "active",    font_nr);
11148 }
11149
11150 static void DrawAndroidElementArea(void)
11151 {
11152   int id = ED_DRAWING_ID_ANDROID_CONTENT;
11153   int num_elements = level.num_android_clone_elements;
11154   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11155   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11156   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11157   int xsize = MAX_ANDROID_ELEMENTS;
11158   int ysize = 1;
11159
11160   // display counter to choose number of element areas
11161   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
11162
11163   if (drawingarea_info[id].text_left != NULL)
11164     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11165
11166   UnmapDrawingArea(id);
11167
11168   ModifyEditorDrawingArea(id, num_elements, 1);
11169
11170   // delete content areas in case of reducing number of them
11171   DrawBackground(sx, sy,
11172                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11173                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11174
11175   MapDrawingArea(id);
11176 }
11177
11178 static void DrawGroupElementArea(void)
11179 {
11180   int id = ED_DRAWING_ID_GROUP_CONTENT;
11181   int num_elements = group_element_info.num_elements;
11182   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11183   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11184   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11185   int xsize = MAX_ELEMENTS_IN_GROUP;
11186   int ysize = 1;
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 DrawPlayerInitialInventoryArea(int element)
11204 {
11205   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11206   int player_nr = GET_PLAYER_NR(element);
11207   int num_elements = level.initial_inventory_size[player_nr];
11208   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11209   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11210   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11211   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11212   int ysize = 1;
11213
11214   // determine horizontal position to the right of specified gadget
11215   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11216     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11217           ED_DRAWINGAREA_TEXT_DISTANCE);
11218
11219   // determine horizontal offset for leading text
11220   if (drawingarea_info[id].text_left != NULL)
11221     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11222
11223   UnmapDrawingArea(id);
11224
11225   ModifyEditorDrawingArea(id, num_elements, 1);
11226
11227   // delete content areas in case of reducing number of them
11228   DrawBackground(sx, sy,
11229                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11230                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11231
11232   MapDrawingArea(id);
11233 }
11234
11235 static void DrawMMBallContentArea(void)
11236 {
11237   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11238   int num_elements = level.num_mm_ball_contents;
11239   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11240   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11241   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11242   int xsize = MAX_MM_BALL_CONTENTS;
11243   int ysize = 1;
11244
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 DrawEnvelopeTextArea(int envelope_nr)
11261 {
11262   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11263   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11264
11265   UnmapGadget(gi);
11266
11267   DrawBackground(gi->x, gi->y,
11268                  gi->textarea.crop_width, gi->textarea.crop_height);
11269
11270   if (envelope_nr != -1)
11271     textarea_info[id].value = level.envelope[envelope_nr].text;
11272
11273   ModifyGadget(gi, GDI_AREA_SIZE,
11274                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11275                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11276                GDI_END);
11277
11278   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11279 }
11280
11281 static void DrawPropertiesInfo(void)
11282 {
11283   static struct
11284   {
11285     int value;
11286     char *text;
11287   }
11288   properties[] =
11289   {
11290     // configurable properties
11291
11292     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11293     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11294     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11295     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11296     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11297     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11298     { EP_PROTECTED,             "- player is protected by it"           },
11299
11300     { EP_DIGGABLE,              "- can be digged away"                  },
11301     { EP_COLLECTIBLE,           "- can be collected"                    },
11302     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11303     { EP_THROWABLE,             "- can be thrown after collecting"      },
11304     { EP_PUSHABLE,              "- can be pushed"                       },
11305
11306     { EP_CAN_FALL,              "- can fall"                            },
11307     { EP_CAN_MOVE,              "- can move"                            },
11308
11309     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11310 #if 0
11311     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11312 #endif
11313     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11314
11315     { EP_SLIPPERY,              "- slippery for falling elements"       },
11316     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11317
11318     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11319     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11320     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11321     { EP_DONT_TOUCH,            "- deadly when touching"                },
11322
11323     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11324
11325     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11326     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11327     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11328
11329     { EP_CAN_CHANGE,            "- can change to other element"         },
11330
11331     // pre-defined properties
11332     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11333     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11334     { EP_SWITCHABLE,            "- can be switched"                     },
11335 #if 0
11336     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11337 #endif
11338
11339     { -1,                       NULL                                    }
11340   };
11341   char *filename = getElementDescriptionFilename(properties_element);
11342   char *num_elements_text = "In this level: ";
11343   char *num_similar_text = "Similar tiles: ";
11344   char *properties_text = "Standard properties: ";
11345   char *description_text = "Description:";
11346   char *no_description_text = "No description available.";
11347   char *none_text = "None";
11348   float percentage;
11349   int num_elements_in_level = 0;
11350   int num_similar_in_level = 0;
11351   int num_hires_tiles_in_level = 0;
11352   int num_standard_properties = 0;
11353   int font1_nr = FONT_TEXT_1;
11354   int font2_nr = FONT_TEXT_2;
11355   int font1_width = getFontWidth(font1_nr);
11356   int font1_height = getFontHeight(font1_nr);
11357   int font2_height = getFontHeight(font2_nr);
11358   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11359   int font2_yoffset = (font1_height - font2_height) / 2;
11360   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11361   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11362   int properties_text_len = strlen(properties_text) * font1_width;
11363   int xpos = ED_ELEMENT_SETTINGS_X(0);
11364   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11365   int i, x, y;
11366
11367   if (setup.editor.show_element_token)
11368   {
11369     int font3_nr = FONT_TEXT_3;
11370     int font3_height = getFontHeight(font3_nr);
11371
11372     DrawTextF(xpos, ypos, font3_nr,
11373               "[%s]", element_info[properties_element].token_name);
11374
11375     ypos += 2 * font3_height;
11376   }
11377
11378   // ----- print number of elements / percentage of this element in level
11379
11380   for (y = 0; y < lev_fieldy; y++)
11381   {
11382     for (x = 0; x < lev_fieldx; x++)
11383     {
11384       if (Tile[x][y] == properties_element)
11385       {
11386         num_elements_in_level++;
11387       }
11388       else if (IS_MM_WALL(Tile[x][y]) &&
11389                map_mm_wall_element(Tile[x][y]) == properties_element)
11390       {
11391         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11392       }
11393     }
11394   }
11395
11396   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11397
11398   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11399
11400   if (num_hires_tiles_in_level > 0)
11401     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11402               "%d wall tiles", num_hires_tiles_in_level);
11403   else if (num_elements_in_level > 0)
11404     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11405               "%d (%.2f %%)", num_elements_in_level, percentage);
11406   else
11407     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11408               none_text);
11409
11410   // ----- print number of similar elements / percentage of them in level
11411
11412   for (y = 0; y < lev_fieldy; y++)
11413   {
11414     for (x = 0; x < lev_fieldx; x++)
11415     {
11416       if (strEqual(element_info[Tile[x][y]].class_name,
11417                    element_info[properties_element].class_name))
11418       {
11419         num_similar_in_level++;
11420       }
11421     }
11422   }
11423
11424   if (num_similar_in_level != num_elements_in_level)
11425   {
11426     ypos += 1 * MAX(font1_height, font2_height);
11427
11428     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11429
11430     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11431
11432     if (num_similar_in_level > 0)
11433       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11434                 "%d (%.2f %%)", num_similar_in_level, percentage);
11435     else
11436       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11437                 none_text);
11438   }
11439
11440   ypos += 2 * MAX(font1_height, font2_height);
11441
11442   // ----- print standard properties of this element
11443
11444   DrawTextS(xpos, ypos, font1_nr, properties_text);
11445
11446   ypos += line1_height;
11447
11448   for (i = 0; properties[i].value != -1; i++)
11449   {
11450     if (!HAS_PROPERTY(properties_element, properties[i].value))
11451       continue;
11452
11453     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11454
11455     ypos += font2_height;
11456
11457     num_standard_properties++;
11458   }
11459
11460   if (num_standard_properties == 0)
11461   {
11462     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11463               font2_nr, none_text);
11464
11465     ypos -= (line1_height - font1_height);
11466   }
11467
11468   ypos += MAX(font1_height, font2_height);
11469
11470   // ----- print special description of this element
11471
11472   PrintInfoText(description_text, font1_nr, xpos, ypos);
11473
11474   ypos += line1_height;
11475
11476   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11477     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11478 }
11479
11480 #define TEXT_COLLECTING                 "Score for collecting"
11481 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11482 #define TEXT_SMASHING                   "Score for smashing"
11483 #define TEXT_SLURPING                   "Score for slurping robot"
11484 #define TEXT_CRACKING                   "Score for cracking"
11485 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11486 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11487 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11488 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11489 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11490 #define TEXT_DURATION                   "Duration when activated"
11491 #define TEXT_DELAY_ON                   "Delay before activating"
11492 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11493 #define TEXT_DELAY_CHANGING             "Delay before changing"
11494 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11495 #define TEXT_DELAY_MOVING               "Delay before moving"
11496 #define TEXT_BALL_DELAY                 "Element generation delay"
11497 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11498 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11499 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11500 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11501 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11502 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11503 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11504 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11505 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11506 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11507 #define TEXT_RANDOM_SEED                "slime random number seed"
11508 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11509 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11510 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11511 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11512 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11513 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11514 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11515 #define TEXT_AUTO_TURN_DELAY            "Creatures auto turn delay"
11516 #define TEXT_GRAVITY_DELAY              "Gravity switch change delay"
11517
11518 static struct
11519 {
11520   int element;
11521   int *value;
11522   char *text;
11523   int min_value;
11524   int max_value;
11525 } elements_with_counter[] =
11526 {
11527   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11528   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11529   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11530   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11531   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11532   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11533   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11534   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11535   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11536   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11537   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11538   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11539   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11540   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11541   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11542   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11543   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11544   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11545   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11546   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11547   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11548   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11549   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11550   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11551   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11552   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11553   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11554   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11555   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11556   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11557   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11558   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11559   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11560   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11561   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11562   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11563   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11564   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11565   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11566   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11567   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11568   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11569   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11570   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11571   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11572   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11573   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11574   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11575   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11576   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11577   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11578   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11579   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11580   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11581   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11582   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11583   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11584   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11585   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11586   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11587   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11588   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11589   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11590   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11591   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11592   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11593   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11594   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11595   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11596   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11597   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11598   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11599   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11600   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11601   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11602   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11603   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11604   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11605   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11606   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11607   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11608   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11609   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11610                                 0, 100                                                          },
11611   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11612                                 0, 100                                                          },
11613   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11614   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11615   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11616                                 0, 100                                                          },
11617   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11618                                 0, 100                                                          },
11619   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11620   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11621   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11622   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11623   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11624   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11625   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11626   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11627   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11628   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11629   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11630                                 -100, 100                                                       },
11631   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11632                                 0, 100                                                          },
11633   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11634                                 0, 100                                                          },
11635   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11636                                 0, 255                                                          },
11637   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11638                                 -1, 65535                                                       },
11639   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11640                                 0, 100                                                          },
11641   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11642                                 0, 3                                                            },
11643   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11644                                 0, 3                                                            },
11645   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11646                                 0, 3                                                            },
11647   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11648                                 0, 3                                                            },
11649   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11650                                 0, 3                                                            },
11651   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11652                                 0, 100                                                          },
11653   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11654                                 1, 100                                                          },
11655   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11656                                 1, 200                                                          },
11657   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11658                                 0, 50                                                           },
11659   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11660                                 0, 50                                                           },
11661   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11662                                 0, 10                                                           },
11663   { EL_BD_CREATURE_SWITCH,      &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
11664   { EL_BD_GRAVITY_SWITCH,       &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
11665                                 1, 60                                                           },
11666   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11667   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11668   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11669   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11670   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11671   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11672   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11673   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11674   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11675   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11676   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11677   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11678   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11679   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11680   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11681   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11682   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11683   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11684   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11685   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11686   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11687   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11688   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11689   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11690   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11691
11692   { -1,                         NULL,                                   NULL                    }
11693 };
11694
11695 static boolean checkPropertiesConfig(int element)
11696 {
11697   int i;
11698
11699   // special case: empty space customization only available in R'n'D game engine
11700   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11701     return FALSE;
11702
11703   // special case: BD style rock customization only available in BD game engine
11704   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11705     return FALSE;
11706
11707   if (IS_GEM(element) ||
11708       IS_CUSTOM_ELEMENT(element) ||
11709       IS_GROUP_ELEMENT(element) ||
11710       IS_EMPTY_ELEMENT(element) ||
11711       IS_BALLOON_ELEMENT(element) ||
11712       IS_ENVELOPE(element) ||
11713       IS_MM_ENVELOPE(element) ||
11714       IS_MM_MCDUFFIN(element) ||
11715       IS_DF_LASER(element) ||
11716       IS_PLAYER_ELEMENT(element) ||
11717       IS_BD_PLAYER_ELEMENT(element) ||
11718       IS_BD_FIREFLY(properties_element) ||
11719       IS_BD_FIREFLY_2(properties_element) ||
11720       IS_BD_BUTTERFLY(properties_element) ||
11721       IS_BD_BUTTERFLY_2(properties_element) ||
11722       IS_BD_STONEFLY(properties_element) ||
11723       IS_BD_DRAGONFLY(properties_element) ||
11724       IS_BD_EXPANDABLE_WALL(properties_element) ||
11725       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11726       IS_BD_CONVEYOR_BELT(properties_element) ||
11727       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11728       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11729       HAS_EDITOR_CONTENT(element) ||
11730       CAN_GROW(element) ||
11731       COULD_MOVE_INTO_ACID(element) ||
11732       MAYBE_DONT_COLLIDE_WITH(element) ||
11733       element == EL_BD_SAND ||
11734       element == EL_BD_ROCK ||
11735       element == EL_BD_MEGA_ROCK ||
11736       element == EL_BD_BOMB ||
11737       element == EL_BD_NITRO_PACK ||
11738       element == EL_BD_SWEET ||
11739       element == EL_BD_VOODOO_DOLL ||
11740       element == EL_BD_WATER ||
11741       element == EL_BD_GRAVITY_SWITCH)
11742   {
11743     return TRUE;
11744   }
11745   else
11746   {
11747     for (i = 0; elements_with_counter[i].element != -1; i++)
11748       if (elements_with_counter[i].element == element)
11749         return TRUE;
11750   }
11751
11752   return FALSE;
11753 }
11754
11755 static void SetAutomaticNumberOfGemsNeeded(void)
11756 {
11757   int x, y;
11758
11759   if (!level.auto_count_gems)
11760     return;
11761
11762   level.gems_needed = 0;
11763
11764   for (x = 0; x < lev_fieldx; x++)
11765   {
11766     for (y = 0; y < lev_fieldy; y++)
11767     {
11768       int element = Tile[x][y];
11769
11770       switch (element)
11771       {
11772         case EL_EMERALD:
11773         case EL_EMERALD_YELLOW:
11774         case EL_EMERALD_RED:
11775         case EL_EMERALD_PURPLE:
11776         case EL_BD_DIAMOND:
11777         case EL_WALL_EMERALD:
11778         case EL_WALL_EMERALD_YELLOW:
11779         case EL_WALL_EMERALD_RED:
11780         case EL_WALL_EMERALD_PURPLE:
11781         case EL_WALL_BD_DIAMOND:
11782         case EL_NUT:
11783         case EL_SP_INFOTRON:
11784         case EL_MM_KETTLE:
11785         case EL_DF_CELL:
11786           level.gems_needed++;
11787           break;
11788
11789         case EL_DIAMOND:
11790         case EL_WALL_DIAMOND:
11791           level.gems_needed += 3;
11792           break;
11793
11794         case EL_PEARL:
11795         case EL_WALL_PEARL:
11796           level.gems_needed += 5;
11797           break;
11798
11799         case EL_CRYSTAL:
11800         case EL_WALL_CRYSTAL:
11801           level.gems_needed += 8;
11802           break;
11803
11804         default:
11805           break;
11806       }
11807     }
11808   }
11809
11810   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11811 }
11812
11813 static void DrawPropertiesConfig(void)
11814 {
11815   boolean draw_footer_line = FALSE;
11816   int max_num_element_counters = 4;
11817   int num_element_counters = 0;
11818   int i;
11819
11820   if (!checkPropertiesConfig(properties_element))
11821   {
11822     int xpos = ED_ELEMENT_SETTINGS_X(0);
11823     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11824
11825     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11826
11827     return;
11828   }
11829
11830   // check if there are elements where a value can be chosen for
11831   for (i = 0; elements_with_counter[i].element != -1; i++)
11832   {
11833     if (elements_with_counter[i].element != properties_element)
11834       continue;
11835
11836     // special case: score for extra diamonds only available in BD game engine
11837     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11838         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11839         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11840       continue;
11841
11842     // special case: some amoeba counters only available in BD game engine
11843     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11844         elements_with_counter[i].value != &level.amoeba_speed &&
11845         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11846       continue;
11847
11848     // special case: score for smashing only available in R'n'D game engine
11849     if ((IS_BD_FIREFLY(elements_with_counter[i].element) ||
11850          IS_BD_BUTTERFLY(elements_with_counter[i].element)) &&
11851         (elements_with_counter[i].value == &level.score[SC_BUG] ||
11852          elements_with_counter[i].value == &level.score[SC_SPACESHIP]) &&
11853         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11854       continue;
11855
11856     // special case: some amoeba counters only available in R'n'D game engine
11857     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11858         elements_with_counter[i].value == &level.amoeba_speed &&
11859         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11860       continue;
11861
11862     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11863
11864     counterbutton_info[counter_id].y =
11865       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11866                                (CAN_GROW(properties_element)                ? 1 : 0) +
11867                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11868                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11869                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11870                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11871                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11872                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11873                                (properties_element == EL_BD_CREATURE_SWITCH ? 2 : 0) +
11874                                (properties_element == EL_BD_GRAVITY_SWITCH  ? 2 : 0) +
11875                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11876                                num_element_counters);
11877
11878     // special case: set magic wall counter for BD game engine separately
11879     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11880       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11881
11882     // special case: set amoeba counters for BD game engine separately
11883     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11884         (properties_element == EL_BD_AMOEBA_2))
11885       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11886
11887     // special case: set position for delay counter for reappearing hammered walls
11888     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11889       counterbutton_info[counter_id].y += 1;
11890
11891     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11892     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11893     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11894     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11895
11896     // default: counter values between 0 and 999
11897     if (counterbutton_info[counter_id].max_value == 0)
11898       counterbutton_info[counter_id].max_value = 999;
11899
11900     MapCounterButtons(counter_id);
11901
11902     num_element_counters++;
11903     if (num_element_counters >= max_num_element_counters)
11904       break;
11905   }
11906
11907   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11908   {
11909     // draw stickybutton gadget
11910     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11911
11912     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11913     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11914
11915     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11916     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11917     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11918     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11919     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11920     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11921     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11922   }
11923
11924   if (HAS_EDITOR_CONTENT(properties_element))
11925   {
11926     // draw stickybutton gadget
11927     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11928
11929     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11930     {
11931       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11932       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11933
11934       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11935       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11936     }
11937     else if (properties_element == EL_BD_AMOEBA_2)
11938     {
11939       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11940       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11941       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11942
11943       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11944       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11945       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11946       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11947     }
11948     else if (IS_AMOEBOID(properties_element))
11949       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11950     else if (properties_element == EL_BD_ACID)
11951     {
11952       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11953       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11954     }
11955     else if (IS_BD_BITER(properties_element))
11956     {
11957       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11958     }
11959     else if (properties_element == EL_BD_BLADDER)
11960     {
11961       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11962     }
11963     else if (properties_element == EL_YAMYAM ||
11964              properties_element == EL_YAMYAM_LEFT ||
11965              properties_element == EL_YAMYAM_RIGHT ||
11966              properties_element == EL_YAMYAM_UP ||
11967              properties_element == EL_YAMYAM_DOWN)
11968       DrawYamYamContentAreas();
11969     else if (properties_element == EL_EMC_MAGIC_BALL)
11970     {
11971       DrawMagicBallContentAreas();
11972
11973       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
11974       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
11975     }
11976     else if (properties_element == EL_EMC_ANDROID)
11977       DrawAndroidElementArea();
11978     else if (properties_element == EL_MM_GRAY_BALL)
11979     {
11980       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
11981       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
11982       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
11983       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
11984
11985       DrawMMBallContentArea();
11986     }
11987   }
11988
11989   if (IS_PLAYER_ELEMENT(properties_element))
11990   {
11991     int player_nr = GET_PLAYER_NR(properties_element);
11992
11993     // these properties can be set for every player individually
11994
11995     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
11996     {
11997       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
11998         &level.start_element[player_nr];
11999       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
12000         &level.artwork_element[player_nr];
12001       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
12002         &level.explosion_element[player_nr];
12003
12004       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
12005         &level.use_start_element[player_nr];
12006       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
12007         &level.use_artwork_element[player_nr];
12008       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
12009         &level.use_explosion_element[player_nr];
12010       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
12011         &level.initial_player_gravity[player_nr];
12012
12013       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
12014         &level.initial_player_stepsize[player_nr];
12015
12016       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
12017       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
12018                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
12019                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
12020       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
12021       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
12022       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
12023       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
12024       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
12025       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
12026       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
12027       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
12028       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
12029       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
12030       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
12031
12032       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
12033       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
12034       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
12035
12036       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
12037     }
12038     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12039     {
12040       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
12041         &level.initial_inventory_content[player_nr][0];
12042
12043       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
12044         &level.initial_inventory_size[player_nr];
12045
12046       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
12047         &level.use_initial_inventory[player_nr];
12048
12049       // draw checkbutton gadgets
12050       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
12051       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
12052       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
12053
12054       // draw counter gadgets
12055       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
12056
12057       // draw drawing area gadgets
12058       DrawPlayerInitialInventoryArea(properties_element);
12059     }
12060   }
12061
12062   if (IS_BD_PLAYER_ELEMENT(properties_element))
12063   {
12064     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12065       ED_ELEMENT_SETTINGS_YPOS(2);
12066     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12067       ED_ELEMENT_SETTINGS_YPOS(3);
12068     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12069       ED_ELEMENT_SETTINGS_YPOS(4);
12070
12071     // draw checkbutton gadgets
12072     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
12073     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
12074     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12075
12076     // draw counter gadgets
12077     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12078     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12079
12080     // draw drawing area gadgets
12081     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
12082   }
12083
12084   if (properties_element == EL_BD_SAND)
12085   {
12086     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
12087   }
12088
12089   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12090   {
12091     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12092       ED_ELEMENT_SETTINGS_YPOS(0);
12093     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12094       ED_ELEMENT_SETTINGS_YPOS(1);
12095
12096     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12097     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12098
12099     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
12100     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
12101   }
12102
12103   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12104   {
12105     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
12106     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
12107   }
12108
12109   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
12110   {
12111     if (IS_BD_FIREFLY(properties_element))
12112     {
12113       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO);
12114       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12115     }
12116     else if (IS_BD_FIREFLY_2(properties_element))
12117     {
12118       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
12119       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12120     }
12121     else if (IS_BD_BUTTERFLY(properties_element))
12122     {
12123       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO);
12124       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12125     }
12126     else if (IS_BD_BUTTERFLY_2(properties_element))
12127     {
12128       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
12129       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12130     }
12131     else if (IS_BD_STONEFLY(properties_element))
12132     {
12133       MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
12134     }
12135     else if (IS_BD_DRAGONFLY(properties_element))
12136     {
12137       MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
12138       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12139     }
12140     else if (properties_element == EL_BD_BOMB)
12141     {
12142       MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
12143     }
12144     else if (properties_element == EL_BD_NITRO_PACK)
12145     {
12146       MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
12147     }
12148   }
12149
12150   if (properties_element == EL_BD_MEGA_ROCK ||
12151       properties_element == EL_BD_SWEET)
12152   {
12153     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12154       ED_ELEMENT_SETTINGS_YPOS(0);
12155     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12156       ED_ELEMENT_SETTINGS_YPOS(1);
12157
12158     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12159     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12160   }
12161
12162   if (properties_element == EL_BD_VOODOO_DOLL)
12163   {
12164     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12165     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12166     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12167     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12168   }
12169
12170   if (properties_element == EL_BD_SLIME)
12171   {
12172     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12173
12174     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12175     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12176     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12177     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12178     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12179     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12180   }
12181
12182   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12183       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12184   {
12185     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12186
12187     if (IS_BD_EXPANDABLE_WALL(properties_element))
12188       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12189   }
12190
12191   if (properties_element == EL_BD_REPLICATOR)
12192   {
12193     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12194   }
12195
12196   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12197       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12198   {
12199     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12200     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12201   }
12202
12203   if (properties_element == EL_BD_WATER)
12204   {
12205     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12206   }
12207
12208   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12209   {
12210     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12211   }
12212
12213   if (properties_element == EL_BD_CREATURE_SWITCH)
12214   {
12215     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12216     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12217   }
12218
12219   if (properties_element == EL_BD_GRAVITY_SWITCH)
12220   {
12221     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12222
12223     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12224     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12225   }
12226
12227   if (properties_element == EL_BD_NUT)
12228   {
12229     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12230   }
12231
12232   // special case: slippery walls option for gems only available in R'n'D game engine
12233   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12234     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12235
12236   if (properties_element == EL_EM_DYNAMITE)
12237     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12238
12239   if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
12240       COULD_MOVE_INTO_ACID(properties_element) &&
12241       !IS_PLAYER_ELEMENT(properties_element) &&
12242       (!IS_CUSTOM_ELEMENT(properties_element) ||
12243        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12244   {
12245     // set position for checkbutton for "can move into acid"
12246     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12247       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12248     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12249       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12250                                IS_BALLOON_ELEMENT(properties_element) ||
12251                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12252
12253     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12254   }
12255
12256   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12257     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12258
12259   if (properties_element == EL_SPRING ||
12260       properties_element == EL_SPRING_LEFT ||
12261       properties_element == EL_SPRING_RIGHT)
12262     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12263
12264   if (properties_element == EL_TIME_ORB_FULL)
12265     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12266
12267   if (properties_element == EL_GAME_OF_LIFE ||
12268       properties_element == EL_BIOMAZE)
12269     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12270
12271   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12272   {
12273     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12274       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12275
12276     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12277   }
12278
12279   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12280     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12281
12282   if (properties_element == EL_SOKOBAN_OBJECT)
12283     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12284
12285   if (properties_element == EL_SOKOBAN_OBJECT ||
12286       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12287       properties_element == EL_SOKOBAN_FIELD_FULL)
12288   {
12289     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12290       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12291                                0 : 1);
12292
12293     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12294   }
12295
12296   if (IS_BALLOON_ELEMENT(properties_element))
12297     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12298
12299   if (IS_ENVELOPE(properties_element) ||
12300       IS_MM_ENVELOPE(properties_element))
12301   {
12302     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12303     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12304     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12305     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12306     int envelope_nr = ENVELOPE_NR(properties_element);
12307
12308     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12309     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12310
12311     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12312     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12313
12314     // display counter to choose size of envelope text area
12315     MapCounterButtons(counter1_id);
12316     MapCounterButtons(counter2_id);
12317
12318     // display checkbuttons to choose auto-wrap and alignment properties
12319     MapCheckbuttonGadget(button1_id);
12320     MapCheckbuttonGadget(button2_id);
12321
12322     DrawEnvelopeTextArea(envelope_nr);
12323   }
12324
12325   if (IS_MM_MCDUFFIN(properties_element))
12326   {
12327     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12328     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12329     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12330   }
12331
12332   if (IS_DF_LASER(properties_element))
12333   {
12334     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12335     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12336     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12337   }
12338
12339   if (IS_CUSTOM_ELEMENT(properties_element))
12340   {
12341     // draw stickybutton gadget
12342     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12343
12344     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12345     {
12346       // draw checkbutton gadgets
12347       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12348            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12349         MapCheckbuttonGadget(i);
12350
12351       // draw counter gadgets
12352       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12353            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12354         MapCounterButtons(i);
12355
12356       // draw selectbox gadgets
12357       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12358            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12359         MapSelectboxGadget(i);
12360
12361       // draw textbutton gadgets
12362       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12363
12364       // draw text input gadgets
12365       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12366
12367       // draw drawing area gadgets
12368       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12369
12370       draw_footer_line = TRUE;
12371     }
12372     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12373     {
12374       // draw checkbutton gadgets
12375       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12376            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12377         MapCheckbuttonGadget(i);
12378
12379       // draw counter gadgets
12380       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12381            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12382         MapCounterButtons(i);
12383
12384       // draw selectbox gadgets
12385       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12386            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12387         MapSelectboxGadget(i);
12388
12389       // draw drawing area gadgets
12390       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12391       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12392       DrawCustomContentArea();
12393     }
12394   }
12395   else if (IS_GROUP_ELEMENT(properties_element))
12396   {
12397     // draw stickybutton gadget
12398     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12399
12400     // draw checkbutton gadgets
12401     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12402     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12403
12404     // draw counter gadgets
12405     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12406
12407     // draw selectbox gadgets
12408     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12409
12410     // draw textbutton gadgets
12411     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12412
12413     // draw drawing area gadgets
12414     DrawGroupElementArea();
12415
12416     // draw text input gadgets
12417     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12418
12419     // draw drawing area gadgets
12420     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12421
12422     draw_footer_line = TRUE;
12423   }
12424   else if (IS_EMPTY_ELEMENT(properties_element))
12425   {
12426     // draw stickybutton gadget
12427     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12428
12429     // draw checkbutton gadgets
12430     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12431     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12432
12433     // draw textbutton gadgets
12434     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12435
12436     // draw drawing area gadgets
12437     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12438
12439     draw_footer_line = TRUE;
12440   }
12441
12442   // draw little footer border line above CE/GE use/save template gadgets
12443   if (draw_footer_line)
12444   {
12445     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12446     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12447     int gd_x = gd->x + gd_gi1->border.width / 2;
12448     int gd_y = gd->y + gd_gi1->height - 1;
12449     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12450
12451     if (tab_color != BLACK_PIXEL)               // black => transparent
12452       FillRectangle(drawto,
12453                     SX + ED_ELEMENT_SETTINGS_X(0),
12454                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12455                     ED_TAB_BAR_HEIGHT,
12456                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12457   }
12458 }
12459
12460 static void DrawPropertiesChangeDrawingAreas(void)
12461 {
12462   if (IS_CUSTOM_ELEMENT(properties_element))
12463   {
12464     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12465     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12466     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12467
12468     DrawCustomChangeContentArea();
12469   }
12470
12471   redraw_mask |= REDRAW_FIELD;
12472 }
12473
12474 static void DrawPropertiesChange(void)
12475 {
12476   int i;
12477
12478   // needed to initially set selectbox options for special action options
12479   setSelectboxSpecialActionOptions();
12480
12481   // draw stickybutton gadget
12482   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12483
12484   // draw checkbutton gadgets
12485   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12486        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12487     MapCheckbuttonGadget(i);
12488
12489   // draw counter gadgets
12490   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12491        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12492     MapCounterButtons(i);
12493
12494   // draw selectbox gadgets
12495   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12496        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12497     MapSelectboxGadget(i);
12498
12499   // draw textbutton gadgets
12500   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12501        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12502     MapTextbuttonGadget(i);
12503
12504   // draw graphicbutton gadgets
12505   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12506        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12507     MapGraphicbuttonGadget(i);
12508
12509   // draw drawing area gadgets
12510   DrawPropertiesChangeDrawingAreas();
12511 }
12512
12513 static void DrawEditorElementAnimation(int x, int y)
12514 {
12515   int graphic;
12516   int frame;
12517
12518   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12519
12520   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12521 }
12522
12523 static void DrawEditorElementName(int x, int y, int font_nr)
12524 {
12525   char *element_name = getElementInfoText(properties_element);
12526   int font_width = getFontWidth(font_nr);
12527   int font_height = getFontHeight(font_nr);
12528   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12529   int max_chars_per_line = max_text_width / font_width;
12530
12531   if (strlen(element_name) <= max_chars_per_line)
12532     DrawTextS(x, y, font_nr, element_name);
12533   else
12534   {
12535     char buffer[max_chars_per_line + 1];
12536     int next_pos = max_chars_per_line;
12537
12538     strncpy(buffer, element_name, max_chars_per_line);
12539     buffer[max_chars_per_line] = '\0';
12540
12541     if (element_name[max_chars_per_line] == ' ')
12542       next_pos++;
12543     else
12544     {
12545       int i;
12546
12547       for (i = max_chars_per_line - 1; i >= 0; i--)
12548         if (buffer[i] == ' ')
12549           break;
12550
12551       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12552       {
12553         buffer[i] = '\0';
12554         next_pos = i + 1;
12555       }
12556     }
12557
12558     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12559
12560     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12561     buffer[max_chars_per_line] = '\0';
12562
12563     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12564   }
12565 }
12566
12567 static void DrawPropertiesWindow(void)
12568 {
12569   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12570   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12571   int border_size = gd->border_size;
12572   int font_nr = FONT_TEXT_1;
12573   int font_height = getFontHeight(font_nr);
12574   int xoffset = TILEX + element_border + 3 * border_size;
12575   int yoffset = (TILEY - font_height) / 2;
12576   int x1 = editor.settings.element_graphic.x + element_border;
12577   int y1 = editor.settings.element_graphic.y + element_border;
12578   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12579             editor.settings.element_name.x);
12580   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12581             editor.settings.element_name.y);
12582   char *text = "Element Settings";
12583   int font2_nr = FONT_TITLE_1;
12584   struct MenuPosInfo *pos = &editor.settings.headline;
12585   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12586   int sy = SY + pos->y;
12587
12588   stick_element_properties_window = FALSE;
12589
12590   // make sure that previous properties edit mode exists for this element
12591   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12592       !IS_CUSTOM_ELEMENT(properties_element))
12593     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12594
12595   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12596       !IS_PLAYER_ELEMENT(properties_element) &&
12597       !IS_CUSTOM_ELEMENT(properties_element))
12598     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12599
12600   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12601       (IS_PLAYER_ELEMENT(properties_element) ||
12602        IS_CUSTOM_ELEMENT(properties_element)))
12603     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12604
12605   CopyElementPropertiesToEditor(properties_element);
12606
12607   UnmapLevelEditorFieldGadgets();
12608   UnmapLevelEditorToolboxDrawingGadgets();
12609   UnmapLevelEditorToolboxCustomGadgets();
12610
12611   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12612
12613   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12614   ClearField();
12615
12616   DrawText(sx, sy, text, font2_nr);
12617
12618   FrameCounter = 0;     // restart animation frame counter
12619
12620   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12621   DrawEditorElementAnimation(SX + x1, SY + y1);
12622   DrawEditorElementName(x2, y2, font_nr);
12623
12624   DrawPropertiesTabulatorGadgets();
12625
12626   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12627     DrawPropertiesInfo();
12628   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12629     DrawPropertiesChange();
12630   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12631     DrawPropertiesConfig();
12632 }
12633
12634 static void DrawPaletteWindow(void)
12635 {
12636   int i;
12637
12638   UnmapLevelEditorFieldGadgets();
12639
12640   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12641   ClearField();
12642
12643   // map buttons to select elements
12644   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12645     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12646   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12647   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12648   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12649 }
12650
12651 static void UpdateCustomElementGraphicGadgets(void)
12652 {
12653   int i;
12654
12655   InitElementPropertiesGfxElement();
12656
12657   ModifyEditorElementList();
12658   RedrawDrawingElements();
12659
12660   // force redraw of all mapped drawing area gadgets
12661   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12662   {
12663     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12664
12665     if (gi->mapped)
12666       MapDrawingArea(i);
12667   }
12668 }
12669
12670 static int getOpenDirectionFromTube(int element)
12671 {
12672   switch (element)
12673   {
12674     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12675     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12676     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12677     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12678     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12679     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12680     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12681     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12682     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12683     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12684     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12685   }
12686
12687   return MV_NONE;
12688 }
12689
12690 static int getTubeFromOpenDirection(int direction)
12691 {
12692   switch (direction)
12693   {
12694     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12695     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12696     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12697     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12698     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12699     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12700     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12701     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12702     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12703     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12704     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12705
12706     // if only one direction, fall back to simple tube with that direction
12707     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12708     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12709     case (MV_UP):                       return EL_TUBE_VERTICAL;
12710     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12711   }
12712
12713   return EL_EMPTY;
12714 }
12715
12716 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12717 {
12718   int element_new = getTubeFromOpenDirection(direction);
12719
12720   return (element_new != EL_EMPTY ? element_new : element_old);
12721 }
12722
12723 static int getOpenDirectionFromBelt(int element)
12724 {
12725   int belt_dir = getBeltDirFromBeltElement(element);
12726
12727   return (belt_dir == MV_LEFT ? MV_RIGHT :
12728           belt_dir == MV_RIGHT ? MV_LEFT :
12729           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12730 }
12731
12732 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12733 {
12734   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12735                   direction == MV_RIGHT ? MV_LEFT :
12736                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12737
12738   if (direction == MV_NONE)
12739     return EL_EMPTY;
12740
12741   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12742 }
12743
12744 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12745                                                  int element_old)
12746 {
12747   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12748
12749   return (element_new != EL_EMPTY ? element_new : element_old);
12750 }
12751
12752 static int getOpenDirectionFromPool(int element)
12753 {
12754   switch (element)
12755   {
12756     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12757     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12758     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12759     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12760     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12761     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12762   }
12763
12764   return MV_NONE;
12765 }
12766
12767 static int getPoolFromOpenDirection(int direction)
12768 {
12769   switch (direction)
12770   {
12771     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12772     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12773     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12774     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12775     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12776     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12777   }
12778
12779   return EL_EMPTY;
12780 }
12781
12782 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12783 {
12784   int element = getPoolFromOpenDirection(direction);
12785   int help_direction = getOpenDirectionFromPool(help_element);
12786
12787   if (element == EL_EMPTY)
12788   {
12789     int help_direction_vertical = help_direction & MV_VERTICAL;
12790
12791     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12792   }
12793
12794   if (element == EL_EMPTY)
12795   {
12796     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12797
12798     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12799   }
12800
12801   return element;
12802 }
12803
12804 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12805 {
12806   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12807
12808   return (element_new != EL_EMPTY ? element_new : element_old);
12809 }
12810
12811 static int getOpenDirectionFromPillar(int element)
12812 {
12813   switch (element)
12814   {
12815     case EL_EMC_WALL_1:                 return (MV_DOWN);
12816     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12817     case EL_EMC_WALL_3:                 return (MV_UP);
12818   }
12819
12820   return MV_NONE;
12821 }
12822
12823 static int getPillarFromOpenDirection(int direction)
12824 {
12825   switch (direction)
12826   {
12827     case (MV_DOWN):                     return EL_EMC_WALL_1;
12828     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12829     case (MV_UP):                       return EL_EMC_WALL_3;
12830   }
12831
12832   return EL_EMPTY;
12833 }
12834
12835 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12836 {
12837   int element_new = getPillarFromOpenDirection(direction);
12838
12839   return (element_new != EL_EMPTY ? element_new : element_old);
12840 }
12841
12842 static int getOpenDirectionFromSteel2(int element)
12843 {
12844   switch (element)
12845   {
12846     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12847     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12848     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12849     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12850     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12851     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12852     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12853     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12854   }
12855
12856   return MV_NONE;
12857 }
12858
12859 static int getSteel2FromOpenDirection(int direction)
12860 {
12861   switch (direction)
12862   {
12863     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12864     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12865     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12866     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12867     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12868     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12869     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12870     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12871   }
12872
12873   return EL_EMPTY;
12874 }
12875
12876 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12877 {
12878   int element_new = getSteel2FromOpenDirection(direction);
12879
12880   return (element_new != EL_EMPTY ? element_new : element_old);
12881 }
12882
12883 static int getOpenDirectionFromChip(int element)
12884 {
12885   switch (element)
12886   {
12887     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12888     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12889     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12890     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12891     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12892   }
12893
12894   return MV_NONE;
12895 }
12896
12897 static int getChipFromOpenDirection(int direction)
12898 {
12899   switch (direction)
12900   {
12901     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12902     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12903     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12904     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12905     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12906   }
12907
12908   return EL_EMPTY;
12909 }
12910
12911 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12912 {
12913   int element_new = getChipFromOpenDirection(direction);
12914
12915   return (element_new != EL_EMPTY ? element_new : element_old);
12916 }
12917
12918 static int getClosedTube(int x, int y)
12919 {
12920   struct XY *xy = xy_directions;
12921   int element_old = IntelliDrawBuffer[x][y];
12922   int direction_old = getOpenDirectionFromTube(element_old);
12923   int direction_new = MV_NONE;
12924   int i;
12925
12926   for (i = 0; i < NUM_DIRECTIONS; i++)
12927   {
12928     int xx = x + xy[i].x;
12929     int yy = y + xy[i].y;
12930     int dir = MV_DIR_FROM_BIT(i);
12931     int dir_opposite = MV_DIR_OPPOSITE(dir);
12932
12933     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12934         (direction_old & dir) &&
12935         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12936       direction_new |= dir;
12937   }
12938
12939   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12940 }
12941
12942 static int getClosedBelt(int x, int y)
12943 {
12944   struct XY *xy = xy_directions;
12945   int element_old = IntelliDrawBuffer[x][y];
12946   int nr = getBeltNrFromBeltElement(element_old);
12947   int direction_old = getOpenDirectionFromBelt(element_old);
12948   int direction_new = MV_NONE;
12949   int i;
12950
12951   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12952   {
12953     int xx = x + xy[i].x;
12954     int yy = y + xy[i].y;
12955     int dir = MV_DIR_FROM_BIT(i);
12956     int dir_opposite = MV_DIR_OPPOSITE(dir);
12957
12958     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12959         (direction_old & dir) &&
12960         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12961       direction_new |= dir;
12962   }
12963
12964   return getBeltFromNrAndOpenDirection(nr, direction_new);
12965 }
12966
12967 static int getClosedPool(int x, int y)
12968 {
12969   struct XY *xy = xy_directions;
12970   int element_old = IntelliDrawBuffer[x][y];
12971   int direction_old = getOpenDirectionFromPool(element_old);
12972   int direction_new = MV_NONE;
12973   int i;
12974
12975   for (i = 0; i < NUM_DIRECTIONS; i++)
12976   {
12977     int xx = x + xy[i].x;
12978     int yy = y + xy[i].y;
12979     int dir = MV_DIR_FROM_BIT(i);
12980     int dir_opposite = MV_DIR_OPPOSITE(dir);
12981
12982     if (IN_LEV_FIELD(xx, yy) &&
12983         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
12984         (direction_old & dir) &&
12985         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12986       direction_new |= dir;
12987   }
12988
12989   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
12990 }
12991
12992 static int getClosedPillar(int x, int y)
12993 {
12994   struct XY *xy = xy_directions;
12995   int element_old = IntelliDrawBuffer[x][y];
12996   int direction_old = getOpenDirectionFromPillar(element_old);
12997   int direction_new = MV_NONE;
12998   int i;
12999
13000   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13001   {
13002     int xx = x + xy[i].x;
13003     int yy = y + xy[i].y;
13004     int dir = MV_DIR_FROM_BIT(i);
13005     int dir_opposite = MV_DIR_OPPOSITE(dir);
13006
13007     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
13008         (direction_old & dir) &&
13009         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13010       direction_new |= dir;
13011   }
13012
13013   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
13014 }
13015
13016 static int getClosedSteel2(int x, int y)
13017 {
13018   struct XY *xy = xy_directions;
13019   int element_old = IntelliDrawBuffer[x][y];
13020   int direction_old = getOpenDirectionFromSteel2(element_old);
13021   int direction_new = MV_NONE;
13022   int i;
13023
13024   for (i = 0; i < NUM_DIRECTIONS; i++)
13025   {
13026     int xx = x + xy[i].x;
13027     int yy = y + xy[i].y;
13028     int dir = MV_DIR_FROM_BIT(i);
13029     int dir_opposite = MV_DIR_OPPOSITE(dir);
13030
13031     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
13032         (direction_old & dir) &&
13033         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13034       direction_new |= dir;
13035   }
13036
13037   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
13038 }
13039
13040 static int getClosedChip(int x, int y)
13041 {
13042   struct XY *xy = xy_directions;
13043   int element_old = IntelliDrawBuffer[x][y];
13044   int direction_old = getOpenDirectionFromChip(element_old);
13045   int direction_new = MV_NONE;
13046   int i;
13047
13048   for (i = 0; i < NUM_DIRECTIONS; i++)
13049   {
13050     int xx = x + xy[i].x;
13051     int yy = y + xy[i].y;
13052     int dir = MV_DIR_FROM_BIT(i);
13053     int dir_opposite = MV_DIR_OPPOSITE(dir);
13054
13055     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
13056         (direction_old & dir) &&
13057         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13058       direction_new |= dir;
13059   }
13060
13061   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
13062 }
13063
13064 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
13065                                 boolean change_level)
13066 {
13067   int sx = x - level_xpos;
13068   int sy = y - level_ypos;
13069   int old_element = Tile[x][y];
13070   int new_element = element;
13071   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
13072   boolean draw_masked = FALSE;
13073
13074   if (IS_MM_WALL_EDITOR(element))
13075   {
13076     element = map_mm_wall_element_editor(element) | new_bitmask;
13077
13078     if (IS_MM_WALL(old_element))
13079       element |= MM_WALL_BITS(old_element);
13080
13081     if (!change_level)
13082       draw_masked = TRUE;
13083   }
13084   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
13085   {
13086     int element_changed = old_element & ~new_bitmask;
13087
13088     if (MM_WALL_BITS(element_changed) != 0)
13089       element = element_changed;
13090   }
13091
13092   IntelliDrawBuffer[x][y] = element;
13093
13094   if (change_level)
13095     Tile[x][y] = element;
13096
13097   if (IN_ED_FIELD(sx, sy))
13098   {
13099     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
13100       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
13101     else if (draw_masked)
13102       DrawEditorElementThruMask(sx, sy, element);
13103     else
13104       DrawEditorElement(sx, sy, element);
13105   }
13106 }
13107
13108 static void SetElementSimple(int x, int y, int element, boolean change_level)
13109 {
13110   SetElementSimpleExt(x, y, 0, 0, element, change_level);
13111 }
13112
13113 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
13114                                            int x2, int y2, int *element2,
13115                                            int (*close_function)(int, int),
13116                                            boolean change_level)
13117 {
13118   // set neighbour elements to newly determined connections
13119   SetElementSimple(x1, y1, *element1, change_level);
13120   SetElementSimple(x2, y2, *element2, change_level);
13121
13122   // remove all open connections of neighbour elements
13123   *element1 = close_function(x1, y1);
13124   *element2 = close_function(x2, y2);
13125
13126   // set neighbour elements to new, minimized connections
13127   SetElementSimple(x1, y1, *element1, change_level);
13128   SetElementSimple(x2, y2, *element2, change_level);
13129 }
13130
13131 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
13132                                   boolean change_level, int button)
13133 {
13134   struct XY *xy = xy_directions;
13135   static int last_x = -1;
13136   static int last_y = -1;
13137
13138   if (new_element == EL_UNDEFINED)
13139   {
13140     last_x = -1;
13141     last_y = -1;
13142
13143     return;
13144   }
13145
13146   int old_element = IntelliDrawBuffer[x][y];
13147
13148   if (IS_TUBE(new_element))
13149   {
13150     int last_element_new = EL_UNDEFINED;
13151     int direction = MV_NONE;
13152     int i;
13153
13154     // if old element is of same kind, keep all existing directions
13155     if (IS_TUBE(old_element))
13156       direction |= getOpenDirectionFromTube(old_element);
13157
13158     for (i = 0; i < NUM_DIRECTIONS; i++)
13159     {
13160       int xx = x + xy[i].x;
13161       int yy = y + xy[i].y;
13162
13163       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13164           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13165       {
13166         int dir = MV_DIR_FROM_BIT(i);
13167         int dir_opposite = MV_DIR_OPPOSITE(dir);
13168         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13169         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13170         int last_direction_new = last_direction_old | dir_opposite;
13171
13172         last_element_new = getTubeFromOpenDirection(last_direction_new);
13173
13174         direction |= dir;
13175       }
13176     }
13177
13178     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13179
13180     if (last_element_new != EL_UNDEFINED)
13181       MergeAndCloseNeighbourElements(x, y, &new_element,
13182                                      last_x, last_y, &last_element_new,
13183                                      getClosedTube, change_level);
13184   }
13185   else if (IS_BELT(new_element))
13186   {
13187     int belt_nr = getBeltNrFromBeltElement(new_element);
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_BELT(old_element))
13194       direction |= getOpenDirectionFromBelt(old_element);
13195
13196     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; 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_BELT(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_belt_nr = getBeltNrFromBeltElement(last_element_old);
13208         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13209         int last_direction_new = last_direction_old | dir_opposite;
13210
13211         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13212                                                          last_direction_new);
13213         direction |= dir;
13214       }
13215     }
13216
13217     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13218                                                         new_element);
13219     if (last_element_new != EL_UNDEFINED)
13220       MergeAndCloseNeighbourElements(x, y, &new_element,
13221                                      last_x, last_y, &last_element_new,
13222                                      getClosedBelt, change_level);
13223   }
13224   else if (IS_ACID_POOL_OR_ACID(new_element))
13225   {
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_ACID_POOL_OR_ACID(old_element))
13232       direction |= getOpenDirectionFromPool(old_element);
13233
13234     for (i = 0; i < NUM_DIRECTIONS; 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_ACID_POOL_OR_ACID(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_direction_old = getOpenDirectionFromPool(last_element_old);
13246         int last_direction_new = last_direction_old | dir_opposite;
13247
13248         last_element_new = getPoolFromOpenDirection(last_direction_new);
13249
13250         direction |= dir;
13251       }
13252     }
13253
13254     // special corrections needed for intuitively correct acid pool drawing
13255     if (last_element_new == EL_EMPTY)
13256       last_element_new = new_element;
13257     else if (last_element_new != EL_UNDEFINED)
13258       new_element = last_element_new;
13259
13260     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13261
13262     if (last_element_new != EL_UNDEFINED)
13263       MergeAndCloseNeighbourElements(x, y, &new_element,
13264                                      last_x, last_y, &last_element_new,
13265                                      getClosedPool, change_level);
13266   }
13267   else if (IS_EMC_PILLAR(new_element))
13268   {
13269     int last_element_new = EL_UNDEFINED;
13270     int direction = MV_NONE;
13271     int i;
13272
13273     // if old element is of same kind, keep all existing directions
13274     if (IS_EMC_PILLAR(old_element))
13275       direction |= getOpenDirectionFromPillar(old_element);
13276
13277     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13278     {
13279       int xx = x + xy[i].x;
13280       int yy = y + xy[i].y;
13281
13282       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13283           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13284       {
13285         int dir = MV_DIR_FROM_BIT(i);
13286         int dir_opposite = MV_DIR_OPPOSITE(dir);
13287         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13288         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13289         int last_direction_new = last_direction_old | dir_opposite;
13290
13291         last_element_new = getPillarFromOpenDirection(last_direction_new);
13292
13293         direction |= dir;
13294       }
13295     }
13296
13297     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13298
13299     if (last_element_new != EL_UNDEFINED)
13300       MergeAndCloseNeighbourElements(x, y, &new_element,
13301                                      last_x, last_y, &last_element_new,
13302                                      getClosedPillar, change_level);
13303   }
13304   else if (IS_DC_STEELWALL_2(new_element))
13305   {
13306     int last_element_new = EL_UNDEFINED;
13307     int direction = MV_NONE;
13308     int i;
13309
13310     // if old element is of same kind, keep all existing directions
13311     if (IS_DC_STEELWALL_2(old_element))
13312       direction |= getOpenDirectionFromSteel2(old_element);
13313
13314     for (i = 0; i < NUM_DIRECTIONS; i++)
13315     {
13316       int xx = x + xy[i].x;
13317       int yy = y + xy[i].y;
13318
13319       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13320           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13321       {
13322         int dir = MV_DIR_FROM_BIT(i);
13323         int dir_opposite = MV_DIR_OPPOSITE(dir);
13324         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13325         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13326         int last_direction_new = last_direction_old | dir_opposite;
13327
13328         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13329
13330         direction |= dir;
13331       }
13332     }
13333
13334     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13335
13336     if (last_element_new != EL_UNDEFINED)
13337       MergeAndCloseNeighbourElements(x, y, &new_element,
13338                                      last_x, last_y, &last_element_new,
13339                                      getClosedSteel2, change_level);
13340   }
13341   else if (IS_SP_CHIP(new_element))
13342   {
13343     int last_element_new = EL_UNDEFINED;
13344     int direction = MV_NONE;
13345     int i;
13346
13347     // (do not keep existing directions, regardless of kind of old element)
13348
13349     for (i = 0; i < NUM_DIRECTIONS; i++)
13350     {
13351       int xx = x + xy[i].x;
13352       int yy = y + xy[i].y;
13353
13354       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13355           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13356       {
13357         int dir = MV_DIR_FROM_BIT(i);
13358         int dir_opposite = MV_DIR_OPPOSITE(dir);
13359         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13360         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13361         int last_direction_new = last_direction_old | dir_opposite;
13362
13363         if (last_direction_old == MV_NONE)
13364         {
13365           last_element_new = getChipFromOpenDirection(last_direction_new);
13366           direction |= dir;
13367         }
13368         else if (last_direction_old & (dir | dir_opposite))
13369         {
13370           direction |= MV_DIR_OPPOSITE(last_direction_old);
13371         }
13372         else
13373         {
13374           direction |= MV_DIR_OPPOSITE(dir);
13375         }
13376       }
13377     }
13378
13379     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13380
13381     if (last_element_new != EL_UNDEFINED)
13382       MergeAndCloseNeighbourElements(x, y, &new_element,
13383                                      last_x, last_y, &last_element_new,
13384                                      getClosedChip, change_level);
13385   }
13386   else if (IS_SP_HARDWARE_BASE(new_element))
13387   {
13388     int nr = GetSimpleRandom(6);
13389
13390     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13391                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13392                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13393                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13394                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13395   }
13396   else if (new_element == EL_SP_HARDWARE_GREEN ||
13397            new_element == EL_SP_HARDWARE_BLUE ||
13398            new_element == EL_SP_HARDWARE_RED)
13399   {
13400     int nr = GetSimpleRandom(3);
13401
13402     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13403                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13404   }
13405   else if (IS_GROUP_ELEMENT(new_element))
13406   {
13407     boolean connected_drawing = FALSE;
13408     int i;
13409
13410     for (i = 0; i < NUM_DIRECTIONS; i++)
13411     {
13412       int xx = x + xy[i].x;
13413       int yy = y + xy[i].y;
13414
13415       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13416           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13417         connected_drawing = TRUE;
13418     }
13419
13420     if (!connected_drawing)
13421       ResolveGroupElement(new_element);
13422
13423     new_element = GetElementFromGroupElement(new_element);
13424   }
13425   else if (IS_BELT_SWITCH(old_element))
13426   {
13427     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13428     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13429
13430     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13431                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13432
13433     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13434   }
13435   else
13436   {
13437     static int swappable_elements[][2] =
13438     {
13439       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13440       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13441       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13442       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13443       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13444       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13445       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13446       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13447       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13448       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13449       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13450       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13451       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13452       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13453       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13454       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13455       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13456       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13457       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13458       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13459       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13460       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13461       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13462       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13463       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13464       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13465       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13466       { EL_PEARL,                       EL_WALL_PEARL                   },
13467       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13468       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13469       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13470       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13471       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13472       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13473       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13474       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13475       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13476       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13477       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13478       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13479       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13480       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13481       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13482       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13483
13484       { -1,                             -1                              },
13485     };
13486     static int rotatable_elements_4[][4] =
13487     {
13488       {
13489         EL_BUG_UP,
13490         EL_BUG_RIGHT,
13491         EL_BUG_DOWN,
13492         EL_BUG_LEFT
13493       },
13494       {
13495         EL_SPACESHIP_UP,
13496         EL_SPACESHIP_RIGHT,
13497         EL_SPACESHIP_DOWN,
13498         EL_SPACESHIP_LEFT
13499       },
13500       {
13501         EL_BD_BUTTERFLY_UP,
13502         EL_BD_BUTTERFLY_RIGHT,
13503         EL_BD_BUTTERFLY_DOWN,
13504         EL_BD_BUTTERFLY_LEFT
13505       },
13506       {
13507         EL_BD_FIREFLY_UP,
13508         EL_BD_FIREFLY_RIGHT,
13509         EL_BD_FIREFLY_DOWN,
13510         EL_BD_FIREFLY_LEFT
13511       },
13512       {
13513         EL_PACMAN_UP,
13514         EL_PACMAN_RIGHT,
13515         EL_PACMAN_DOWN,
13516         EL_PACMAN_LEFT
13517       },
13518       {
13519         EL_YAMYAM_UP,
13520         EL_YAMYAM_RIGHT,
13521         EL_YAMYAM_DOWN,
13522         EL_YAMYAM_LEFT
13523       },
13524       {
13525         EL_ARROW_UP,
13526         EL_ARROW_RIGHT,
13527         EL_ARROW_DOWN,
13528         EL_ARROW_LEFT
13529       },
13530       {
13531         EL_SP_PORT_UP,
13532         EL_SP_PORT_RIGHT,
13533         EL_SP_PORT_DOWN,
13534         EL_SP_PORT_LEFT
13535       },
13536       {
13537         EL_SP_GRAVITY_PORT_UP,
13538         EL_SP_GRAVITY_PORT_RIGHT,
13539         EL_SP_GRAVITY_PORT_DOWN,
13540         EL_SP_GRAVITY_PORT_LEFT
13541       },
13542       {
13543         EL_SP_GRAVITY_ON_PORT_UP,
13544         EL_SP_GRAVITY_ON_PORT_RIGHT,
13545         EL_SP_GRAVITY_ON_PORT_DOWN,
13546         EL_SP_GRAVITY_ON_PORT_LEFT
13547       },
13548       {
13549         EL_SP_GRAVITY_OFF_PORT_UP,
13550         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13551         EL_SP_GRAVITY_OFF_PORT_DOWN,
13552         EL_SP_GRAVITY_OFF_PORT_LEFT
13553       },
13554       {
13555         EL_MOLE_UP,
13556         EL_MOLE_RIGHT,
13557         EL_MOLE_DOWN,
13558         EL_MOLE_LEFT
13559       },
13560       {
13561         EL_BALLOON_SWITCH_UP,
13562         EL_BALLOON_SWITCH_RIGHT,
13563         EL_BALLOON_SWITCH_DOWN,
13564         EL_BALLOON_SWITCH_LEFT
13565       },
13566       {
13567         EL_MM_MCDUFFIN_UP,
13568         EL_MM_MCDUFFIN_RIGHT,
13569         EL_MM_MCDUFFIN_DOWN,
13570         EL_MM_MCDUFFIN_LEFT
13571       },
13572       {
13573         EL_MM_MIRROR_FIXED_1,
13574         EL_MM_MIRROR_FIXED_4,
13575         EL_MM_MIRROR_FIXED_3,
13576         EL_MM_MIRROR_FIXED_2
13577       },
13578       {
13579         EL_MM_STEEL_GRID_FIXED_1,
13580         EL_MM_STEEL_GRID_FIXED_4,
13581         EL_MM_STEEL_GRID_FIXED_2,
13582         EL_MM_STEEL_GRID_FIXED_3
13583       },
13584       {
13585         EL_MM_WOODEN_GRID_FIXED_1,
13586         EL_MM_WOODEN_GRID_FIXED_4,
13587         EL_MM_WOODEN_GRID_FIXED_2,
13588         EL_MM_WOODEN_GRID_FIXED_3
13589       },
13590       {
13591         EL_MM_POLARIZER_CROSS_1,
13592         EL_MM_POLARIZER_CROSS_4,
13593         EL_MM_POLARIZER_CROSS_3,
13594         EL_MM_POLARIZER_CROSS_2
13595       },
13596       {
13597         EL_MM_PACMAN_UP,
13598         EL_MM_PACMAN_RIGHT,
13599         EL_MM_PACMAN_DOWN,
13600         EL_MM_PACMAN_LEFT
13601       },
13602       {
13603         EL_DF_LASER_UP,
13604         EL_DF_LASER_RIGHT,
13605         EL_DF_LASER_DOWN,
13606         EL_DF_LASER_LEFT
13607       },
13608       {
13609         EL_DF_RECEIVER_UP,
13610         EL_DF_RECEIVER_RIGHT,
13611         EL_DF_RECEIVER_DOWN,
13612         EL_DF_RECEIVER_LEFT
13613       },
13614       {
13615         EL_DF_SLOPE_1,
13616         EL_DF_SLOPE_4,
13617         EL_DF_SLOPE_3,
13618         EL_DF_SLOPE_2
13619       },
13620
13621       {
13622         -1,
13623       },
13624     };
13625     static int rotatable_elements_8[][8] =
13626     {
13627       {
13628         EL_DF_STEEL_GRID_FIXED_1,
13629         EL_DF_STEEL_GRID_FIXED_8,
13630         EL_DF_STEEL_GRID_FIXED_7,
13631         EL_DF_STEEL_GRID_FIXED_6,
13632         EL_DF_STEEL_GRID_FIXED_5,
13633         EL_DF_STEEL_GRID_FIXED_4,
13634         EL_DF_STEEL_GRID_FIXED_3,
13635         EL_DF_STEEL_GRID_FIXED_2
13636       },
13637       {
13638         EL_DF_WOODEN_GRID_FIXED_1,
13639         EL_DF_WOODEN_GRID_FIXED_8,
13640         EL_DF_WOODEN_GRID_FIXED_7,
13641         EL_DF_WOODEN_GRID_FIXED_6,
13642         EL_DF_WOODEN_GRID_FIXED_5,
13643         EL_DF_WOODEN_GRID_FIXED_4,
13644         EL_DF_WOODEN_GRID_FIXED_3,
13645         EL_DF_WOODEN_GRID_FIXED_2
13646       },
13647       {
13648         EL_DF_STEEL_GRID_ROTATING_1,
13649         EL_DF_STEEL_GRID_ROTATING_8,
13650         EL_DF_STEEL_GRID_ROTATING_7,
13651         EL_DF_STEEL_GRID_ROTATING_6,
13652         EL_DF_STEEL_GRID_ROTATING_5,
13653         EL_DF_STEEL_GRID_ROTATING_4,
13654         EL_DF_STEEL_GRID_ROTATING_3,
13655         EL_DF_STEEL_GRID_ROTATING_2
13656       },
13657       {
13658         EL_DF_WOODEN_GRID_ROTATING_1,
13659         EL_DF_WOODEN_GRID_ROTATING_8,
13660         EL_DF_WOODEN_GRID_ROTATING_7,
13661         EL_DF_WOODEN_GRID_ROTATING_6,
13662         EL_DF_WOODEN_GRID_ROTATING_5,
13663         EL_DF_WOODEN_GRID_ROTATING_4,
13664         EL_DF_WOODEN_GRID_ROTATING_3,
13665         EL_DF_WOODEN_GRID_ROTATING_2
13666       },
13667
13668       {
13669         -1,
13670       },
13671     };
13672     static int rotatable_elements_16[][16] =
13673     {
13674       {
13675         EL_MM_MIRROR_1,
13676         EL_MM_MIRROR_16,
13677         EL_MM_MIRROR_15,
13678         EL_MM_MIRROR_14,
13679         EL_MM_MIRROR_13,
13680         EL_MM_MIRROR_12,
13681         EL_MM_MIRROR_11,
13682         EL_MM_MIRROR_10,
13683         EL_MM_MIRROR_9,
13684         EL_MM_MIRROR_8,
13685         EL_MM_MIRROR_7,
13686         EL_MM_MIRROR_6,
13687         EL_MM_MIRROR_5,
13688         EL_MM_MIRROR_4,
13689         EL_MM_MIRROR_3,
13690         EL_MM_MIRROR_2
13691       },
13692       {
13693         EL_MM_TELEPORTER_5,
13694         EL_MM_TELEPORTER_4,
13695         EL_MM_TELEPORTER_3,
13696         EL_MM_TELEPORTER_2,
13697         EL_MM_TELEPORTER_1,
13698         EL_MM_TELEPORTER_16,
13699         EL_MM_TELEPORTER_15,
13700         EL_MM_TELEPORTER_14,
13701         EL_MM_TELEPORTER_13,
13702         EL_MM_TELEPORTER_12,
13703         EL_MM_TELEPORTER_11,
13704         EL_MM_TELEPORTER_10,
13705         EL_MM_TELEPORTER_9,
13706         EL_MM_TELEPORTER_8,
13707         EL_MM_TELEPORTER_7,
13708         EL_MM_TELEPORTER_6
13709       },
13710       {
13711         EL_MM_TELEPORTER_RED_5,
13712         EL_MM_TELEPORTER_RED_4,
13713         EL_MM_TELEPORTER_RED_3,
13714         EL_MM_TELEPORTER_RED_2,
13715         EL_MM_TELEPORTER_RED_1,
13716         EL_MM_TELEPORTER_RED_16,
13717         EL_MM_TELEPORTER_RED_15,
13718         EL_MM_TELEPORTER_RED_14,
13719         EL_MM_TELEPORTER_RED_13,
13720         EL_MM_TELEPORTER_RED_12,
13721         EL_MM_TELEPORTER_RED_11,
13722         EL_MM_TELEPORTER_RED_10,
13723         EL_MM_TELEPORTER_RED_9,
13724         EL_MM_TELEPORTER_RED_8,
13725         EL_MM_TELEPORTER_RED_7,
13726         EL_MM_TELEPORTER_RED_6
13727       },
13728       {
13729         EL_MM_TELEPORTER_YELLOW_5,
13730         EL_MM_TELEPORTER_YELLOW_4,
13731         EL_MM_TELEPORTER_YELLOW_3,
13732         EL_MM_TELEPORTER_YELLOW_2,
13733         EL_MM_TELEPORTER_YELLOW_1,
13734         EL_MM_TELEPORTER_YELLOW_16,
13735         EL_MM_TELEPORTER_YELLOW_15,
13736         EL_MM_TELEPORTER_YELLOW_14,
13737         EL_MM_TELEPORTER_YELLOW_13,
13738         EL_MM_TELEPORTER_YELLOW_12,
13739         EL_MM_TELEPORTER_YELLOW_11,
13740         EL_MM_TELEPORTER_YELLOW_10,
13741         EL_MM_TELEPORTER_YELLOW_9,
13742         EL_MM_TELEPORTER_YELLOW_8,
13743         EL_MM_TELEPORTER_YELLOW_7,
13744         EL_MM_TELEPORTER_YELLOW_6
13745       },
13746       {
13747         EL_MM_TELEPORTER_GREEN_5,
13748         EL_MM_TELEPORTER_GREEN_4,
13749         EL_MM_TELEPORTER_GREEN_3,
13750         EL_MM_TELEPORTER_GREEN_2,
13751         EL_MM_TELEPORTER_GREEN_1,
13752         EL_MM_TELEPORTER_GREEN_16,
13753         EL_MM_TELEPORTER_GREEN_15,
13754         EL_MM_TELEPORTER_GREEN_14,
13755         EL_MM_TELEPORTER_GREEN_13,
13756         EL_MM_TELEPORTER_GREEN_12,
13757         EL_MM_TELEPORTER_GREEN_11,
13758         EL_MM_TELEPORTER_GREEN_10,
13759         EL_MM_TELEPORTER_GREEN_9,
13760         EL_MM_TELEPORTER_GREEN_8,
13761         EL_MM_TELEPORTER_GREEN_7,
13762         EL_MM_TELEPORTER_GREEN_6
13763       },
13764       {
13765         EL_MM_TELEPORTER_BLUE_5,
13766         EL_MM_TELEPORTER_BLUE_4,
13767         EL_MM_TELEPORTER_BLUE_3,
13768         EL_MM_TELEPORTER_BLUE_2,
13769         EL_MM_TELEPORTER_BLUE_1,
13770         EL_MM_TELEPORTER_BLUE_16,
13771         EL_MM_TELEPORTER_BLUE_15,
13772         EL_MM_TELEPORTER_BLUE_14,
13773         EL_MM_TELEPORTER_BLUE_13,
13774         EL_MM_TELEPORTER_BLUE_12,
13775         EL_MM_TELEPORTER_BLUE_11,
13776         EL_MM_TELEPORTER_BLUE_10,
13777         EL_MM_TELEPORTER_BLUE_9,
13778         EL_MM_TELEPORTER_BLUE_8,
13779         EL_MM_TELEPORTER_BLUE_7,
13780         EL_MM_TELEPORTER_BLUE_6
13781       },
13782       {
13783         EL_MM_POLARIZER_1,
13784         EL_MM_POLARIZER_16,
13785         EL_MM_POLARIZER_15,
13786         EL_MM_POLARIZER_14,
13787         EL_MM_POLARIZER_13,
13788         EL_MM_POLARIZER_12,
13789         EL_MM_POLARIZER_11,
13790         EL_MM_POLARIZER_10,
13791         EL_MM_POLARIZER_9,
13792         EL_MM_POLARIZER_8,
13793         EL_MM_POLARIZER_7,
13794         EL_MM_POLARIZER_6,
13795         EL_MM_POLARIZER_5,
13796         EL_MM_POLARIZER_4,
13797         EL_MM_POLARIZER_3,
13798         EL_MM_POLARIZER_2
13799       },
13800       {
13801         EL_DF_MIRROR_1,
13802         EL_DF_MIRROR_16,
13803         EL_DF_MIRROR_15,
13804         EL_DF_MIRROR_14,
13805         EL_DF_MIRROR_13,
13806         EL_DF_MIRROR_12,
13807         EL_DF_MIRROR_11,
13808         EL_DF_MIRROR_10,
13809         EL_DF_MIRROR_9,
13810         EL_DF_MIRROR_8,
13811         EL_DF_MIRROR_7,
13812         EL_DF_MIRROR_6,
13813         EL_DF_MIRROR_5,
13814         EL_DF_MIRROR_4,
13815         EL_DF_MIRROR_3,
13816         EL_DF_MIRROR_2
13817       },
13818       {
13819         EL_DF_MIRROR_ROTATING_1,
13820         EL_DF_MIRROR_ROTATING_16,
13821         EL_DF_MIRROR_ROTATING_15,
13822         EL_DF_MIRROR_ROTATING_14,
13823         EL_DF_MIRROR_ROTATING_13,
13824         EL_DF_MIRROR_ROTATING_12,
13825         EL_DF_MIRROR_ROTATING_11,
13826         EL_DF_MIRROR_ROTATING_10,
13827         EL_DF_MIRROR_ROTATING_9,
13828         EL_DF_MIRROR_ROTATING_8,
13829         EL_DF_MIRROR_ROTATING_7,
13830         EL_DF_MIRROR_ROTATING_6,
13831         EL_DF_MIRROR_ROTATING_5,
13832         EL_DF_MIRROR_ROTATING_4,
13833         EL_DF_MIRROR_ROTATING_3,
13834         EL_DF_MIRROR_ROTATING_2
13835       },
13836       {
13837         EL_DF_MIRROR_FIXED_1,
13838         EL_DF_MIRROR_FIXED_16,
13839         EL_DF_MIRROR_FIXED_15,
13840         EL_DF_MIRROR_FIXED_14,
13841         EL_DF_MIRROR_FIXED_13,
13842         EL_DF_MIRROR_FIXED_12,
13843         EL_DF_MIRROR_FIXED_11,
13844         EL_DF_MIRROR_FIXED_10,
13845         EL_DF_MIRROR_FIXED_9,
13846         EL_DF_MIRROR_FIXED_8,
13847         EL_DF_MIRROR_FIXED_7,
13848         EL_DF_MIRROR_FIXED_6,
13849         EL_DF_MIRROR_FIXED_5,
13850         EL_DF_MIRROR_FIXED_4,
13851         EL_DF_MIRROR_FIXED_3,
13852         EL_DF_MIRROR_FIXED_2
13853       },
13854
13855       {
13856         -1,
13857       },
13858     };
13859     int i, j;
13860
13861     for (i = 0; swappable_elements[i][0] != -1; i++)
13862     {
13863       int element1 = swappable_elements[i][0];
13864       int element2 = swappable_elements[i][1];
13865
13866       if (old_element == element1 || old_element == element2)
13867         new_element = (old_element == element1 ? element2 : element1);
13868     }
13869
13870     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13871     {
13872       for (j = 0; j < 4; j++)
13873       {
13874         int element = rotatable_elements_4[i][j];
13875
13876         if (old_element == element)
13877           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13878                          button == 2 ? rotatable_elements_4[i][0]           :
13879                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13880                          old_element);
13881       }
13882     }
13883
13884     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13885     {
13886       for (j = 0; j < 8; j++)
13887       {
13888         int element = rotatable_elements_8[i][j];
13889
13890         if (old_element == element)
13891           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13892                          button == 2 ? rotatable_elements_8[i][0]           :
13893                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13894                          old_element);
13895       }
13896     }
13897
13898     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13899     {
13900       for (j = 0; j < 16; j++)
13901       {
13902         int element = rotatable_elements_16[i][j];
13903
13904         if (old_element == element)
13905           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13906                          button == 2 ? rotatable_elements_16[i][0]             :
13907                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13908                          old_element);
13909       }
13910     }
13911
13912     if (old_element != new_element)
13913     {
13914       int max_infotext_len = getMaxInfoTextLength();
13915       char infotext[MAX_OUTPUT_LINESIZE + 1];
13916
13917       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13918       infotext[max_infotext_len] = '\0';
13919
13920       ClearEditorGadgetInfoText();
13921
13922       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13923                 infotext);
13924     }
13925   }
13926
13927   if (IS_MM_WALL_EDITOR(new_element))
13928     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13929   else
13930     SetElementSimple(x, y, new_element, change_level);
13931
13932   last_x = x;
13933   last_y = y;
13934 }
13935
13936 static void ResetIntelliDraw(void)
13937 {
13938   int x, y;
13939
13940   for (x = 0; x < lev_fieldx; x++)
13941     for (y = 0; y < lev_fieldy; y++)
13942       IntelliDrawBuffer[x][y] = Tile[x][y];
13943
13944   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13945 }
13946
13947 static boolean draw_mode_hires = FALSE;
13948
13949 static boolean isHiresTileElement(int element)
13950 {
13951   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13952 }
13953
13954 static boolean isHiresDrawElement(int element)
13955 {
13956   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13957 }
13958
13959 static int numHiresTiles(int element)
13960 {
13961   if (IS_MM_WALL(element))
13962     return get_number_of_bits(MM_WALL_BITS(element));
13963
13964   return 1;
13965 }
13966
13967 static void SetDrawModeHiRes(int element)
13968 {
13969   draw_mode_hires =
13970     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13971      isHiresDrawElement(element));
13972 }
13973
13974 static boolean getDrawModeHiRes(void)
13975 {
13976   return draw_mode_hires;
13977 }
13978
13979 static int getLoResScreenPos(int pos)
13980 {
13981   return (getDrawModeHiRes() ? pos / 2 : pos);
13982 }
13983
13984 static int getLoResScreenMod(int pos)
13985 {
13986   return (getDrawModeHiRes() ? pos % 2 : 0);
13987 }
13988
13989 static void SetElementExt(int x, int y, int dx, int dy, int element,
13990                           boolean change_level, int button)
13991 {
13992   if (element < 0)
13993     SetElementSimple(x, y, Tile[x][y], change_level);
13994   else if (GetKeyModState() & KMOD_Shift)
13995     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
13996   else
13997     SetElementSimpleExt(x, y, dx, dy, element, change_level);
13998 }
13999
14000 static void SetElement(int x, int y, int element)
14001 {
14002   SetElementExt(x, y, 0, 0, element, TRUE, -1);
14003 }
14004
14005 static void SetElementButton(int x, int y, int dx, int dy, int element,
14006                              int button)
14007 {
14008   SetElementExt(x, y, dx, dy, element, TRUE, button);
14009 }
14010
14011 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
14012 {
14013   int lx = getLoResScreenPos(sx2) + level_xpos;
14014   int ly = getLoResScreenPos(sy2) + level_ypos;
14015   int dx = getLoResScreenMod(sx2);
14016   int dy = getLoResScreenMod(sy2);
14017
14018   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
14019 }
14020
14021 static void SetLevelElementHiRes(int lx2, int ly2, int element)
14022 {
14023   int lx = lx2 / 2;
14024   int ly = ly2 / 2;
14025   int dx = lx2 % 2;
14026   int dy = ly2 % 2;
14027
14028   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
14029 }
14030
14031 static int getLevelElementHiRes(int lx2, int ly2)
14032 {
14033   int lx = lx2 / 2;
14034   int ly = ly2 / 2;
14035   int dx = lx2 % 2;
14036   int dy = ly2 % 2;
14037   int element = Tile[lx][ly];
14038   unsigned int bitmask = (dx + 1) << (dy * 2);
14039
14040   if (IS_MM_WALL(element))
14041   {
14042     if (element & bitmask)
14043       return map_mm_wall_element(element);
14044     else
14045       return EL_EMPTY;
14046   }
14047
14048   return element;
14049 }
14050
14051 static void DrawLineElement(int x, int y, int element, boolean change_level)
14052 {
14053   SetElementHiRes(x, y, element, change_level);
14054 }
14055
14056 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
14057                      int element, boolean change_level)
14058 {
14059   int xsize = ABS(to_x - from_x);
14060   int ysize = ABS(to_y - from_y);
14061   int dx = (to_x < from_x ? -1 : +1);
14062   int dy = (to_y < from_y ? -1 : +1);
14063   int i;
14064
14065   if (from_y == to_y)                   // horizontal line
14066   {
14067     for (i = 0; i <= xsize; i++)
14068       DrawLineElement(from_x + i * dx, from_y, element, change_level);
14069   }
14070   else if (from_x == to_x)              // vertical line
14071   {
14072     for (i = 0; i <= ysize; i++)
14073       DrawLineElement(from_x, from_y + i * dy, element, change_level);
14074   }
14075   else                                  // diagonal line
14076   {
14077     if (ysize < xsize)                  // a < 1
14078     {
14079       float a = (float)ysize / (float)xsize;
14080
14081       for (i = 0; i <= xsize; i++)
14082       {
14083         int x = dx * i;
14084         int y = dy * (int)(a * i + 0.5);
14085
14086         DrawLineElement(from_x + x, from_y + y, element, change_level);
14087       }
14088     }
14089     else                                // a >= 1
14090     {
14091       float a = (float)xsize / (float)ysize;
14092
14093       for (i = 0; i <= ysize; i++)
14094       {
14095         int x = dx * (int)(a * i + 0.5);
14096         int y = dy * i;
14097
14098         DrawLineElement(from_x + x, from_y + y, element, change_level);
14099       }
14100     }
14101   }
14102 }
14103
14104 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
14105                     int element, boolean change_level)
14106 {
14107   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
14108   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
14109   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
14110   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
14111 }
14112
14113 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
14114                           int element, boolean change_level)
14115 {
14116   int y;
14117
14118   if (from_y > to_y)
14119     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
14120
14121   for (y = from_y; y <= to_y; y++)
14122     DrawLine(from_x, y, to_x, y, element, change_level);
14123 }
14124
14125 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
14126                        int element, boolean change_level)
14127 {
14128   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
14129   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
14130   int len_x = ABS(to_x - from_x);
14131   int len_y = ABS(to_y - from_y);
14132   int radius, x, y;
14133
14134   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
14135
14136   // not optimal (some points get drawn twice) but simple,
14137   // and fast enough for the few points we are drawing
14138
14139   for (x = 0; x <= radius; x++)
14140   {
14141     int sx, sy, sx2, sy2, lx, ly;
14142
14143     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
14144
14145     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14146     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14147     sx = getLoResScreenPos(sx2);
14148     sy = getLoResScreenPos(sy2);
14149     lx = sx + level_xpos;
14150     ly = sy + level_ypos;
14151
14152     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14153       DrawLineElement(sx2, sy2, element, change_level);
14154   }
14155
14156   for (y = 0; y <= radius; y++)
14157   {
14158     int sx, sy, sx2, sy2, lx, ly;
14159
14160     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14161
14162     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14163     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14164     sx = getLoResScreenPos(sx2);
14165     sy = getLoResScreenPos(sy2);
14166     lx = sx + level_xpos;
14167     ly = sy + level_ypos;
14168
14169     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14170       DrawLineElement(sx2, sy2, element, change_level);
14171   }
14172 }
14173
14174 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14175                     int element, boolean change_level)
14176 {
14177   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14178   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14179
14180   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14181 }
14182
14183 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14184
14185 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14186 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14187                        int element, boolean change_level)
14188 {
14189   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14190   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14191   int mirror_to_x2 = from_x - (to_x2 - from_x);
14192   int mirror_to_y2 = from_y - (to_y2 - from_y);
14193
14194   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14195   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14196   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14197   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14198 }
14199 #endif
14200
14201 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14202 {
14203   int from_sx, from_sy;
14204   int to_sx, to_sy;
14205
14206   if (from_x > to_x)
14207     swap_numbers(&from_x, &to_x);
14208
14209   if (from_y > to_y)
14210     swap_numbers(&from_y, &to_y);
14211
14212   from_sx = SX + from_x * ed_tilesize;
14213   from_sy = SY + from_y * ed_tilesize;
14214   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14215   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14216
14217   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14218   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14219   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14220   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14221
14222   if (from_x == to_x && from_y == to_y)
14223     MarkTileDirty(from_x/2, from_y/2);
14224   else
14225     redraw_mask |= REDRAW_FIELD;
14226 }
14227
14228 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14229                         int element, boolean change_level)
14230 {
14231   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14232 }
14233
14234 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14235                        int element, boolean change_level)
14236 {
14237   if (element == -1 || change_level)
14238     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14239   else
14240     DrawAreaBorder(from_x, from_y, to_x, to_y);
14241 }
14242
14243 // values for CopyBrushExt()
14244 #define CB_AREA_TO_BRUSH                0
14245 #define CB_BRUSH_TO_CURSOR              1
14246 #define CB_BRUSH_TO_LEVEL               2
14247 #define CB_DELETE_OLD_CURSOR            3
14248 #define CB_DUMP_BRUSH                   4
14249 #define CB_DUMP_BRUSH_SMALL             5
14250 #define CB_CLIPBOARD_TO_BRUSH           6
14251 #define CB_BRUSH_TO_CLIPBOARD           7
14252 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14253 #define CB_UPDATE_BRUSH_POSITION        9
14254 #define CB_FLIP_BRUSH_X                 10
14255 #define CB_FLIP_BRUSH_Y                 11
14256 #define CB_FLIP_BRUSH_XY                12
14257
14258 #define MAX_CB_PART_SIZE        10
14259 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14260 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14261 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14262                                  MAX_CB_NUM_LINES *     \
14263                                  MAX_CB_PART_SIZE)
14264
14265 static int getFlippedTileExt(int map[], int element)
14266 {
14267   int i;
14268
14269   for (i = 0; map[i] != -1; i++)
14270     if (map[i] == element)
14271       return map[i ^ 1];        // get flipped element by flipping LSB of index
14272
14273   return element;
14274 }
14275
14276 static int getFlippedTileX(int element)
14277 {
14278   int map[] =
14279   {
14280     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14281     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14282     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14283     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14284     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14285     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14286     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14287     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14288     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14289     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14290     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14291     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14292     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14293     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14294     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14295     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14296     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14297     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14298     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14299     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14300     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14301     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14302     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14303     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14304     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14305     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14306     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14307     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14308     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14309     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14310
14311     -1
14312   };
14313
14314   return getFlippedTileExt(map, element);
14315 }
14316
14317 static int getFlippedTileY(int element)
14318 {
14319   int map[] =
14320   {
14321     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14322     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14323     EL_BUG_UP,                          EL_BUG_DOWN,
14324     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14325     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14326     EL_ARROW_UP,                        EL_ARROW_DOWN,
14327     EL_MOLE_UP,                         EL_MOLE_DOWN,
14328     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14329     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14330     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14331     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14332     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14333     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14334     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14335     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14336     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14337     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14338     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14339     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14340     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14341     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14342     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14343     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14344     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14345
14346     -1
14347   };
14348
14349   return getFlippedTileExt(map, element);
14350 }
14351
14352 static int getFlippedTileXY(int element)
14353 {
14354   int map[] =
14355   {
14356     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14357     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14358     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14359     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14360     EL_BUG_LEFT,                        EL_BUG_UP,
14361     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14362     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14363     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14364     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14365     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14366     EL_ARROW_LEFT,                      EL_ARROW_UP,
14367     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14368     EL_MOLE_LEFT,                       EL_MOLE_UP,
14369     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14370     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14371     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14372     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14373     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14374     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14375     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14376     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14377     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14378     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14379     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14380     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14381     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14382     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14383     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14384     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14385     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14386     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14387     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14388     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14389     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14390     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14391     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14392     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14393     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14394     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14395     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14396     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14397     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14398
14399     -1
14400   };
14401
14402   return getFlippedTileExt(map, element);
14403 }
14404
14405 static int getFlippedTile(int element, int mode)
14406 {
14407   if (IS_MM_ELEMENT(element))
14408   {
14409     // get MM game element
14410     element = map_element_RND_to_MM(element);
14411
14412     // get flipped game element
14413     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14414                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14415                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14416                element);
14417
14418     // get RND game element again
14419     element = map_element_MM_to_RND(element);
14420   }
14421   else
14422   {
14423     // get flipped game element
14424     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14425                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14426                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14427                element);
14428   }
14429
14430   return element;
14431 }
14432
14433 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14434 {
14435   // flip tiles
14436   short tile1_flipped = getFlippedTile(*tile1, mode);
14437   short tile2_flipped = getFlippedTile(*tile2, mode);
14438
14439   // swap tiles
14440   *tile1 = tile2_flipped;
14441   *tile2 = tile1_flipped;
14442 }
14443
14444 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14445 {
14446   DrawLineElement(sx, sy, element, change_level);
14447 }
14448
14449 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14450                          int button, int mode)
14451 {
14452   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14453   static int brush_width, brush_height;
14454   static int last_cursor_x = -1, last_cursor_y = -1;
14455   static boolean delete_old_brush = FALSE;
14456   int new_element = BUTTON_ELEMENT(button);
14457   int x, y;
14458
14459   if (mode == CB_DUMP_BRUSH ||
14460       mode == CB_DUMP_BRUSH_SMALL ||
14461       mode == CB_BRUSH_TO_CLIPBOARD ||
14462       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14463   {
14464     if (edit_mode != ED_MODE_DRAWING)
14465       return;
14466
14467     char part[MAX_CB_PART_SIZE + 1] = "";
14468     char text[MAX_CB_TEXT_SIZE + 1] = "";
14469     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14470     int height = (draw_with_brush ? brush_height : lev_fieldy);
14471     char *format = "%s%03d";
14472
14473     for (y = 0; y < height; y++)
14474       for (x = 0; x < width; x++)
14475         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14476           format = "%s%04d";
14477
14478     for (y = 0; y < height; y++)
14479     {
14480       for (x = 0; x < width; x++)
14481       {
14482         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14483         char *prefix = (mode == CB_DUMP_BRUSH ||
14484                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14485
14486         if (element >= NUM_FILE_ELEMENTS)
14487           element = EL_UNKNOWN;
14488
14489         // copy brush to level sketch text buffer for the R'n'D forum:
14490         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14491         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14492         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14493         strcat(text, part);
14494       }
14495
14496       strcat(text, "\n");
14497     }
14498
14499     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14500         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14501       SDL_SetClipboardText(text);
14502     else
14503       Print("%s", text);        // print brush data to console and log file
14504
14505     return;
14506   }
14507
14508   if (mode == CB_CLIPBOARD_TO_BRUSH)
14509   {
14510     if (edit_mode != ED_MODE_DRAWING)
14511       return;
14512
14513     if (!SDL_HasClipboardText())
14514     {
14515       Request("Clipboard is empty!", REQ_CONFIRM);
14516
14517       return;
14518     }
14519
14520     boolean copy_to_brush = (draw_with_brush ||
14521                              drawing_function == GADGET_ID_GRAB_BRUSH);
14522
14523     // this will delete the old brush, if already drawing with a brush
14524     if (copy_to_brush)
14525       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14526
14527     // initialization is required for "odd" (incomplete) clipboard content
14528     for (x = 0; x < MAX_LEV_FIELDX; x++)
14529       for (y = 0; y < MAX_LEV_FIELDY; y++)
14530         brush_buffer[x][y] = EL_EMPTY;
14531
14532     brush_width  = 0;
14533     brush_height = 0;
14534     x = 0;
14535     y = 0;
14536
14537     char *clipboard_text = SDL_GetClipboardText();
14538     char *ptr = clipboard_text;
14539     boolean allow_new_row = FALSE;
14540     boolean stop = FALSE;
14541
14542     while (*ptr && !stop)
14543     {
14544       boolean prefix_found = FALSE;
14545       boolean start_new_row = FALSE;
14546
14547       // level sketch element number prefixes (may be multi-byte characters)
14548       char *prefix_list[] = { "`", "¸" };
14549       int i;
14550
14551       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14552       {
14553         char *prefix = prefix_list[i];
14554
14555         // check if string is large enough for prefix
14556         if (strlen(ptr) < strlen(prefix))
14557         {
14558           stop = TRUE;
14559
14560           break;
14561         }
14562
14563         // check if string starts with prefix
14564         if (strPrefix(ptr, prefix))
14565         {
14566           ptr += strlen(prefix);
14567
14568           prefix_found = TRUE;
14569
14570           break;
14571         }
14572       }
14573
14574       // check if prefix found and followed by (at least) three digits
14575       if (prefix_found &&
14576           strlen(ptr) >= 3 &&
14577           ptr[0] >= '0' && ptr[0] <= '9' &&
14578           ptr[1] >= '0' && ptr[1] <= '9' &&
14579           ptr[2] >= '0' && ptr[2] <= '9')
14580       {
14581         int element = ((ptr[0] - '0') * 100 +
14582                        (ptr[1] - '0') * 10 +
14583                        (ptr[2] - '0'));
14584
14585         ptr += 3;
14586
14587         // level sketch element number might consist of four digits
14588         if (ptr[0] >= '0' && ptr[0] <= '9')
14589         {
14590           element = element * 10 + (ptr[0] - '0');
14591           ptr++;
14592         }
14593
14594         // remap some (historic, now obsolete) elements
14595         element = getMappedElement(element);
14596
14597         if (element >= NUM_FILE_ELEMENTS)
14598           element = EL_UNKNOWN;
14599
14600         brush_buffer[x][y] = element;
14601
14602         brush_width  = MAX(x + 1, brush_width);
14603         brush_height = MAX(y + 1, brush_height);
14604
14605         x++;
14606
14607         if (x >= MAX_LEV_FIELDX)
14608           start_new_row = TRUE;
14609
14610         allow_new_row = TRUE;
14611       }
14612       else
14613       {
14614         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14615           start_new_row = TRUE;
14616
14617         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14618       }
14619
14620       if (start_new_row)
14621       {
14622         x = 0;
14623         y++;
14624
14625         if (y >= MAX_LEV_FIELDY)
14626           stop = TRUE;
14627
14628         allow_new_row = FALSE;
14629       }
14630     }
14631
14632     SDL_free(clipboard_text);
14633
14634     if (brush_width == 0 || brush_height == 0)
14635     {
14636       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14637
14638       return;
14639     }
14640
14641     if (copy_to_brush)
14642     {
14643       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14644       int mx, my;
14645
14646       SDL_GetMouseState(&mx, &my);
14647
14648       // if inside drawing area, activate and draw brush at last mouse position
14649       if (mx >= gi->x && mx < gi->x + gi->width &&
14650           my >= gi->y && my < gi->y + gi->height)
14651         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14652
14653       draw_with_brush = TRUE;
14654     }
14655     else
14656     {
14657       char request[100];
14658
14659       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14660               brush_width, brush_height);
14661
14662       if (!Request(request, REQ_ASK))
14663         return;
14664
14665       for (x = 0; x < MAX_LEV_FIELDX; x++)
14666         for (y = 0; y < MAX_LEV_FIELDY; y++)
14667           Tile[x][y] = brush_buffer[x][y];
14668
14669       lev_fieldx = level.fieldx = brush_width;
14670       lev_fieldy = level.fieldy = brush_height;
14671
14672       boolean use_bd_engine = TRUE;
14673       boolean use_em_engine = TRUE;
14674       boolean use_sp_engine = TRUE;
14675       boolean use_mm_engine = TRUE;
14676
14677       for (x = 0; x < MAX_LEV_FIELDX; x++)
14678       {
14679         for (y = 0; y < MAX_LEV_FIELDY; y++)
14680         {
14681           int element = Tile[x][y];
14682
14683           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14684             use_bd_engine = FALSE;
14685
14686           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14687             use_em_engine = FALSE;
14688
14689           if (!IS_SP_ELEMENT(element))
14690             use_sp_engine = FALSE;
14691
14692           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14693             use_mm_engine = FALSE;
14694         }
14695       }
14696
14697       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14698                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14699                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14700                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14701                                 GAME_ENGINE_TYPE_RND);
14702
14703       // update element selection list
14704       ReinitializeElementList();
14705       ModifyEditorElementList();
14706
14707       SetBorderElement();
14708
14709       DrawEditModeWindow();
14710       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14711     }
14712
14713     return;
14714   }
14715
14716   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14717     return;
14718
14719   if (mode == CB_AREA_TO_BRUSH)
14720   {
14721     int from_lx, from_ly;
14722
14723     if (from_x > to_x)
14724       swap_numbers(&from_x, &to_x);
14725
14726     if (from_y > to_y)
14727       swap_numbers(&from_y, &to_y);
14728
14729     brush_width = to_x - from_x + 1;
14730     brush_height = to_y - from_y + 1;
14731
14732     from_lx = from_x + level_xpos;
14733     from_ly = from_y + level_ypos;
14734
14735     for (y = 0; y < brush_height; y++)
14736     {
14737       for (x = 0; x < brush_width; x++)
14738       {
14739         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14740
14741         if (button != 1)
14742           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14743       }
14744     }
14745
14746     if (button != 1)
14747       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14748
14749     delete_old_brush = FALSE;
14750   }
14751   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14752            mode == CB_BRUSH_TO_LEVEL)
14753   {
14754     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14755     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14756     int cursor_from_x = cursor_x - brush_width / 2;
14757     int cursor_from_y = cursor_y - brush_height / 2;
14758     int border_from_x = cursor_x, border_from_y = cursor_y;
14759     int border_to_x = cursor_x, border_to_y = cursor_y;
14760
14761     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14762       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14763
14764     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14765         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14766     {
14767       delete_old_brush = FALSE;
14768
14769       return;
14770     }
14771
14772     for (y = 0; y < brush_height; y++)
14773     {
14774       for (x = 0; x < brush_width; x++)
14775       {
14776         int sx = cursor_from_x + x;
14777         int sy = cursor_from_y + y;
14778         int lx = sx + level_xpos;
14779         int ly = sy + level_ypos;
14780         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14781         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14782                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14783                        brush_buffer[x][y] : new_element);
14784
14785         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14786         {
14787           if (sx < border_from_x)
14788             border_from_x = sx;
14789           else if (sx > border_to_x)
14790             border_to_x = sx;
14791           if (sy < border_from_y)
14792             border_from_y = sy;
14793           else if (sy > border_to_y)
14794             border_to_y = sy;
14795
14796           DrawBrushElement(sx, sy, element, change_level);
14797         }
14798       }
14799     }
14800
14801     if (mode != CB_DELETE_OLD_CURSOR)
14802       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14803
14804     last_cursor_x = cursor_x;
14805     last_cursor_y = cursor_y;
14806
14807     delete_old_brush = TRUE;
14808   }
14809   else if (mode == CB_FLIP_BRUSH_X)
14810   {
14811     for (y = 0; y < brush_height; y++)
14812       for (x = 0; x < (brush_width + 1) / 2; x++)
14813         SwapFlippedTiles(&brush_buffer[x][y],
14814                          &brush_buffer[brush_width - x - 1][y], mode);
14815
14816     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14817   }
14818   else if (mode == CB_FLIP_BRUSH_Y)
14819   {
14820     for (y = 0; y < (brush_height + 1) / 2; y++)
14821       for (x = 0; x < brush_width; x++)
14822         SwapFlippedTiles(&brush_buffer[x][y],
14823                          &brush_buffer[x][brush_height - y - 1], mode);
14824
14825     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14826   }
14827   else if (mode == CB_FLIP_BRUSH_XY)
14828   {
14829     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14830
14831     for (y = 0; y < MAX(brush_width, brush_height); y++)
14832       for (x = 0; x <= y; x++)
14833         SwapFlippedTiles(&brush_buffer[x][y],
14834                          &brush_buffer[y][x], mode);
14835
14836     swap_numbers(&brush_width, &brush_height);
14837
14838     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14839   }
14840
14841   if (mode == CB_UPDATE_BRUSH_POSITION)
14842   {
14843     last_cursor_x = from_x;
14844     last_cursor_y = from_y;
14845   }
14846 }
14847
14848 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14849                             int button)
14850 {
14851   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14852 }
14853
14854 static void CopyBrushToLevel(int x, int y, int button)
14855 {
14856   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14857 }
14858
14859 static void CopyBrushToCursor(int x, int y)
14860 {
14861   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14862 }
14863
14864 static void UpdateBrushPosition(int x, int y)
14865 {
14866   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14867 }
14868
14869 static void DeleteBrushFromCursor(void)
14870 {
14871   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14872 }
14873
14874 static void FlipBrushX(void)
14875 {
14876   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14877 }
14878
14879 static void FlipBrushY(void)
14880 {
14881   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14882 }
14883
14884 static void RotateBrush(void)
14885 {
14886   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14887   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14888 }
14889
14890 void DumpBrush(void)
14891 {
14892   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14893 }
14894
14895 void DumpBrush_Small(void)
14896 {
14897   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14898 }
14899
14900 void CopyClipboardToBrush(void)
14901 {
14902   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14903 }
14904
14905 void CopyBrushToClipboard(void)
14906 {
14907   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14908 }
14909
14910 void CopyBrushToClipboard_Small(void)
14911 {
14912   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14913 }
14914
14915 void UndoLevelEditorOperation(void)
14916 {
14917   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14918 }
14919
14920 void RedoLevelEditorOperation(void)
14921 {
14922   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14923 }
14924
14925 static void FloodFill(int from_x, int from_y, int fill_element)
14926 {
14927   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14928 }
14929
14930 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14931 {
14932   int from_x = from_sx2 + 2 * level_xpos;
14933   int from_y = from_sy2 + 2 * level_ypos;
14934   int max_fillx = lev_fieldx * 2;
14935   int max_filly = lev_fieldy * 2;
14936   short Fill[max_fillx][max_filly];
14937   int x, y;
14938
14939   for (x = 0; x < max_fillx; x++)
14940     for (y = 0; y < max_filly; y++)
14941       Fill[x][y] = getLevelElementHiRes(x, y);
14942
14943   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14944                     Fill, max_fillx, max_filly);
14945
14946   for (x = 0; x < max_fillx; x++)
14947     for (y = 0; y < max_filly; y++)
14948       if (Fill[x][y] == fill_element)
14949         SetLevelElementHiRes(x, y, Fill[x][y]);
14950 }
14951
14952 // values for DrawLevelText() modes
14953 #define TEXT_INIT               0
14954 #define TEXT_SETCURSOR          1
14955 #define TEXT_WRITECHAR          2
14956 #define TEXT_BACKSPACE          3
14957 #define TEXT_NEWLINE            4
14958 #define TEXT_END                5
14959 #define TEXT_QUERY_TYPING       6
14960
14961 static int DrawLevelText(int sx, int sy, char letter, int mode)
14962 {
14963   static short delete_buffer[MAX_LEV_FIELDX];
14964   static int start_sx;
14965   static int last_sx, last_sy;
14966   static boolean typing = FALSE;
14967   int letter_element;
14968   int lx = 0, ly = 0;
14969
14970   // map lower case letters to upper case and convert special characters
14971   if (letter >= 'a' && letter <= 'z')
14972     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
14973   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
14974     letter_element = EL_CHAR_AUMLAUT;
14975   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
14976     letter_element = EL_CHAR_OUMLAUT;
14977   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
14978     letter_element = EL_CHAR_UUMLAUT;
14979   else if (letter == '^')
14980     letter_element = EL_CHAR_COPYRIGHT;
14981   else
14982     letter_element = EL_CHAR_ASCII0 + letter;
14983
14984   if (mode != TEXT_INIT)
14985   {
14986     if (!typing)
14987       return FALSE;
14988
14989     if (mode != TEXT_SETCURSOR)
14990     {
14991       sx = last_sx;
14992       sy = last_sy;
14993     }
14994
14995     lx = last_sx + level_xpos;
14996     ly = last_sy + level_ypos;
14997   }
14998
14999   switch (mode)
15000   {
15001     case TEXT_INIT:
15002       if (typing)
15003         DrawLevelText(0, 0, 0, TEXT_END);
15004
15005       typing = TRUE;
15006       start_sx = sx;
15007       last_sx = sx;
15008       last_sy = sy;
15009       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
15010       break;
15011
15012     case TEXT_SETCURSOR:
15013       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
15014       DrawAreaBorder(sx, sy, sx, sy);
15015       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
15016                      ed_tilesize, ed_tilesize);
15017       last_sx = sx;
15018       last_sy = sy;
15019       break;
15020
15021     case TEXT_WRITECHAR:
15022       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
15023       {
15024         if (new_element1 >= EL_STEEL_CHAR_START &&
15025             new_element1 <= EL_STEEL_CHAR_END)
15026           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
15027
15028         delete_buffer[sx - start_sx] = Tile[lx][ly];
15029         Tile[lx][ly] = letter_element;
15030
15031         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
15032           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
15033         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15034           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15035         else
15036           DrawLevelText(0, 0, 0, TEXT_END);
15037
15038         level.changed = TRUE;
15039       }
15040       break;
15041
15042     case TEXT_BACKSPACE:
15043       if (sx > start_sx)
15044       {
15045         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
15046         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
15047         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
15048       }
15049       break;
15050
15051     case TEXT_NEWLINE:
15052       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15053         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15054       else
15055         DrawLevelText(0, 0, 0, TEXT_END);
15056       break;
15057
15058     case TEXT_END:
15059       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15060       DrawEditorElement(sx, sy, Tile[lx][ly]);
15061       StopTextInput();
15062       typing = FALSE;
15063       break;
15064
15065     case TEXT_QUERY_TYPING:
15066       break;
15067
15068     default:
15069       break;
15070   }
15071
15072   return typing;
15073 }
15074
15075 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
15076                           int element, boolean change_level)
15077 {
15078   int lx = sx + level_xpos;
15079   int ly = sy + level_ypos;
15080
15081   if (element == -1)
15082     DrawEditorElement(sx, sy, Tile[lx][ly]);
15083   else
15084     DrawAreaBorder(sx, sy, sx, sy);
15085 }
15086
15087 static void CheckLevelBorderElement(boolean redraw_playfield)
15088 {
15089   int last_border_element = BorderElement;
15090
15091   SetBorderElement();
15092
15093   if (redraw_playfield && BorderElement != last_border_element)
15094     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15095 }
15096
15097 static void CopyLevelToUndoBuffer(int mode)
15098 {
15099   static boolean accumulated_undo = FALSE;
15100   boolean new_undo_buffer_position = TRUE;
15101   int x, y;
15102
15103   if (undo_buffer_steps == 0)
15104     accumulated_undo = FALSE;
15105
15106   switch (mode)
15107   {
15108     case UNDO_IMMEDIATE:
15109       accumulated_undo = FALSE;
15110       break;
15111
15112     case UNDO_ACCUMULATE:
15113       if (accumulated_undo)
15114         new_undo_buffer_position = FALSE;
15115       accumulated_undo = TRUE;
15116       break;
15117
15118     default:
15119       break;
15120   }
15121
15122   if (new_undo_buffer_position)
15123   {
15124     // advance position in undo buffer ring
15125     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
15126
15127     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
15128       undo_buffer_steps++;
15129   }
15130
15131   // always reset redo buffer when storing level change into undo buffer
15132   redo_buffer_steps = 0;
15133
15134   for (x = 0; x < lev_fieldx; x++)
15135     for (y = 0; y < lev_fieldy; y++)
15136       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
15137
15138   // check if drawing operation forces change of border style
15139   CheckLevelBorderElement(TRUE);
15140
15141   level.changed = TRUE;
15142 }
15143
15144 static void RandomPlacement(int new_element)
15145 {
15146   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
15147   int num_free_positions = 0;
15148   int num_percentage, num_elements;
15149   int x, y;
15150
15151   ResetIntelliDraw();
15152
15153   // determine number of free positions for randomly placing the new element
15154   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
15155   {
15156     free_position[x][y] =
15157       (random_placement_background_restricted ?
15158        Tile[x][y] == random_placement_background_element :
15159        Tile[x][y] != new_element);
15160
15161     if (free_position[x][y])
15162       num_free_positions++;
15163   }
15164
15165   // determine number of new elements to place there
15166   num_percentage = num_free_positions * random_placement_value / 100;
15167   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15168                   num_percentage : random_placement_value);
15169
15170   // if less free positions than elements to place, fill all these positions
15171   if (num_free_positions < num_elements)
15172   {
15173     for (x = 0; x < lev_fieldx; x++)
15174       for (y = 0; y < lev_fieldy; y++)
15175         if (free_position[x][y])
15176           SetElement(x, y, new_element);
15177   }
15178   else
15179   {
15180     while (num_elements > 0)
15181     {
15182       x = GetSimpleRandom(lev_fieldx);
15183       y = GetSimpleRandom(lev_fieldy);
15184
15185       // don't place element at the same position twice
15186       if (free_position[x][y])
15187       {
15188         free_position[x][y] = FALSE;
15189         SetElement(x, y, new_element);
15190         num_elements--;
15191       }
15192     }
15193   }
15194
15195   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15196   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15197 }
15198
15199 static void WrapLevel(int dx, int dy)
15200 {
15201   int wrap_dx = lev_fieldx - dx;
15202   int wrap_dy = lev_fieldy - dy;
15203   int x, y;
15204
15205   for (x = 0; x < lev_fieldx; x++)
15206     for (y = 0; y < lev_fieldy; y++)
15207       TileBackup[x][y] = Tile[x][y];
15208
15209   for (x = 0; x < lev_fieldx; x++)
15210     for (y = 0; y < lev_fieldy; y++)
15211       Tile[x][y] =
15212         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15213
15214   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15215   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15216 }
15217
15218 static void DrawAreaElementHighlight(boolean highlighted,
15219                                      boolean highlighted_similar)
15220 {
15221   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15222
15223   if (!highlighted)
15224     return;
15225
15226   int x, y;
15227
15228   for (x = 0; x < ed_fieldx; x++)
15229   {
15230     for (y = 0; y < ed_fieldy; y++)
15231     {
15232       boolean highlight = FALSE;
15233       int lx = x + level_xpos;
15234       int ly = y + level_ypos;
15235
15236       if (!IN_LEV_FIELD(lx, ly))
15237         continue;
15238
15239       // check if element is the same
15240       if (Tile[lx][ly] == new_element1)
15241         highlight = TRUE;
15242
15243       // check if element is similar
15244       if (highlighted_similar &&
15245           strEqual(element_info[Tile[lx][ly]].class_name,
15246                    element_info[new_element1].class_name))
15247         highlight = TRUE;
15248
15249       // check if element is matching MM style wall
15250       if (IS_MM_WALL(Tile[lx][ly]) &&
15251           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15252         highlight = TRUE;
15253
15254       if (!highlight)
15255         continue;
15256
15257       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15258       {
15259         int i;
15260
15261         for (i = 0; i < 4; i++)
15262         {
15263           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15264             continue;
15265
15266           int xx = x * 2 + (i % 2);
15267           int yy = y * 2 + (i / 2);
15268           int sx = SX + xx * ed_tilesize / 2;
15269           int sy = SY + yy * ed_tilesize / 2;
15270           int from_sx = sx;
15271           int from_sy = sy;
15272           int to_sx = sx + ed_tilesize / 2 - 1;
15273           int to_sy = sy + ed_tilesize / 2 - 1;
15274
15275           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15276           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15277           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15278           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15279         }
15280       }
15281       else
15282       {
15283         int sx = SX + x * ed_tilesize;
15284         int sy = SY + y * ed_tilesize;
15285         int from_sx = sx;
15286         int from_sy = sy;
15287         int to_sx = sx + ed_tilesize - 1;
15288         int to_sy = sy + ed_tilesize - 1;
15289
15290         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15291         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15292         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15293         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15294       }
15295     }
15296   }
15297 }
15298
15299 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15300 {
15301   char *template_filename_old = getLocalLevelTemplateFilename();
15302   char *template_filename_new =
15303     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15304
15305   if (copyFile(template_filename_old, template_filename_new) != 0)
15306     Request("Cannot copy level template!", REQ_CONFIRM);
15307
15308   free(template_filename_new);
15309 }
15310
15311 static void HandleDrawingAreas(struct GadgetInfo *gi)
15312 {
15313   static boolean started_inside_drawing_area = FALSE;
15314   static int last_sx = -1;
15315   static int last_sy = -1;
15316   static int last_sx2 = -1;
15317   static int last_sy2 = -1;
15318   int id = gi->custom_id;
15319   int type_id = gi->custom_type_id;
15320   boolean button_press_event;
15321   boolean button_release_event;
15322   boolean inside_drawing_area = !gi->event.off_borders;
15323   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15324   int actual_drawing_function;
15325   int button = gi->event.button;
15326   int new_element = BUTTON_ELEMENT(button);
15327   int sx = gi->event.x, sy = gi->event.y;
15328   int min_sx = 0, min_sy = 0;
15329   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15330   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15331   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15332   int sx2 = gi->event.mx / mini_item_xsize;
15333   int sy2 = gi->event.my / mini_item_ysize;
15334   int dx = sx2 % 2;
15335   int dy = sy2 % 2;
15336   int lx = 0, ly = 0;
15337   int x, y;
15338
15339   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15340   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15341
15342   // make sure to stay inside drawing area boundaries
15343   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15344   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15345
15346   if (draw_level)
15347   {
15348     int min_lx = 0, min_ly = 0;
15349     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15350
15351     // get positions inside level field
15352     lx = sx + level_xpos;
15353     ly = sy + level_ypos;
15354
15355     if (!IN_LEV_FIELD(lx, ly))
15356       inside_drawing_area = FALSE;
15357
15358     // make sure to stay inside level field boundaries
15359     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15360     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15361
15362     // correct drawing area positions accordingly
15363     sx = lx - level_xpos;
15364     sy = ly - level_ypos;
15365   }
15366
15367   // also correct MM wall-sized (double) drawing area positions accordingly
15368   if (sx2 / 2 < sx || sx2 / 2 > sx)
15369   {
15370     dx = (sx2 / 2 < sx ? 0 : 1);
15371     sx2 = sx * 2 + dx;
15372   }
15373   if (sy2 / 2 < sy || sy2 / 2 > sy)
15374   {
15375     dy = (sy2 / 2 < sy ? 0 : 1);
15376     sy2 = sy * 2 + dy;
15377   }
15378
15379   if (!button_press_event && !button_release_event)
15380   {
15381     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15382     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15383                              isHiresTileElement(old_element) &&
15384                              isHiresDrawElement(new_element));
15385
15386     // prevent handling events for every pixel position when moving mouse
15387     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15388         (sx2 == last_sx2 && sy2 == last_sy2))
15389       return;
15390   }
15391
15392   last_sx = sx;
15393   last_sy = sy;
15394   last_sx2 = sx2;
15395   last_sy2 = sy2;
15396
15397   if (button_press_event)
15398     started_inside_drawing_area = inside_drawing_area;
15399
15400   if (!started_inside_drawing_area)
15401     return;
15402
15403   if (!IS_VALID_BUTTON(button))
15404     return;
15405
15406   // handle info callback for each invocation of action callback
15407   gi->callback_info(gi);
15408
15409   // automatically switch to 'single item' drawing mode, if needed
15410   actual_drawing_function =
15411     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15412      drawing_function : GADGET_ID_SINGLE_ITEMS);
15413
15414   // clicking into drawing area with pressed Control key picks element
15415   if (GetKeyModState() & KMOD_Control)
15416   {
15417     last_drawing_function = drawing_function;
15418     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15419   }
15420
15421   if (GetKeyModState() & KMOD_Shift)
15422   {
15423     if (button_press_event || button_release_event)
15424       ResetIntelliDraw();
15425   }
15426
15427   SetDrawModeHiRes(-1);         // reset to normal draw mode
15428
15429   switch (actual_drawing_function)
15430   {
15431     case GADGET_ID_SINGLE_ITEMS:
15432       if (draw_level)
15433       {
15434         if (button_release_event)
15435         {
15436           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15437
15438           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15439               !inside_drawing_area)
15440             DeleteBrushFromCursor();
15441
15442           break;
15443         }
15444
15445         if (draw_with_brush)
15446         {
15447           CopyBrushToLevel(sx, sy, button);
15448         }
15449         else
15450         {
15451           SetDrawModeHiRes(new_element);
15452
15453           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15454           {
15455             // remove player at old position
15456             for (y = 0; y < lev_fieldy; y++)
15457             {
15458               for (x = 0; x < lev_fieldx; x++)
15459               {
15460                 int old_element = Tile[x][y];
15461
15462                 if (IS_PLAYER_ELEMENT(old_element) &&
15463                     IS_PLAYER_ELEMENT(new_element))
15464                 {
15465                   int replaced_with_element =
15466                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15467                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15468
15469                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15470                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15471
15472                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15473                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15474
15475                      new_element >= EL_PLAYER_1 &&
15476                      new_element <= EL_PLAYER_4 &&
15477                      new_element == old_element ? EL_EMPTY :
15478
15479                      old_element);
15480
15481                   SetElement(x, y, replaced_with_element);
15482                 }
15483                 else if (IS_MM_MCDUFFIN(old_element) &&
15484                          IS_MM_MCDUFFIN(new_element))
15485                 {
15486                   // remove McDuffin at old position
15487                   SetElement(x, y, EL_EMPTY);
15488                 }
15489               }
15490             }
15491           }
15492
15493           SetElementButton(lx, ly, dx, dy, new_element, button);
15494         }
15495       }
15496       else if (!button_release_event)
15497       {
15498         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15499
15500         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15501           DrawMiniGraphicExt(drawto,
15502                              gi->x + sx * MINI_TILEX,
15503                              gi->y + sy * MINI_TILEY,
15504                              el2edimg(new_element));
15505         else
15506           DrawFixedGraphicExt(drawto,
15507                               gi->x + sx * TILEX,
15508                               gi->y + sy * TILEY,
15509                               el2edimg(new_element), 0);
15510
15511         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15512           new_element = GFX_ELEMENT(new_element);
15513
15514         drawingarea_info[type_id].value[pos] = new_element;
15515
15516         CopyElementPropertiesToGame(properties_element);
15517
15518         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15519         {
15520           UpdateCustomElementGraphicGadgets();
15521
15522           FrameCounter = 0;     // restart animation frame counter
15523         }
15524       }
15525       break;
15526
15527     case GADGET_ID_CONNECTED_ITEMS:
15528       {
15529         static int last_sx = -1;
15530         static int last_sy = -1;
15531
15532         if (button_release_event)
15533           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15534
15535         SetDrawModeHiRes(new_element);
15536
15537         if (getDrawModeHiRes())
15538         {
15539           sx = sx2;
15540           sy = sy2;
15541         }
15542
15543         if (!button_press_event)
15544           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15545
15546         last_sx = sx;
15547         last_sy = sy;
15548       }
15549       break;
15550
15551     case GADGET_ID_LINE:
15552     case GADGET_ID_ARC:
15553     case GADGET_ID_RECTANGLE:
15554     case GADGET_ID_FILLED_BOX:
15555       SetDrawModeHiRes(new_element);
15556
15557       if (getDrawModeHiRes())
15558       {
15559         sx = sx2;
15560         sy = sy2;
15561       }
15562       // FALLTHROUGH
15563     case GADGET_ID_GRAB_BRUSH:
15564     case GADGET_ID_TEXT:
15565       {
15566         static int last_sx = -1;
15567         static int last_sy = -1;
15568         static int start_sx = -1;
15569         static int start_sy = -1;
15570         void (*draw_func)(int, int, int, int, int, boolean);
15571
15572         if (drawing_function == GADGET_ID_LINE)
15573           draw_func = DrawLine;
15574         else if (drawing_function == GADGET_ID_ARC)
15575           draw_func = DrawArc;
15576         else if (drawing_function == GADGET_ID_RECTANGLE)
15577           draw_func = DrawBox;
15578         else if (drawing_function == GADGET_ID_FILLED_BOX)
15579           draw_func = DrawFilledBox;
15580         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15581           draw_func = SelectArea;
15582         else // (drawing_function == GADGET_ID_TEXT)
15583           draw_func = SetTextCursor;
15584
15585         if (button_press_event)
15586         {
15587           draw_func(sx, sy, sx, sy, new_element, FALSE);
15588           start_sx = last_sx = sx;
15589           start_sy = last_sy = sy;
15590
15591           if (drawing_function == GADGET_ID_TEXT)
15592             DrawLevelText(0, 0, 0, TEXT_END);
15593         }
15594         else if (button_release_event)
15595         {
15596           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15597           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15598           {
15599             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15600             CopyBrushToCursor(sx, sy);
15601             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15602                           MB_LEFTBUTTON);
15603             draw_with_brush = TRUE;
15604           }
15605           else if (drawing_function == GADGET_ID_TEXT)
15606             DrawLevelText(sx, sy, 0, TEXT_INIT);
15607           else
15608             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15609         }
15610         else if (last_sx != sx || last_sy != sy)
15611         {
15612           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15613           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15614             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15615           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15616           last_sx = sx;
15617           last_sy = sy;
15618         }
15619       }
15620       break;
15621
15622     case GADGET_ID_FLOOD_FILL:
15623       if (button_press_event && Tile[lx][ly] != new_element)
15624       {
15625         if (IS_MM_WALL_EDITOR(new_element))
15626           FloodFillWall_MM(sx2, sy2, new_element);
15627         else
15628           FloodFill(lx, ly, new_element);
15629
15630         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15631         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15632       }
15633       break;
15634
15635     case GADGET_ID_PICK_ELEMENT:
15636       if (button_release_event)
15637         ClickOnGadget(level_editor_gadget[last_drawing_function],
15638                       MB_LEFTBUTTON);
15639       else if (draw_level)
15640         PickDrawingElement(button, Tile[lx][ly]);
15641       else
15642       {
15643         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15644
15645         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15646       }
15647
15648     default:
15649       break;
15650   }
15651
15652   // do not mark level as modified for certain non-level-changing gadgets
15653   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15654        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15655       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15656       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15657     return;
15658
15659   level.changed = TRUE;
15660 }
15661
15662 static void HandleCounterButtons(struct GadgetInfo *gi)
15663 {
15664   int gadget_id = gi->custom_id;
15665   int counter_id = gi->custom_type_id;
15666   int button = gi->event.button;
15667   int *counter_value = counterbutton_info[counter_id].value;
15668   int step = BUTTON_STEPSIZE(button) *
15669     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15670
15671   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15672   {
15673     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15674     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15675     boolean level_changed = LevelChanged();
15676
15677     if ((level_changed && pressed) || (!level_changed && released))
15678       return;
15679
15680     if (level_changed && !Request("Level has changed! Discard changes?",
15681                                   REQ_ASK))
15682     {
15683       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15684         ModifyEditorCounterValue(counter_id, *counter_value);
15685
15686       return;
15687     }
15688   }
15689
15690   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15691     *counter_value = gi->textinput.number_value;
15692   else
15693     ModifyEditorCounterValue(counter_id, *counter_value + step);
15694
15695   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15696   {
15697     int last_game_engine_type = level.game_engine_type;
15698
15699     LoadLevel(level_nr);
15700     LoadScore(level_nr);
15701
15702     SaveLevelSetup_SeriesInfo();
15703
15704     TapeErase();
15705
15706     ResetUndoBuffer();
15707     DrawEditModeWindow();
15708
15709     if (level.game_engine_type != last_game_engine_type)
15710     {
15711       // update element selection list
15712       ReinitializeElementList();
15713       ModifyEditorElementList();
15714     }
15715
15716     return;
15717   }
15718
15719   switch (counter_id)
15720   {
15721     case ED_COUNTER_ID_YAMYAM_CONTENT:
15722       DrawYamYamContentAreas();
15723       break;
15724
15725     case ED_COUNTER_ID_BALL_CONTENT:
15726       DrawMagicBallContentAreas();
15727       break;
15728
15729     case ED_COUNTER_ID_ANDROID_CONTENT:
15730       DrawAndroidElementArea();
15731       break;
15732
15733     case ED_COUNTER_ID_GROUP_CONTENT:
15734       DrawGroupElementArea();
15735       CopyGroupElementPropertiesToGame(properties_element);
15736       break;
15737
15738     case ED_COUNTER_ID_INVENTORY_SIZE:
15739       DrawPlayerInitialInventoryArea(properties_element);
15740       break;
15741
15742     case ED_COUNTER_ID_MM_BALL_CONTENT:
15743       DrawMMBallContentArea();
15744       break;
15745
15746     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15747     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15748       DrawEnvelopeTextArea(-1);
15749       break;
15750
15751     case ED_COUNTER_ID_LEVEL_XSIZE:
15752     case ED_COUNTER_ID_LEVEL_YSIZE:
15753       lev_fieldx = level.fieldx;
15754       lev_fieldy = level.fieldy;
15755
15756       // check if resizing of level results in change of border border
15757       SetBorderElement();
15758
15759       break;
15760
15761     default:
15762       break;
15763   }
15764
15765   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15766        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15767       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15768        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15769     CopyElementPropertiesToGame(properties_element);
15770
15771   // do not mark level as modified for certain non-level-changing gadgets
15772   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15773        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15774       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15775        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15776     return;
15777
15778   level.changed = TRUE;
15779 }
15780
15781 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15782 {
15783   int type_id = gi->custom_type_id;
15784
15785   strcpy(textinput_info[type_id].value, gi->textinput.value);
15786
15787   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15788   {
15789     CopyElementPropertiesToGame(properties_element);
15790
15791     ModifyEditorElementList();  // update changed button info text
15792   }
15793
15794   // do not mark level as modified for certain non-level-changing gadgets
15795   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15796       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15797     return;
15798
15799   level.changed = TRUE;
15800 }
15801
15802 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15803 {
15804   int type_id = gi->custom_type_id;
15805
15806   strncpy(textarea_info[type_id].value, gi->textarea.value,
15807           MAX_ENVELOPE_TEXT_LEN);
15808   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15809
15810   level.changed = TRUE;
15811 }
15812
15813 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15814 {
15815   int type_id = gi->custom_type_id;
15816   int value_old = *selectbox_info[type_id].value;
15817   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15818
15819   *selectbox_info[type_id].value = value_new;
15820
15821   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15822   {
15823     DrawLevelConfigWindow();
15824   }
15825   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15826   {
15827     element_info[properties_element].current_change_page = gi->selectbox.index;
15828
15829     DrawPropertiesWindow();
15830   }
15831   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15832             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15833            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15834             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15835            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15836   {
15837     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15838     {
15839       // when changing action type, also check action mode and action arg
15840       if (value_old != value_new)
15841         setSelectboxSpecialActionVariablesIfNeeded();
15842
15843       DrawPropertiesChange();
15844     }
15845
15846     CopyElementPropertiesToGame(properties_element);
15847   }
15848   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15849   {
15850     // show or hide "engine" tabulator depending on game engine type
15851     DrawLevelConfigWindow();
15852
15853     // update element selection list depending on game engine type
15854     ReinitializeElementList();
15855     ModifyEditorElementList();
15856   }
15857   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15858   {
15859     // update BD cycle delay counter gadgets depending on BD scheduling type
15860     DrawLevelConfigWindow();
15861   }
15862
15863   // do not mark level as modified for certain non-level-changing gadgets
15864   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15865       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15866     return;
15867
15868   level.changed = TRUE;
15869 }
15870
15871 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15872 {
15873   int type_id = gi->custom_type_id;
15874   int i;
15875
15876   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15877       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15878   {
15879     edit_mode_levelconfig = gi->custom_type_id;
15880
15881     DrawLevelConfigWindow();
15882   }
15883   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15884            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15885   {
15886     edit_mode_properties = gi->custom_type_id;
15887
15888     DrawPropertiesWindow();
15889   }
15890   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15891            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15892   {
15893     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15894
15895     // backup original "level.field" (needed to track playfield changes)
15896     CopyPlayfield(level.field, TileBackup);
15897
15898     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15899     CopyPlayfield(Tile, level.field);
15900
15901     if (new_template ||
15902         Request("Save this template and kill the old?", REQ_ASK))
15903       SaveLevelTemplate();
15904
15905     if (new_template)
15906       Request("Template saved!", REQ_CONFIRM);
15907
15908     // restore original "level.field" (needed to track playfield changes)
15909     CopyPlayfield(TileBackup, level.field);
15910   }
15911   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15912   {
15913     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15914
15915     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15916         leveldir_current->readonly)
15917     {
15918       Request("This level set is read-only!", REQ_CONFIRM);
15919
15920       return;
15921     }
15922
15923     if (strEqual(levelset_name, ""))
15924     {
15925       Request("Please enter level set title!", REQ_CONFIRM);
15926
15927       return;
15928     }
15929
15930     if (strEqual(levelset_author, ""))
15931     {
15932       Request("Please enter level set author!", REQ_CONFIRM);
15933
15934       return;
15935     }
15936
15937     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15938     {
15939       if (UpdateUserLevelSet(levelset_subdir,
15940                              levelset_name,
15941                              levelset_author,
15942                              levelset_num_levels))
15943       {
15944         Request("Level set updated!", REQ_CONFIRM);
15945       }
15946       else
15947       {
15948         Request("Updating level set failed!", REQ_CONFIRM);
15949       }
15950     }
15951     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15952     {
15953       if (level.changed && !Request("Level has changed! Discard changes?",
15954                                      REQ_ASK))
15955         return;
15956
15957       if (CreateUserLevelSet(levelset_subdir,
15958                              levelset_name,
15959                              levelset_author,
15960                              levelset_num_levels,
15961                              levelset_use_levelset_artwork))
15962       {
15963         if (levelset_copy_level_template)
15964           CopyLevelTemplateToUserLevelSet(levelset_subdir);
15965
15966         Request("New level set created!", REQ_CONFIRM);
15967
15968         AddUserLevelSetToLevelInfo(levelset_subdir);
15969         ChangeEditorToLevelSet(levelset_subdir);
15970       }
15971       else
15972       {
15973         Request("Creating new level set failed!", REQ_CONFIRM);
15974       }
15975     }
15976   }
15977   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
15978            custom_element.num_change_pages < MAX_CHANGE_PAGES)
15979   {
15980     struct ElementInfo *ei = &element_info[properties_element];
15981
15982     // when modifying custom element, ask for copying level template
15983     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15984       return;
15985
15986     setElementChangePages(ei, ei->num_change_pages + 1);
15987
15988     // set new change page to be new current change page
15989     ei->current_change_page = ei->num_change_pages - 1;
15990     ei->change = &ei->change_page[ei->current_change_page];
15991
15992     setElementChangeInfoToDefaults(ei->change);
15993
15994     DrawPropertiesWindow();
15995
15996     level.changed = TRUE;
15997   }
15998   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
15999            custom_element.num_change_pages > MIN_CHANGE_PAGES)
16000   {
16001     struct ElementInfo *ei = &element_info[properties_element];
16002
16003     // when modifying custom element, ask for copying level template
16004     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16005       return;
16006
16007     // copy all change pages after change page to be deleted
16008     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
16009       ei->change_page[i] = ei->change_page[i + 1];
16010
16011     setElementChangePages(ei, ei->num_change_pages - 1);
16012
16013     DrawPropertiesWindow();
16014
16015     level.changed = TRUE;
16016   }
16017 }
16018
16019 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
16020 {
16021   int type_id = gi->custom_type_id;
16022
16023   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
16024       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
16025   {
16026     struct ElementInfo *ei = &element_info[properties_element];
16027     int step = BUTTON_STEPSIZE(gi->event.button);
16028
16029     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
16030     ei->current_change_page += step;
16031
16032     if (ei->current_change_page < 0)
16033       ei->current_change_page = 0;
16034     else if (ei->current_change_page >= ei->num_change_pages)
16035       ei->current_change_page = ei->num_change_pages - 1;
16036
16037     DrawPropertiesWindow();
16038   }
16039   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
16040            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16041   {
16042     struct ElementInfo *ei = &element_info[properties_element];
16043     int current_change_page = ei->current_change_page;
16044
16045     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
16046     {
16047       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
16048         ei->change_page[current_change_page];
16049     }
16050     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16051     {
16052       // when modifying custom element, ask for copying level template
16053       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16054         return;
16055
16056       ei->change_page[current_change_page] =
16057         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
16058
16059       level.changed = TRUE;
16060     }
16061
16062     DrawPropertiesWindow();
16063   }
16064 }
16065
16066 static void HandleRadiobuttons(struct GadgetInfo *gi)
16067 {
16068   int type_id = gi->custom_type_id;
16069
16070   *radiobutton_info[type_id].value =
16071     radiobutton_info[type_id].checked_value;
16072
16073   // do not mark level as modified for certain non-level-changing gadgets
16074   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
16075       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
16076     return;
16077
16078   level.changed = TRUE;
16079 }
16080
16081 static void HandleCheckbuttons(struct GadgetInfo *gi)
16082 {
16083   int type_id = gi->custom_type_id;
16084
16085   *checkbutton_info[type_id].value ^= TRUE;
16086
16087   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
16088       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
16089       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
16090       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
16091          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
16092         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
16093          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
16094        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
16095   {
16096     CopyElementPropertiesToGame(properties_element);
16097   }
16098
16099   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
16100   {
16101     UpdateCustomElementGraphicGadgets();
16102   }
16103   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
16104            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
16105   {
16106     boolean template_related_changes_found = FALSE;
16107     int i;
16108
16109     // check if any custom, group or empty elements have been changed
16110     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
16111       if ((IS_CUSTOM_ELEMENT(i) ||
16112            IS_GROUP_ELEMENT(i) ||
16113            IS_EMPTY_ELEMENT(i)) &&
16114           element_info[i].modified_settings)
16115         template_related_changes_found = TRUE;
16116
16117     if (level.use_custom_template &&
16118         !fileExists(getGlobalLevelTemplateFilename()))
16119     {
16120       Request("No level template found!", REQ_CONFIRM);
16121
16122       level.use_custom_template = FALSE;
16123
16124       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16125
16126       return;
16127     }
16128
16129     if (level.use_custom_template &&
16130         template_related_changes_found &&
16131         !Request("Discard changes and use level template?", REQ_ASK))
16132     {
16133       level.use_custom_template = FALSE;
16134
16135       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16136
16137       return;
16138     }
16139
16140     if (!level.use_custom_template &&
16141         Request("Copy settings from level template?", REQ_ASK))
16142     {
16143       return;
16144     }
16145
16146     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
16147
16148     DrawEditModeWindow();
16149   }
16150   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
16151   {
16152     if (setup.editor.use_template_for_new_levels &&
16153         !fileExists(getGlobalLevelTemplateFilename()))
16154     {
16155       Request("No level template found!", REQ_CONFIRM);
16156
16157       return;
16158     }
16159
16160     if (setup.editor.use_template_for_new_levels &&
16161         level.changed &&
16162         !Request("Discard level and load template?", REQ_ASK))
16163     {
16164       return;
16165     }
16166
16167     if (!setup.editor.use_template_for_new_levels &&
16168         level.changed &&
16169         !Request("Discard level and use empty level?", REQ_ASK))
16170     {
16171       return;
16172     }
16173
16174     LoadLevel(level_nr);
16175     LoadScore(level_nr);
16176
16177     TapeErase();
16178
16179     ResetUndoBuffer();
16180     DrawEditModeWindow();
16181   }
16182   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16183   {
16184     SetAutomaticNumberOfGemsNeeded();
16185   }
16186
16187   // do not mark level as modified for certain non-level-changing gadgets
16188   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16189        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16190       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16191        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16192        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16193       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16194     return;
16195
16196   level.changed = TRUE;
16197 }
16198
16199 static void HandleControlButtons(struct GadgetInfo *gi)
16200 {
16201   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16202   static int last_edit_mode = ED_MODE_DRAWING;
16203   static int last_custom_copy_mode = -1;
16204   static int last_button = 0;
16205   int id = gi->custom_id;
16206   int button = gi->event.button;
16207   int step = BUTTON_STEPSIZE(button);
16208   int new_element = BUTTON_ELEMENT(button);
16209   int last_properties_element = properties_element;
16210   int x, y;
16211
16212   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16213     DrawLevelText(0, 0, 0, TEXT_END);
16214
16215   if (id < ED_NUM_CTRL1_BUTTONS &&
16216       id != GADGET_ID_SINGLE_ITEMS &&
16217       id != GADGET_ID_PICK_ELEMENT &&
16218       edit_mode != ED_MODE_DRAWING &&
16219       drawing_function != GADGET_ID_PICK_ELEMENT &&
16220       !(GetKeyModState() & KMOD_Control))
16221     ChangeEditModeWindow(ED_MODE_DRAWING);
16222
16223   // element copy mode active, but no element button pressed => deactivate
16224   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16225     last_custom_copy_mode = -1;
16226
16227   // when showing palette on element buttons, change element of button used
16228   if (editor.palette.show_on_element_buttons &&
16229       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16230   {
16231     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16232
16233     id = GADGET_ID_PALETTE;
16234   }
16235
16236   switch (id)
16237   {
16238     case GADGET_ID_SCROLL_LEFT:
16239       if (level_xpos >= 0)
16240       {
16241         if (lev_fieldx < ed_fieldx - 2)
16242           break;
16243
16244         level_xpos -= step;
16245         if (level_xpos < -1)
16246           level_xpos = -1;
16247         if (button == 1)
16248           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16249         else
16250           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16251
16252         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16253                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16254       }
16255       break;
16256
16257     case GADGET_ID_SCROLL_RIGHT:
16258       if (level_xpos <= lev_fieldx - ed_fieldx)
16259       {
16260         if (lev_fieldx < ed_fieldx - 2)
16261           break;
16262
16263         level_xpos += step;
16264         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16265           level_xpos = lev_fieldx - ed_fieldx + 1;
16266         if (button == 1)
16267           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16268         else
16269           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16270
16271         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16272                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16273       }
16274       break;
16275
16276     case GADGET_ID_SCROLL_UP:
16277       if (level_ypos >= 0)
16278       {
16279         if (lev_fieldy < ed_fieldy - 2)
16280           break;
16281
16282         level_ypos -= step;
16283         if (level_ypos < -1)
16284           level_ypos = -1;
16285         if (button == 1)
16286           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16287         else
16288           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16289
16290         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16291                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16292       }
16293       break;
16294
16295     case GADGET_ID_SCROLL_DOWN:
16296       if (level_ypos <= lev_fieldy - ed_fieldy)
16297       {
16298         if (lev_fieldy < ed_fieldy - 2)
16299           break;
16300
16301         level_ypos += step;
16302         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16303           level_ypos = lev_fieldy - ed_fieldy + 1;
16304         if (button == 1)
16305           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16306         else
16307           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16308
16309         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16310                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16311       }
16312       break;
16313
16314     case GADGET_ID_SCROLL_HORIZONTAL:
16315       level_xpos = gi->event.item_position - 1;
16316
16317       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16318       BackToFront();
16319
16320       break;
16321
16322     case GADGET_ID_SCROLL_VERTICAL:
16323       level_ypos = gi->event.item_position - 1;
16324
16325       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16326       BackToFront();
16327
16328       break;
16329
16330     case GADGET_ID_SCROLL_LIST_UP:
16331     case GADGET_ID_SCROLL_LIST_DOWN:
16332     case GADGET_ID_SCROLL_LIST_VERTICAL:
16333       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16334         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16335       else
16336       {
16337         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16338         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16339
16340         if (element_shift < 0)
16341           element_shift = 0;
16342         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16343           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16344
16345         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16346                      GDI_SCROLLBAR_ITEM_POSITION,
16347                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16348       }
16349
16350       ModifyEditorElementList();
16351
16352       break;
16353
16354     case GADGET_ID_PROPERTIES:
16355       // always switch off element properties when they are already displayed
16356       last_properties_element = new_element;
16357     case GADGET_ID_ELEMENT_LEFT:
16358     case GADGET_ID_ELEMENT_MIDDLE:
16359     case GADGET_ID_ELEMENT_RIGHT:
16360       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16361                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16362                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16363                             new_element);
16364
16365       if (edit_mode != ED_MODE_PROPERTIES)
16366       {
16367         last_edit_mode = edit_mode;
16368
16369         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16370
16371         last_level_drawing_function = drawing_function;
16372         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16373                       MB_LEFTBUTTON);
16374       }
16375       else if (properties_element != last_properties_element)
16376       {
16377         DrawEditModeWindow();
16378       }
16379       else
16380       {
16381         ChangeEditModeWindow(ED_MODE_DRAWING);
16382
16383         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16384                       MB_LEFTBUTTON);
16385       }
16386       break;
16387
16388     case GADGET_ID_PALETTE:
16389       if (edit_mode != ED_MODE_PALETTE)
16390       {
16391         last_edit_mode = edit_mode;
16392
16393         ChangeEditModeWindow(ED_MODE_PALETTE);
16394       }
16395       else
16396       {
16397         ChangeEditModeWindow(last_edit_mode);
16398       }
16399       break;
16400
16401     case GADGET_ID_WRAP_LEFT:
16402       WrapLevel(-step, 0);
16403       break;
16404
16405     case GADGET_ID_WRAP_RIGHT:
16406       WrapLevel(step, 0);
16407       break;
16408
16409     case GADGET_ID_WRAP_UP:
16410       WrapLevel(0, -step);
16411       break;
16412
16413     case GADGET_ID_WRAP_DOWN:
16414       WrapLevel(0, step);
16415       break;
16416
16417     case GADGET_ID_SINGLE_ITEMS:
16418     case GADGET_ID_CONNECTED_ITEMS:
16419     case GADGET_ID_LINE:
16420     case GADGET_ID_ARC:
16421     case GADGET_ID_TEXT:
16422     case GADGET_ID_RECTANGLE:
16423     case GADGET_ID_FILLED_BOX:
16424     case GADGET_ID_FLOOD_FILL:
16425     case GADGET_ID_GRAB_BRUSH:
16426     case GADGET_ID_PICK_ELEMENT:
16427       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16428         last_drawing_function = drawing_function;
16429       drawing_function = id;
16430       draw_with_brush = FALSE;
16431       break;
16432
16433     case GADGET_ID_RANDOM_PLACEMENT:
16434       RandomPlacement(new_element);
16435       break;
16436
16437     case GADGET_ID_ZOOM:
16438       // zoom level editor tile size in or out (or reset to default size)
16439       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16440                      button == 2 ? ed_tilesize_default :
16441                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16442
16443       // when using touch device, cycle through all zoom tilesizes
16444       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16445         ed_tilesize = MICRO_TILESIZE;
16446
16447       // limit zoom level by upper and lower bound
16448       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16449
16450       InitZoomLevelSettings(ed_tilesize);
16451
16452       if (edit_mode == ED_MODE_DRAWING)
16453       {
16454         DrawDrawingWindow();
16455
16456         // redraw zoom gadget info text
16457         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16458       }
16459
16460       // save current editor zoom tilesize
16461       SaveSetup_AutoSetup();
16462
16463       break;
16464
16465     case GADGET_ID_CUSTOM_COPY_FROM:
16466     case GADGET_ID_CUSTOM_COPY_TO:
16467     case GADGET_ID_CUSTOM_EXCHANGE:
16468       last_custom_copy_mode = id;
16469       last_drawing_function = drawing_function;
16470       break;
16471
16472     case GADGET_ID_CUSTOM_COPY:
16473       CopyCustomElement(properties_element, -1, id);
16474       break;
16475
16476     case GADGET_ID_CUSTOM_PASTE:
16477       CopyCustomElement(-1, properties_element, id);
16478       break;
16479
16480     case GADGET_ID_UNDO:
16481       if (button < 0)   // keep button value (even if modifier keys are pressed)
16482         button = -button;
16483       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16484         button = 3;
16485
16486       if (button == 1 && undo_buffer_steps == 0)
16487       {
16488         Request("Undo buffer empty!", REQ_CONFIRM);
16489
16490         break;
16491       }
16492       else if (button == 2)
16493       {
16494         break;
16495       }
16496       else if (button == 3 && redo_buffer_steps == 0)
16497       {
16498         Request("Redo buffer empty!", REQ_CONFIRM);
16499
16500         break;
16501       }
16502
16503       if (edit_mode != ED_MODE_DRAWING)
16504         ChangeEditModeWindow(ED_MODE_DRAWING);
16505
16506       if (button == 1)
16507       {
16508         // undo
16509
16510         undo_buffer_position =
16511           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16512
16513         undo_buffer_steps--;
16514         redo_buffer_steps++;
16515       }
16516       else
16517       {
16518         // redo
16519
16520         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16521
16522         undo_buffer_steps++;
16523         redo_buffer_steps--;
16524       }
16525
16526       for (x = 0; x < lev_fieldx; x++)
16527         for (y = 0; y < lev_fieldy; y++)
16528           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16529
16530       // check if undo operation forces change of border style
16531       CheckLevelBorderElement(FALSE);
16532
16533       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16534
16535       break;
16536
16537     case GADGET_ID_CONF:
16538       if (edit_mode != ED_MODE_LEVELCONFIG)
16539       {
16540         last_edit_mode = edit_mode;
16541
16542         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16543       }
16544       else
16545       {
16546         ChangeEditModeWindow(ED_MODE_DRAWING);
16547       }
16548       break;
16549
16550     case GADGET_ID_CLEAR:
16551       if (edit_mode != ED_MODE_DRAWING)
16552         ChangeEditModeWindow(ED_MODE_DRAWING);
16553
16554       for (x = 0; x < MAX_LEV_FIELDX; x++)
16555         for (y = 0; y < MAX_LEV_FIELDY; y++)
16556           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16557
16558       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16559
16560       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16561       break;
16562
16563     case GADGET_ID_SAVE:
16564     {
16565       // saving read-only levels into personal level set modifies global vars
16566       // "leveldir_current" and "level_nr"; restore them after saving level
16567       LevelDirTree *leveldir_former = leveldir_current;
16568       int level_nr_former = level_nr;
16569       char *level_filename;
16570       boolean new_level;
16571
16572       if (leveldir_current->readonly &&
16573           !PrepareSavingIntoPersonalLevelSet())
16574         break;
16575
16576       level_filename = getDefaultLevelFilename(level_nr);
16577       new_level = !fileExists(level_filename);
16578
16579       if (new_level ||
16580           Request("Save this level and kill the old?", REQ_ASK))
16581       {
16582         if (leveldir_former->readonly)
16583           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16584
16585         SetAutomaticNumberOfGemsNeeded();
16586
16587         CopyPlayfield(Tile, level.field);
16588         SaveLevel(level_nr);
16589
16590         level.changed = FALSE;
16591
16592         if (new_level)
16593         {
16594           char level_saved_msg[64];
16595
16596           if (leveldir_former->readonly)
16597             sprintf(level_saved_msg,
16598                     "Level saved as level %d into personal level set!",
16599                     level_nr);
16600           else
16601             strcpy(level_saved_msg, "Level saved!");
16602
16603           Request(level_saved_msg, REQ_CONFIRM);
16604         }
16605       }
16606
16607       // "cd" back to copied-from levelset (in case of saved read-only level)
16608       leveldir_current = leveldir_former;
16609       level_nr = level_nr_former;
16610
16611       break;
16612     }
16613
16614     case GADGET_ID_TEST:
16615       if (LevelChanged())
16616         level.game_version = GAME_VERSION_ACTUAL;
16617
16618       CopyPlayfield(level.field, TileBackup);
16619       CopyPlayfield(Tile, level.field);
16620
16621       CopyNativeLevel_RND_to_Native(&level);
16622
16623       UnmapLevelEditorGadgets();
16624       UndrawSpecialEditorDoor();
16625
16626       CloseDoor(DOOR_CLOSE_ALL);
16627
16628       // needed before playing if editor playfield area has different size
16629       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16630
16631       // redraw_mask = REDRAW_ALL;
16632
16633       level_editor_test_game = TRUE;
16634
16635       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16636
16637       break;
16638
16639     case GADGET_ID_EXIT:
16640       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16641       break;
16642
16643     default:
16644       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16645           id <= GADGET_ID_ELEMENTLIST_LAST)
16646       {
16647         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16648
16649         new_element = editor_elements[element_position + element_shift];
16650
16651         if (IS_EDITOR_CASCADE(new_element))
16652         {
16653           int i;
16654
16655           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16656           {
16657             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16658             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16659
16660             if (*cascade_element == new_element)
16661             {
16662               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16663               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16664
16665               // update element selection list
16666               ReinitializeElementList();
16667               ModifyEditorElementList();
16668
16669               // update cascading gadget info text
16670               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16671
16672               // save current editor cascading state
16673               SaveSetup_EditorCascade();
16674
16675               break;
16676             }
16677           }
16678
16679           break;
16680         }
16681
16682         if (last_custom_copy_mode != -1)
16683         {
16684           if (CopyCustomElement(properties_element, new_element,
16685                                 last_custom_copy_mode))
16686           {
16687             ClickOnGadget(level_editor_gadget[last_drawing_function],
16688                           MB_LEFTBUTTON);
16689
16690             last_custom_copy_mode = -1;
16691           }
16692
16693           break;
16694         }
16695
16696         // change element of button used to show palette
16697         if (editor.palette.show_on_element_buttons)
16698           button = last_button;
16699
16700         PickDrawingElement(button, new_element);
16701
16702         if (!stick_element_properties_window &&
16703             drawing_function != GADGET_ID_PICK_ELEMENT &&
16704             !(GetKeyModState() & KMOD_Control))
16705         {
16706           properties_element = new_element;
16707           if (edit_mode == ED_MODE_PROPERTIES)
16708             DrawPropertiesWindow();
16709         }
16710
16711         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16712           ClickOnGadget(level_editor_gadget[last_drawing_function],
16713                         MB_LEFTBUTTON);
16714
16715         if (!use_permanent_palette)
16716           ChangeEditModeWindow(last_edit_mode);
16717       }
16718 #ifdef DEBUG
16719       else if (gi->event.type == GD_EVENT_PRESSED)
16720         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16721       else if (gi->event.type == GD_EVENT_RELEASED)
16722         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16723       else if (gi->event.type == GD_EVENT_MOVING)
16724         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16725       else
16726         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16727 #endif
16728       break;
16729   }
16730 }
16731
16732 void HandleLevelEditorKeyInput(Key key)
16733 {
16734   char letter = getCharFromKey(key);
16735
16736   if (drawing_function == GADGET_ID_TEXT &&
16737       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16738   {
16739     if (letter)
16740       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16741     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16742       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16743     else if (key == KSYM_Return)
16744       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16745     else if (key == KSYM_Escape)
16746       DrawLevelText(0, 0, 0, TEXT_END);
16747
16748     return;
16749   }
16750
16751   int id = GADGET_ID_NONE;
16752   int new_element_shift = element_shift;
16753   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16754   int button = MB_LEFTBUTTON;
16755   int i;
16756
16757   switch (key)
16758   {
16759     case KSYM_Left:
16760       id = GADGET_ID_SCROLL_LEFT;
16761       break;
16762     case KSYM_Right:
16763       id = GADGET_ID_SCROLL_RIGHT;
16764       break;
16765     case KSYM_Up:
16766       id = GADGET_ID_SCROLL_UP;
16767       break;
16768     case KSYM_Down:
16769       id = GADGET_ID_SCROLL_DOWN;
16770       break;
16771
16772     case KSYM_Page_Up:
16773     case KSYM_Page_Down:
16774       step *= (key == KSYM_Page_Up ? -1 : +1);
16775       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16776
16777       if (element_shift < 0)
16778         element_shift = 0;
16779       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16780         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16781
16782       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16783                    GDI_SCROLLBAR_ITEM_POSITION,
16784                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16785
16786       ModifyEditorElementList();
16787
16788       break;
16789
16790     case KSYM_Home:
16791     case KSYM_End:
16792       element_shift = (key == KSYM_Home ? 0 :
16793                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16794
16795       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16796                    GDI_SCROLLBAR_ITEM_POSITION,
16797                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16798
16799       ModifyEditorElementList();
16800
16801       break;
16802
16803     case KSYM_Insert:
16804     case KSYM_Delete:
16805
16806       // this is needed to prevent interference with running "True X-Mouse"
16807       if (GetKeyModStateFromEvents() & KMOD_Control)
16808         break;
16809
16810       // check for last or next editor cascade block in element list
16811       for (i = 0; i < num_editor_elements; i++)
16812       {
16813         if ((key == KSYM_Insert && i == element_shift) ||
16814             (key == KSYM_Delete && new_element_shift > element_shift))
16815           break;
16816
16817         // jump to next cascade block (or to start of element list)
16818         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16819           new_element_shift = i;
16820       }
16821
16822       if (i < num_editor_elements)
16823         element_shift = new_element_shift;
16824
16825       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16826         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16827
16828       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16829                    GDI_SCROLLBAR_ITEM_POSITION,
16830                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16831
16832       ModifyEditorElementList();
16833
16834       break;
16835
16836     case KSYM_Escape:
16837       if (edit_mode == ED_MODE_DRAWING)
16838         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16839       else if (edit_mode == ED_MODE_LEVELCONFIG)
16840         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16841       else if (edit_mode == ED_MODE_PROPERTIES)
16842         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16843       else if (edit_mode == ED_MODE_PALETTE)
16844         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16845       else              // should never happen
16846         ChangeEditModeWindow(ED_MODE_DRAWING);
16847
16848       break;
16849
16850     default:
16851       break;
16852   }
16853
16854   if (id != GADGET_ID_NONE)
16855     ClickOnGadget(level_editor_gadget[id], button);
16856   else if (letter == '1' || letter == '?')
16857     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16858   else if (letter == '2')
16859     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16860   else if (letter == '3')
16861     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16862   else if (letter == '.')
16863     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16864   else if (letter == 'U')
16865     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16866   else if (letter == '-' || key == KSYM_KP_Subtract)
16867     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16868   else if (letter == '0' || key == KSYM_KP_0)
16869     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16870   else if (letter == '+' || key == KSYM_KP_Add ||
16871            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16872     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16873   else if (key == KSYM_Return ||
16874            key == KSYM_space ||
16875            key == setup.shortcut.toggle_pause)
16876     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16877   else
16878     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16879       if (letter && letter == controlbutton_info[i].shortcut)
16880         if (!anyTextGadgetActive())
16881           ClickOnGadget(level_editor_gadget[i], button);
16882
16883   if (draw_with_brush)
16884   {
16885     if (letter == 'x')
16886       FlipBrushX();
16887     else if (letter == 'y')
16888       FlipBrushY();
16889     else if (letter == 'z')
16890       RotateBrush();
16891   }
16892 }
16893
16894 static void HandleLevelEditorIdle_Properties(void)
16895 {
16896   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16897   int x = editor.settings.element_graphic.x + element_border;
16898   int y = editor.settings.element_graphic.y + element_border;
16899   static DelayCounter action_delay = { 0 };
16900   int i;
16901
16902   action_delay.value = GameFrameDelay;
16903
16904   if (!DelayReached(&action_delay))
16905     return;
16906
16907   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16908   {
16909     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16910
16911     if (gi->mapped && gi->active && gi->selectbox.open)
16912       return;
16913   }
16914
16915   DrawEditorElementAnimation(SX + x, SY + y);
16916
16917   redraw_mask |= REDRAW_FIELD;
16918
16919   FrameCounter++;       // increase animation frame counter
16920 }
16921
16922 static void HandleLevelEditorIdle_Drawing(void)
16923 {
16924   static boolean last_highlighted = FALSE;
16925   static boolean last_highlighted_similar = FALSE;
16926   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16927   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16928
16929   if (highlighted != last_highlighted ||
16930       (highlighted && highlighted_similar != last_highlighted_similar))
16931   {
16932     DrawAreaElementHighlight(highlighted, highlighted_similar);
16933
16934     redraw_mask |= REDRAW_FIELD;
16935   }
16936
16937   last_highlighted = highlighted;
16938   last_highlighted_similar = highlighted_similar;
16939 }
16940
16941 void HandleLevelEditorIdle(void)
16942 {
16943   if (edit_mode == ED_MODE_PROPERTIES)
16944     HandleLevelEditorIdle_Properties();
16945   else if (edit_mode == ED_MODE_DRAWING)
16946     HandleLevelEditorIdle_Drawing();
16947 }
16948
16949 static void ClearEditorGadgetInfoText(void)
16950 {
16951   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16952 }
16953
16954 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16955 {
16956   char infotext[MAX_OUTPUT_LINESIZE + 1];
16957   int max_infotext_len = getMaxInfoTextLength();
16958
16959   if (gi == NULL || strlen(gi->info_text) == 0)
16960     return;
16961
16962   strncpy(infotext, gi->info_text, max_infotext_len);
16963   infotext[max_infotext_len] = '\0';
16964
16965   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
16966   {
16967     int key = controlbutton_info[gi->custom_id].shortcut;
16968
16969     if (key)
16970     {
16971       char shortcut[MAX_OUTPUT_LINESIZE + 1];
16972
16973       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
16974         sprintf(shortcut, " ('.' or '%c')", key);
16975       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
16976         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
16977       else if (gi->custom_id == GADGET_ID_TEST)
16978         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
16979       else if (gi->custom_id == GADGET_ID_UNDO)
16980         sprintf(shortcut, " ('%c/Shift-U')", key);
16981       else if (gi->custom_id == GADGET_ID_ZOOM)
16982         sprintf(shortcut, " ('%c', '0', '-')", key);
16983       else
16984         sprintf(shortcut, " ('%s%c')",
16985                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
16986
16987       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
16988         strcat(infotext, shortcut);
16989     }
16990   }
16991
16992   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
16993 }
16994
16995 void HandleEditorGadgetInfoText(void *ptr)
16996 {
16997   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
16998
16999   if (game_status != GAME_MODE_EDITOR)
17000     return;
17001
17002   ClearEditorGadgetInfoText();
17003
17004   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
17005     return;
17006
17007   // misuse this function to delete brush cursor, if needed
17008   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
17009     DeleteBrushFromCursor();
17010
17011   PrintEditorGadgetInfoText(gi);
17012 }
17013
17014 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
17015 {
17016   int id = gi->custom_id;
17017   int type_id = gi->custom_type_id;
17018   int sx = gi->event.x;
17019   int sy = gi->event.y;
17020   int lx = sx + level_xpos;
17021   int ly = sy + level_ypos;
17022   int min_sx = 0, min_sy = 0;
17023   int max_sx = gi->drawing.area_xsize - 1;
17024   int max_sy = gi->drawing.area_ysize - 1;
17025   int actual_drawing_function = drawing_function;
17026   int max_infotext_len = getMaxInfoTextLength();
17027   char infotext[MAX_OUTPUT_LINESIZE + 1];
17028
17029   infotext[0] = '\0';           // start with empty info text
17030
17031   // pressed Control key: simulate picking element
17032   if (GetKeyModState() & KMOD_Control)
17033     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
17034
17035   ClearEditorGadgetInfoText();
17036
17037   if (gi->event.type == GD_EVENT_INFO_LEAVING)
17038     return;
17039
17040   // make sure to stay inside drawing area boundaries
17041   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
17042   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
17043
17044   if (id == GADGET_ID_DRAWING_LEVEL)
17045   {
17046     if (button_status)
17047     {
17048       int min_lx = 0, min_ly = 0;
17049       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
17050
17051       // get positions inside level field
17052       lx = sx + level_xpos;
17053       ly = sy + level_ypos;
17054
17055       // make sure to stay inside level field boundaries
17056       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
17057       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
17058
17059       // correct drawing area positions accordingly
17060       sx = lx - level_xpos;
17061       sy = ly - level_ypos;
17062     }
17063
17064     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17065     {
17066       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
17067       {
17068         static int start_lx = 0;
17069         static int start_ly = 0;
17070         char *text;
17071
17072         if (gi->event.type == GD_EVENT_PRESSED)
17073         {
17074           start_lx = lx;
17075           start_ly = ly;
17076         }
17077
17078         switch (actual_drawing_function)
17079         {
17080           case GADGET_ID_SINGLE_ITEMS:
17081             text = "Drawing single items";
17082             break;
17083           case GADGET_ID_CONNECTED_ITEMS:
17084             text = "Drawing connected items";
17085             break;
17086           case GADGET_ID_LINE:
17087             text = "Drawing line";
17088             break;
17089           case GADGET_ID_ARC:
17090             text = "Drawing arc";
17091             break;
17092           case GADGET_ID_TEXT:
17093             text = "Setting text cursor";
17094             break;
17095           case GADGET_ID_RECTANGLE:
17096             text = "Drawing rectangle";
17097             break;
17098           case GADGET_ID_FILLED_BOX:
17099             text = "Drawing filled box";
17100             break;
17101           case GADGET_ID_FLOOD_FILL:
17102             text = "Flood fill";
17103             break;
17104           case GADGET_ID_GRAB_BRUSH:
17105             text = "Grabbing brush";
17106             break;
17107           case GADGET_ID_PICK_ELEMENT:
17108             text = "Picking element";
17109             break;
17110
17111           default:
17112             text = "Drawing position";
17113             break;
17114         }
17115
17116         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17117           sprintf(infotext, "%s: %d, %d", text, lx, ly);
17118         else
17119           sprintf(infotext, "%s: %d, %d", text,
17120                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
17121       }
17122       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17123         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
17124       else
17125         sprintf(infotext, "Level position: %d, %d", lx, ly);
17126     }
17127
17128     // misuse this function to draw brush cursor, if needed
17129     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
17130     {
17131       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17132         CopyBrushToCursor(sx, sy);
17133       else
17134         DeleteBrushFromCursor();
17135     }
17136
17137     if (!draw_with_brush)
17138       UpdateBrushPosition(sx, sy);
17139   }
17140   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17141   {
17142     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
17143     int element = drawingarea_info[type_id].value[pos];
17144
17145     strncpy(infotext, getElementInfoText(element), max_infotext_len);
17146   }
17147   else
17148   {
17149     if (id == GADGET_ID_CUSTOM_CONTENT)
17150       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
17151     else if (id == GADGET_ID_GROUP_CONTENT)
17152       sprintf(infotext, "group element position: %d", sx + 1);
17153     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
17154              id <= GADGET_ID_YAMYAM_CONTENT_7)
17155       sprintf(infotext, "content area %d position: %d, %d",
17156               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
17157     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17158              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17159       sprintf(infotext, "content area %d position: %d, %d",
17160               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17161     else if (id == GADGET_ID_ANDROID_CONTENT)
17162       sprintf(infotext, "android element position: %d", sx + 1);
17163     else if (drawingarea_info[type_id].infotext != NULL)
17164       strcpy(infotext, drawingarea_info[type_id].infotext);
17165   }
17166
17167   infotext[max_infotext_len] = '\0';
17168
17169   if (strlen(infotext) > 0)
17170     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17171 }
17172
17173 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17174                             boolean quick_quit)
17175 {
17176   if (!ask_if_level_has_changed ||
17177       !LevelChanged() ||
17178       Request("Level has changed! Exit without saving?",
17179               REQ_ASK | REQ_STAY_OPEN))
17180   {
17181     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17182     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17183
17184     // draw normal door
17185     UndrawSpecialEditorDoor();
17186
17187     // use door animation if door 1 viewport is unchanged and contains toolbox
17188     if (useEditorDoorAnimation())
17189       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17190
17191     // close editor doors if viewport definition is the same as in main menu
17192     if (vp_door_1->x      == DX     &&
17193         vp_door_1->y      == DY     &&
17194         vp_door_1->width  == DXSIZE &&
17195         vp_door_1->height == DYSIZE &&
17196         vp_door_2->x      == VX     &&
17197         vp_door_2->y      == VY     &&
17198         vp_door_2->width  == VXSIZE &&
17199         vp_door_2->height == VYSIZE)
17200       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17201     else
17202       SetDoorState(DOOR_CLOSE_ALL);
17203
17204     BackToFront();
17205
17206     if (quick_quit)
17207       FadeSkipNextFadeIn();
17208
17209     SetGameStatus(GAME_MODE_MAIN);
17210
17211     DrawMainMenu();
17212   }
17213   else
17214   {
17215     if (!global.use_envelope_request)
17216     {
17217       CloseDoor(DOOR_CLOSE_1);
17218       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17219     }
17220   }
17221 }