fixed creature switch settings in level editor (BD engine)
[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(2),
3963     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3964     &level.bd_creatures_turn_on_hatching,
3965     NULL, NULL,
3966     "Creatures auto 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_INBOX,
5133   EL_BD_STEELWALL,
5134   EL_BD_WALL,
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_SAND_2,
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 ? 1 : 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     {
11950       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11951     }
11952     else if (properties_element == EL_BD_ACID)
11953     {
11954       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11955       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11956     }
11957     else if (IS_BD_BITER(properties_element))
11958     {
11959       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11960     }
11961     else if (properties_element == EL_BD_BLADDER)
11962     {
11963       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11964     }
11965     else if (properties_element == EL_YAMYAM ||
11966              properties_element == EL_YAMYAM_LEFT ||
11967              properties_element == EL_YAMYAM_RIGHT ||
11968              properties_element == EL_YAMYAM_UP ||
11969              properties_element == EL_YAMYAM_DOWN)
11970     {
11971       DrawYamYamContentAreas();
11972     }
11973     else if (properties_element == EL_EMC_MAGIC_BALL)
11974     {
11975       DrawMagicBallContentAreas();
11976
11977       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
11978       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
11979     }
11980     else if (properties_element == EL_EMC_ANDROID)
11981     {
11982       DrawAndroidElementArea();
11983     }
11984     else if (properties_element == EL_MM_GRAY_BALL)
11985     {
11986       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
11987       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
11988       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
11989       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
11990
11991       DrawMMBallContentArea();
11992     }
11993   }
11994
11995   if (IS_PLAYER_ELEMENT(properties_element))
11996   {
11997     int player_nr = GET_PLAYER_NR(properties_element);
11998
11999     // these properties can be set for every player individually
12000
12001     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12002     {
12003       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
12004         &level.start_element[player_nr];
12005       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
12006         &level.artwork_element[player_nr];
12007       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
12008         &level.explosion_element[player_nr];
12009
12010       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
12011         &level.use_start_element[player_nr];
12012       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
12013         &level.use_artwork_element[player_nr];
12014       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
12015         &level.use_explosion_element[player_nr];
12016       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
12017         &level.initial_player_gravity[player_nr];
12018
12019       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
12020         &level.initial_player_stepsize[player_nr];
12021
12022       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
12023       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
12024                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
12025                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
12026       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
12027       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
12028       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
12029       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
12030       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
12031       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
12032       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
12033       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
12034       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
12035       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
12036       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
12037
12038       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
12039       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
12040       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
12041
12042       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
12043     }
12044     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12045     {
12046       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
12047         &level.initial_inventory_content[player_nr][0];
12048
12049       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
12050         &level.initial_inventory_size[player_nr];
12051
12052       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
12053         &level.use_initial_inventory[player_nr];
12054
12055       // draw checkbutton gadgets
12056       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
12057       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
12058       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
12059
12060       // draw counter gadgets
12061       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
12062
12063       // draw drawing area gadgets
12064       DrawPlayerInitialInventoryArea(properties_element);
12065     }
12066   }
12067
12068   if (IS_BD_PLAYER_ELEMENT(properties_element))
12069   {
12070     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12071       ED_ELEMENT_SETTINGS_YPOS(2);
12072     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12073       ED_ELEMENT_SETTINGS_YPOS(3);
12074     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12075       ED_ELEMENT_SETTINGS_YPOS(4);
12076
12077     // draw checkbutton gadgets
12078     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
12079     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
12080     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12081
12082     // draw counter gadgets
12083     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12084     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12085
12086     // draw drawing area gadgets
12087     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
12088   }
12089
12090   if (properties_element == EL_BD_SAND)
12091   {
12092     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
12093   }
12094
12095   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12096   {
12097     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12098       ED_ELEMENT_SETTINGS_YPOS(0);
12099     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12100       ED_ELEMENT_SETTINGS_YPOS(1);
12101
12102     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12103     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12104
12105     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
12106     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
12107   }
12108
12109   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12110   {
12111     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
12112     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
12113   }
12114
12115   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
12116   {
12117     if (IS_BD_FIREFLY(properties_element))
12118     {
12119       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO);
12120       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12121     }
12122     else if (IS_BD_FIREFLY_2(properties_element))
12123     {
12124       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
12125       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12126     }
12127     else if (IS_BD_BUTTERFLY(properties_element))
12128     {
12129       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO);
12130       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12131     }
12132     else if (IS_BD_BUTTERFLY_2(properties_element))
12133     {
12134       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
12135       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12136     }
12137     else if (IS_BD_STONEFLY(properties_element))
12138     {
12139       MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
12140     }
12141     else if (IS_BD_DRAGONFLY(properties_element))
12142     {
12143       MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
12144       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12145     }
12146     else if (properties_element == EL_BD_BOMB)
12147     {
12148       MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
12149     }
12150     else if (properties_element == EL_BD_NITRO_PACK)
12151     {
12152       MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
12153     }
12154   }
12155
12156   if (properties_element == EL_BD_MEGA_ROCK ||
12157       properties_element == EL_BD_SWEET)
12158   {
12159     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12160       ED_ELEMENT_SETTINGS_YPOS(0);
12161     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12162       ED_ELEMENT_SETTINGS_YPOS(1);
12163
12164     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12165     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12166   }
12167
12168   if (properties_element == EL_BD_VOODOO_DOLL)
12169   {
12170     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12171     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12172     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12173     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12174   }
12175
12176   if (properties_element == EL_BD_SLIME)
12177   {
12178     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12179
12180     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12181     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12182     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12183     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12184     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12185     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12186   }
12187
12188   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12189       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12190   {
12191     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12192
12193     if (IS_BD_EXPANDABLE_WALL(properties_element))
12194       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12195   }
12196
12197   if (properties_element == EL_BD_REPLICATOR)
12198   {
12199     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12200   }
12201
12202   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12203       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12204   {
12205     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12206     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12207   }
12208
12209   if (properties_element == EL_BD_WATER)
12210   {
12211     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12212   }
12213
12214   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12215   {
12216     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12217   }
12218
12219   if (properties_element == EL_BD_CREATURE_SWITCH)
12220   {
12221     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12222     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12223   }
12224
12225   if (properties_element == EL_BD_GRAVITY_SWITCH)
12226   {
12227     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12228
12229     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12230     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12231   }
12232
12233   if (properties_element == EL_BD_NUT)
12234   {
12235     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12236   }
12237
12238   // special case: slippery walls option for gems only available in R'n'D game engine
12239   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12240     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12241
12242   if (properties_element == EL_EM_DYNAMITE)
12243     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12244
12245   if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
12246       COULD_MOVE_INTO_ACID(properties_element) &&
12247       !IS_PLAYER_ELEMENT(properties_element) &&
12248       (!IS_CUSTOM_ELEMENT(properties_element) ||
12249        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12250   {
12251     // set position for checkbutton for "can move into acid"
12252     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12253       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12254     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12255       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12256                                IS_BALLOON_ELEMENT(properties_element) ||
12257                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12258
12259     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12260   }
12261
12262   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12263     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12264
12265   if (properties_element == EL_SPRING ||
12266       properties_element == EL_SPRING_LEFT ||
12267       properties_element == EL_SPRING_RIGHT)
12268     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12269
12270   if (properties_element == EL_TIME_ORB_FULL)
12271     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12272
12273   if (properties_element == EL_GAME_OF_LIFE ||
12274       properties_element == EL_BIOMAZE)
12275     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12276
12277   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12278   {
12279     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12280       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12281
12282     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12283   }
12284
12285   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12286     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12287
12288   if (properties_element == EL_SOKOBAN_OBJECT)
12289     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12290
12291   if (properties_element == EL_SOKOBAN_OBJECT ||
12292       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12293       properties_element == EL_SOKOBAN_FIELD_FULL)
12294   {
12295     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12296       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12297                                0 : 1);
12298
12299     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12300   }
12301
12302   if (IS_BALLOON_ELEMENT(properties_element))
12303     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12304
12305   if (IS_ENVELOPE(properties_element) ||
12306       IS_MM_ENVELOPE(properties_element))
12307   {
12308     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12309     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12310     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12311     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12312     int envelope_nr = ENVELOPE_NR(properties_element);
12313
12314     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12315     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12316
12317     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12318     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12319
12320     // display counter to choose size of envelope text area
12321     MapCounterButtons(counter1_id);
12322     MapCounterButtons(counter2_id);
12323
12324     // display checkbuttons to choose auto-wrap and alignment properties
12325     MapCheckbuttonGadget(button1_id);
12326     MapCheckbuttonGadget(button2_id);
12327
12328     DrawEnvelopeTextArea(envelope_nr);
12329   }
12330
12331   if (IS_MM_MCDUFFIN(properties_element))
12332   {
12333     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12334     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12335     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12336   }
12337
12338   if (IS_DF_LASER(properties_element))
12339   {
12340     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12341     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12342     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12343   }
12344
12345   if (IS_CUSTOM_ELEMENT(properties_element))
12346   {
12347     // draw stickybutton gadget
12348     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12349
12350     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12351     {
12352       // draw checkbutton gadgets
12353       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12354            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12355         MapCheckbuttonGadget(i);
12356
12357       // draw counter gadgets
12358       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12359            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12360         MapCounterButtons(i);
12361
12362       // draw selectbox gadgets
12363       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12364            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12365         MapSelectboxGadget(i);
12366
12367       // draw textbutton gadgets
12368       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12369
12370       // draw text input gadgets
12371       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12372
12373       // draw drawing area gadgets
12374       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12375
12376       draw_footer_line = TRUE;
12377     }
12378     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12379     {
12380       // draw checkbutton gadgets
12381       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12382            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12383         MapCheckbuttonGadget(i);
12384
12385       // draw counter gadgets
12386       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12387            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12388         MapCounterButtons(i);
12389
12390       // draw selectbox gadgets
12391       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12392            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12393         MapSelectboxGadget(i);
12394
12395       // draw drawing area gadgets
12396       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12397       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12398       DrawCustomContentArea();
12399     }
12400   }
12401   else if (IS_GROUP_ELEMENT(properties_element))
12402   {
12403     // draw stickybutton gadget
12404     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12405
12406     // draw checkbutton gadgets
12407     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12408     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12409
12410     // draw counter gadgets
12411     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12412
12413     // draw selectbox gadgets
12414     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12415
12416     // draw textbutton gadgets
12417     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12418
12419     // draw drawing area gadgets
12420     DrawGroupElementArea();
12421
12422     // draw text input gadgets
12423     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12424
12425     // draw drawing area gadgets
12426     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12427
12428     draw_footer_line = TRUE;
12429   }
12430   else if (IS_EMPTY_ELEMENT(properties_element))
12431   {
12432     // draw stickybutton gadget
12433     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12434
12435     // draw checkbutton gadgets
12436     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12437     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12438
12439     // draw textbutton gadgets
12440     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12441
12442     // draw drawing area gadgets
12443     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12444
12445     draw_footer_line = TRUE;
12446   }
12447
12448   // draw little footer border line above CE/GE use/save template gadgets
12449   if (draw_footer_line)
12450   {
12451     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12452     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12453     int gd_x = gd->x + gd_gi1->border.width / 2;
12454     int gd_y = gd->y + gd_gi1->height - 1;
12455     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12456
12457     if (tab_color != BLACK_PIXEL)               // black => transparent
12458       FillRectangle(drawto,
12459                     SX + ED_ELEMENT_SETTINGS_X(0),
12460                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12461                     ED_TAB_BAR_HEIGHT,
12462                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12463   }
12464 }
12465
12466 static void DrawPropertiesChangeDrawingAreas(void)
12467 {
12468   if (IS_CUSTOM_ELEMENT(properties_element))
12469   {
12470     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12471     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12472     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12473
12474     DrawCustomChangeContentArea();
12475   }
12476
12477   redraw_mask |= REDRAW_FIELD;
12478 }
12479
12480 static void DrawPropertiesChange(void)
12481 {
12482   int i;
12483
12484   // needed to initially set selectbox options for special action options
12485   setSelectboxSpecialActionOptions();
12486
12487   // draw stickybutton gadget
12488   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12489
12490   // draw checkbutton gadgets
12491   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12492        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12493     MapCheckbuttonGadget(i);
12494
12495   // draw counter gadgets
12496   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12497        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12498     MapCounterButtons(i);
12499
12500   // draw selectbox gadgets
12501   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12502        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12503     MapSelectboxGadget(i);
12504
12505   // draw textbutton gadgets
12506   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12507        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12508     MapTextbuttonGadget(i);
12509
12510   // draw graphicbutton gadgets
12511   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12512        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12513     MapGraphicbuttonGadget(i);
12514
12515   // draw drawing area gadgets
12516   DrawPropertiesChangeDrawingAreas();
12517 }
12518
12519 static void DrawEditorElementAnimation(int x, int y)
12520 {
12521   int graphic;
12522   int frame;
12523
12524   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12525
12526   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12527 }
12528
12529 static void DrawEditorElementName(int x, int y, int font_nr)
12530 {
12531   char *element_name = getElementInfoText(properties_element);
12532   int font_width = getFontWidth(font_nr);
12533   int font_height = getFontHeight(font_nr);
12534   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12535   int max_chars_per_line = max_text_width / font_width;
12536
12537   if (strlen(element_name) <= max_chars_per_line)
12538     DrawTextS(x, y, font_nr, element_name);
12539   else
12540   {
12541     char buffer[max_chars_per_line + 1];
12542     int next_pos = max_chars_per_line;
12543
12544     strncpy(buffer, element_name, max_chars_per_line);
12545     buffer[max_chars_per_line] = '\0';
12546
12547     if (element_name[max_chars_per_line] == ' ')
12548       next_pos++;
12549     else
12550     {
12551       int i;
12552
12553       for (i = max_chars_per_line - 1; i >= 0; i--)
12554         if (buffer[i] == ' ')
12555           break;
12556
12557       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12558       {
12559         buffer[i] = '\0';
12560         next_pos = i + 1;
12561       }
12562     }
12563
12564     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12565
12566     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12567     buffer[max_chars_per_line] = '\0';
12568
12569     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12570   }
12571 }
12572
12573 static void DrawPropertiesWindow(void)
12574 {
12575   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12576   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12577   int border_size = gd->border_size;
12578   int font_nr = FONT_TEXT_1;
12579   int font_height = getFontHeight(font_nr);
12580   int xoffset = TILEX + element_border + 3 * border_size;
12581   int yoffset = (TILEY - font_height) / 2;
12582   int x1 = editor.settings.element_graphic.x + element_border;
12583   int y1 = editor.settings.element_graphic.y + element_border;
12584   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12585             editor.settings.element_name.x);
12586   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12587             editor.settings.element_name.y);
12588   char *text = "Element Settings";
12589   int font2_nr = FONT_TITLE_1;
12590   struct MenuPosInfo *pos = &editor.settings.headline;
12591   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12592   int sy = SY + pos->y;
12593
12594   stick_element_properties_window = FALSE;
12595
12596   // make sure that previous properties edit mode exists for this element
12597   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12598       !IS_CUSTOM_ELEMENT(properties_element))
12599     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12600
12601   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12602       !IS_PLAYER_ELEMENT(properties_element) &&
12603       !IS_CUSTOM_ELEMENT(properties_element))
12604     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12605
12606   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12607       (IS_PLAYER_ELEMENT(properties_element) ||
12608        IS_CUSTOM_ELEMENT(properties_element)))
12609     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12610
12611   CopyElementPropertiesToEditor(properties_element);
12612
12613   UnmapLevelEditorFieldGadgets();
12614   UnmapLevelEditorToolboxDrawingGadgets();
12615   UnmapLevelEditorToolboxCustomGadgets();
12616
12617   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12618
12619   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12620   ClearField();
12621
12622   DrawText(sx, sy, text, font2_nr);
12623
12624   FrameCounter = 0;     // restart animation frame counter
12625
12626   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12627   DrawEditorElementAnimation(SX + x1, SY + y1);
12628   DrawEditorElementName(x2, y2, font_nr);
12629
12630   DrawPropertiesTabulatorGadgets();
12631
12632   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12633     DrawPropertiesInfo();
12634   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12635     DrawPropertiesChange();
12636   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12637     DrawPropertiesConfig();
12638 }
12639
12640 static void DrawPaletteWindow(void)
12641 {
12642   int i;
12643
12644   UnmapLevelEditorFieldGadgets();
12645
12646   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12647   ClearField();
12648
12649   // map buttons to select elements
12650   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12651     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12652   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12653   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12654   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12655 }
12656
12657 static void UpdateCustomElementGraphicGadgets(void)
12658 {
12659   int i;
12660
12661   InitElementPropertiesGfxElement();
12662
12663   ModifyEditorElementList();
12664   RedrawDrawingElements();
12665
12666   // force redraw of all mapped drawing area gadgets
12667   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12668   {
12669     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12670
12671     if (gi->mapped)
12672       MapDrawingArea(i);
12673   }
12674 }
12675
12676 static int getOpenDirectionFromTube(int element)
12677 {
12678   switch (element)
12679   {
12680     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12681     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12682     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12683     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12684     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12685     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12686     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12687     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12688     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12689     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12690     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12691   }
12692
12693   return MV_NONE;
12694 }
12695
12696 static int getTubeFromOpenDirection(int direction)
12697 {
12698   switch (direction)
12699   {
12700     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12701     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12702     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12703     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12704     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12705     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12706     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12707     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12708     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12709     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12710     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12711
12712     // if only one direction, fall back to simple tube with that direction
12713     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12714     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12715     case (MV_UP):                       return EL_TUBE_VERTICAL;
12716     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12717   }
12718
12719   return EL_EMPTY;
12720 }
12721
12722 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12723 {
12724   int element_new = getTubeFromOpenDirection(direction);
12725
12726   return (element_new != EL_EMPTY ? element_new : element_old);
12727 }
12728
12729 static int getOpenDirectionFromBelt(int element)
12730 {
12731   int belt_dir = getBeltDirFromBeltElement(element);
12732
12733   return (belt_dir == MV_LEFT ? MV_RIGHT :
12734           belt_dir == MV_RIGHT ? MV_LEFT :
12735           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12736 }
12737
12738 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12739 {
12740   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12741                   direction == MV_RIGHT ? MV_LEFT :
12742                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12743
12744   if (direction == MV_NONE)
12745     return EL_EMPTY;
12746
12747   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12748 }
12749
12750 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12751                                                  int element_old)
12752 {
12753   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12754
12755   return (element_new != EL_EMPTY ? element_new : element_old);
12756 }
12757
12758 static int getOpenDirectionFromPool(int element)
12759 {
12760   switch (element)
12761   {
12762     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12763     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12764     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12765     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12766     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12767     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12768   }
12769
12770   return MV_NONE;
12771 }
12772
12773 static int getPoolFromOpenDirection(int direction)
12774 {
12775   switch (direction)
12776   {
12777     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12778     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12779     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12780     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12781     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12782     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12783   }
12784
12785   return EL_EMPTY;
12786 }
12787
12788 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12789 {
12790   int element = getPoolFromOpenDirection(direction);
12791   int help_direction = getOpenDirectionFromPool(help_element);
12792
12793   if (element == EL_EMPTY)
12794   {
12795     int help_direction_vertical = help_direction & MV_VERTICAL;
12796
12797     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12798   }
12799
12800   if (element == EL_EMPTY)
12801   {
12802     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12803
12804     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12805   }
12806
12807   return element;
12808 }
12809
12810 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12811 {
12812   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12813
12814   return (element_new != EL_EMPTY ? element_new : element_old);
12815 }
12816
12817 static int getOpenDirectionFromPillar(int element)
12818 {
12819   switch (element)
12820   {
12821     case EL_EMC_WALL_1:                 return (MV_DOWN);
12822     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12823     case EL_EMC_WALL_3:                 return (MV_UP);
12824   }
12825
12826   return MV_NONE;
12827 }
12828
12829 static int getPillarFromOpenDirection(int direction)
12830 {
12831   switch (direction)
12832   {
12833     case (MV_DOWN):                     return EL_EMC_WALL_1;
12834     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12835     case (MV_UP):                       return EL_EMC_WALL_3;
12836   }
12837
12838   return EL_EMPTY;
12839 }
12840
12841 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12842 {
12843   int element_new = getPillarFromOpenDirection(direction);
12844
12845   return (element_new != EL_EMPTY ? element_new : element_old);
12846 }
12847
12848 static int getOpenDirectionFromSteel2(int element)
12849 {
12850   switch (element)
12851   {
12852     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12853     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12854     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12855     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12856     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12857     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12858     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12859     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12860   }
12861
12862   return MV_NONE;
12863 }
12864
12865 static int getSteel2FromOpenDirection(int direction)
12866 {
12867   switch (direction)
12868   {
12869     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12870     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12871     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12872     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12873     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12874     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12875     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12876     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12877   }
12878
12879   return EL_EMPTY;
12880 }
12881
12882 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12883 {
12884   int element_new = getSteel2FromOpenDirection(direction);
12885
12886   return (element_new != EL_EMPTY ? element_new : element_old);
12887 }
12888
12889 static int getOpenDirectionFromChip(int element)
12890 {
12891   switch (element)
12892   {
12893     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12894     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12895     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12896     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12897     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12898   }
12899
12900   return MV_NONE;
12901 }
12902
12903 static int getChipFromOpenDirection(int direction)
12904 {
12905   switch (direction)
12906   {
12907     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12908     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12909     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12910     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12911     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12912   }
12913
12914   return EL_EMPTY;
12915 }
12916
12917 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12918 {
12919   int element_new = getChipFromOpenDirection(direction);
12920
12921   return (element_new != EL_EMPTY ? element_new : element_old);
12922 }
12923
12924 static int getClosedTube(int x, int y)
12925 {
12926   struct XY *xy = xy_directions;
12927   int element_old = IntelliDrawBuffer[x][y];
12928   int direction_old = getOpenDirectionFromTube(element_old);
12929   int direction_new = MV_NONE;
12930   int i;
12931
12932   for (i = 0; i < NUM_DIRECTIONS; i++)
12933   {
12934     int xx = x + xy[i].x;
12935     int yy = y + xy[i].y;
12936     int dir = MV_DIR_FROM_BIT(i);
12937     int dir_opposite = MV_DIR_OPPOSITE(dir);
12938
12939     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12940         (direction_old & dir) &&
12941         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12942       direction_new |= dir;
12943   }
12944
12945   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12946 }
12947
12948 static int getClosedBelt(int x, int y)
12949 {
12950   struct XY *xy = xy_directions;
12951   int element_old = IntelliDrawBuffer[x][y];
12952   int nr = getBeltNrFromBeltElement(element_old);
12953   int direction_old = getOpenDirectionFromBelt(element_old);
12954   int direction_new = MV_NONE;
12955   int i;
12956
12957   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12958   {
12959     int xx = x + xy[i].x;
12960     int yy = y + xy[i].y;
12961     int dir = MV_DIR_FROM_BIT(i);
12962     int dir_opposite = MV_DIR_OPPOSITE(dir);
12963
12964     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12965         (direction_old & dir) &&
12966         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12967       direction_new |= dir;
12968   }
12969
12970   return getBeltFromNrAndOpenDirection(nr, direction_new);
12971 }
12972
12973 static int getClosedPool(int x, int y)
12974 {
12975   struct XY *xy = xy_directions;
12976   int element_old = IntelliDrawBuffer[x][y];
12977   int direction_old = getOpenDirectionFromPool(element_old);
12978   int direction_new = MV_NONE;
12979   int i;
12980
12981   for (i = 0; i < NUM_DIRECTIONS; i++)
12982   {
12983     int xx = x + xy[i].x;
12984     int yy = y + xy[i].y;
12985     int dir = MV_DIR_FROM_BIT(i);
12986     int dir_opposite = MV_DIR_OPPOSITE(dir);
12987
12988     if (IN_LEV_FIELD(xx, yy) &&
12989         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
12990         (direction_old & dir) &&
12991         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12992       direction_new |= dir;
12993   }
12994
12995   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
12996 }
12997
12998 static int getClosedPillar(int x, int y)
12999 {
13000   struct XY *xy = xy_directions;
13001   int element_old = IntelliDrawBuffer[x][y];
13002   int direction_old = getOpenDirectionFromPillar(element_old);
13003   int direction_new = MV_NONE;
13004   int i;
13005
13006   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13007   {
13008     int xx = x + xy[i].x;
13009     int yy = y + xy[i].y;
13010     int dir = MV_DIR_FROM_BIT(i);
13011     int dir_opposite = MV_DIR_OPPOSITE(dir);
13012
13013     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
13014         (direction_old & dir) &&
13015         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13016       direction_new |= dir;
13017   }
13018
13019   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
13020 }
13021
13022 static int getClosedSteel2(int x, int y)
13023 {
13024   struct XY *xy = xy_directions;
13025   int element_old = IntelliDrawBuffer[x][y];
13026   int direction_old = getOpenDirectionFromSteel2(element_old);
13027   int direction_new = MV_NONE;
13028   int i;
13029
13030   for (i = 0; i < NUM_DIRECTIONS; i++)
13031   {
13032     int xx = x + xy[i].x;
13033     int yy = y + xy[i].y;
13034     int dir = MV_DIR_FROM_BIT(i);
13035     int dir_opposite = MV_DIR_OPPOSITE(dir);
13036
13037     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
13038         (direction_old & dir) &&
13039         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13040       direction_new |= dir;
13041   }
13042
13043   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
13044 }
13045
13046 static int getClosedChip(int x, int y)
13047 {
13048   struct XY *xy = xy_directions;
13049   int element_old = IntelliDrawBuffer[x][y];
13050   int direction_old = getOpenDirectionFromChip(element_old);
13051   int direction_new = MV_NONE;
13052   int i;
13053
13054   for (i = 0; i < NUM_DIRECTIONS; i++)
13055   {
13056     int xx = x + xy[i].x;
13057     int yy = y + xy[i].y;
13058     int dir = MV_DIR_FROM_BIT(i);
13059     int dir_opposite = MV_DIR_OPPOSITE(dir);
13060
13061     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
13062         (direction_old & dir) &&
13063         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13064       direction_new |= dir;
13065   }
13066
13067   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
13068 }
13069
13070 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
13071                                 boolean change_level)
13072 {
13073   int sx = x - level_xpos;
13074   int sy = y - level_ypos;
13075   int old_element = Tile[x][y];
13076   int new_element = element;
13077   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
13078   boolean draw_masked = FALSE;
13079
13080   if (IS_MM_WALL_EDITOR(element))
13081   {
13082     element = map_mm_wall_element_editor(element) | new_bitmask;
13083
13084     if (IS_MM_WALL(old_element))
13085       element |= MM_WALL_BITS(old_element);
13086
13087     if (!change_level)
13088       draw_masked = TRUE;
13089   }
13090   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
13091   {
13092     int element_changed = old_element & ~new_bitmask;
13093
13094     if (MM_WALL_BITS(element_changed) != 0)
13095       element = element_changed;
13096   }
13097
13098   IntelliDrawBuffer[x][y] = element;
13099
13100   if (change_level)
13101     Tile[x][y] = element;
13102
13103   if (IN_ED_FIELD(sx, sy))
13104   {
13105     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
13106       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
13107     else if (draw_masked)
13108       DrawEditorElementThruMask(sx, sy, element);
13109     else
13110       DrawEditorElement(sx, sy, element);
13111   }
13112 }
13113
13114 static void SetElementSimple(int x, int y, int element, boolean change_level)
13115 {
13116   SetElementSimpleExt(x, y, 0, 0, element, change_level);
13117 }
13118
13119 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
13120                                            int x2, int y2, int *element2,
13121                                            int (*close_function)(int, int),
13122                                            boolean change_level)
13123 {
13124   // set neighbour elements to newly determined connections
13125   SetElementSimple(x1, y1, *element1, change_level);
13126   SetElementSimple(x2, y2, *element2, change_level);
13127
13128   // remove all open connections of neighbour elements
13129   *element1 = close_function(x1, y1);
13130   *element2 = close_function(x2, y2);
13131
13132   // set neighbour elements to new, minimized connections
13133   SetElementSimple(x1, y1, *element1, change_level);
13134   SetElementSimple(x2, y2, *element2, change_level);
13135 }
13136
13137 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
13138                                   boolean change_level, int button)
13139 {
13140   struct XY *xy = xy_directions;
13141   static int last_x = -1;
13142   static int last_y = -1;
13143
13144   if (new_element == EL_UNDEFINED)
13145   {
13146     last_x = -1;
13147     last_y = -1;
13148
13149     return;
13150   }
13151
13152   int old_element = IntelliDrawBuffer[x][y];
13153
13154   if (IS_TUBE(new_element))
13155   {
13156     int last_element_new = EL_UNDEFINED;
13157     int direction = MV_NONE;
13158     int i;
13159
13160     // if old element is of same kind, keep all existing directions
13161     if (IS_TUBE(old_element))
13162       direction |= getOpenDirectionFromTube(old_element);
13163
13164     for (i = 0; i < NUM_DIRECTIONS; i++)
13165     {
13166       int xx = x + xy[i].x;
13167       int yy = y + xy[i].y;
13168
13169       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13170           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13171       {
13172         int dir = MV_DIR_FROM_BIT(i);
13173         int dir_opposite = MV_DIR_OPPOSITE(dir);
13174         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13175         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13176         int last_direction_new = last_direction_old | dir_opposite;
13177
13178         last_element_new = getTubeFromOpenDirection(last_direction_new);
13179
13180         direction |= dir;
13181       }
13182     }
13183
13184     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13185
13186     if (last_element_new != EL_UNDEFINED)
13187       MergeAndCloseNeighbourElements(x, y, &new_element,
13188                                      last_x, last_y, &last_element_new,
13189                                      getClosedTube, change_level);
13190   }
13191   else if (IS_BELT(new_element))
13192   {
13193     int belt_nr = getBeltNrFromBeltElement(new_element);
13194     int last_element_new = EL_UNDEFINED;
13195     int direction = MV_NONE;
13196     int i;
13197
13198     // if old element is of same kind, keep all existing directions
13199     if (IS_BELT(old_element))
13200       direction |= getOpenDirectionFromBelt(old_element);
13201
13202     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13203     {
13204       int xx = x + xy[i].x;
13205       int yy = y + xy[i].y;
13206
13207       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13208           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
13209       {
13210         int dir = MV_DIR_FROM_BIT(i);
13211         int dir_opposite = MV_DIR_OPPOSITE(dir);
13212         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13213         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
13214         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13215         int last_direction_new = last_direction_old | dir_opposite;
13216
13217         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13218                                                          last_direction_new);
13219         direction |= dir;
13220       }
13221     }
13222
13223     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13224                                                         new_element);
13225     if (last_element_new != EL_UNDEFINED)
13226       MergeAndCloseNeighbourElements(x, y, &new_element,
13227                                      last_x, last_y, &last_element_new,
13228                                      getClosedBelt, change_level);
13229   }
13230   else if (IS_ACID_POOL_OR_ACID(new_element))
13231   {
13232     int last_element_new = EL_UNDEFINED;
13233     int direction = MV_NONE;
13234     int i;
13235
13236     // if old element is of same kind, keep all existing directions
13237     if (IS_ACID_POOL_OR_ACID(old_element))
13238       direction |= getOpenDirectionFromPool(old_element);
13239
13240     for (i = 0; i < NUM_DIRECTIONS; i++)
13241     {
13242       int xx = x + xy[i].x;
13243       int yy = y + xy[i].y;
13244
13245       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13246           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
13247       {
13248         int dir = MV_DIR_FROM_BIT(i);
13249         int dir_opposite = MV_DIR_OPPOSITE(dir);
13250         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13251         int last_direction_old = getOpenDirectionFromPool(last_element_old);
13252         int last_direction_new = last_direction_old | dir_opposite;
13253
13254         last_element_new = getPoolFromOpenDirection(last_direction_new);
13255
13256         direction |= dir;
13257       }
13258     }
13259
13260     // special corrections needed for intuitively correct acid pool drawing
13261     if (last_element_new == EL_EMPTY)
13262       last_element_new = new_element;
13263     else if (last_element_new != EL_UNDEFINED)
13264       new_element = last_element_new;
13265
13266     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13267
13268     if (last_element_new != EL_UNDEFINED)
13269       MergeAndCloseNeighbourElements(x, y, &new_element,
13270                                      last_x, last_y, &last_element_new,
13271                                      getClosedPool, change_level);
13272   }
13273   else if (IS_EMC_PILLAR(new_element))
13274   {
13275     int last_element_new = EL_UNDEFINED;
13276     int direction = MV_NONE;
13277     int i;
13278
13279     // if old element is of same kind, keep all existing directions
13280     if (IS_EMC_PILLAR(old_element))
13281       direction |= getOpenDirectionFromPillar(old_element);
13282
13283     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13284     {
13285       int xx = x + xy[i].x;
13286       int yy = y + xy[i].y;
13287
13288       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13289           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13290       {
13291         int dir = MV_DIR_FROM_BIT(i);
13292         int dir_opposite = MV_DIR_OPPOSITE(dir);
13293         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13294         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13295         int last_direction_new = last_direction_old | dir_opposite;
13296
13297         last_element_new = getPillarFromOpenDirection(last_direction_new);
13298
13299         direction |= dir;
13300       }
13301     }
13302
13303     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13304
13305     if (last_element_new != EL_UNDEFINED)
13306       MergeAndCloseNeighbourElements(x, y, &new_element,
13307                                      last_x, last_y, &last_element_new,
13308                                      getClosedPillar, change_level);
13309   }
13310   else if (IS_DC_STEELWALL_2(new_element))
13311   {
13312     int last_element_new = EL_UNDEFINED;
13313     int direction = MV_NONE;
13314     int i;
13315
13316     // if old element is of same kind, keep all existing directions
13317     if (IS_DC_STEELWALL_2(old_element))
13318       direction |= getOpenDirectionFromSteel2(old_element);
13319
13320     for (i = 0; i < NUM_DIRECTIONS; i++)
13321     {
13322       int xx = x + xy[i].x;
13323       int yy = y + xy[i].y;
13324
13325       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13326           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13327       {
13328         int dir = MV_DIR_FROM_BIT(i);
13329         int dir_opposite = MV_DIR_OPPOSITE(dir);
13330         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13331         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13332         int last_direction_new = last_direction_old | dir_opposite;
13333
13334         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13335
13336         direction |= dir;
13337       }
13338     }
13339
13340     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13341
13342     if (last_element_new != EL_UNDEFINED)
13343       MergeAndCloseNeighbourElements(x, y, &new_element,
13344                                      last_x, last_y, &last_element_new,
13345                                      getClosedSteel2, change_level);
13346   }
13347   else if (IS_SP_CHIP(new_element))
13348   {
13349     int last_element_new = EL_UNDEFINED;
13350     int direction = MV_NONE;
13351     int i;
13352
13353     // (do not keep existing directions, regardless of kind of old element)
13354
13355     for (i = 0; i < NUM_DIRECTIONS; i++)
13356     {
13357       int xx = x + xy[i].x;
13358       int yy = y + xy[i].y;
13359
13360       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13361           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13362       {
13363         int dir = MV_DIR_FROM_BIT(i);
13364         int dir_opposite = MV_DIR_OPPOSITE(dir);
13365         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13366         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13367         int last_direction_new = last_direction_old | dir_opposite;
13368
13369         if (last_direction_old == MV_NONE)
13370         {
13371           last_element_new = getChipFromOpenDirection(last_direction_new);
13372           direction |= dir;
13373         }
13374         else if (last_direction_old & (dir | dir_opposite))
13375         {
13376           direction |= MV_DIR_OPPOSITE(last_direction_old);
13377         }
13378         else
13379         {
13380           direction |= MV_DIR_OPPOSITE(dir);
13381         }
13382       }
13383     }
13384
13385     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13386
13387     if (last_element_new != EL_UNDEFINED)
13388       MergeAndCloseNeighbourElements(x, y, &new_element,
13389                                      last_x, last_y, &last_element_new,
13390                                      getClosedChip, change_level);
13391   }
13392   else if (IS_SP_HARDWARE_BASE(new_element))
13393   {
13394     int nr = GetSimpleRandom(6);
13395
13396     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13397                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13398                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13399                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13400                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13401   }
13402   else if (new_element == EL_SP_HARDWARE_GREEN ||
13403            new_element == EL_SP_HARDWARE_BLUE ||
13404            new_element == EL_SP_HARDWARE_RED)
13405   {
13406     int nr = GetSimpleRandom(3);
13407
13408     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13409                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13410   }
13411   else if (IS_GROUP_ELEMENT(new_element))
13412   {
13413     boolean connected_drawing = FALSE;
13414     int i;
13415
13416     for (i = 0; i < NUM_DIRECTIONS; i++)
13417     {
13418       int xx = x + xy[i].x;
13419       int yy = y + xy[i].y;
13420
13421       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13422           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13423         connected_drawing = TRUE;
13424     }
13425
13426     if (!connected_drawing)
13427       ResolveGroupElement(new_element);
13428
13429     new_element = GetElementFromGroupElement(new_element);
13430   }
13431   else if (IS_BELT_SWITCH(old_element))
13432   {
13433     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13434     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13435
13436     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13437                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13438
13439     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13440   }
13441   else
13442   {
13443     static int swappable_elements[][2] =
13444     {
13445       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13446       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13447       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13448       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13449       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13450       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13451       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13452       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13453       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13454       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13455       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13456       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13457       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13458       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13459       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13460       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13461       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13462       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13463       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13464       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13465       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13466       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13467       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13468       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13469       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13470       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13471       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13472       { EL_PEARL,                       EL_WALL_PEARL                   },
13473       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13474       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13475       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13476       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13477       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13478       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13479       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13480       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13481       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13482       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13483       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13484       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13485       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13486       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13487       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13488       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13489
13490       { -1,                             -1                              },
13491     };
13492     static int rotatable_elements_4[][4] =
13493     {
13494       {
13495         EL_BUG_UP,
13496         EL_BUG_RIGHT,
13497         EL_BUG_DOWN,
13498         EL_BUG_LEFT
13499       },
13500       {
13501         EL_SPACESHIP_UP,
13502         EL_SPACESHIP_RIGHT,
13503         EL_SPACESHIP_DOWN,
13504         EL_SPACESHIP_LEFT
13505       },
13506       {
13507         EL_BD_BUTTERFLY_UP,
13508         EL_BD_BUTTERFLY_RIGHT,
13509         EL_BD_BUTTERFLY_DOWN,
13510         EL_BD_BUTTERFLY_LEFT
13511       },
13512       {
13513         EL_BD_FIREFLY_UP,
13514         EL_BD_FIREFLY_RIGHT,
13515         EL_BD_FIREFLY_DOWN,
13516         EL_BD_FIREFLY_LEFT
13517       },
13518       {
13519         EL_PACMAN_UP,
13520         EL_PACMAN_RIGHT,
13521         EL_PACMAN_DOWN,
13522         EL_PACMAN_LEFT
13523       },
13524       {
13525         EL_YAMYAM_UP,
13526         EL_YAMYAM_RIGHT,
13527         EL_YAMYAM_DOWN,
13528         EL_YAMYAM_LEFT
13529       },
13530       {
13531         EL_ARROW_UP,
13532         EL_ARROW_RIGHT,
13533         EL_ARROW_DOWN,
13534         EL_ARROW_LEFT
13535       },
13536       {
13537         EL_SP_PORT_UP,
13538         EL_SP_PORT_RIGHT,
13539         EL_SP_PORT_DOWN,
13540         EL_SP_PORT_LEFT
13541       },
13542       {
13543         EL_SP_GRAVITY_PORT_UP,
13544         EL_SP_GRAVITY_PORT_RIGHT,
13545         EL_SP_GRAVITY_PORT_DOWN,
13546         EL_SP_GRAVITY_PORT_LEFT
13547       },
13548       {
13549         EL_SP_GRAVITY_ON_PORT_UP,
13550         EL_SP_GRAVITY_ON_PORT_RIGHT,
13551         EL_SP_GRAVITY_ON_PORT_DOWN,
13552         EL_SP_GRAVITY_ON_PORT_LEFT
13553       },
13554       {
13555         EL_SP_GRAVITY_OFF_PORT_UP,
13556         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13557         EL_SP_GRAVITY_OFF_PORT_DOWN,
13558         EL_SP_GRAVITY_OFF_PORT_LEFT
13559       },
13560       {
13561         EL_MOLE_UP,
13562         EL_MOLE_RIGHT,
13563         EL_MOLE_DOWN,
13564         EL_MOLE_LEFT
13565       },
13566       {
13567         EL_BALLOON_SWITCH_UP,
13568         EL_BALLOON_SWITCH_RIGHT,
13569         EL_BALLOON_SWITCH_DOWN,
13570         EL_BALLOON_SWITCH_LEFT
13571       },
13572       {
13573         EL_MM_MCDUFFIN_UP,
13574         EL_MM_MCDUFFIN_RIGHT,
13575         EL_MM_MCDUFFIN_DOWN,
13576         EL_MM_MCDUFFIN_LEFT
13577       },
13578       {
13579         EL_MM_MIRROR_FIXED_1,
13580         EL_MM_MIRROR_FIXED_4,
13581         EL_MM_MIRROR_FIXED_3,
13582         EL_MM_MIRROR_FIXED_2
13583       },
13584       {
13585         EL_MM_STEEL_GRID_FIXED_1,
13586         EL_MM_STEEL_GRID_FIXED_4,
13587         EL_MM_STEEL_GRID_FIXED_2,
13588         EL_MM_STEEL_GRID_FIXED_3
13589       },
13590       {
13591         EL_MM_WOODEN_GRID_FIXED_1,
13592         EL_MM_WOODEN_GRID_FIXED_4,
13593         EL_MM_WOODEN_GRID_FIXED_2,
13594         EL_MM_WOODEN_GRID_FIXED_3
13595       },
13596       {
13597         EL_MM_POLARIZER_CROSS_1,
13598         EL_MM_POLARIZER_CROSS_4,
13599         EL_MM_POLARIZER_CROSS_3,
13600         EL_MM_POLARIZER_CROSS_2
13601       },
13602       {
13603         EL_MM_PACMAN_UP,
13604         EL_MM_PACMAN_RIGHT,
13605         EL_MM_PACMAN_DOWN,
13606         EL_MM_PACMAN_LEFT
13607       },
13608       {
13609         EL_DF_LASER_UP,
13610         EL_DF_LASER_RIGHT,
13611         EL_DF_LASER_DOWN,
13612         EL_DF_LASER_LEFT
13613       },
13614       {
13615         EL_DF_RECEIVER_UP,
13616         EL_DF_RECEIVER_RIGHT,
13617         EL_DF_RECEIVER_DOWN,
13618         EL_DF_RECEIVER_LEFT
13619       },
13620       {
13621         EL_DF_SLOPE_1,
13622         EL_DF_SLOPE_4,
13623         EL_DF_SLOPE_3,
13624         EL_DF_SLOPE_2
13625       },
13626
13627       {
13628         -1,
13629       },
13630     };
13631     static int rotatable_elements_8[][8] =
13632     {
13633       {
13634         EL_DF_STEEL_GRID_FIXED_1,
13635         EL_DF_STEEL_GRID_FIXED_8,
13636         EL_DF_STEEL_GRID_FIXED_7,
13637         EL_DF_STEEL_GRID_FIXED_6,
13638         EL_DF_STEEL_GRID_FIXED_5,
13639         EL_DF_STEEL_GRID_FIXED_4,
13640         EL_DF_STEEL_GRID_FIXED_3,
13641         EL_DF_STEEL_GRID_FIXED_2
13642       },
13643       {
13644         EL_DF_WOODEN_GRID_FIXED_1,
13645         EL_DF_WOODEN_GRID_FIXED_8,
13646         EL_DF_WOODEN_GRID_FIXED_7,
13647         EL_DF_WOODEN_GRID_FIXED_6,
13648         EL_DF_WOODEN_GRID_FIXED_5,
13649         EL_DF_WOODEN_GRID_FIXED_4,
13650         EL_DF_WOODEN_GRID_FIXED_3,
13651         EL_DF_WOODEN_GRID_FIXED_2
13652       },
13653       {
13654         EL_DF_STEEL_GRID_ROTATING_1,
13655         EL_DF_STEEL_GRID_ROTATING_8,
13656         EL_DF_STEEL_GRID_ROTATING_7,
13657         EL_DF_STEEL_GRID_ROTATING_6,
13658         EL_DF_STEEL_GRID_ROTATING_5,
13659         EL_DF_STEEL_GRID_ROTATING_4,
13660         EL_DF_STEEL_GRID_ROTATING_3,
13661         EL_DF_STEEL_GRID_ROTATING_2
13662       },
13663       {
13664         EL_DF_WOODEN_GRID_ROTATING_1,
13665         EL_DF_WOODEN_GRID_ROTATING_8,
13666         EL_DF_WOODEN_GRID_ROTATING_7,
13667         EL_DF_WOODEN_GRID_ROTATING_6,
13668         EL_DF_WOODEN_GRID_ROTATING_5,
13669         EL_DF_WOODEN_GRID_ROTATING_4,
13670         EL_DF_WOODEN_GRID_ROTATING_3,
13671         EL_DF_WOODEN_GRID_ROTATING_2
13672       },
13673
13674       {
13675         -1,
13676       },
13677     };
13678     static int rotatable_elements_16[][16] =
13679     {
13680       {
13681         EL_MM_MIRROR_1,
13682         EL_MM_MIRROR_16,
13683         EL_MM_MIRROR_15,
13684         EL_MM_MIRROR_14,
13685         EL_MM_MIRROR_13,
13686         EL_MM_MIRROR_12,
13687         EL_MM_MIRROR_11,
13688         EL_MM_MIRROR_10,
13689         EL_MM_MIRROR_9,
13690         EL_MM_MIRROR_8,
13691         EL_MM_MIRROR_7,
13692         EL_MM_MIRROR_6,
13693         EL_MM_MIRROR_5,
13694         EL_MM_MIRROR_4,
13695         EL_MM_MIRROR_3,
13696         EL_MM_MIRROR_2
13697       },
13698       {
13699         EL_MM_TELEPORTER_5,
13700         EL_MM_TELEPORTER_4,
13701         EL_MM_TELEPORTER_3,
13702         EL_MM_TELEPORTER_2,
13703         EL_MM_TELEPORTER_1,
13704         EL_MM_TELEPORTER_16,
13705         EL_MM_TELEPORTER_15,
13706         EL_MM_TELEPORTER_14,
13707         EL_MM_TELEPORTER_13,
13708         EL_MM_TELEPORTER_12,
13709         EL_MM_TELEPORTER_11,
13710         EL_MM_TELEPORTER_10,
13711         EL_MM_TELEPORTER_9,
13712         EL_MM_TELEPORTER_8,
13713         EL_MM_TELEPORTER_7,
13714         EL_MM_TELEPORTER_6
13715       },
13716       {
13717         EL_MM_TELEPORTER_RED_5,
13718         EL_MM_TELEPORTER_RED_4,
13719         EL_MM_TELEPORTER_RED_3,
13720         EL_MM_TELEPORTER_RED_2,
13721         EL_MM_TELEPORTER_RED_1,
13722         EL_MM_TELEPORTER_RED_16,
13723         EL_MM_TELEPORTER_RED_15,
13724         EL_MM_TELEPORTER_RED_14,
13725         EL_MM_TELEPORTER_RED_13,
13726         EL_MM_TELEPORTER_RED_12,
13727         EL_MM_TELEPORTER_RED_11,
13728         EL_MM_TELEPORTER_RED_10,
13729         EL_MM_TELEPORTER_RED_9,
13730         EL_MM_TELEPORTER_RED_8,
13731         EL_MM_TELEPORTER_RED_7,
13732         EL_MM_TELEPORTER_RED_6
13733       },
13734       {
13735         EL_MM_TELEPORTER_YELLOW_5,
13736         EL_MM_TELEPORTER_YELLOW_4,
13737         EL_MM_TELEPORTER_YELLOW_3,
13738         EL_MM_TELEPORTER_YELLOW_2,
13739         EL_MM_TELEPORTER_YELLOW_1,
13740         EL_MM_TELEPORTER_YELLOW_16,
13741         EL_MM_TELEPORTER_YELLOW_15,
13742         EL_MM_TELEPORTER_YELLOW_14,
13743         EL_MM_TELEPORTER_YELLOW_13,
13744         EL_MM_TELEPORTER_YELLOW_12,
13745         EL_MM_TELEPORTER_YELLOW_11,
13746         EL_MM_TELEPORTER_YELLOW_10,
13747         EL_MM_TELEPORTER_YELLOW_9,
13748         EL_MM_TELEPORTER_YELLOW_8,
13749         EL_MM_TELEPORTER_YELLOW_7,
13750         EL_MM_TELEPORTER_YELLOW_6
13751       },
13752       {
13753         EL_MM_TELEPORTER_GREEN_5,
13754         EL_MM_TELEPORTER_GREEN_4,
13755         EL_MM_TELEPORTER_GREEN_3,
13756         EL_MM_TELEPORTER_GREEN_2,
13757         EL_MM_TELEPORTER_GREEN_1,
13758         EL_MM_TELEPORTER_GREEN_16,
13759         EL_MM_TELEPORTER_GREEN_15,
13760         EL_MM_TELEPORTER_GREEN_14,
13761         EL_MM_TELEPORTER_GREEN_13,
13762         EL_MM_TELEPORTER_GREEN_12,
13763         EL_MM_TELEPORTER_GREEN_11,
13764         EL_MM_TELEPORTER_GREEN_10,
13765         EL_MM_TELEPORTER_GREEN_9,
13766         EL_MM_TELEPORTER_GREEN_8,
13767         EL_MM_TELEPORTER_GREEN_7,
13768         EL_MM_TELEPORTER_GREEN_6
13769       },
13770       {
13771         EL_MM_TELEPORTER_BLUE_5,
13772         EL_MM_TELEPORTER_BLUE_4,
13773         EL_MM_TELEPORTER_BLUE_3,
13774         EL_MM_TELEPORTER_BLUE_2,
13775         EL_MM_TELEPORTER_BLUE_1,
13776         EL_MM_TELEPORTER_BLUE_16,
13777         EL_MM_TELEPORTER_BLUE_15,
13778         EL_MM_TELEPORTER_BLUE_14,
13779         EL_MM_TELEPORTER_BLUE_13,
13780         EL_MM_TELEPORTER_BLUE_12,
13781         EL_MM_TELEPORTER_BLUE_11,
13782         EL_MM_TELEPORTER_BLUE_10,
13783         EL_MM_TELEPORTER_BLUE_9,
13784         EL_MM_TELEPORTER_BLUE_8,
13785         EL_MM_TELEPORTER_BLUE_7,
13786         EL_MM_TELEPORTER_BLUE_6
13787       },
13788       {
13789         EL_MM_POLARIZER_1,
13790         EL_MM_POLARIZER_16,
13791         EL_MM_POLARIZER_15,
13792         EL_MM_POLARIZER_14,
13793         EL_MM_POLARIZER_13,
13794         EL_MM_POLARIZER_12,
13795         EL_MM_POLARIZER_11,
13796         EL_MM_POLARIZER_10,
13797         EL_MM_POLARIZER_9,
13798         EL_MM_POLARIZER_8,
13799         EL_MM_POLARIZER_7,
13800         EL_MM_POLARIZER_6,
13801         EL_MM_POLARIZER_5,
13802         EL_MM_POLARIZER_4,
13803         EL_MM_POLARIZER_3,
13804         EL_MM_POLARIZER_2
13805       },
13806       {
13807         EL_DF_MIRROR_1,
13808         EL_DF_MIRROR_16,
13809         EL_DF_MIRROR_15,
13810         EL_DF_MIRROR_14,
13811         EL_DF_MIRROR_13,
13812         EL_DF_MIRROR_12,
13813         EL_DF_MIRROR_11,
13814         EL_DF_MIRROR_10,
13815         EL_DF_MIRROR_9,
13816         EL_DF_MIRROR_8,
13817         EL_DF_MIRROR_7,
13818         EL_DF_MIRROR_6,
13819         EL_DF_MIRROR_5,
13820         EL_DF_MIRROR_4,
13821         EL_DF_MIRROR_3,
13822         EL_DF_MIRROR_2
13823       },
13824       {
13825         EL_DF_MIRROR_ROTATING_1,
13826         EL_DF_MIRROR_ROTATING_16,
13827         EL_DF_MIRROR_ROTATING_15,
13828         EL_DF_MIRROR_ROTATING_14,
13829         EL_DF_MIRROR_ROTATING_13,
13830         EL_DF_MIRROR_ROTATING_12,
13831         EL_DF_MIRROR_ROTATING_11,
13832         EL_DF_MIRROR_ROTATING_10,
13833         EL_DF_MIRROR_ROTATING_9,
13834         EL_DF_MIRROR_ROTATING_8,
13835         EL_DF_MIRROR_ROTATING_7,
13836         EL_DF_MIRROR_ROTATING_6,
13837         EL_DF_MIRROR_ROTATING_5,
13838         EL_DF_MIRROR_ROTATING_4,
13839         EL_DF_MIRROR_ROTATING_3,
13840         EL_DF_MIRROR_ROTATING_2
13841       },
13842       {
13843         EL_DF_MIRROR_FIXED_1,
13844         EL_DF_MIRROR_FIXED_16,
13845         EL_DF_MIRROR_FIXED_15,
13846         EL_DF_MIRROR_FIXED_14,
13847         EL_DF_MIRROR_FIXED_13,
13848         EL_DF_MIRROR_FIXED_12,
13849         EL_DF_MIRROR_FIXED_11,
13850         EL_DF_MIRROR_FIXED_10,
13851         EL_DF_MIRROR_FIXED_9,
13852         EL_DF_MIRROR_FIXED_8,
13853         EL_DF_MIRROR_FIXED_7,
13854         EL_DF_MIRROR_FIXED_6,
13855         EL_DF_MIRROR_FIXED_5,
13856         EL_DF_MIRROR_FIXED_4,
13857         EL_DF_MIRROR_FIXED_3,
13858         EL_DF_MIRROR_FIXED_2
13859       },
13860
13861       {
13862         -1,
13863       },
13864     };
13865     int i, j;
13866
13867     for (i = 0; swappable_elements[i][0] != -1; i++)
13868     {
13869       int element1 = swappable_elements[i][0];
13870       int element2 = swappable_elements[i][1];
13871
13872       if (old_element == element1 || old_element == element2)
13873         new_element = (old_element == element1 ? element2 : element1);
13874     }
13875
13876     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13877     {
13878       for (j = 0; j < 4; j++)
13879       {
13880         int element = rotatable_elements_4[i][j];
13881
13882         if (old_element == element)
13883           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13884                          button == 2 ? rotatable_elements_4[i][0]           :
13885                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13886                          old_element);
13887       }
13888     }
13889
13890     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13891     {
13892       for (j = 0; j < 8; j++)
13893       {
13894         int element = rotatable_elements_8[i][j];
13895
13896         if (old_element == element)
13897           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13898                          button == 2 ? rotatable_elements_8[i][0]           :
13899                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13900                          old_element);
13901       }
13902     }
13903
13904     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13905     {
13906       for (j = 0; j < 16; j++)
13907       {
13908         int element = rotatable_elements_16[i][j];
13909
13910         if (old_element == element)
13911           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13912                          button == 2 ? rotatable_elements_16[i][0]             :
13913                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13914                          old_element);
13915       }
13916     }
13917
13918     if (old_element != new_element)
13919     {
13920       int max_infotext_len = getMaxInfoTextLength();
13921       char infotext[MAX_OUTPUT_LINESIZE + 1];
13922
13923       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13924       infotext[max_infotext_len] = '\0';
13925
13926       ClearEditorGadgetInfoText();
13927
13928       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13929                 infotext);
13930     }
13931   }
13932
13933   if (IS_MM_WALL_EDITOR(new_element))
13934     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13935   else
13936     SetElementSimple(x, y, new_element, change_level);
13937
13938   last_x = x;
13939   last_y = y;
13940 }
13941
13942 static void ResetIntelliDraw(void)
13943 {
13944   int x, y;
13945
13946   for (x = 0; x < lev_fieldx; x++)
13947     for (y = 0; y < lev_fieldy; y++)
13948       IntelliDrawBuffer[x][y] = Tile[x][y];
13949
13950   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13951 }
13952
13953 static boolean draw_mode_hires = FALSE;
13954
13955 static boolean isHiresTileElement(int element)
13956 {
13957   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13958 }
13959
13960 static boolean isHiresDrawElement(int element)
13961 {
13962   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13963 }
13964
13965 static int numHiresTiles(int element)
13966 {
13967   if (IS_MM_WALL(element))
13968     return get_number_of_bits(MM_WALL_BITS(element));
13969
13970   return 1;
13971 }
13972
13973 static void SetDrawModeHiRes(int element)
13974 {
13975   draw_mode_hires =
13976     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13977      isHiresDrawElement(element));
13978 }
13979
13980 static boolean getDrawModeHiRes(void)
13981 {
13982   return draw_mode_hires;
13983 }
13984
13985 static int getLoResScreenPos(int pos)
13986 {
13987   return (getDrawModeHiRes() ? pos / 2 : pos);
13988 }
13989
13990 static int getLoResScreenMod(int pos)
13991 {
13992   return (getDrawModeHiRes() ? pos % 2 : 0);
13993 }
13994
13995 static void SetElementExt(int x, int y, int dx, int dy, int element,
13996                           boolean change_level, int button)
13997 {
13998   if (element < 0)
13999     SetElementSimple(x, y, Tile[x][y], change_level);
14000   else if (GetKeyModState() & KMOD_Shift)
14001     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
14002   else
14003     SetElementSimpleExt(x, y, dx, dy, element, change_level);
14004 }
14005
14006 static void SetElement(int x, int y, int element)
14007 {
14008   SetElementExt(x, y, 0, 0, element, TRUE, -1);
14009 }
14010
14011 static void SetElementButton(int x, int y, int dx, int dy, int element,
14012                              int button)
14013 {
14014   SetElementExt(x, y, dx, dy, element, TRUE, button);
14015 }
14016
14017 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
14018 {
14019   int lx = getLoResScreenPos(sx2) + level_xpos;
14020   int ly = getLoResScreenPos(sy2) + level_ypos;
14021   int dx = getLoResScreenMod(sx2);
14022   int dy = getLoResScreenMod(sy2);
14023
14024   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
14025 }
14026
14027 static void SetLevelElementHiRes(int lx2, int ly2, int element)
14028 {
14029   int lx = lx2 / 2;
14030   int ly = ly2 / 2;
14031   int dx = lx2 % 2;
14032   int dy = ly2 % 2;
14033
14034   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
14035 }
14036
14037 static int getLevelElementHiRes(int lx2, int ly2)
14038 {
14039   int lx = lx2 / 2;
14040   int ly = ly2 / 2;
14041   int dx = lx2 % 2;
14042   int dy = ly2 % 2;
14043   int element = Tile[lx][ly];
14044   unsigned int bitmask = (dx + 1) << (dy * 2);
14045
14046   if (IS_MM_WALL(element))
14047   {
14048     if (element & bitmask)
14049       return map_mm_wall_element(element);
14050     else
14051       return EL_EMPTY;
14052   }
14053
14054   return element;
14055 }
14056
14057 static void DrawLineElement(int x, int y, int element, boolean change_level)
14058 {
14059   SetElementHiRes(x, y, element, change_level);
14060 }
14061
14062 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
14063                      int element, boolean change_level)
14064 {
14065   int xsize = ABS(to_x - from_x);
14066   int ysize = ABS(to_y - from_y);
14067   int dx = (to_x < from_x ? -1 : +1);
14068   int dy = (to_y < from_y ? -1 : +1);
14069   int i;
14070
14071   if (from_y == to_y)                   // horizontal line
14072   {
14073     for (i = 0; i <= xsize; i++)
14074       DrawLineElement(from_x + i * dx, from_y, element, change_level);
14075   }
14076   else if (from_x == to_x)              // vertical line
14077   {
14078     for (i = 0; i <= ysize; i++)
14079       DrawLineElement(from_x, from_y + i * dy, element, change_level);
14080   }
14081   else                                  // diagonal line
14082   {
14083     if (ysize < xsize)                  // a < 1
14084     {
14085       float a = (float)ysize / (float)xsize;
14086
14087       for (i = 0; i <= xsize; i++)
14088       {
14089         int x = dx * i;
14090         int y = dy * (int)(a * i + 0.5);
14091
14092         DrawLineElement(from_x + x, from_y + y, element, change_level);
14093       }
14094     }
14095     else                                // a >= 1
14096     {
14097       float a = (float)xsize / (float)ysize;
14098
14099       for (i = 0; i <= ysize; i++)
14100       {
14101         int x = dx * (int)(a * i + 0.5);
14102         int y = dy * i;
14103
14104         DrawLineElement(from_x + x, from_y + y, element, change_level);
14105       }
14106     }
14107   }
14108 }
14109
14110 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
14111                     int element, boolean change_level)
14112 {
14113   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
14114   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
14115   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
14116   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
14117 }
14118
14119 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
14120                           int element, boolean change_level)
14121 {
14122   int y;
14123
14124   if (from_y > to_y)
14125     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
14126
14127   for (y = from_y; y <= to_y; y++)
14128     DrawLine(from_x, y, to_x, y, element, change_level);
14129 }
14130
14131 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
14132                        int element, boolean change_level)
14133 {
14134   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
14135   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
14136   int len_x = ABS(to_x - from_x);
14137   int len_y = ABS(to_y - from_y);
14138   int radius, x, y;
14139
14140   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
14141
14142   // not optimal (some points get drawn twice) but simple,
14143   // and fast enough for the few points we are drawing
14144
14145   for (x = 0; x <= radius; x++)
14146   {
14147     int sx, sy, sx2, sy2, lx, ly;
14148
14149     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
14150
14151     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14152     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14153     sx = getLoResScreenPos(sx2);
14154     sy = getLoResScreenPos(sy2);
14155     lx = sx + level_xpos;
14156     ly = sy + level_ypos;
14157
14158     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14159       DrawLineElement(sx2, sy2, element, change_level);
14160   }
14161
14162   for (y = 0; y <= radius; y++)
14163   {
14164     int sx, sy, sx2, sy2, lx, ly;
14165
14166     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14167
14168     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14169     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14170     sx = getLoResScreenPos(sx2);
14171     sy = getLoResScreenPos(sy2);
14172     lx = sx + level_xpos;
14173     ly = sy + level_ypos;
14174
14175     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14176       DrawLineElement(sx2, sy2, element, change_level);
14177   }
14178 }
14179
14180 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14181                     int element, boolean change_level)
14182 {
14183   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14184   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14185
14186   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14187 }
14188
14189 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14190
14191 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14192 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14193                        int element, boolean change_level)
14194 {
14195   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14196   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14197   int mirror_to_x2 = from_x - (to_x2 - from_x);
14198   int mirror_to_y2 = from_y - (to_y2 - from_y);
14199
14200   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14201   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14202   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14203   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14204 }
14205 #endif
14206
14207 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14208 {
14209   int from_sx, from_sy;
14210   int to_sx, to_sy;
14211
14212   if (from_x > to_x)
14213     swap_numbers(&from_x, &to_x);
14214
14215   if (from_y > to_y)
14216     swap_numbers(&from_y, &to_y);
14217
14218   from_sx = SX + from_x * ed_tilesize;
14219   from_sy = SY + from_y * ed_tilesize;
14220   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14221   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14222
14223   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14224   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14225   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14226   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14227
14228   if (from_x == to_x && from_y == to_y)
14229     MarkTileDirty(from_x/2, from_y/2);
14230   else
14231     redraw_mask |= REDRAW_FIELD;
14232 }
14233
14234 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14235                         int element, boolean change_level)
14236 {
14237   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14238 }
14239
14240 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14241                        int element, boolean change_level)
14242 {
14243   if (element == -1 || change_level)
14244     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14245   else
14246     DrawAreaBorder(from_x, from_y, to_x, to_y);
14247 }
14248
14249 // values for CopyBrushExt()
14250 #define CB_AREA_TO_BRUSH                0
14251 #define CB_BRUSH_TO_CURSOR              1
14252 #define CB_BRUSH_TO_LEVEL               2
14253 #define CB_DELETE_OLD_CURSOR            3
14254 #define CB_DUMP_BRUSH                   4
14255 #define CB_DUMP_BRUSH_SMALL             5
14256 #define CB_CLIPBOARD_TO_BRUSH           6
14257 #define CB_BRUSH_TO_CLIPBOARD           7
14258 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14259 #define CB_UPDATE_BRUSH_POSITION        9
14260 #define CB_FLIP_BRUSH_X                 10
14261 #define CB_FLIP_BRUSH_Y                 11
14262 #define CB_FLIP_BRUSH_XY                12
14263
14264 #define MAX_CB_PART_SIZE        10
14265 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14266 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14267 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14268                                  MAX_CB_NUM_LINES *     \
14269                                  MAX_CB_PART_SIZE)
14270
14271 static int getFlippedTileExt(int map[], int element)
14272 {
14273   int i;
14274
14275   for (i = 0; map[i] != -1; i++)
14276     if (map[i] == element)
14277       return map[i ^ 1];        // get flipped element by flipping LSB of index
14278
14279   return element;
14280 }
14281
14282 static int getFlippedTileX(int element)
14283 {
14284   int map[] =
14285   {
14286     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14287     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14288     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14289     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14290     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14291     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14292     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14293     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14294     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14295     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14296     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14297     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14298     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14299     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14300     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14301     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14302     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14303     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14304     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14305     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14306     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14307     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14308     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14309     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14310     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14311     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14312     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14313     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14314     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14315     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14316
14317     -1
14318   };
14319
14320   return getFlippedTileExt(map, element);
14321 }
14322
14323 static int getFlippedTileY(int element)
14324 {
14325   int map[] =
14326   {
14327     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14328     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14329     EL_BUG_UP,                          EL_BUG_DOWN,
14330     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14331     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14332     EL_ARROW_UP,                        EL_ARROW_DOWN,
14333     EL_MOLE_UP,                         EL_MOLE_DOWN,
14334     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14335     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14336     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14337     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14338     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14339     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14340     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14341     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14342     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14343     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14344     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14345     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14346     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14347     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14348     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14349     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14350     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14351
14352     -1
14353   };
14354
14355   return getFlippedTileExt(map, element);
14356 }
14357
14358 static int getFlippedTileXY(int element)
14359 {
14360   int map[] =
14361   {
14362     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14363     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14364     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14365     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14366     EL_BUG_LEFT,                        EL_BUG_UP,
14367     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14368     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14369     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14370     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14371     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14372     EL_ARROW_LEFT,                      EL_ARROW_UP,
14373     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14374     EL_MOLE_LEFT,                       EL_MOLE_UP,
14375     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14376     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14377     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14378     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14379     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14380     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14381     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14382     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14383     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14384     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14385     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14386     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14387     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14388     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14389     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14390     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14391     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14392     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14393     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14394     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14395     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14396     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14397     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14398     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14399     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14400     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14401     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14402     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14403     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14404
14405     -1
14406   };
14407
14408   return getFlippedTileExt(map, element);
14409 }
14410
14411 static int getFlippedTile(int element, int mode)
14412 {
14413   if (IS_MM_ELEMENT(element))
14414   {
14415     // get MM game element
14416     element = map_element_RND_to_MM(element);
14417
14418     // get flipped game element
14419     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14420                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14421                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14422                element);
14423
14424     // get RND game element again
14425     element = map_element_MM_to_RND(element);
14426   }
14427   else
14428   {
14429     // get flipped game element
14430     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14431                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14432                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14433                element);
14434   }
14435
14436   return element;
14437 }
14438
14439 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14440 {
14441   // flip tiles
14442   short tile1_flipped = getFlippedTile(*tile1, mode);
14443   short tile2_flipped = getFlippedTile(*tile2, mode);
14444
14445   // swap tiles
14446   *tile1 = tile2_flipped;
14447   *tile2 = tile1_flipped;
14448 }
14449
14450 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14451 {
14452   DrawLineElement(sx, sy, element, change_level);
14453 }
14454
14455 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14456                          int button, int mode)
14457 {
14458   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14459   static int brush_width, brush_height;
14460   static int last_cursor_x = -1, last_cursor_y = -1;
14461   static boolean delete_old_brush = FALSE;
14462   int new_element = BUTTON_ELEMENT(button);
14463   int x, y;
14464
14465   if (mode == CB_DUMP_BRUSH ||
14466       mode == CB_DUMP_BRUSH_SMALL ||
14467       mode == CB_BRUSH_TO_CLIPBOARD ||
14468       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14469   {
14470     if (edit_mode != ED_MODE_DRAWING)
14471       return;
14472
14473     char part[MAX_CB_PART_SIZE + 1] = "";
14474     char text[MAX_CB_TEXT_SIZE + 1] = "";
14475     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14476     int height = (draw_with_brush ? brush_height : lev_fieldy);
14477     char *format = "%s%03d";
14478
14479     for (y = 0; y < height; y++)
14480       for (x = 0; x < width; x++)
14481         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14482           format = "%s%04d";
14483
14484     for (y = 0; y < height; y++)
14485     {
14486       for (x = 0; x < width; x++)
14487       {
14488         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14489         char *prefix = (mode == CB_DUMP_BRUSH ||
14490                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14491
14492         if (element >= NUM_FILE_ELEMENTS)
14493           element = EL_UNKNOWN;
14494
14495         // copy brush to level sketch text buffer for the R'n'D forum:
14496         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14497         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14498         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14499         strcat(text, part);
14500       }
14501
14502       strcat(text, "\n");
14503     }
14504
14505     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14506         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14507       SDL_SetClipboardText(text);
14508     else
14509       Print("%s", text);        // print brush data to console and log file
14510
14511     return;
14512   }
14513
14514   if (mode == CB_CLIPBOARD_TO_BRUSH)
14515   {
14516     if (edit_mode != ED_MODE_DRAWING)
14517       return;
14518
14519     if (!SDL_HasClipboardText())
14520     {
14521       Request("Clipboard is empty!", REQ_CONFIRM);
14522
14523       return;
14524     }
14525
14526     boolean copy_to_brush = (draw_with_brush ||
14527                              drawing_function == GADGET_ID_GRAB_BRUSH);
14528
14529     // this will delete the old brush, if already drawing with a brush
14530     if (copy_to_brush)
14531       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14532
14533     // initialization is required for "odd" (incomplete) clipboard content
14534     for (x = 0; x < MAX_LEV_FIELDX; x++)
14535       for (y = 0; y < MAX_LEV_FIELDY; y++)
14536         brush_buffer[x][y] = EL_EMPTY;
14537
14538     brush_width  = 0;
14539     brush_height = 0;
14540     x = 0;
14541     y = 0;
14542
14543     char *clipboard_text = SDL_GetClipboardText();
14544     char *ptr = clipboard_text;
14545     boolean allow_new_row = FALSE;
14546     boolean stop = FALSE;
14547
14548     while (*ptr && !stop)
14549     {
14550       boolean prefix_found = FALSE;
14551       boolean start_new_row = FALSE;
14552
14553       // level sketch element number prefixes (may be multi-byte characters)
14554       char *prefix_list[] = { "`", "¸" };
14555       int i;
14556
14557       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14558       {
14559         char *prefix = prefix_list[i];
14560
14561         // check if string is large enough for prefix
14562         if (strlen(ptr) < strlen(prefix))
14563         {
14564           stop = TRUE;
14565
14566           break;
14567         }
14568
14569         // check if string starts with prefix
14570         if (strPrefix(ptr, prefix))
14571         {
14572           ptr += strlen(prefix);
14573
14574           prefix_found = TRUE;
14575
14576           break;
14577         }
14578       }
14579
14580       // check if prefix found and followed by (at least) three digits
14581       if (prefix_found &&
14582           strlen(ptr) >= 3 &&
14583           ptr[0] >= '0' && ptr[0] <= '9' &&
14584           ptr[1] >= '0' && ptr[1] <= '9' &&
14585           ptr[2] >= '0' && ptr[2] <= '9')
14586       {
14587         int element = ((ptr[0] - '0') * 100 +
14588                        (ptr[1] - '0') * 10 +
14589                        (ptr[2] - '0'));
14590
14591         ptr += 3;
14592
14593         // level sketch element number might consist of four digits
14594         if (ptr[0] >= '0' && ptr[0] <= '9')
14595         {
14596           element = element * 10 + (ptr[0] - '0');
14597           ptr++;
14598         }
14599
14600         // remap some (historic, now obsolete) elements
14601         element = getMappedElement(element);
14602
14603         if (element >= NUM_FILE_ELEMENTS)
14604           element = EL_UNKNOWN;
14605
14606         brush_buffer[x][y] = element;
14607
14608         brush_width  = MAX(x + 1, brush_width);
14609         brush_height = MAX(y + 1, brush_height);
14610
14611         x++;
14612
14613         if (x >= MAX_LEV_FIELDX)
14614           start_new_row = TRUE;
14615
14616         allow_new_row = TRUE;
14617       }
14618       else
14619       {
14620         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14621           start_new_row = TRUE;
14622
14623         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14624       }
14625
14626       if (start_new_row)
14627       {
14628         x = 0;
14629         y++;
14630
14631         if (y >= MAX_LEV_FIELDY)
14632           stop = TRUE;
14633
14634         allow_new_row = FALSE;
14635       }
14636     }
14637
14638     SDL_free(clipboard_text);
14639
14640     if (brush_width == 0 || brush_height == 0)
14641     {
14642       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14643
14644       return;
14645     }
14646
14647     if (copy_to_brush)
14648     {
14649       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14650       int mx, my;
14651
14652       SDL_GetMouseState(&mx, &my);
14653
14654       // if inside drawing area, activate and draw brush at last mouse position
14655       if (mx >= gi->x && mx < gi->x + gi->width &&
14656           my >= gi->y && my < gi->y + gi->height)
14657         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14658
14659       draw_with_brush = TRUE;
14660     }
14661     else
14662     {
14663       char request[100];
14664
14665       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14666               brush_width, brush_height);
14667
14668       if (!Request(request, REQ_ASK))
14669         return;
14670
14671       for (x = 0; x < MAX_LEV_FIELDX; x++)
14672         for (y = 0; y < MAX_LEV_FIELDY; y++)
14673           Tile[x][y] = brush_buffer[x][y];
14674
14675       lev_fieldx = level.fieldx = brush_width;
14676       lev_fieldy = level.fieldy = brush_height;
14677
14678       boolean use_bd_engine = TRUE;
14679       boolean use_em_engine = TRUE;
14680       boolean use_sp_engine = TRUE;
14681       boolean use_mm_engine = TRUE;
14682
14683       for (x = 0; x < MAX_LEV_FIELDX; x++)
14684       {
14685         for (y = 0; y < MAX_LEV_FIELDY; y++)
14686         {
14687           int element = Tile[x][y];
14688
14689           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14690             use_bd_engine = FALSE;
14691
14692           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14693             use_em_engine = FALSE;
14694
14695           if (!IS_SP_ELEMENT(element))
14696             use_sp_engine = FALSE;
14697
14698           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14699             use_mm_engine = FALSE;
14700         }
14701       }
14702
14703       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14704                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14705                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14706                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14707                                 GAME_ENGINE_TYPE_RND);
14708
14709       // update element selection list
14710       ReinitializeElementList();
14711       ModifyEditorElementList();
14712
14713       SetBorderElement();
14714
14715       DrawEditModeWindow();
14716       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14717     }
14718
14719     return;
14720   }
14721
14722   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14723     return;
14724
14725   if (mode == CB_AREA_TO_BRUSH)
14726   {
14727     int from_lx, from_ly;
14728
14729     if (from_x > to_x)
14730       swap_numbers(&from_x, &to_x);
14731
14732     if (from_y > to_y)
14733       swap_numbers(&from_y, &to_y);
14734
14735     brush_width = to_x - from_x + 1;
14736     brush_height = to_y - from_y + 1;
14737
14738     from_lx = from_x + level_xpos;
14739     from_ly = from_y + level_ypos;
14740
14741     for (y = 0; y < brush_height; y++)
14742     {
14743       for (x = 0; x < brush_width; x++)
14744       {
14745         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14746
14747         if (button != 1)
14748           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14749       }
14750     }
14751
14752     if (button != 1)
14753       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14754
14755     delete_old_brush = FALSE;
14756   }
14757   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14758            mode == CB_BRUSH_TO_LEVEL)
14759   {
14760     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14761     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14762     int cursor_from_x = cursor_x - brush_width / 2;
14763     int cursor_from_y = cursor_y - brush_height / 2;
14764     int border_from_x = cursor_x, border_from_y = cursor_y;
14765     int border_to_x = cursor_x, border_to_y = cursor_y;
14766
14767     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14768       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14769
14770     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14771         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14772     {
14773       delete_old_brush = FALSE;
14774
14775       return;
14776     }
14777
14778     for (y = 0; y < brush_height; y++)
14779     {
14780       for (x = 0; x < brush_width; x++)
14781       {
14782         int sx = cursor_from_x + x;
14783         int sy = cursor_from_y + y;
14784         int lx = sx + level_xpos;
14785         int ly = sy + level_ypos;
14786         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14787         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14788                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14789                        brush_buffer[x][y] : new_element);
14790
14791         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14792         {
14793           if (sx < border_from_x)
14794             border_from_x = sx;
14795           else if (sx > border_to_x)
14796             border_to_x = sx;
14797           if (sy < border_from_y)
14798             border_from_y = sy;
14799           else if (sy > border_to_y)
14800             border_to_y = sy;
14801
14802           DrawBrushElement(sx, sy, element, change_level);
14803         }
14804       }
14805     }
14806
14807     if (mode != CB_DELETE_OLD_CURSOR)
14808       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14809
14810     last_cursor_x = cursor_x;
14811     last_cursor_y = cursor_y;
14812
14813     delete_old_brush = TRUE;
14814   }
14815   else if (mode == CB_FLIP_BRUSH_X)
14816   {
14817     for (y = 0; y < brush_height; y++)
14818       for (x = 0; x < (brush_width + 1) / 2; x++)
14819         SwapFlippedTiles(&brush_buffer[x][y],
14820                          &brush_buffer[brush_width - x - 1][y], mode);
14821
14822     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14823   }
14824   else if (mode == CB_FLIP_BRUSH_Y)
14825   {
14826     for (y = 0; y < (brush_height + 1) / 2; y++)
14827       for (x = 0; x < brush_width; x++)
14828         SwapFlippedTiles(&brush_buffer[x][y],
14829                          &brush_buffer[x][brush_height - y - 1], mode);
14830
14831     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14832   }
14833   else if (mode == CB_FLIP_BRUSH_XY)
14834   {
14835     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14836
14837     for (y = 0; y < MAX(brush_width, brush_height); y++)
14838       for (x = 0; x <= y; x++)
14839         SwapFlippedTiles(&brush_buffer[x][y],
14840                          &brush_buffer[y][x], mode);
14841
14842     swap_numbers(&brush_width, &brush_height);
14843
14844     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14845   }
14846
14847   if (mode == CB_UPDATE_BRUSH_POSITION)
14848   {
14849     last_cursor_x = from_x;
14850     last_cursor_y = from_y;
14851   }
14852 }
14853
14854 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14855                             int button)
14856 {
14857   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14858 }
14859
14860 static void CopyBrushToLevel(int x, int y, int button)
14861 {
14862   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14863 }
14864
14865 static void CopyBrushToCursor(int x, int y)
14866 {
14867   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14868 }
14869
14870 static void UpdateBrushPosition(int x, int y)
14871 {
14872   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14873 }
14874
14875 static void DeleteBrushFromCursor(void)
14876 {
14877   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14878 }
14879
14880 static void FlipBrushX(void)
14881 {
14882   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14883 }
14884
14885 static void FlipBrushY(void)
14886 {
14887   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14888 }
14889
14890 static void RotateBrush(void)
14891 {
14892   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14893   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14894 }
14895
14896 void DumpBrush(void)
14897 {
14898   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14899 }
14900
14901 void DumpBrush_Small(void)
14902 {
14903   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14904 }
14905
14906 void CopyClipboardToBrush(void)
14907 {
14908   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14909 }
14910
14911 void CopyBrushToClipboard(void)
14912 {
14913   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14914 }
14915
14916 void CopyBrushToClipboard_Small(void)
14917 {
14918   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14919 }
14920
14921 void UndoLevelEditorOperation(void)
14922 {
14923   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14924 }
14925
14926 void RedoLevelEditorOperation(void)
14927 {
14928   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14929 }
14930
14931 static void FloodFill(int from_x, int from_y, int fill_element)
14932 {
14933   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14934 }
14935
14936 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14937 {
14938   int from_x = from_sx2 + 2 * level_xpos;
14939   int from_y = from_sy2 + 2 * level_ypos;
14940   int max_fillx = lev_fieldx * 2;
14941   int max_filly = lev_fieldy * 2;
14942   short Fill[max_fillx][max_filly];
14943   int x, y;
14944
14945   for (x = 0; x < max_fillx; x++)
14946     for (y = 0; y < max_filly; y++)
14947       Fill[x][y] = getLevelElementHiRes(x, y);
14948
14949   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14950                     Fill, max_fillx, max_filly);
14951
14952   for (x = 0; x < max_fillx; x++)
14953     for (y = 0; y < max_filly; y++)
14954       if (Fill[x][y] == fill_element)
14955         SetLevelElementHiRes(x, y, Fill[x][y]);
14956 }
14957
14958 // values for DrawLevelText() modes
14959 #define TEXT_INIT               0
14960 #define TEXT_SETCURSOR          1
14961 #define TEXT_WRITECHAR          2
14962 #define TEXT_BACKSPACE          3
14963 #define TEXT_NEWLINE            4
14964 #define TEXT_END                5
14965 #define TEXT_QUERY_TYPING       6
14966
14967 static int DrawLevelText(int sx, int sy, char letter, int mode)
14968 {
14969   static short delete_buffer[MAX_LEV_FIELDX];
14970   static int start_sx;
14971   static int last_sx, last_sy;
14972   static boolean typing = FALSE;
14973   int letter_element;
14974   int lx = 0, ly = 0;
14975
14976   // map lower case letters to upper case and convert special characters
14977   if (letter >= 'a' && letter <= 'z')
14978     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
14979   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
14980     letter_element = EL_CHAR_AUMLAUT;
14981   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
14982     letter_element = EL_CHAR_OUMLAUT;
14983   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
14984     letter_element = EL_CHAR_UUMLAUT;
14985   else if (letter == '^')
14986     letter_element = EL_CHAR_COPYRIGHT;
14987   else
14988     letter_element = EL_CHAR_ASCII0 + letter;
14989
14990   if (mode != TEXT_INIT)
14991   {
14992     if (!typing)
14993       return FALSE;
14994
14995     if (mode != TEXT_SETCURSOR)
14996     {
14997       sx = last_sx;
14998       sy = last_sy;
14999     }
15000
15001     lx = last_sx + level_xpos;
15002     ly = last_sy + level_ypos;
15003   }
15004
15005   switch (mode)
15006   {
15007     case TEXT_INIT:
15008       if (typing)
15009         DrawLevelText(0, 0, 0, TEXT_END);
15010
15011       typing = TRUE;
15012       start_sx = sx;
15013       last_sx = sx;
15014       last_sy = sy;
15015       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
15016       break;
15017
15018     case TEXT_SETCURSOR:
15019       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
15020       DrawAreaBorder(sx, sy, sx, sy);
15021       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
15022                      ed_tilesize, ed_tilesize);
15023       last_sx = sx;
15024       last_sy = sy;
15025       break;
15026
15027     case TEXT_WRITECHAR:
15028       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
15029       {
15030         if (new_element1 >= EL_STEEL_CHAR_START &&
15031             new_element1 <= EL_STEEL_CHAR_END)
15032           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
15033
15034         delete_buffer[sx - start_sx] = Tile[lx][ly];
15035         Tile[lx][ly] = letter_element;
15036
15037         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
15038           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
15039         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15040           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15041         else
15042           DrawLevelText(0, 0, 0, TEXT_END);
15043
15044         level.changed = TRUE;
15045       }
15046       break;
15047
15048     case TEXT_BACKSPACE:
15049       if (sx > start_sx)
15050       {
15051         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
15052         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
15053         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
15054       }
15055       break;
15056
15057     case TEXT_NEWLINE:
15058       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15059         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15060       else
15061         DrawLevelText(0, 0, 0, TEXT_END);
15062       break;
15063
15064     case TEXT_END:
15065       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15066       DrawEditorElement(sx, sy, Tile[lx][ly]);
15067       StopTextInput();
15068       typing = FALSE;
15069       break;
15070
15071     case TEXT_QUERY_TYPING:
15072       break;
15073
15074     default:
15075       break;
15076   }
15077
15078   return typing;
15079 }
15080
15081 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
15082                           int element, boolean change_level)
15083 {
15084   int lx = sx + level_xpos;
15085   int ly = sy + level_ypos;
15086
15087   if (element == -1)
15088     DrawEditorElement(sx, sy, Tile[lx][ly]);
15089   else
15090     DrawAreaBorder(sx, sy, sx, sy);
15091 }
15092
15093 static void CheckLevelBorderElement(boolean redraw_playfield)
15094 {
15095   int last_border_element = BorderElement;
15096
15097   SetBorderElement();
15098
15099   if (redraw_playfield && BorderElement != last_border_element)
15100     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15101 }
15102
15103 static void CopyLevelToUndoBuffer(int mode)
15104 {
15105   static boolean accumulated_undo = FALSE;
15106   boolean new_undo_buffer_position = TRUE;
15107   int x, y;
15108
15109   if (undo_buffer_steps == 0)
15110     accumulated_undo = FALSE;
15111
15112   switch (mode)
15113   {
15114     case UNDO_IMMEDIATE:
15115       accumulated_undo = FALSE;
15116       break;
15117
15118     case UNDO_ACCUMULATE:
15119       if (accumulated_undo)
15120         new_undo_buffer_position = FALSE;
15121       accumulated_undo = TRUE;
15122       break;
15123
15124     default:
15125       break;
15126   }
15127
15128   if (new_undo_buffer_position)
15129   {
15130     // advance position in undo buffer ring
15131     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
15132
15133     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
15134       undo_buffer_steps++;
15135   }
15136
15137   // always reset redo buffer when storing level change into undo buffer
15138   redo_buffer_steps = 0;
15139
15140   for (x = 0; x < lev_fieldx; x++)
15141     for (y = 0; y < lev_fieldy; y++)
15142       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
15143
15144   // check if drawing operation forces change of border style
15145   CheckLevelBorderElement(TRUE);
15146
15147   level.changed = TRUE;
15148 }
15149
15150 static void RandomPlacement(int new_element)
15151 {
15152   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
15153   int num_free_positions = 0;
15154   int num_percentage, num_elements;
15155   int x, y;
15156
15157   ResetIntelliDraw();
15158
15159   // determine number of free positions for randomly placing the new element
15160   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
15161   {
15162     free_position[x][y] =
15163       (random_placement_background_restricted ?
15164        Tile[x][y] == random_placement_background_element :
15165        Tile[x][y] != new_element);
15166
15167     if (free_position[x][y])
15168       num_free_positions++;
15169   }
15170
15171   // determine number of new elements to place there
15172   num_percentage = num_free_positions * random_placement_value / 100;
15173   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15174                   num_percentage : random_placement_value);
15175
15176   // if less free positions than elements to place, fill all these positions
15177   if (num_free_positions < num_elements)
15178   {
15179     for (x = 0; x < lev_fieldx; x++)
15180       for (y = 0; y < lev_fieldy; y++)
15181         if (free_position[x][y])
15182           SetElement(x, y, new_element);
15183   }
15184   else
15185   {
15186     while (num_elements > 0)
15187     {
15188       x = GetSimpleRandom(lev_fieldx);
15189       y = GetSimpleRandom(lev_fieldy);
15190
15191       // don't place element at the same position twice
15192       if (free_position[x][y])
15193       {
15194         free_position[x][y] = FALSE;
15195         SetElement(x, y, new_element);
15196         num_elements--;
15197       }
15198     }
15199   }
15200
15201   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15202   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15203 }
15204
15205 static void WrapLevel(int dx, int dy)
15206 {
15207   int wrap_dx = lev_fieldx - dx;
15208   int wrap_dy = lev_fieldy - dy;
15209   int x, y;
15210
15211   for (x = 0; x < lev_fieldx; x++)
15212     for (y = 0; y < lev_fieldy; y++)
15213       TileBackup[x][y] = Tile[x][y];
15214
15215   for (x = 0; x < lev_fieldx; x++)
15216     for (y = 0; y < lev_fieldy; y++)
15217       Tile[x][y] =
15218         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15219
15220   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15221   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15222 }
15223
15224 static void DrawAreaElementHighlight(boolean highlighted,
15225                                      boolean highlighted_similar)
15226 {
15227   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15228
15229   if (!highlighted)
15230     return;
15231
15232   int x, y;
15233
15234   for (x = 0; x < ed_fieldx; x++)
15235   {
15236     for (y = 0; y < ed_fieldy; y++)
15237     {
15238       boolean highlight = FALSE;
15239       int lx = x + level_xpos;
15240       int ly = y + level_ypos;
15241
15242       if (!IN_LEV_FIELD(lx, ly))
15243         continue;
15244
15245       // check if element is the same
15246       if (Tile[lx][ly] == new_element1)
15247         highlight = TRUE;
15248
15249       // check if element is similar
15250       if (highlighted_similar &&
15251           strEqual(element_info[Tile[lx][ly]].class_name,
15252                    element_info[new_element1].class_name))
15253         highlight = TRUE;
15254
15255       // check if element is matching MM style wall
15256       if (IS_MM_WALL(Tile[lx][ly]) &&
15257           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15258         highlight = TRUE;
15259
15260       if (!highlight)
15261         continue;
15262
15263       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15264       {
15265         int i;
15266
15267         for (i = 0; i < 4; i++)
15268         {
15269           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15270             continue;
15271
15272           int xx = x * 2 + (i % 2);
15273           int yy = y * 2 + (i / 2);
15274           int sx = SX + xx * ed_tilesize / 2;
15275           int sy = SY + yy * ed_tilesize / 2;
15276           int from_sx = sx;
15277           int from_sy = sy;
15278           int to_sx = sx + ed_tilesize / 2 - 1;
15279           int to_sy = sy + ed_tilesize / 2 - 1;
15280
15281           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15282           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15283           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15284           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15285         }
15286       }
15287       else
15288       {
15289         int sx = SX + x * ed_tilesize;
15290         int sy = SY + y * ed_tilesize;
15291         int from_sx = sx;
15292         int from_sy = sy;
15293         int to_sx = sx + ed_tilesize - 1;
15294         int to_sy = sy + ed_tilesize - 1;
15295
15296         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15297         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15298         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15299         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15300       }
15301     }
15302   }
15303 }
15304
15305 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15306 {
15307   char *template_filename_old = getLocalLevelTemplateFilename();
15308   char *template_filename_new =
15309     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15310
15311   if (copyFile(template_filename_old, template_filename_new) != 0)
15312     Request("Cannot copy level template!", REQ_CONFIRM);
15313
15314   free(template_filename_new);
15315 }
15316
15317 static void HandleDrawingAreas(struct GadgetInfo *gi)
15318 {
15319   static boolean started_inside_drawing_area = FALSE;
15320   static int last_sx = -1;
15321   static int last_sy = -1;
15322   static int last_sx2 = -1;
15323   static int last_sy2 = -1;
15324   int id = gi->custom_id;
15325   int type_id = gi->custom_type_id;
15326   boolean button_press_event;
15327   boolean button_release_event;
15328   boolean inside_drawing_area = !gi->event.off_borders;
15329   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15330   int actual_drawing_function;
15331   int button = gi->event.button;
15332   int new_element = BUTTON_ELEMENT(button);
15333   int sx = gi->event.x, sy = gi->event.y;
15334   int min_sx = 0, min_sy = 0;
15335   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15336   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15337   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15338   int sx2 = gi->event.mx / mini_item_xsize;
15339   int sy2 = gi->event.my / mini_item_ysize;
15340   int dx = sx2 % 2;
15341   int dy = sy2 % 2;
15342   int lx = 0, ly = 0;
15343   int x, y;
15344
15345   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15346   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15347
15348   // make sure to stay inside drawing area boundaries
15349   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15350   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15351
15352   if (draw_level)
15353   {
15354     int min_lx = 0, min_ly = 0;
15355     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15356
15357     // get positions inside level field
15358     lx = sx + level_xpos;
15359     ly = sy + level_ypos;
15360
15361     if (!IN_LEV_FIELD(lx, ly))
15362       inside_drawing_area = FALSE;
15363
15364     // make sure to stay inside level field boundaries
15365     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15366     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15367
15368     // correct drawing area positions accordingly
15369     sx = lx - level_xpos;
15370     sy = ly - level_ypos;
15371   }
15372
15373   // also correct MM wall-sized (double) drawing area positions accordingly
15374   if (sx2 / 2 < sx || sx2 / 2 > sx)
15375   {
15376     dx = (sx2 / 2 < sx ? 0 : 1);
15377     sx2 = sx * 2 + dx;
15378   }
15379   if (sy2 / 2 < sy || sy2 / 2 > sy)
15380   {
15381     dy = (sy2 / 2 < sy ? 0 : 1);
15382     sy2 = sy * 2 + dy;
15383   }
15384
15385   if (!button_press_event && !button_release_event)
15386   {
15387     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15388     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15389                              isHiresTileElement(old_element) &&
15390                              isHiresDrawElement(new_element));
15391
15392     // prevent handling events for every pixel position when moving mouse
15393     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15394         (sx2 == last_sx2 && sy2 == last_sy2))
15395       return;
15396   }
15397
15398   last_sx = sx;
15399   last_sy = sy;
15400   last_sx2 = sx2;
15401   last_sy2 = sy2;
15402
15403   if (button_press_event)
15404     started_inside_drawing_area = inside_drawing_area;
15405
15406   if (!started_inside_drawing_area)
15407     return;
15408
15409   if (!IS_VALID_BUTTON(button))
15410     return;
15411
15412   // handle info callback for each invocation of action callback
15413   gi->callback_info(gi);
15414
15415   // automatically switch to 'single item' drawing mode, if needed
15416   actual_drawing_function =
15417     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15418      drawing_function : GADGET_ID_SINGLE_ITEMS);
15419
15420   // clicking into drawing area with pressed Control key picks element
15421   if (GetKeyModState() & KMOD_Control)
15422   {
15423     last_drawing_function = drawing_function;
15424     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15425   }
15426
15427   if (GetKeyModState() & KMOD_Shift)
15428   {
15429     if (button_press_event || button_release_event)
15430       ResetIntelliDraw();
15431   }
15432
15433   SetDrawModeHiRes(-1);         // reset to normal draw mode
15434
15435   switch (actual_drawing_function)
15436   {
15437     case GADGET_ID_SINGLE_ITEMS:
15438       if (draw_level)
15439       {
15440         if (button_release_event)
15441         {
15442           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15443
15444           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15445               !inside_drawing_area)
15446             DeleteBrushFromCursor();
15447
15448           break;
15449         }
15450
15451         if (draw_with_brush)
15452         {
15453           CopyBrushToLevel(sx, sy, button);
15454         }
15455         else
15456         {
15457           SetDrawModeHiRes(new_element);
15458
15459           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15460           {
15461             // remove player at old position
15462             for (y = 0; y < lev_fieldy; y++)
15463             {
15464               for (x = 0; x < lev_fieldx; x++)
15465               {
15466                 int old_element = Tile[x][y];
15467
15468                 if (IS_PLAYER_ELEMENT(old_element) &&
15469                     IS_PLAYER_ELEMENT(new_element))
15470                 {
15471                   int replaced_with_element =
15472                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15473                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15474
15475                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15476                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15477
15478                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15479                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15480
15481                      new_element >= EL_PLAYER_1 &&
15482                      new_element <= EL_PLAYER_4 &&
15483                      new_element == old_element ? EL_EMPTY :
15484
15485                      old_element);
15486
15487                   SetElement(x, y, replaced_with_element);
15488                 }
15489                 else if (IS_MM_MCDUFFIN(old_element) &&
15490                          IS_MM_MCDUFFIN(new_element))
15491                 {
15492                   // remove McDuffin at old position
15493                   SetElement(x, y, EL_EMPTY);
15494                 }
15495               }
15496             }
15497           }
15498
15499           SetElementButton(lx, ly, dx, dy, new_element, button);
15500         }
15501       }
15502       else if (!button_release_event)
15503       {
15504         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15505
15506         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15507           DrawMiniGraphicExt(drawto,
15508                              gi->x + sx * MINI_TILEX,
15509                              gi->y + sy * MINI_TILEY,
15510                              el2edimg(new_element));
15511         else
15512           DrawFixedGraphicExt(drawto,
15513                               gi->x + sx * TILEX,
15514                               gi->y + sy * TILEY,
15515                               el2edimg(new_element), 0);
15516
15517         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15518           new_element = GFX_ELEMENT(new_element);
15519
15520         drawingarea_info[type_id].value[pos] = new_element;
15521
15522         CopyElementPropertiesToGame(properties_element);
15523
15524         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15525         {
15526           UpdateCustomElementGraphicGadgets();
15527
15528           FrameCounter = 0;     // restart animation frame counter
15529         }
15530       }
15531       break;
15532
15533     case GADGET_ID_CONNECTED_ITEMS:
15534       {
15535         static int last_sx = -1;
15536         static int last_sy = -1;
15537
15538         if (button_release_event)
15539           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15540
15541         SetDrawModeHiRes(new_element);
15542
15543         if (getDrawModeHiRes())
15544         {
15545           sx = sx2;
15546           sy = sy2;
15547         }
15548
15549         if (!button_press_event)
15550           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15551
15552         last_sx = sx;
15553         last_sy = sy;
15554       }
15555       break;
15556
15557     case GADGET_ID_LINE:
15558     case GADGET_ID_ARC:
15559     case GADGET_ID_RECTANGLE:
15560     case GADGET_ID_FILLED_BOX:
15561       SetDrawModeHiRes(new_element);
15562
15563       if (getDrawModeHiRes())
15564       {
15565         sx = sx2;
15566         sy = sy2;
15567       }
15568       // FALLTHROUGH
15569     case GADGET_ID_GRAB_BRUSH:
15570     case GADGET_ID_TEXT:
15571       {
15572         static int last_sx = -1;
15573         static int last_sy = -1;
15574         static int start_sx = -1;
15575         static int start_sy = -1;
15576         void (*draw_func)(int, int, int, int, int, boolean);
15577
15578         if (drawing_function == GADGET_ID_LINE)
15579           draw_func = DrawLine;
15580         else if (drawing_function == GADGET_ID_ARC)
15581           draw_func = DrawArc;
15582         else if (drawing_function == GADGET_ID_RECTANGLE)
15583           draw_func = DrawBox;
15584         else if (drawing_function == GADGET_ID_FILLED_BOX)
15585           draw_func = DrawFilledBox;
15586         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15587           draw_func = SelectArea;
15588         else // (drawing_function == GADGET_ID_TEXT)
15589           draw_func = SetTextCursor;
15590
15591         if (button_press_event)
15592         {
15593           draw_func(sx, sy, sx, sy, new_element, FALSE);
15594           start_sx = last_sx = sx;
15595           start_sy = last_sy = sy;
15596
15597           if (drawing_function == GADGET_ID_TEXT)
15598             DrawLevelText(0, 0, 0, TEXT_END);
15599         }
15600         else if (button_release_event)
15601         {
15602           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15603           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15604           {
15605             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15606             CopyBrushToCursor(sx, sy);
15607             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15608                           MB_LEFTBUTTON);
15609             draw_with_brush = TRUE;
15610           }
15611           else if (drawing_function == GADGET_ID_TEXT)
15612             DrawLevelText(sx, sy, 0, TEXT_INIT);
15613           else
15614             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15615         }
15616         else if (last_sx != sx || last_sy != sy)
15617         {
15618           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15619           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15620             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15621           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15622           last_sx = sx;
15623           last_sy = sy;
15624         }
15625       }
15626       break;
15627
15628     case GADGET_ID_FLOOD_FILL:
15629       if (button_press_event && Tile[lx][ly] != new_element)
15630       {
15631         if (IS_MM_WALL_EDITOR(new_element))
15632           FloodFillWall_MM(sx2, sy2, new_element);
15633         else
15634           FloodFill(lx, ly, new_element);
15635
15636         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15637         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15638       }
15639       break;
15640
15641     case GADGET_ID_PICK_ELEMENT:
15642       if (button_release_event)
15643         ClickOnGadget(level_editor_gadget[last_drawing_function],
15644                       MB_LEFTBUTTON);
15645       else if (draw_level)
15646         PickDrawingElement(button, Tile[lx][ly]);
15647       else
15648       {
15649         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15650
15651         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15652       }
15653
15654     default:
15655       break;
15656   }
15657
15658   // do not mark level as modified for certain non-level-changing gadgets
15659   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15660        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15661       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15662       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15663     return;
15664
15665   level.changed = TRUE;
15666 }
15667
15668 static void HandleCounterButtons(struct GadgetInfo *gi)
15669 {
15670   int gadget_id = gi->custom_id;
15671   int counter_id = gi->custom_type_id;
15672   int button = gi->event.button;
15673   int *counter_value = counterbutton_info[counter_id].value;
15674   int step = BUTTON_STEPSIZE(button) *
15675     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15676
15677   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15678   {
15679     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15680     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15681     boolean level_changed = LevelChanged();
15682
15683     if ((level_changed && pressed) || (!level_changed && released))
15684       return;
15685
15686     if (level_changed && !Request("Level has changed! Discard changes?",
15687                                   REQ_ASK))
15688     {
15689       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15690         ModifyEditorCounterValue(counter_id, *counter_value);
15691
15692       return;
15693     }
15694   }
15695
15696   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15697     *counter_value = gi->textinput.number_value;
15698   else
15699     ModifyEditorCounterValue(counter_id, *counter_value + step);
15700
15701   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15702   {
15703     int last_game_engine_type = level.game_engine_type;
15704
15705     LoadLevel(level_nr);
15706     LoadScore(level_nr);
15707
15708     SaveLevelSetup_SeriesInfo();
15709
15710     TapeErase();
15711
15712     ResetUndoBuffer();
15713     DrawEditModeWindow();
15714
15715     if (level.game_engine_type != last_game_engine_type)
15716     {
15717       // update element selection list
15718       ReinitializeElementList();
15719       ModifyEditorElementList();
15720     }
15721
15722     return;
15723   }
15724
15725   switch (counter_id)
15726   {
15727     case ED_COUNTER_ID_YAMYAM_CONTENT:
15728       DrawYamYamContentAreas();
15729       break;
15730
15731     case ED_COUNTER_ID_BALL_CONTENT:
15732       DrawMagicBallContentAreas();
15733       break;
15734
15735     case ED_COUNTER_ID_ANDROID_CONTENT:
15736       DrawAndroidElementArea();
15737       break;
15738
15739     case ED_COUNTER_ID_GROUP_CONTENT:
15740       DrawGroupElementArea();
15741       CopyGroupElementPropertiesToGame(properties_element);
15742       break;
15743
15744     case ED_COUNTER_ID_INVENTORY_SIZE:
15745       DrawPlayerInitialInventoryArea(properties_element);
15746       break;
15747
15748     case ED_COUNTER_ID_MM_BALL_CONTENT:
15749       DrawMMBallContentArea();
15750       break;
15751
15752     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15753     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15754       DrawEnvelopeTextArea(-1);
15755       break;
15756
15757     case ED_COUNTER_ID_LEVEL_XSIZE:
15758     case ED_COUNTER_ID_LEVEL_YSIZE:
15759       lev_fieldx = level.fieldx;
15760       lev_fieldy = level.fieldy;
15761
15762       // check if resizing of level results in change of border border
15763       SetBorderElement();
15764
15765       break;
15766
15767     default:
15768       break;
15769   }
15770
15771   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15772        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15773       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15774        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15775     CopyElementPropertiesToGame(properties_element);
15776
15777   // do not mark level as modified for certain non-level-changing gadgets
15778   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15779        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15780       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15781        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15782     return;
15783
15784   level.changed = TRUE;
15785 }
15786
15787 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15788 {
15789   int type_id = gi->custom_type_id;
15790
15791   strcpy(textinput_info[type_id].value, gi->textinput.value);
15792
15793   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15794   {
15795     CopyElementPropertiesToGame(properties_element);
15796
15797     ModifyEditorElementList();  // update changed button info text
15798   }
15799
15800   // do not mark level as modified for certain non-level-changing gadgets
15801   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15802       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15803     return;
15804
15805   level.changed = TRUE;
15806 }
15807
15808 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15809 {
15810   int type_id = gi->custom_type_id;
15811
15812   strncpy(textarea_info[type_id].value, gi->textarea.value,
15813           MAX_ENVELOPE_TEXT_LEN);
15814   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15815
15816   level.changed = TRUE;
15817 }
15818
15819 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15820 {
15821   int type_id = gi->custom_type_id;
15822   int value_old = *selectbox_info[type_id].value;
15823   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15824
15825   *selectbox_info[type_id].value = value_new;
15826
15827   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15828   {
15829     DrawLevelConfigWindow();
15830   }
15831   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15832   {
15833     element_info[properties_element].current_change_page = gi->selectbox.index;
15834
15835     DrawPropertiesWindow();
15836   }
15837   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15838             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15839            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15840             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15841            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15842   {
15843     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15844     {
15845       // when changing action type, also check action mode and action arg
15846       if (value_old != value_new)
15847         setSelectboxSpecialActionVariablesIfNeeded();
15848
15849       DrawPropertiesChange();
15850     }
15851
15852     CopyElementPropertiesToGame(properties_element);
15853   }
15854   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15855   {
15856     // show or hide "engine" tabulator depending on game engine type
15857     DrawLevelConfigWindow();
15858
15859     // update element selection list depending on game engine type
15860     ReinitializeElementList();
15861     ModifyEditorElementList();
15862   }
15863   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15864   {
15865     // update BD cycle delay counter gadgets depending on BD scheduling type
15866     DrawLevelConfigWindow();
15867   }
15868
15869   // do not mark level as modified for certain non-level-changing gadgets
15870   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15871       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15872     return;
15873
15874   level.changed = TRUE;
15875 }
15876
15877 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15878 {
15879   int type_id = gi->custom_type_id;
15880   int i;
15881
15882   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15883       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15884   {
15885     edit_mode_levelconfig = gi->custom_type_id;
15886
15887     DrawLevelConfigWindow();
15888   }
15889   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15890            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15891   {
15892     edit_mode_properties = gi->custom_type_id;
15893
15894     DrawPropertiesWindow();
15895   }
15896   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15897            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15898   {
15899     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15900
15901     // backup original "level.field" (needed to track playfield changes)
15902     CopyPlayfield(level.field, TileBackup);
15903
15904     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15905     CopyPlayfield(Tile, level.field);
15906
15907     if (new_template ||
15908         Request("Save this template and kill the old?", REQ_ASK))
15909       SaveLevelTemplate();
15910
15911     if (new_template)
15912       Request("Template saved!", REQ_CONFIRM);
15913
15914     // restore original "level.field" (needed to track playfield changes)
15915     CopyPlayfield(TileBackup, level.field);
15916   }
15917   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15918   {
15919     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15920
15921     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15922         leveldir_current->readonly)
15923     {
15924       Request("This level set is read-only!", REQ_CONFIRM);
15925
15926       return;
15927     }
15928
15929     if (strEqual(levelset_name, ""))
15930     {
15931       Request("Please enter level set title!", REQ_CONFIRM);
15932
15933       return;
15934     }
15935
15936     if (strEqual(levelset_author, ""))
15937     {
15938       Request("Please enter level set author!", REQ_CONFIRM);
15939
15940       return;
15941     }
15942
15943     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15944     {
15945       if (UpdateUserLevelSet(levelset_subdir,
15946                              levelset_name,
15947                              levelset_author,
15948                              levelset_num_levels))
15949       {
15950         Request("Level set updated!", REQ_CONFIRM);
15951       }
15952       else
15953       {
15954         Request("Updating level set failed!", REQ_CONFIRM);
15955       }
15956     }
15957     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15958     {
15959       if (level.changed && !Request("Level has changed! Discard changes?",
15960                                      REQ_ASK))
15961         return;
15962
15963       if (CreateUserLevelSet(levelset_subdir,
15964                              levelset_name,
15965                              levelset_author,
15966                              levelset_num_levels,
15967                              levelset_use_levelset_artwork))
15968       {
15969         if (levelset_copy_level_template)
15970           CopyLevelTemplateToUserLevelSet(levelset_subdir);
15971
15972         Request("New level set created!", REQ_CONFIRM);
15973
15974         AddUserLevelSetToLevelInfo(levelset_subdir);
15975         ChangeEditorToLevelSet(levelset_subdir);
15976       }
15977       else
15978       {
15979         Request("Creating new level set failed!", REQ_CONFIRM);
15980       }
15981     }
15982   }
15983   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
15984            custom_element.num_change_pages < MAX_CHANGE_PAGES)
15985   {
15986     struct ElementInfo *ei = &element_info[properties_element];
15987
15988     // when modifying custom element, ask for copying level template
15989     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15990       return;
15991
15992     setElementChangePages(ei, ei->num_change_pages + 1);
15993
15994     // set new change page to be new current change page
15995     ei->current_change_page = ei->num_change_pages - 1;
15996     ei->change = &ei->change_page[ei->current_change_page];
15997
15998     setElementChangeInfoToDefaults(ei->change);
15999
16000     DrawPropertiesWindow();
16001
16002     level.changed = TRUE;
16003   }
16004   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
16005            custom_element.num_change_pages > MIN_CHANGE_PAGES)
16006   {
16007     struct ElementInfo *ei = &element_info[properties_element];
16008
16009     // when modifying custom element, ask for copying level template
16010     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16011       return;
16012
16013     // copy all change pages after change page to be deleted
16014     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
16015       ei->change_page[i] = ei->change_page[i + 1];
16016
16017     setElementChangePages(ei, ei->num_change_pages - 1);
16018
16019     DrawPropertiesWindow();
16020
16021     level.changed = TRUE;
16022   }
16023 }
16024
16025 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
16026 {
16027   int type_id = gi->custom_type_id;
16028
16029   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
16030       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
16031   {
16032     struct ElementInfo *ei = &element_info[properties_element];
16033     int step = BUTTON_STEPSIZE(gi->event.button);
16034
16035     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
16036     ei->current_change_page += step;
16037
16038     if (ei->current_change_page < 0)
16039       ei->current_change_page = 0;
16040     else if (ei->current_change_page >= ei->num_change_pages)
16041       ei->current_change_page = ei->num_change_pages - 1;
16042
16043     DrawPropertiesWindow();
16044   }
16045   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
16046            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16047   {
16048     struct ElementInfo *ei = &element_info[properties_element];
16049     int current_change_page = ei->current_change_page;
16050
16051     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
16052     {
16053       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
16054         ei->change_page[current_change_page];
16055     }
16056     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16057     {
16058       // when modifying custom element, ask for copying level template
16059       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16060         return;
16061
16062       ei->change_page[current_change_page] =
16063         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
16064
16065       level.changed = TRUE;
16066     }
16067
16068     DrawPropertiesWindow();
16069   }
16070 }
16071
16072 static void HandleRadiobuttons(struct GadgetInfo *gi)
16073 {
16074   int type_id = gi->custom_type_id;
16075
16076   *radiobutton_info[type_id].value =
16077     radiobutton_info[type_id].checked_value;
16078
16079   // do not mark level as modified for certain non-level-changing gadgets
16080   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
16081       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
16082     return;
16083
16084   level.changed = TRUE;
16085 }
16086
16087 static void HandleCheckbuttons(struct GadgetInfo *gi)
16088 {
16089   int type_id = gi->custom_type_id;
16090
16091   *checkbutton_info[type_id].value ^= TRUE;
16092
16093   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
16094       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
16095       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
16096       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
16097          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
16098         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
16099          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
16100        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
16101   {
16102     CopyElementPropertiesToGame(properties_element);
16103   }
16104
16105   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
16106   {
16107     UpdateCustomElementGraphicGadgets();
16108   }
16109   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
16110            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
16111   {
16112     boolean template_related_changes_found = FALSE;
16113     int i;
16114
16115     // check if any custom, group or empty elements have been changed
16116     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
16117       if ((IS_CUSTOM_ELEMENT(i) ||
16118            IS_GROUP_ELEMENT(i) ||
16119            IS_EMPTY_ELEMENT(i)) &&
16120           element_info[i].modified_settings)
16121         template_related_changes_found = TRUE;
16122
16123     if (level.use_custom_template &&
16124         !fileExists(getGlobalLevelTemplateFilename()))
16125     {
16126       Request("No level template found!", REQ_CONFIRM);
16127
16128       level.use_custom_template = FALSE;
16129
16130       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16131
16132       return;
16133     }
16134
16135     if (level.use_custom_template &&
16136         template_related_changes_found &&
16137         !Request("Discard changes and use level template?", REQ_ASK))
16138     {
16139       level.use_custom_template = FALSE;
16140
16141       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16142
16143       return;
16144     }
16145
16146     if (!level.use_custom_template &&
16147         Request("Copy settings from level template?", REQ_ASK))
16148     {
16149       return;
16150     }
16151
16152     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
16153
16154     DrawEditModeWindow();
16155   }
16156   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
16157   {
16158     if (setup.editor.use_template_for_new_levels &&
16159         !fileExists(getGlobalLevelTemplateFilename()))
16160     {
16161       Request("No level template found!", REQ_CONFIRM);
16162
16163       return;
16164     }
16165
16166     if (setup.editor.use_template_for_new_levels &&
16167         level.changed &&
16168         !Request("Discard level and load template?", REQ_ASK))
16169     {
16170       return;
16171     }
16172
16173     if (!setup.editor.use_template_for_new_levels &&
16174         level.changed &&
16175         !Request("Discard level and use empty level?", REQ_ASK))
16176     {
16177       return;
16178     }
16179
16180     LoadLevel(level_nr);
16181     LoadScore(level_nr);
16182
16183     TapeErase();
16184
16185     ResetUndoBuffer();
16186     DrawEditModeWindow();
16187   }
16188   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16189   {
16190     SetAutomaticNumberOfGemsNeeded();
16191   }
16192
16193   // do not mark level as modified for certain non-level-changing gadgets
16194   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16195        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16196       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16197        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16198        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16199       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16200     return;
16201
16202   level.changed = TRUE;
16203 }
16204
16205 static void HandleControlButtons(struct GadgetInfo *gi)
16206 {
16207   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16208   static int last_edit_mode = ED_MODE_DRAWING;
16209   static int last_custom_copy_mode = -1;
16210   static int last_button = 0;
16211   int id = gi->custom_id;
16212   int button = gi->event.button;
16213   int step = BUTTON_STEPSIZE(button);
16214   int new_element = BUTTON_ELEMENT(button);
16215   int last_properties_element = properties_element;
16216   int x, y;
16217
16218   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16219     DrawLevelText(0, 0, 0, TEXT_END);
16220
16221   if (id < ED_NUM_CTRL1_BUTTONS &&
16222       id != GADGET_ID_SINGLE_ITEMS &&
16223       id != GADGET_ID_PICK_ELEMENT &&
16224       edit_mode != ED_MODE_DRAWING &&
16225       drawing_function != GADGET_ID_PICK_ELEMENT &&
16226       !(GetKeyModState() & KMOD_Control))
16227     ChangeEditModeWindow(ED_MODE_DRAWING);
16228
16229   // element copy mode active, but no element button pressed => deactivate
16230   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16231     last_custom_copy_mode = -1;
16232
16233   // when showing palette on element buttons, change element of button used
16234   if (editor.palette.show_on_element_buttons &&
16235       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16236   {
16237     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16238
16239     id = GADGET_ID_PALETTE;
16240   }
16241
16242   switch (id)
16243   {
16244     case GADGET_ID_SCROLL_LEFT:
16245       if (level_xpos >= 0)
16246       {
16247         if (lev_fieldx < ed_fieldx - 2)
16248           break;
16249
16250         level_xpos -= step;
16251         if (level_xpos < -1)
16252           level_xpos = -1;
16253         if (button == 1)
16254           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16255         else
16256           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16257
16258         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16259                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16260       }
16261       break;
16262
16263     case GADGET_ID_SCROLL_RIGHT:
16264       if (level_xpos <= lev_fieldx - ed_fieldx)
16265       {
16266         if (lev_fieldx < ed_fieldx - 2)
16267           break;
16268
16269         level_xpos += step;
16270         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16271           level_xpos = lev_fieldx - ed_fieldx + 1;
16272         if (button == 1)
16273           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16274         else
16275           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16276
16277         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16278                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16279       }
16280       break;
16281
16282     case GADGET_ID_SCROLL_UP:
16283       if (level_ypos >= 0)
16284       {
16285         if (lev_fieldy < ed_fieldy - 2)
16286           break;
16287
16288         level_ypos -= step;
16289         if (level_ypos < -1)
16290           level_ypos = -1;
16291         if (button == 1)
16292           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16293         else
16294           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16295
16296         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16297                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16298       }
16299       break;
16300
16301     case GADGET_ID_SCROLL_DOWN:
16302       if (level_ypos <= lev_fieldy - ed_fieldy)
16303       {
16304         if (lev_fieldy < ed_fieldy - 2)
16305           break;
16306
16307         level_ypos += step;
16308         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16309           level_ypos = lev_fieldy - ed_fieldy + 1;
16310         if (button == 1)
16311           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16312         else
16313           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16314
16315         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16316                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16317       }
16318       break;
16319
16320     case GADGET_ID_SCROLL_HORIZONTAL:
16321       level_xpos = gi->event.item_position - 1;
16322
16323       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16324       BackToFront();
16325
16326       break;
16327
16328     case GADGET_ID_SCROLL_VERTICAL:
16329       level_ypos = gi->event.item_position - 1;
16330
16331       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16332       BackToFront();
16333
16334       break;
16335
16336     case GADGET_ID_SCROLL_LIST_UP:
16337     case GADGET_ID_SCROLL_LIST_DOWN:
16338     case GADGET_ID_SCROLL_LIST_VERTICAL:
16339       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16340         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16341       else
16342       {
16343         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16344         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16345
16346         if (element_shift < 0)
16347           element_shift = 0;
16348         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16349           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16350
16351         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16352                      GDI_SCROLLBAR_ITEM_POSITION,
16353                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16354       }
16355
16356       ModifyEditorElementList();
16357
16358       break;
16359
16360     case GADGET_ID_PROPERTIES:
16361       // always switch off element properties when they are already displayed
16362       last_properties_element = new_element;
16363     case GADGET_ID_ELEMENT_LEFT:
16364     case GADGET_ID_ELEMENT_MIDDLE:
16365     case GADGET_ID_ELEMENT_RIGHT:
16366       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16367                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16368                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16369                             new_element);
16370
16371       if (edit_mode != ED_MODE_PROPERTIES)
16372       {
16373         last_edit_mode = edit_mode;
16374
16375         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16376
16377         last_level_drawing_function = drawing_function;
16378         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16379                       MB_LEFTBUTTON);
16380       }
16381       else if (properties_element != last_properties_element)
16382       {
16383         DrawEditModeWindow();
16384       }
16385       else
16386       {
16387         ChangeEditModeWindow(ED_MODE_DRAWING);
16388
16389         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16390                       MB_LEFTBUTTON);
16391       }
16392       break;
16393
16394     case GADGET_ID_PALETTE:
16395       if (edit_mode != ED_MODE_PALETTE)
16396       {
16397         last_edit_mode = edit_mode;
16398
16399         ChangeEditModeWindow(ED_MODE_PALETTE);
16400       }
16401       else
16402       {
16403         ChangeEditModeWindow(last_edit_mode);
16404       }
16405       break;
16406
16407     case GADGET_ID_WRAP_LEFT:
16408       WrapLevel(-step, 0);
16409       break;
16410
16411     case GADGET_ID_WRAP_RIGHT:
16412       WrapLevel(step, 0);
16413       break;
16414
16415     case GADGET_ID_WRAP_UP:
16416       WrapLevel(0, -step);
16417       break;
16418
16419     case GADGET_ID_WRAP_DOWN:
16420       WrapLevel(0, step);
16421       break;
16422
16423     case GADGET_ID_SINGLE_ITEMS:
16424     case GADGET_ID_CONNECTED_ITEMS:
16425     case GADGET_ID_LINE:
16426     case GADGET_ID_ARC:
16427     case GADGET_ID_TEXT:
16428     case GADGET_ID_RECTANGLE:
16429     case GADGET_ID_FILLED_BOX:
16430     case GADGET_ID_FLOOD_FILL:
16431     case GADGET_ID_GRAB_BRUSH:
16432     case GADGET_ID_PICK_ELEMENT:
16433       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16434         last_drawing_function = drawing_function;
16435       drawing_function = id;
16436       draw_with_brush = FALSE;
16437       break;
16438
16439     case GADGET_ID_RANDOM_PLACEMENT:
16440       RandomPlacement(new_element);
16441       break;
16442
16443     case GADGET_ID_ZOOM:
16444       // zoom level editor tile size in or out (or reset to default size)
16445       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16446                      button == 2 ? ed_tilesize_default :
16447                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16448
16449       // when using touch device, cycle through all zoom tilesizes
16450       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16451         ed_tilesize = MICRO_TILESIZE;
16452
16453       // limit zoom level by upper and lower bound
16454       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16455
16456       InitZoomLevelSettings(ed_tilesize);
16457
16458       if (edit_mode == ED_MODE_DRAWING)
16459       {
16460         DrawDrawingWindow();
16461
16462         // redraw zoom gadget info text
16463         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16464       }
16465
16466       // save current editor zoom tilesize
16467       SaveSetup_AutoSetup();
16468
16469       break;
16470
16471     case GADGET_ID_CUSTOM_COPY_FROM:
16472     case GADGET_ID_CUSTOM_COPY_TO:
16473     case GADGET_ID_CUSTOM_EXCHANGE:
16474       last_custom_copy_mode = id;
16475       last_drawing_function = drawing_function;
16476       break;
16477
16478     case GADGET_ID_CUSTOM_COPY:
16479       CopyCustomElement(properties_element, -1, id);
16480       break;
16481
16482     case GADGET_ID_CUSTOM_PASTE:
16483       CopyCustomElement(-1, properties_element, id);
16484       break;
16485
16486     case GADGET_ID_UNDO:
16487       if (button < 0)   // keep button value (even if modifier keys are pressed)
16488         button = -button;
16489       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16490         button = 3;
16491
16492       if (button == 1 && undo_buffer_steps == 0)
16493       {
16494         Request("Undo buffer empty!", REQ_CONFIRM);
16495
16496         break;
16497       }
16498       else if (button == 2)
16499       {
16500         break;
16501       }
16502       else if (button == 3 && redo_buffer_steps == 0)
16503       {
16504         Request("Redo buffer empty!", REQ_CONFIRM);
16505
16506         break;
16507       }
16508
16509       if (edit_mode != ED_MODE_DRAWING)
16510         ChangeEditModeWindow(ED_MODE_DRAWING);
16511
16512       if (button == 1)
16513       {
16514         // undo
16515
16516         undo_buffer_position =
16517           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16518
16519         undo_buffer_steps--;
16520         redo_buffer_steps++;
16521       }
16522       else
16523       {
16524         // redo
16525
16526         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16527
16528         undo_buffer_steps++;
16529         redo_buffer_steps--;
16530       }
16531
16532       for (x = 0; x < lev_fieldx; x++)
16533         for (y = 0; y < lev_fieldy; y++)
16534           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16535
16536       // check if undo operation forces change of border style
16537       CheckLevelBorderElement(FALSE);
16538
16539       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16540
16541       break;
16542
16543     case GADGET_ID_CONF:
16544       if (edit_mode != ED_MODE_LEVELCONFIG)
16545       {
16546         last_edit_mode = edit_mode;
16547
16548         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16549       }
16550       else
16551       {
16552         ChangeEditModeWindow(ED_MODE_DRAWING);
16553       }
16554       break;
16555
16556     case GADGET_ID_CLEAR:
16557       if (edit_mode != ED_MODE_DRAWING)
16558         ChangeEditModeWindow(ED_MODE_DRAWING);
16559
16560       for (x = 0; x < MAX_LEV_FIELDX; x++)
16561         for (y = 0; y < MAX_LEV_FIELDY; y++)
16562           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16563
16564       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16565
16566       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16567       break;
16568
16569     case GADGET_ID_SAVE:
16570     {
16571       // saving read-only levels into personal level set modifies global vars
16572       // "leveldir_current" and "level_nr"; restore them after saving level
16573       LevelDirTree *leveldir_former = leveldir_current;
16574       int level_nr_former = level_nr;
16575       char *level_filename;
16576       boolean new_level;
16577
16578       if (leveldir_current->readonly &&
16579           !PrepareSavingIntoPersonalLevelSet())
16580         break;
16581
16582       level_filename = getDefaultLevelFilename(level_nr);
16583       new_level = !fileExists(level_filename);
16584
16585       if (new_level ||
16586           Request("Save this level and kill the old?", REQ_ASK))
16587       {
16588         if (leveldir_former->readonly)
16589           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16590
16591         SetAutomaticNumberOfGemsNeeded();
16592
16593         CopyPlayfield(Tile, level.field);
16594         SaveLevel(level_nr);
16595
16596         level.changed = FALSE;
16597
16598         if (new_level)
16599         {
16600           char level_saved_msg[64];
16601
16602           if (leveldir_former->readonly)
16603             sprintf(level_saved_msg,
16604                     "Level saved as level %d into personal level set!",
16605                     level_nr);
16606           else
16607             strcpy(level_saved_msg, "Level saved!");
16608
16609           Request(level_saved_msg, REQ_CONFIRM);
16610         }
16611       }
16612
16613       // "cd" back to copied-from levelset (in case of saved read-only level)
16614       leveldir_current = leveldir_former;
16615       level_nr = level_nr_former;
16616
16617       break;
16618     }
16619
16620     case GADGET_ID_TEST:
16621       if (LevelChanged())
16622         level.game_version = GAME_VERSION_ACTUAL;
16623
16624       CopyPlayfield(level.field, TileBackup);
16625       CopyPlayfield(Tile, level.field);
16626
16627       CopyNativeLevel_RND_to_Native(&level);
16628
16629       UnmapLevelEditorGadgets();
16630       UndrawSpecialEditorDoor();
16631
16632       CloseDoor(DOOR_CLOSE_ALL);
16633
16634       // needed before playing if editor playfield area has different size
16635       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16636
16637       // redraw_mask = REDRAW_ALL;
16638
16639       level_editor_test_game = TRUE;
16640
16641       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16642
16643       break;
16644
16645     case GADGET_ID_EXIT:
16646       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16647       break;
16648
16649     default:
16650       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16651           id <= GADGET_ID_ELEMENTLIST_LAST)
16652       {
16653         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16654
16655         new_element = editor_elements[element_position + element_shift];
16656
16657         if (IS_EDITOR_CASCADE(new_element))
16658         {
16659           int i;
16660
16661           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16662           {
16663             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16664             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16665
16666             if (*cascade_element == new_element)
16667             {
16668               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16669               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16670
16671               // update element selection list
16672               ReinitializeElementList();
16673               ModifyEditorElementList();
16674
16675               // update cascading gadget info text
16676               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16677
16678               // save current editor cascading state
16679               SaveSetup_EditorCascade();
16680
16681               break;
16682             }
16683           }
16684
16685           break;
16686         }
16687
16688         if (last_custom_copy_mode != -1)
16689         {
16690           if (CopyCustomElement(properties_element, new_element,
16691                                 last_custom_copy_mode))
16692           {
16693             ClickOnGadget(level_editor_gadget[last_drawing_function],
16694                           MB_LEFTBUTTON);
16695
16696             last_custom_copy_mode = -1;
16697           }
16698
16699           break;
16700         }
16701
16702         // change element of button used to show palette
16703         if (editor.palette.show_on_element_buttons)
16704           button = last_button;
16705
16706         PickDrawingElement(button, new_element);
16707
16708         if (!stick_element_properties_window &&
16709             drawing_function != GADGET_ID_PICK_ELEMENT &&
16710             !(GetKeyModState() & KMOD_Control))
16711         {
16712           properties_element = new_element;
16713           if (edit_mode == ED_MODE_PROPERTIES)
16714             DrawPropertiesWindow();
16715         }
16716
16717         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16718           ClickOnGadget(level_editor_gadget[last_drawing_function],
16719                         MB_LEFTBUTTON);
16720
16721         if (!use_permanent_palette)
16722           ChangeEditModeWindow(last_edit_mode);
16723       }
16724 #ifdef DEBUG
16725       else if (gi->event.type == GD_EVENT_PRESSED)
16726         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16727       else if (gi->event.type == GD_EVENT_RELEASED)
16728         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16729       else if (gi->event.type == GD_EVENT_MOVING)
16730         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16731       else
16732         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16733 #endif
16734       break;
16735   }
16736 }
16737
16738 void HandleLevelEditorKeyInput(Key key)
16739 {
16740   char letter = getCharFromKey(key);
16741
16742   if (drawing_function == GADGET_ID_TEXT &&
16743       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16744   {
16745     if (letter)
16746       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16747     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16748       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16749     else if (key == KSYM_Return)
16750       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16751     else if (key == KSYM_Escape)
16752       DrawLevelText(0, 0, 0, TEXT_END);
16753
16754     return;
16755   }
16756
16757   int id = GADGET_ID_NONE;
16758   int new_element_shift = element_shift;
16759   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16760   int button = MB_LEFTBUTTON;
16761   int i;
16762
16763   switch (key)
16764   {
16765     case KSYM_Left:
16766       id = GADGET_ID_SCROLL_LEFT;
16767       break;
16768     case KSYM_Right:
16769       id = GADGET_ID_SCROLL_RIGHT;
16770       break;
16771     case KSYM_Up:
16772       id = GADGET_ID_SCROLL_UP;
16773       break;
16774     case KSYM_Down:
16775       id = GADGET_ID_SCROLL_DOWN;
16776       break;
16777
16778     case KSYM_Page_Up:
16779     case KSYM_Page_Down:
16780       step *= (key == KSYM_Page_Up ? -1 : +1);
16781       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16782
16783       if (element_shift < 0)
16784         element_shift = 0;
16785       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16786         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16787
16788       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16789                    GDI_SCROLLBAR_ITEM_POSITION,
16790                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16791
16792       ModifyEditorElementList();
16793
16794       break;
16795
16796     case KSYM_Home:
16797     case KSYM_End:
16798       element_shift = (key == KSYM_Home ? 0 :
16799                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16800
16801       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16802                    GDI_SCROLLBAR_ITEM_POSITION,
16803                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16804
16805       ModifyEditorElementList();
16806
16807       break;
16808
16809     case KSYM_Insert:
16810     case KSYM_Delete:
16811
16812       // this is needed to prevent interference with running "True X-Mouse"
16813       if (GetKeyModStateFromEvents() & KMOD_Control)
16814         break;
16815
16816       // check for last or next editor cascade block in element list
16817       for (i = 0; i < num_editor_elements; i++)
16818       {
16819         if ((key == KSYM_Insert && i == element_shift) ||
16820             (key == KSYM_Delete && new_element_shift > element_shift))
16821           break;
16822
16823         // jump to next cascade block (or to start of element list)
16824         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16825           new_element_shift = i;
16826       }
16827
16828       if (i < num_editor_elements)
16829         element_shift = new_element_shift;
16830
16831       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16832         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16833
16834       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16835                    GDI_SCROLLBAR_ITEM_POSITION,
16836                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16837
16838       ModifyEditorElementList();
16839
16840       break;
16841
16842     case KSYM_Escape:
16843       if (edit_mode == ED_MODE_DRAWING)
16844         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16845       else if (edit_mode == ED_MODE_LEVELCONFIG)
16846         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16847       else if (edit_mode == ED_MODE_PROPERTIES)
16848         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16849       else if (edit_mode == ED_MODE_PALETTE)
16850         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16851       else              // should never happen
16852         ChangeEditModeWindow(ED_MODE_DRAWING);
16853
16854       break;
16855
16856     default:
16857       break;
16858   }
16859
16860   if (id != GADGET_ID_NONE)
16861     ClickOnGadget(level_editor_gadget[id], button);
16862   else if (letter == '1' || letter == '?')
16863     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16864   else if (letter == '2')
16865     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16866   else if (letter == '3')
16867     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16868   else if (letter == '.')
16869     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16870   else if (letter == 'U')
16871     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16872   else if (letter == '-' || key == KSYM_KP_Subtract)
16873     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16874   else if (letter == '0' || key == KSYM_KP_0)
16875     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16876   else if (letter == '+' || key == KSYM_KP_Add ||
16877            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16878     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16879   else if (key == KSYM_Return ||
16880            key == KSYM_space ||
16881            key == setup.shortcut.toggle_pause)
16882     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16883   else
16884     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16885       if (letter && letter == controlbutton_info[i].shortcut)
16886         if (!anyTextGadgetActive())
16887           ClickOnGadget(level_editor_gadget[i], button);
16888
16889   if (draw_with_brush)
16890   {
16891     if (letter == 'x')
16892       FlipBrushX();
16893     else if (letter == 'y')
16894       FlipBrushY();
16895     else if (letter == 'z')
16896       RotateBrush();
16897   }
16898 }
16899
16900 static void HandleLevelEditorIdle_Properties(void)
16901 {
16902   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16903   int x = editor.settings.element_graphic.x + element_border;
16904   int y = editor.settings.element_graphic.y + element_border;
16905   static DelayCounter action_delay = { 0 };
16906   int i;
16907
16908   action_delay.value = GameFrameDelay;
16909
16910   if (!DelayReached(&action_delay))
16911     return;
16912
16913   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16914   {
16915     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16916
16917     if (gi->mapped && gi->active && gi->selectbox.open)
16918       return;
16919   }
16920
16921   DrawEditorElementAnimation(SX + x, SY + y);
16922
16923   redraw_mask |= REDRAW_FIELD;
16924
16925   FrameCounter++;       // increase animation frame counter
16926 }
16927
16928 static void HandleLevelEditorIdle_Drawing(void)
16929 {
16930   static boolean last_highlighted = FALSE;
16931   static boolean last_highlighted_similar = FALSE;
16932   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16933   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16934
16935   if (highlighted != last_highlighted ||
16936       (highlighted && highlighted_similar != last_highlighted_similar))
16937   {
16938     DrawAreaElementHighlight(highlighted, highlighted_similar);
16939
16940     redraw_mask |= REDRAW_FIELD;
16941   }
16942
16943   last_highlighted = highlighted;
16944   last_highlighted_similar = highlighted_similar;
16945 }
16946
16947 void HandleLevelEditorIdle(void)
16948 {
16949   if (edit_mode == ED_MODE_PROPERTIES)
16950     HandleLevelEditorIdle_Properties();
16951   else if (edit_mode == ED_MODE_DRAWING)
16952     HandleLevelEditorIdle_Drawing();
16953 }
16954
16955 static void ClearEditorGadgetInfoText(void)
16956 {
16957   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16958 }
16959
16960 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16961 {
16962   char infotext[MAX_OUTPUT_LINESIZE + 1];
16963   int max_infotext_len = getMaxInfoTextLength();
16964
16965   if (gi == NULL || strlen(gi->info_text) == 0)
16966     return;
16967
16968   strncpy(infotext, gi->info_text, max_infotext_len);
16969   infotext[max_infotext_len] = '\0';
16970
16971   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
16972   {
16973     int key = controlbutton_info[gi->custom_id].shortcut;
16974
16975     if (key)
16976     {
16977       char shortcut[MAX_OUTPUT_LINESIZE + 1];
16978
16979       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
16980         sprintf(shortcut, " ('.' or '%c')", key);
16981       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
16982         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
16983       else if (gi->custom_id == GADGET_ID_TEST)
16984         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
16985       else if (gi->custom_id == GADGET_ID_UNDO)
16986         sprintf(shortcut, " ('%c/Shift-U')", key);
16987       else if (gi->custom_id == GADGET_ID_ZOOM)
16988         sprintf(shortcut, " ('%c', '0', '-')", key);
16989       else
16990         sprintf(shortcut, " ('%s%c')",
16991                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
16992
16993       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
16994         strcat(infotext, shortcut);
16995     }
16996   }
16997
16998   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
16999 }
17000
17001 void HandleEditorGadgetInfoText(void *ptr)
17002 {
17003   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
17004
17005   if (game_status != GAME_MODE_EDITOR)
17006     return;
17007
17008   ClearEditorGadgetInfoText();
17009
17010   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
17011     return;
17012
17013   // misuse this function to delete brush cursor, if needed
17014   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
17015     DeleteBrushFromCursor();
17016
17017   PrintEditorGadgetInfoText(gi);
17018 }
17019
17020 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
17021 {
17022   int id = gi->custom_id;
17023   int type_id = gi->custom_type_id;
17024   int sx = gi->event.x;
17025   int sy = gi->event.y;
17026   int lx = sx + level_xpos;
17027   int ly = sy + level_ypos;
17028   int min_sx = 0, min_sy = 0;
17029   int max_sx = gi->drawing.area_xsize - 1;
17030   int max_sy = gi->drawing.area_ysize - 1;
17031   int actual_drawing_function = drawing_function;
17032   int max_infotext_len = getMaxInfoTextLength();
17033   char infotext[MAX_OUTPUT_LINESIZE + 1];
17034
17035   infotext[0] = '\0';           // start with empty info text
17036
17037   // pressed Control key: simulate picking element
17038   if (GetKeyModState() & KMOD_Control)
17039     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
17040
17041   ClearEditorGadgetInfoText();
17042
17043   if (gi->event.type == GD_EVENT_INFO_LEAVING)
17044     return;
17045
17046   // make sure to stay inside drawing area boundaries
17047   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
17048   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
17049
17050   if (id == GADGET_ID_DRAWING_LEVEL)
17051   {
17052     if (button_status)
17053     {
17054       int min_lx = 0, min_ly = 0;
17055       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
17056
17057       // get positions inside level field
17058       lx = sx + level_xpos;
17059       ly = sy + level_ypos;
17060
17061       // make sure to stay inside level field boundaries
17062       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
17063       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
17064
17065       // correct drawing area positions accordingly
17066       sx = lx - level_xpos;
17067       sy = ly - level_ypos;
17068     }
17069
17070     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17071     {
17072       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
17073       {
17074         static int start_lx = 0;
17075         static int start_ly = 0;
17076         char *text;
17077
17078         if (gi->event.type == GD_EVENT_PRESSED)
17079         {
17080           start_lx = lx;
17081           start_ly = ly;
17082         }
17083
17084         switch (actual_drawing_function)
17085         {
17086           case GADGET_ID_SINGLE_ITEMS:
17087             text = "Drawing single items";
17088             break;
17089           case GADGET_ID_CONNECTED_ITEMS:
17090             text = "Drawing connected items";
17091             break;
17092           case GADGET_ID_LINE:
17093             text = "Drawing line";
17094             break;
17095           case GADGET_ID_ARC:
17096             text = "Drawing arc";
17097             break;
17098           case GADGET_ID_TEXT:
17099             text = "Setting text cursor";
17100             break;
17101           case GADGET_ID_RECTANGLE:
17102             text = "Drawing rectangle";
17103             break;
17104           case GADGET_ID_FILLED_BOX:
17105             text = "Drawing filled box";
17106             break;
17107           case GADGET_ID_FLOOD_FILL:
17108             text = "Flood fill";
17109             break;
17110           case GADGET_ID_GRAB_BRUSH:
17111             text = "Grabbing brush";
17112             break;
17113           case GADGET_ID_PICK_ELEMENT:
17114             text = "Picking element";
17115             break;
17116
17117           default:
17118             text = "Drawing position";
17119             break;
17120         }
17121
17122         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17123           sprintf(infotext, "%s: %d, %d", text, lx, ly);
17124         else
17125           sprintf(infotext, "%s: %d, %d", text,
17126                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
17127       }
17128       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17129         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
17130       else
17131         sprintf(infotext, "Level position: %d, %d", lx, ly);
17132     }
17133
17134     // misuse this function to draw brush cursor, if needed
17135     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
17136     {
17137       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17138         CopyBrushToCursor(sx, sy);
17139       else
17140         DeleteBrushFromCursor();
17141     }
17142
17143     if (!draw_with_brush)
17144       UpdateBrushPosition(sx, sy);
17145   }
17146   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17147   {
17148     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
17149     int element = drawingarea_info[type_id].value[pos];
17150
17151     strncpy(infotext, getElementInfoText(element), max_infotext_len);
17152   }
17153   else
17154   {
17155     if (id == GADGET_ID_CUSTOM_CONTENT)
17156       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
17157     else if (id == GADGET_ID_GROUP_CONTENT)
17158       sprintf(infotext, "group element position: %d", sx + 1);
17159     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
17160              id <= GADGET_ID_YAMYAM_CONTENT_7)
17161       sprintf(infotext, "content area %d position: %d, %d",
17162               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
17163     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17164              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17165       sprintf(infotext, "content area %d position: %d, %d",
17166               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17167     else if (id == GADGET_ID_ANDROID_CONTENT)
17168       sprintf(infotext, "android element position: %d", sx + 1);
17169     else if (drawingarea_info[type_id].infotext != NULL)
17170       strcpy(infotext, drawingarea_info[type_id].infotext);
17171   }
17172
17173   infotext[max_infotext_len] = '\0';
17174
17175   if (strlen(infotext) > 0)
17176     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17177 }
17178
17179 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17180                             boolean quick_quit)
17181 {
17182   if (!ask_if_level_has_changed ||
17183       !LevelChanged() ||
17184       Request("Level has changed! Exit without saving?",
17185               REQ_ASK | REQ_STAY_OPEN))
17186   {
17187     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17188     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17189
17190     // draw normal door
17191     UndrawSpecialEditorDoor();
17192
17193     // use door animation if door 1 viewport is unchanged and contains toolbox
17194     if (useEditorDoorAnimation())
17195       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17196
17197     // close editor doors if viewport definition is the same as in main menu
17198     if (vp_door_1->x      == DX     &&
17199         vp_door_1->y      == DY     &&
17200         vp_door_1->width  == DXSIZE &&
17201         vp_door_1->height == DYSIZE &&
17202         vp_door_2->x      == VX     &&
17203         vp_door_2->y      == VY     &&
17204         vp_door_2->width  == VXSIZE &&
17205         vp_door_2->height == VYSIZE)
17206       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17207     else
17208       SetDoorState(DOOR_CLOSE_ALL);
17209
17210     BackToFront();
17211
17212     if (quick_quit)
17213       FadeSkipNextFadeIn();
17214
17215     SetGameStatus(GAME_MODE_MAIN);
17216
17217     DrawMainMenu();
17218   }
17219   else
17220   {
17221     if (!global.use_envelope_request)
17222     {
17223       CloseDoor(DOOR_CLOSE_1);
17224       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17225     }
17226   }
17227 }