minor code formatting changes
[rocksndiamonds.git] / src / editor.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // editor.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "game.h"
21 #include "init.h"
22 #include "tape.h"
23
24
25 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
26
27
28 // ----------------------------------------------------------------------------
29 // screen and artwork graphic pixel position definitions
30 // ----------------------------------------------------------------------------
31
32 // values for the control window
33 #define ED_CTRL1_BUTTONS_HORIZ          4       // toolbox
34 #define ED_CTRL1_BUTTONS_VERT           4
35 #define ED_CTRL2_BUTTONS_HORIZ          3       // level
36 #define ED_CTRL2_BUTTONS_VERT           2
37 #define ED_CTRL3_BUTTONS_HORIZ          3       // CE and GE
38 #define ED_CTRL3_BUTTONS_VERT           1
39 #define ED_CTRL4_BUTTONS_HORIZ          2       // CE and GE
40 #define ED_CTRL4_BUTTONS_VERT           1
41 #define ED_CTRL5_BUTTONS_HORIZ          1       // properties
42 #define ED_CTRL5_BUTTONS_VERT           1
43 #define ED_CTRL6_BUTTONS_HORIZ          3       // properties
44 #define ED_CTRL6_BUTTONS_VERT           1
45 #define ED_CTRL7_BUTTONS_HORIZ          1       // palette
46 #define ED_CTRL7_BUTTONS_VERT           1
47
48 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
49 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
50 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
51 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
52 #define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
53 #define ED_NUM_CTRL6_BUTTONS   (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT)
54 #define ED_NUM_CTRL7_BUTTONS   (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT)
55 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
56 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
57 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
58 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
59 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
60 #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS)
61 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_7_BUTTONS
62
63 // values for the element list
64 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
65 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
66 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
67 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
68 #define ED_ELEMENTLIST_COLS             MAX(1, editor.palette.cols)
69 #define ED_ELEMENTLIST_ROWS             MAX(1, editor.palette.rows)
70 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (ED_ELEMENTLIST_COLS)
71 #define ED_ELEMENTLIST_BUTTONS_VERT     (ED_ELEMENTLIST_ROWS)
72 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
73                                          ED_ELEMENTLIST_BUTTONS_VERT)
74
75 // standard distances
76 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
77 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
78 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
79 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
80 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
81 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
82 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
83                                          ED_DRAWINGAREA_BORDER_SIZE)
84 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
85
86 // values for drawingarea gadgets
87 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
88 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
89 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
90 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
91 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
92
93 // values for checkbutton gadgets
94 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
95 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
96
97 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
98 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
99
100 #define ED_SETTINGS_LEVEL_TABS_X        (editor.settings.tabs.x)
101 #define ED_SETTINGS_LEVEL_TABS_Y        (editor.settings.tabs.y)
102 #define ED_SETTINGS_ELEMENT_TABS_X      (editor.settings.tabs.x)
103 #define ED_SETTINGS_ELEMENT_TABS_Y      (editor.settings.tabs.y +       \
104                                          editor.settings.tabs.yoffset2)
105
106 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
107 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
108
109 #define ED_LEVEL_TABS_XSTART            (ED_SETTINGS_LEVEL_TABS_X)
110 #define ED_LEVEL_TABS_YSTART            (ED_SETTINGS_LEVEL_TABS_Y)
111 #define ED_LEVEL_SETTINGS_XSTART        (ED_SETTINGS_LEVEL_TABS_X +     \
112                                          ED_SETTINGS_TABS_XOFFSET)
113 #define ED_LEVEL_SETTINGS_YSTART        (ED_SETTINGS_LEVEL_TABS_Y +     \
114                                          ED_TABBUTTON_YSIZE +           \
115                                          ED_GADGET_TINY_DISTANCE +      \
116                                          ED_TAB_BAR_HEIGHT +            \
117                                          ED_SETTINGS_TABS_YOFFSET +     \
118                                          getFontHeight(FONT_TEXT_1) +   \
119                                          ED_GADGET_TEXT_DISTANCE)
120 #define ED_ELEMENT_TABS_XSTART          (ED_SETTINGS_ELEMENT_TABS_X)
121 #define ED_ELEMENT_TABS_YSTART          (ED_SETTINGS_ELEMENT_TABS_Y)
122 #define ED_ELEMENT_SETTINGS_XSTART      (ED_SETTINGS_ELEMENT_TABS_X +   \
123                                          ED_SETTINGS_TABS_XOFFSET)
124 #define ED_ELEMENT_SETTINGS_YSTART      (ED_SETTINGS_ELEMENT_TABS_Y +   \
125                                          ED_TABBUTTON_YSIZE +           \
126                                          ED_GADGET_TINY_DISTANCE +      \
127                                          ED_TAB_BAR_HEIGHT +            \
128                                          ED_SETTINGS_TABS_YOFFSET)
129
130 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
131                                          ED_GADGET_TEXT_DISTANCE)
132 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
133                                          ED_GADGET_LINE_DISTANCE)
134
135 #define ED_POS_RANGE                    (10000)
136 #define ED_POS_LEVEL_TABS_FIRST         (1 * ED_POS_RANGE)
137 #define ED_POS_LEVEL_TABS_LAST          (2 * ED_POS_RANGE - 1)
138 #define ED_POS_LEVEL_SETTINGS_FIRST     (2 * ED_POS_RANGE)
139 #define ED_POS_LEVEL_SETTINGS_LAST      (3 * ED_POS_RANGE - 1)
140 #define ED_POS_ELEMENT_TABS_FIRST       (3 * ED_POS_RANGE)
141 #define ED_POS_ELEMENT_TABS_LAST        (4 * ED_POS_RANGE - 1)
142 #define ED_POS_ELEMENT_SETTINGS_FIRST   (4 * ED_POS_RANGE)
143 #define ED_POS_ELEMENT_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
144
145 #define ED_LEVEL_TABS_XPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
146 #define ED_LEVEL_TABS_YPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
147
148 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
149 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
150
151 #define ED_ELEMENT_TABS_XPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
152 #define ED_ELEMENT_TABS_YPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
153
154 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
155 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
156
157 #define IS_POS_LEVEL_TABS(n)          ((n) >= ED_POS_LEVEL_TABS_FIRST && \
158                                        (n) <= ED_POS_LEVEL_TABS_LAST)
159 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
160                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
161 #define IS_POS_ELEMENT_TABS(n)        ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
162                                        (n) <= ED_POS_ELEMENT_TABS_LAST)
163 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
164                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
165
166 #define ED_LEVEL_TABS_LINE(n)           ((n) - ED_POS_LEVEL_TABS_FIRST)
167 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
168 #define ED_ELEMENT_TABS_LINE(n)         ((n) - ED_POS_ELEMENT_TABS_FIRST)
169 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
170
171 #define ED_LEVEL_TABS_X(n)              (ED_LEVEL_TABS_XSTART + \
172                                          (n) * ED_SETTINGS_TABS_XOFFSET)
173 #define ED_LEVEL_TABS_Y(n)              (ED_LEVEL_TABS_YSTART + \
174                                          (n) * ED_SETTINGS_TABS_YOFFSET)
175
176 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
177                                          (n) * ED_SETTINGS_XOFFSET)
178 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
179                                          (n) * ED_SETTINGS_YOFFSET)
180
181 #define ED_ELEMENT_TABS_X(n)            (ED_ELEMENT_TABS_XSTART +       \
182                                          (n) * ED_SETTINGS_TABS_XOFFSET)
183 #define ED_ELEMENT_TABS_Y(n)            (ED_ELEMENT_TABS_YSTART +       \
184                                          (n) * ED_SETTINGS_TABS_YOFFSET)
185
186 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
187                                          (n) * ED_SETTINGS_XOFFSET)
188 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
189                                          (n) * ED_SETTINGS_YOFFSET)
190
191 #define ED_POS_TO_LEVEL_TABS_X(n)       \
192   (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n)))
193 #define ED_POS_TO_LEVEL_TABS_Y(n)       \
194   (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n)))
195
196 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
197   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
198 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
199   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
200
201 #define ED_POS_TO_ELEMENT_TABS_X(n)     \
202   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
203 #define ED_POS_TO_ELEMENT_TABS_Y(n)     \
204   (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n)))
205
206 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
207   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
208 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
209   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
210
211 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_TABS(n) ? \
212                                          ED_POS_TO_LEVEL_TABS_X(n) : \
213                                          IS_POS_LEVEL_SETTINGS(n) ?     \
214                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
215                                          IS_POS_ELEMENT_TABS(n) ?       \
216                                          ED_POS_TO_ELEMENT_TABS_X(n) : \
217                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
218                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
219 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_TABS(n) ? \
220                                          ED_POS_TO_LEVEL_TABS_Y(n) : \
221                                          IS_POS_LEVEL_SETTINGS(n) ?     \
222                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
223                                          IS_POS_ELEMENT_TABS(n) ?       \
224                                          ED_POS_TO_ELEMENT_TABS_Y(n) : \
225                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
226                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
227
228 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
229                                          ED_DRAWINGAREA_TILE_SIZE)
230 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
231                                          ED_DRAWINGAREA_TILE_SIZE)
232
233 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
234                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
235 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
236                                          (ED_CHECKBUTTON_YSIZE -        \
237                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
238
239 #define ED_AREA_XOFFSET_2(n)      (0)
240 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
241                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
242
243 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
244                                     ED_SETTINGS_XOFF((i).xoffset) +     \
245                                     ED_AREA_XOFFSET_1((i).x) -          \
246                                     ED_AREA_XOFFSET_2((i).area_xsize))
247 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
248                                     ED_SETTINGS_YOFF((i).yoffset) +     \
249                                     ED_AREA_YOFFSET_1((i).y) -          \
250                                     ED_AREA_YOFFSET_2((i).area_ysize))
251
252 // values for element content drawing areas
253 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
254 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
255 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
256 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
257
258 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
259 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
260 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
261 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
262
263 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
264 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
265 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
266 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
267
268 // element content
269 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
270 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
271
272 // yamyam content
273 #define ED_XPOS_YAM                     0
274 #define ED_YPOS_YAM                     5
275 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
276 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
277 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
278 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
279 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
280                                          ED_SETTINGS_XOFF(n))
281 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
282                                          ED_SETTINGS_YOFF(n) +          \
283                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
284                                          ED_AREA_YOFFSET_2(3))
285
286 // magic ball content
287 #define ED_XPOS_BALL                    0
288 #define ED_YPOS_BALL                    6
289 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
290 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
291 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
292 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
293 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
294                                          ED_SETTINGS_XOFF(n))
295 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
296                                          ED_SETTINGS_YOFF(n) +          \
297                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
298                                          ED_AREA_YOFFSET_2(3))
299
300 // values for scrolling gadgets for drawing area
301 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
302 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
303
304 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
305 #define ED_SCROLL_UP_YPOS               (0)
306 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
307 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
308 #define ED_SCROLL_LEFT_XPOS             (0)
309 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
310 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
311 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
312 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
313                                          ED_SCROLLBUTTON_XSIZE)
314 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
315 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
316 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
317 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
318 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
319                                          ED_SCROLLBUTTON_YSIZE)
320 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
321 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
322
323 // values for scrolling gadgets for element list
324 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
325 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
326
327 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
328                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
329                                          ED_ELEMENTLIST_XSIZE)
330 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
331 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
332 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
333                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
334                                          ED_ELEMENTLIST_YSIZE -         \
335                                          ED_SCROLLBUTTON2_YSIZE)
336 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
337 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
338                                          ED_SCROLLBUTTON2_YSIZE)
339 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
340 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
341                                          ED_ELEMENTLIST_YSIZE -         \
342                                          2 * ED_SCROLLBUTTON2_YSIZE)
343
344 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText()
345 #define INFOTEXT_FONT           FONT_TEXT_2
346 #define INFOTEXT_XSIZE          SXSIZE
347 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
348 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
349 #define INFOTEXT_X              (editor.settings.tooltip.x)
350 #define INFOTEXT_Y              (editor.settings.tooltip.y)
351 #define INFOTEXT_XY_REDEFINED   (INFOTEXT_X != -1 || INFOTEXT_Y != -1)
352 #define INFOTEXT_XPOS           SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0)
353 #define INFOTEXT_YPOS           SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \
354                                       SYSIZE - INFOTEXT_YSIZE)
355
356
357 // ----------------------------------------------------------------------------
358 // editor gadget definitions
359 // ----------------------------------------------------------------------------
360
361 enum
362 {
363   GADGET_ID_NONE = -1,
364
365   // drawing toolbox buttons
366
367   GADGET_ID_SINGLE_ITEMS,
368   GADGET_ID_CONNECTED_ITEMS,
369   GADGET_ID_LINE,
370   GADGET_ID_ARC,
371   GADGET_ID_RECTANGLE,
372   GADGET_ID_FILLED_BOX,
373   GADGET_ID_WRAP_UP,
374   GADGET_ID_TEXT,
375   GADGET_ID_FLOOD_FILL,
376   GADGET_ID_WRAP_LEFT,
377   GADGET_ID_ZOOM,
378   GADGET_ID_WRAP_RIGHT,
379   GADGET_ID_RANDOM_PLACEMENT,
380   GADGET_ID_GRAB_BRUSH,
381   GADGET_ID_WRAP_DOWN,
382   GADGET_ID_PICK_ELEMENT,
383
384   GADGET_ID_UNDO,
385   GADGET_ID_CONF,
386   GADGET_ID_SAVE,
387   GADGET_ID_CLEAR,
388   GADGET_ID_TEST,
389   GADGET_ID_EXIT,
390
391   GADGET_ID_CUSTOM_COPY_FROM,
392   GADGET_ID_CUSTOM_COPY_TO,
393   GADGET_ID_CUSTOM_EXCHANGE,
394   GADGET_ID_CUSTOM_COPY,
395   GADGET_ID_CUSTOM_PASTE,
396
397   GADGET_ID_PROPERTIES,
398   GADGET_ID_ELEMENT_LEFT,
399   GADGET_ID_ELEMENT_MIDDLE,
400   GADGET_ID_ELEMENT_RIGHT,
401   GADGET_ID_PALETTE,
402
403   // counter gadget identifiers
404
405   GADGET_ID_SELECT_LEVEL_DOWN,
406   GADGET_ID_SELECT_LEVEL_TEXT,
407   GADGET_ID_SELECT_LEVEL_UP,
408   GADGET_ID_LEVEL_XSIZE_DOWN,
409   GADGET_ID_LEVEL_XSIZE_TEXT,
410   GADGET_ID_LEVEL_XSIZE_UP,
411   GADGET_ID_LEVEL_YSIZE_DOWN,
412   GADGET_ID_LEVEL_YSIZE_TEXT,
413   GADGET_ID_LEVEL_YSIZE_UP,
414   GADGET_ID_LEVEL_RANDOM_DOWN,
415   GADGET_ID_LEVEL_RANDOM_TEXT,
416   GADGET_ID_LEVEL_RANDOM_UP,
417   GADGET_ID_LEVEL_GEMSLIMIT_DOWN,
418   GADGET_ID_LEVEL_GEMSLIMIT_TEXT,
419   GADGET_ID_LEVEL_GEMSLIMIT_UP,
420   GADGET_ID_LEVEL_TIMELIMIT_DOWN,
421   GADGET_ID_LEVEL_TIMELIMIT_TEXT,
422   GADGET_ID_LEVEL_TIMELIMIT_UP,
423   GADGET_ID_LEVEL_TIMESCORE_DOWN,
424   GADGET_ID_LEVEL_TIMESCORE_TEXT,
425   GADGET_ID_LEVEL_TIMESCORE_UP,
426   GADGET_ID_LEVEL_RANDOM_SEED_DOWN,
427   GADGET_ID_LEVEL_RANDOM_SEED_TEXT,
428   GADGET_ID_LEVEL_RANDOM_SEED_UP,
429   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
430   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
431   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
432   GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,
433   GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,
434   GADGET_ID_BD_CYCLE_DELAY_MS_UP,
435   GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,
436   GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,
437   GADGET_ID_BD_CYCLE_DELAY_C64_UP,
438   GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,
439   GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,
440   GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
441   GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,
442   GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,
443   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
444   GADGET_ID_BD_PUSHING_PROB_DOWN,
445   GADGET_ID_BD_PUSHING_PROB_TEXT,
446   GADGET_ID_BD_PUSHING_PROB_UP,
447   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,
448   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,
449   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
450   GADGET_ID_ELEMENT_VALUE1_DOWN,
451   GADGET_ID_ELEMENT_VALUE1_TEXT,
452   GADGET_ID_ELEMENT_VALUE1_UP,
453   GADGET_ID_ELEMENT_VALUE2_DOWN,
454   GADGET_ID_ELEMENT_VALUE2_TEXT,
455   GADGET_ID_ELEMENT_VALUE2_UP,
456   GADGET_ID_ELEMENT_VALUE3_DOWN,
457   GADGET_ID_ELEMENT_VALUE3_TEXT,
458   GADGET_ID_ELEMENT_VALUE3_UP,
459   GADGET_ID_ELEMENT_VALUE4_DOWN,
460   GADGET_ID_ELEMENT_VALUE4_TEXT,
461   GADGET_ID_ELEMENT_VALUE4_UP,
462   GADGET_ID_YAMYAM_CONTENT_DOWN,
463   GADGET_ID_YAMYAM_CONTENT_TEXT,
464   GADGET_ID_YAMYAM_CONTENT_UP,
465   GADGET_ID_BALL_CONTENT_DOWN,
466   GADGET_ID_BALL_CONTENT_TEXT,
467   GADGET_ID_BALL_CONTENT_UP,
468   GADGET_ID_ANDROID_CONTENT_DOWN,
469   GADGET_ID_ANDROID_CONTENT_TEXT,
470   GADGET_ID_ANDROID_CONTENT_UP,
471   GADGET_ID_ENVELOPE_XSIZE_DOWN,
472   GADGET_ID_ENVELOPE_XSIZE_TEXT,
473   GADGET_ID_ENVELOPE_XSIZE_UP,
474   GADGET_ID_ENVELOPE_YSIZE_DOWN,
475   GADGET_ID_ENVELOPE_YSIZE_TEXT,
476   GADGET_ID_ENVELOPE_YSIZE_UP,
477   GADGET_ID_INVENTORY_SIZE_DOWN,
478   GADGET_ID_INVENTORY_SIZE_TEXT,
479   GADGET_ID_INVENTORY_SIZE_UP,
480   GADGET_ID_MM_BALL_CONTENT_DOWN,
481   GADGET_ID_MM_BALL_CONTENT_TEXT,
482   GADGET_ID_MM_BALL_CONTENT_UP,
483   GADGET_ID_CUSTOM_SCORE_DOWN,
484   GADGET_ID_CUSTOM_SCORE_TEXT,
485   GADGET_ID_CUSTOM_SCORE_UP,
486   GADGET_ID_CUSTOM_GEMCOUNT_DOWN,
487   GADGET_ID_CUSTOM_GEMCOUNT_TEXT,
488   GADGET_ID_CUSTOM_GEMCOUNT_UP,
489   GADGET_ID_CUSTOM_VALUE_FIX_DOWN,
490   GADGET_ID_CUSTOM_VALUE_FIX_TEXT,
491   GADGET_ID_CUSTOM_VALUE_FIX_UP,
492   GADGET_ID_CUSTOM_VALUE_RND_DOWN,
493   GADGET_ID_CUSTOM_VALUE_RND_TEXT,
494   GADGET_ID_CUSTOM_VALUE_RND_UP,
495   GADGET_ID_PUSH_DELAY_FIX_DOWN,
496   GADGET_ID_PUSH_DELAY_FIX_TEXT,
497   GADGET_ID_PUSH_DELAY_FIX_UP,
498   GADGET_ID_PUSH_DELAY_RND_DOWN,
499   GADGET_ID_PUSH_DELAY_RND_TEXT,
500   GADGET_ID_PUSH_DELAY_RND_UP,
501   GADGET_ID_DROP_DELAY_FIX_DOWN,
502   GADGET_ID_DROP_DELAY_FIX_TEXT,
503   GADGET_ID_DROP_DELAY_FIX_UP,
504   GADGET_ID_DROP_DELAY_RND_DOWN,
505   GADGET_ID_DROP_DELAY_RND_TEXT,
506   GADGET_ID_DROP_DELAY_RND_UP,
507   GADGET_ID_MOVE_DELAY_FIX_DOWN,
508   GADGET_ID_MOVE_DELAY_FIX_TEXT,
509   GADGET_ID_MOVE_DELAY_FIX_UP,
510   GADGET_ID_MOVE_DELAY_RND_DOWN,
511   GADGET_ID_MOVE_DELAY_RND_TEXT,
512   GADGET_ID_MOVE_DELAY_RND_UP,
513   GADGET_ID_STEP_DELAY_FIX_DOWN,
514   GADGET_ID_STEP_DELAY_FIX_TEXT,
515   GADGET_ID_STEP_DELAY_FIX_UP,
516   GADGET_ID_STEP_DELAY_RND_DOWN,
517   GADGET_ID_STEP_DELAY_RND_TEXT,
518   GADGET_ID_STEP_DELAY_RND_UP,
519   GADGET_ID_EXPLOSION_DELAY_DOWN,
520   GADGET_ID_EXPLOSION_DELAY_TEXT,
521   GADGET_ID_EXPLOSION_DELAY_UP,
522   GADGET_ID_IGNITION_DELAY_DOWN,
523   GADGET_ID_IGNITION_DELAY_TEXT,
524   GADGET_ID_IGNITION_DELAY_UP,
525   GADGET_ID_CHANGE_DELAY_FIX_DOWN,
526   GADGET_ID_CHANGE_DELAY_FIX_TEXT,
527   GADGET_ID_CHANGE_DELAY_FIX_UP,
528   GADGET_ID_CHANGE_DELAY_RND_DOWN,
529   GADGET_ID_CHANGE_DELAY_RND_TEXT,
530   GADGET_ID_CHANGE_DELAY_RND_UP,
531   GADGET_ID_CHANGE_CONT_RND_DOWN,
532   GADGET_ID_CHANGE_CONT_RND_TEXT,
533   GADGET_ID_CHANGE_CONT_RND_UP,
534   GADGET_ID_GROUP_CONTENT_DOWN,
535   GADGET_ID_GROUP_CONTENT_TEXT,
536   GADGET_ID_GROUP_CONTENT_UP,
537
538   // drawing area identifiers
539
540   GADGET_ID_DRAWING_LEVEL,
541   GADGET_ID_YAMYAM_CONTENT_0,
542   GADGET_ID_YAMYAM_CONTENT_1,
543   GADGET_ID_YAMYAM_CONTENT_2,
544   GADGET_ID_YAMYAM_CONTENT_3,
545   GADGET_ID_YAMYAM_CONTENT_4,
546   GADGET_ID_YAMYAM_CONTENT_5,
547   GADGET_ID_YAMYAM_CONTENT_6,
548   GADGET_ID_YAMYAM_CONTENT_7,
549   GADGET_ID_MAGIC_BALL_CONTENT_0,
550   GADGET_ID_MAGIC_BALL_CONTENT_1,
551   GADGET_ID_MAGIC_BALL_CONTENT_2,
552   GADGET_ID_MAGIC_BALL_CONTENT_3,
553   GADGET_ID_MAGIC_BALL_CONTENT_4,
554   GADGET_ID_MAGIC_BALL_CONTENT_5,
555   GADGET_ID_MAGIC_BALL_CONTENT_6,
556   GADGET_ID_MAGIC_BALL_CONTENT_7,
557   GADGET_ID_ANDROID_CONTENT,
558   GADGET_ID_AMOEBA_CONTENT,
559   GADGET_ID_BD_SNAP_ELEMENT,
560   GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,
561   GADGET_ID_BD_MAGIC_WALL_ROCK_TO,
562   GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
563   GADGET_ID_BD_MAGIC_WALL_NUT_TO,
564   GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
565   GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
566   GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
567   GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,
568   GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,
569   GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
570   GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
571   GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
572   GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
573   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
574   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
575   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
576   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
577   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
578   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
579   GADGET_ID_BD_ACID_EATS_ELEMENT,
580   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
581   GADGET_ID_BD_BITER_EATS_ELEMENT,
582   GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
583   GADGET_ID_BD_NUT_CONTENT,
584   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
585   GADGET_ID_BD_SAND_LOOKS_LIKE,
586   GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,
587   GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
588   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
589   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
590   GADGET_ID_BD_FIREFLY_EXPLODES_TO,
591   GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,
592   GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,
593   GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,
594   GADGET_ID_BD_STONEFLY_EXPLODES_TO,
595   GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,
596   GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,
597   GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,
598   GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,
599   GADGET_ID_BD_EXPLOSION_TURNS_TO,
600   GADGET_ID_START_ELEMENT,
601   GADGET_ID_ARTWORK_ELEMENT,
602   GADGET_ID_EXPLOSION_ELEMENT,
603   GADGET_ID_INVENTORY_CONTENT,
604   GADGET_ID_MM_BALL_CONTENT,
605   GADGET_ID_CUSTOM_GRAPHIC,
606   GADGET_ID_CUSTOM_CONTENT,
607   GADGET_ID_CUSTOM_MOVE_ENTER,
608   GADGET_ID_CUSTOM_MOVE_LEAVE,
609   GADGET_ID_CUSTOM_CHANGE_TARGET,
610   GADGET_ID_CUSTOM_CHANGE_CONTENT,
611   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
612   GADGET_ID_CUSTOM_CHANGE_ACTION,
613   GADGET_ID_GROUP_CONTENT,
614   GADGET_ID_RANDOM_BACKGROUND,
615
616   // text input identifiers
617
618   GADGET_ID_LEVEL_NAME,
619   GADGET_ID_LEVEL_AUTHOR,
620   GADGET_ID_LEVELSET_NAME,
621   GADGET_ID_LEVELSET_AUTHOR,
622   GADGET_ID_ELEMENT_NAME,
623
624   // text area identifiers
625
626   GADGET_ID_ENVELOPE_INFO,
627
628   // selectbox identifiers
629
630   GADGET_ID_TIME_OR_STEPS,
631   GADGET_ID_TIME_SCORE_BASE,
632   GADGET_ID_GAME_ENGINE_TYPE,
633   GADGET_ID_BD_SCHEDULING_TYPE,
634   GADGET_ID_LEVELSET_SAVE_MODE,
635   GADGET_ID_WIND_DIRECTION,
636   GADGET_ID_PLAYER_SPEED,
637   GADGET_ID_BD_GRAVITY_DIRECTION,
638   GADGET_ID_MM_BALL_CHOICE_MODE,
639   GADGET_ID_CUSTOM_WALK_TO_ACTION,
640   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
641   GADGET_ID_CUSTOM_DEADLINESS,
642   GADGET_ID_CUSTOM_MOVE_PATTERN,
643   GADGET_ID_CUSTOM_MOVE_DIRECTION,
644   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
645   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
646   GADGET_ID_CUSTOM_SMASH_TARGETS,
647   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
648   GADGET_ID_CUSTOM_ACCESS_TYPE,
649   GADGET_ID_CUSTOM_ACCESS_LAYER,
650   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
651   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
652   GADGET_ID_CHANGE_TIME_UNITS,
653   GADGET_ID_CHANGE_DIRECT_ACTION,
654   GADGET_ID_CHANGE_OTHER_ACTION,
655   GADGET_ID_CHANGE_SIDE,
656   GADGET_ID_CHANGE_PLAYER,
657   GADGET_ID_CHANGE_PAGE,
658   GADGET_ID_CHANGE_REPLACE_WHEN,
659   GADGET_ID_ACTION_TYPE,
660   GADGET_ID_ACTION_MODE,
661   GADGET_ID_ACTION_ARG,
662   GADGET_ID_SELECT_CHANGE_PAGE,
663   GADGET_ID_GROUP_CHOICE_MODE,
664
665   // textbutton identifiers
666
667   GADGET_ID_LEVELCONFIG_LEVEL,
668   GADGET_ID_LEVELCONFIG_LEVELSET,
669   GADGET_ID_LEVELCONFIG_EDITOR,
670   GADGET_ID_LEVELCONFIG_ENGINE,
671   GADGET_ID_PROPERTIES_INFO,
672   GADGET_ID_PROPERTIES_CONFIG,
673   GADGET_ID_PROPERTIES_CONFIG_1,
674   GADGET_ID_PROPERTIES_CONFIG_2,
675   GADGET_ID_PROPERTIES_CHANGE,
676   GADGET_ID_SAVE_AS_TEMPLATE_1,
677   GADGET_ID_SAVE_AS_TEMPLATE_2,
678   GADGET_ID_SAVE_LEVELSET,
679   GADGET_ID_ADD_CHANGE_PAGE,
680   GADGET_ID_DEL_CHANGE_PAGE,
681
682   // graphicbutton identifiers
683
684   GADGET_ID_PREV_CHANGE_PAGE,
685   GADGET_ID_NEXT_CHANGE_PAGE,
686   GADGET_ID_COPY_CHANGE_PAGE,
687   GADGET_ID_PASTE_CHANGE_PAGE,
688
689   // gadgets for scrolling of drawing area
690
691   GADGET_ID_SCROLL_UP,
692   GADGET_ID_SCROLL_DOWN,
693   GADGET_ID_SCROLL_LEFT,
694   GADGET_ID_SCROLL_RIGHT,
695   GADGET_ID_SCROLL_HORIZONTAL,
696   GADGET_ID_SCROLL_VERTICAL,
697
698   // gadgets for scrolling element list
699
700   GADGET_ID_SCROLL_LIST_UP,
701   GADGET_ID_SCROLL_LIST_DOWN,
702   GADGET_ID_SCROLL_LIST_VERTICAL,
703
704   // checkbuttons/radiobuttons for level/element properties
705
706   GADGET_ID_AUTO_COUNT_GEMS,
707   GADGET_ID_RATE_TIME_OVER_SCORE,
708   GADGET_ID_USE_LEVELSET_ARTWORK,
709   GADGET_ID_COPY_LEVEL_TEMPLATE,
710   GADGET_ID_RANDOM_PERCENTAGE,
711   GADGET_ID_RANDOM_QUANTITY,
712   GADGET_ID_RANDOM_RESTRICTED,
713   GADGET_ID_BD_INTERMISSION,
714   GADGET_ID_BD_PAL_TIMING,
715   GADGET_ID_BD_LINE_SHIFTING_BORDERS,
716   GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
717   GADGET_ID_BD_SHORT_EXPLOSIONS,
718   GADGET_ID_STICK_ELEMENT,
719   GADGET_ID_EM_SLIPPERY_GEMS,
720   GADGET_ID_EM_EXPLODES_BY_FIRE,
721   GADGET_ID_USE_SPRING_BUG,
722   GADGET_ID_USE_TIME_ORB_BUG,
723   GADGET_ID_USE_LIFE_BUGS,
724   GADGET_ID_RANDOM_BALL_CONTENT,
725   GADGET_ID_INITIAL_BALL_ACTIVE,
726   GADGET_ID_GROW_INTO_DIGGABLE,
727   GADGET_ID_SB_FIELDS_NEEDED,
728   GADGET_ID_SB_OBJECTS_NEEDED,
729   GADGET_ID_AUTO_EXIT_SOKOBAN,
730   GADGET_ID_SOLVED_BY_ONE_PLAYER,
731   GADGET_ID_FINISH_DIG_COLLECT,
732   GADGET_ID_KEEP_WALKABLE_CE,
733   GADGET_ID_CONTINUOUS_SNAPPING,
734   GADGET_ID_BLOCK_SNAP_FIELD,
735   GADGET_ID_BLOCK_LAST_FIELD,
736   GADGET_ID_SP_BLOCK_LAST_FIELD,
737   GADGET_ID_INSTANT_RELOCATION,
738   GADGET_ID_SHIFTED_RELOCATION,
739   GADGET_ID_LAZY_RELOCATION,
740   GADGET_ID_USE_START_ELEMENT,
741   GADGET_ID_USE_ARTWORK_ELEMENT,
742   GADGET_ID_USE_EXPLOSION_ELEMENT,
743   GADGET_ID_INITIAL_GRAVITY,
744   GADGET_ID_USE_INITIAL_INVENTORY,
745   GADGET_ID_CAN_PASS_TO_WALKABLE,
746   GADGET_ID_CAN_FALL_INTO_ACID,
747   GADGET_ID_CAN_MOVE_INTO_ACID,
748   GADGET_ID_DONT_COLLIDE_WITH,
749   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
750   GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
751   GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
752   GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,
753   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
754   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
755   GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,
756   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
757   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
758   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
759   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
760   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
761   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
762   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
763   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
764   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
765   GADGET_ID_BD_REPLICATORS_ACTIVE,
766   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
767   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
768   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
769   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
770   GADGET_ID_BD_INFINITE_ROCKETS,
771   GADGET_ID_BD_CREATURES_START_BACKWARDS,
772   GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
773   GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
774   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
775   GADGET_ID_ENVELOPE_AUTOWRAP,
776   GADGET_ID_ENVELOPE_CENTERED,
777   GADGET_ID_MM_LASER_RED,
778   GADGET_ID_MM_LASER_GREEN,
779   GADGET_ID_MM_LASER_BLUE,
780   GADGET_ID_DF_LASER_RED,
781   GADGET_ID_DF_LASER_GREEN,
782   GADGET_ID_DF_LASER_BLUE,
783   GADGET_ID_ROTATE_MM_BALL_CONTENT,
784   GADGET_ID_EXPLODE_MM_BALL,
785   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
786   GADGET_ID_CUSTOM_CAN_EXPLODE,
787   GADGET_ID_CUSTOM_EXPLODE_FIRE,
788   GADGET_ID_CUSTOM_EXPLODE_SMASH,
789   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
790   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
791   GADGET_ID_CUSTOM_DEADLY,
792   GADGET_ID_CUSTOM_CAN_MOVE,
793   GADGET_ID_CUSTOM_CAN_FALL,
794   GADGET_ID_CUSTOM_CAN_SMASH,
795   GADGET_ID_CUSTOM_SLIPPERY,
796   GADGET_ID_CUSTOM_ACCESSIBLE,
797   GADGET_ID_CUSTOM_GRAV_REACHABLE,
798   GADGET_ID_CUSTOM_USE_LAST_VALUE,
799   GADGET_ID_CUSTOM_USE_GRAPHIC,
800   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
801   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
802   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
803   GADGET_ID_CUSTOM_CAN_CHANGE,
804   GADGET_ID_CHANGE_USE_CONTENT,
805   GADGET_ID_CHANGE_USE_EXPLOSION,
806   GADGET_ID_CHANGE_ONLY_COMPLETE,
807   GADGET_ID_CHANGE_USE_RANDOM,
808   GADGET_ID_CHANGE_HAS_ACTION,
809   GADGET_ID_CHANGE_DELAY,
810   GADGET_ID_CHANGE_BY_DIRECT_ACT,
811   GADGET_ID_CHANGE_BY_OTHER_ACT,
812
813   NUM_STATIC_GADGET_IDS
814 };
815
816 // gadgets for buttons in element list (dynamic)
817 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
818 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
819                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
820
821 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
822
823 // radio button numbers
824 enum
825 {
826   RADIO_NR_NONE,
827   RADIO_NR_DRAWING_TOOLBOX,
828   RADIO_NR_RANDOM_ELEMENTS
829 };
830
831 // values for counter gadgets
832 enum
833 {
834   ED_COUNTER_ID_SELECT_LEVEL,
835   ED_COUNTER_ID_LEVEL_XSIZE,
836   ED_COUNTER_ID_LEVEL_YSIZE,
837   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
838   ED_COUNTER_ID_LEVEL_TIMELIMIT,
839   ED_COUNTER_ID_LEVEL_TIMESCORE,
840   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
841   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
842   ED_COUNTER_ID_LEVEL_RANDOM,
843   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
844   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
845   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
846   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
847   ED_COUNTER_ID_BD_PUSHING_PROB,
848   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
849   ED_COUNTER_ID_ELEMENT_VALUE1,
850   ED_COUNTER_ID_ELEMENT_VALUE2,
851   ED_COUNTER_ID_ELEMENT_VALUE3,
852   ED_COUNTER_ID_ELEMENT_VALUE4,
853   ED_COUNTER_ID_YAMYAM_CONTENT,
854   ED_COUNTER_ID_BALL_CONTENT,
855   ED_COUNTER_ID_ANDROID_CONTENT,
856   ED_COUNTER_ID_ENVELOPE_XSIZE,
857   ED_COUNTER_ID_ENVELOPE_YSIZE,
858   ED_COUNTER_ID_INVENTORY_SIZE,
859   ED_COUNTER_ID_MM_BALL_CONTENT,
860   ED_COUNTER_ID_CUSTOM_SCORE,
861   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
862   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
863   ED_COUNTER_ID_CUSTOM_VALUE_RND,
864   ED_COUNTER_ID_PUSH_DELAY_FIX,
865   ED_COUNTER_ID_PUSH_DELAY_RND,
866   ED_COUNTER_ID_DROP_DELAY_FIX,
867   ED_COUNTER_ID_DROP_DELAY_RND,
868   ED_COUNTER_ID_MOVE_DELAY_FIX,
869   ED_COUNTER_ID_MOVE_DELAY_RND,
870   ED_COUNTER_ID_STEP_DELAY_FIX,
871   ED_COUNTER_ID_STEP_DELAY_RND,
872   ED_COUNTER_ID_EXPLOSION_DELAY,
873   ED_COUNTER_ID_IGNITION_DELAY,
874   ED_COUNTER_ID_GROUP_CONTENT,
875   ED_COUNTER_ID_CHANGE_DELAY_FIX,
876   ED_COUNTER_ID_CHANGE_DELAY_RND,
877   ED_COUNTER_ID_CHANGE_CONT_RND,
878
879   ED_NUM_COUNTERBUTTONS
880 };
881
882 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
883 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
884 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
885 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
886 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
887 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
888
889 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
890 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
891 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
892 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
893 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
894 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
895
896 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
897 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
898
899 // values for scrollbutton gadgets
900 enum
901 {
902   ED_SCROLLBUTTON_ID_AREA_UP,
903   ED_SCROLLBUTTON_ID_AREA_DOWN,
904   ED_SCROLLBUTTON_ID_AREA_LEFT,
905   ED_SCROLLBUTTON_ID_AREA_RIGHT,
906   ED_SCROLLBUTTON_ID_LIST_UP,
907   ED_SCROLLBUTTON_ID_LIST_DOWN,
908
909   ED_NUM_SCROLLBUTTONS
910 };
911
912 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
913 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
914
915 // values for scrollbar gadgets
916 enum
917 {
918   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
919   ED_SCROLLBAR_ID_AREA_VERTICAL,
920   ED_SCROLLBAR_ID_LIST_VERTICAL,
921
922   ED_NUM_SCROLLBARS
923 };
924
925 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
926 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
927
928 // values for text input gadgets
929 enum
930 {
931   ED_TEXTINPUT_ID_LEVEL_NAME,
932   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
933   ED_TEXTINPUT_ID_LEVELSET_NAME,
934   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
935   ED_TEXTINPUT_ID_ELEMENT_NAME,
936
937   ED_NUM_TEXTINPUT
938 };
939
940 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
941 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
942
943 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
944 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
945
946 // values for text area gadgets
947 enum
948 {
949   ED_TEXTAREA_ID_ENVELOPE_INFO,
950
951   ED_NUM_TEXTAREAS
952 };
953
954 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
955 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
956
957 // values for selectbox gadgets
958 enum
959 {
960   ED_SELECTBOX_ID_TIME_OR_STEPS,
961   ED_SELECTBOX_ID_TIME_SCORE_BASE,
962   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
963   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
964   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
965   ED_SELECTBOX_ID_WIND_DIRECTION,
966   ED_SELECTBOX_ID_PLAYER_SPEED,
967   ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
968   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
969   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
970   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
971   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
972   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
973   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
974   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
975   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
976   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
977   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
978   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
979   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
980   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
981   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
982   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
983   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
984   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
985   ED_SELECTBOX_ID_CHANGE_SIDE,
986   ED_SELECTBOX_ID_CHANGE_PLAYER,
987   ED_SELECTBOX_ID_CHANGE_PAGE,
988   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
989   ED_SELECTBOX_ID_ACTION_TYPE,
990   ED_SELECTBOX_ID_ACTION_MODE,
991   ED_SELECTBOX_ID_ACTION_ARG,
992   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
993   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
994
995   ED_NUM_SELECTBOX
996 };
997
998 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
999 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
1000
1001 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1002 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
1003
1004 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1005 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
1006
1007 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
1008 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
1009 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
1010 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
1011 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
1012 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
1013
1014 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
1015 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
1016
1017 // values for textbutton gadgets
1018 enum
1019 {
1020   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
1021   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1022   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1023   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1024   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1025   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1026   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1027   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1028   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1029   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1030   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1031   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1032   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1033   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1034
1035   ED_NUM_TEXTBUTTONS
1036 };
1037
1038 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1039 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1040
1041 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1042 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1043
1044 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1045 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1046
1047 // values for graphicbutton gadgets
1048 enum
1049 {
1050   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1051   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1052   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1053   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1054
1055   ED_NUM_GRAPHICBUTTONS
1056 };
1057
1058 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1059 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1060
1061 // values for checkbutton gadgets
1062 enum
1063 {
1064   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1065   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1066   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1067   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1068   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1069   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1070   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1071   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1072   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1073   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1074   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1075   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1076   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1077   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1078   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1079   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1080   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1081   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1082   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1083   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1084   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1085   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1086   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1087   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1088   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1089   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1090   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1091   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1092   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1093   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1094   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1095   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1096   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1097   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1098   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1099   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1100   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1101   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1102   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1103   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1104   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1105   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1106   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1107   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1108   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1109   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1110   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
1111   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1112   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1113   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
1114   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1115   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1116   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1117   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1118   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1119   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1120   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1121   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1122   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1123   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1124   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1125   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1126   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1127   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1128   ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
1129   ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
1130   ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
1131   ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
1132   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1133   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1134   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1135   ED_CHECKBUTTON_ID_MM_LASER_RED,
1136   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1137   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1138   ED_CHECKBUTTON_ID_DF_LASER_RED,
1139   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1140   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1141   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1142   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1143   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1144   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1145   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1146   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1147   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1148   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1149   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1150   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1151   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1152   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1153   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1154   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1155   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1156   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1157   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1158   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1159   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1160   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1161   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1162   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1163   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1164   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1165   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1166   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1167   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1168
1169   ED_NUM_CHECKBUTTONS
1170 };
1171
1172 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1173 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1174
1175 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1176 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1177
1178 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1179 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1180
1181 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1182 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
1183
1184 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1185 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1186 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1187 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1188 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1189 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1190
1191 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1192 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1193
1194 // values for radiobutton gadgets
1195 enum
1196 {
1197   ED_RADIOBUTTON_ID_PERCENTAGE,
1198   ED_RADIOBUTTON_ID_QUANTITY,
1199
1200   ED_NUM_RADIOBUTTONS
1201 };
1202
1203 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1204 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1205
1206 // values for drawing area gadgets
1207 enum
1208 {
1209   ED_DRAWING_ID_DRAWING_LEVEL,
1210   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1211   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1212   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1213   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1214   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1215   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1216   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1217   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1218   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1219   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1220   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1221   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1222   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1223   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1224   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1225   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1226   ED_DRAWING_ID_ANDROID_CONTENT,
1227   ED_DRAWING_ID_AMOEBA_CONTENT,
1228   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1229   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1230   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1231   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1232   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1233   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1234   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1235   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1236   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1237   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1238   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1239   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1240   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1241   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1242   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1243   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1244   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1245   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1246   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1247   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1248   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1249   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1250   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1251   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1252   ED_DRAWING_ID_BD_NUT_CONTENT,
1253   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1254   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1255   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
1256   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
1257   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
1258   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
1259   ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
1260   ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
1261   ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
1262   ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
1263   ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
1264   ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
1265   ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
1266   ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
1267   ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
1268   ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
1269   ED_DRAWING_ID_START_ELEMENT,
1270   ED_DRAWING_ID_ARTWORK_ELEMENT,
1271   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1272   ED_DRAWING_ID_INVENTORY_CONTENT,
1273   ED_DRAWING_ID_MM_BALL_CONTENT,
1274   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1275   ED_DRAWING_ID_CUSTOM_CONTENT,
1276   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1277   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1278   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1279   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1280   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1281   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1282   ED_DRAWING_ID_GROUP_CONTENT,
1283   ED_DRAWING_ID_RANDOM_BACKGROUND,
1284
1285   ED_NUM_DRAWING_AREAS
1286 };
1287
1288 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1289 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1290
1291
1292 // ----------------------------------------------------------------------------
1293 // some internally used definitions
1294 // ----------------------------------------------------------------------------
1295
1296 // values for CopyLevelToUndoBuffer()
1297 #define UNDO_IMMEDIATE                  0
1298 #define UNDO_ACCUMULATE                 1
1299
1300 // values for scrollbars
1301 #define ED_SCROLL_NO                    0
1302 #define ED_SCROLL_LEFT                  1
1303 #define ED_SCROLL_RIGHT                 2
1304 #define ED_SCROLL_UP                    4
1305 #define ED_SCROLL_DOWN                  8
1306
1307 // screens in the level editor
1308 #define ED_MODE_DRAWING                 0
1309 #define ED_MODE_LEVELCONFIG             1
1310 #define ED_MODE_PROPERTIES              2
1311 #define ED_MODE_PALETTE                 3
1312
1313 // sub-screens in the global settings section
1314 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1315 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1316 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1317 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1318
1319 // sub-screens in the element properties section
1320 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1321 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1322 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1323 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1324 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1325
1326 // how many steps can be cancelled
1327 #define NUM_UNDO_STEPS                  (64 + 1)
1328
1329 // values for elements with score for certain actions
1330 #define MIN_SCORE                       0
1331 #define MAX_SCORE                       999
1332
1333 // values for elements with count for collecting
1334 #define MIN_COLLECT_COUNT               0
1335 #define MAX_COLLECT_COUNT               999
1336
1337 // values for random placement
1338 #define RANDOM_USE_PERCENTAGE           0
1339 #define RANDOM_USE_QUANTITY             1
1340
1341 // values for level set save mode
1342 #define LEVELSET_SAVE_MODE_UPDATE       0
1343 #define LEVELSET_SAVE_MODE_CREATE       1
1344
1345 // default value for element tile size in drawing area
1346 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1347 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1348
1349
1350 // ----------------------------------------------------------------------------
1351 // some internally used data structure definitions
1352 // ----------------------------------------------------------------------------
1353
1354 static struct
1355 {
1356   int graphic;
1357   int gadget_id;
1358   struct XYTileSize *pos;
1359   int gadget_type;
1360   char *infotext;
1361   char shortcut;
1362 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1363 {
1364   // note: some additional characters are already reserved for "cheat mode"
1365   // shortcuts (":XYZ" style) -- for details, see "events.c"
1366
1367   // ---------- toolbox control buttons ---------------------------------------
1368
1369   {
1370     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1371     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1372     "Draw single items",                        's'
1373   },
1374   {
1375     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1376     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1377     "Draw connected items",                     'd'
1378   },
1379   {
1380     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1381     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1382     "Draw lines",                               'l'
1383   },
1384   {
1385     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1386     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1387     "Draw arcs",                                'a'
1388   },
1389   {
1390     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1391     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1392     "Draw outline rectangles",                  'r'
1393   },
1394   {
1395     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1396     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1397     "Draw filled rectangles",                   'R'
1398   },
1399   {
1400     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1401     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1402     "Wrap (rotate) level up",                   0
1403   },
1404   {
1405     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1406     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1407     "Enter text elements",                      't'
1408   },
1409   {
1410     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1411     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1412     "Flood fill",                               'f'
1413   },
1414   {
1415     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1416     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1417     "Wrap (rotate) level left",                 0
1418   },
1419   {
1420     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1421     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1422     "Zoom level tile size",                     '+'
1423   },
1424   {
1425     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1426     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1427     "Wrap (rotate) level right",                0
1428   },
1429   {
1430     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1431     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1432     "Random element placement",                 0
1433   },
1434   {
1435     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1436     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1437     "Grab brush",                               'b'
1438   },
1439   {
1440     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1441     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1442     "Wrap (rotate) level down",                 0
1443   },
1444   {
1445     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1446     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1447     "Pick drawing element",                     ','
1448   },
1449
1450   // ---------- level control buttons -----------------------------------------
1451
1452   {
1453     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1454     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1455     "Undo/redo last operation",                 'u'
1456   },
1457   {
1458     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1459     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1460     "Level and editor settings",                'I'
1461   },
1462   {
1463     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1464     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1465     "Save level",                               'S'
1466   },
1467   {
1468     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1469     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1470     "Clear level",                              'C'
1471   },
1472   {
1473     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1474     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1475     "Test level",                               'T'
1476   },
1477   {
1478     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1479     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1480     "Exit level editor",                        'E'
1481   },
1482
1483   // ---------- CE and GE control buttons -------------------------------------
1484
1485   {
1486     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1487     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1488     "Copy settings from other element",         0
1489   },
1490   {
1491     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1492     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1493     "Copy settings to other element",           0
1494   },
1495   {
1496     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1497     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1498     "Exchange element with other element",      0
1499   },
1500   {
1501     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1502     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1503     "Copy settings from this element",          0
1504   },
1505   {
1506     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1507     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1508     "Paste settings to this element",           0
1509   },
1510
1511   // ---------- palette control buttons ---------------------------------------
1512
1513   {
1514     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1515     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1516     "Properties of drawing element",            'p'
1517   },
1518   {
1519     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1520     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1521     "Properties of drawing element 1",          '1'
1522   },
1523   {
1524     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1525     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1526     "Properties of drawing element 2",          '2'
1527   },
1528   {
1529     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1530     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1531     "Properties of drawing element 3",          '3'
1532   },
1533   {
1534     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1535     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1536     "Show list of elements",                    'e'
1537   }
1538 };
1539
1540 static int random_placement_value = 10;
1541 static int random_placement_method = RANDOM_USE_QUANTITY;
1542 static int random_placement_background_element = EL_SAND;
1543 static boolean random_placement_background_restricted = FALSE;
1544 static boolean stick_element_properties_window = FALSE;
1545 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1546 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1547 static struct ElementChangeInfo custom_element_change;
1548 static struct ElementGroupInfo group_element_info;
1549 static struct ElementInfo custom_element;
1550
1551 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1552 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1553 static int levelset_num_levels = 100;
1554 static boolean levelset_use_levelset_artwork = FALSE;
1555 static boolean levelset_copy_level_template = FALSE;
1556 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1557
1558 static struct
1559 {
1560   int gadget_type_id;
1561   int x, y;
1562   int min_value, max_value;
1563   int gadget_id_down, gadget_id_up;
1564   int gadget_id_text;
1565   int gadget_id_align;
1566   int *value;
1567   char *text_above, *text_left, *text_right;
1568 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1569 {
1570   // ---------- current level number ------------------------------------------
1571
1572   {
1573     ED_COUNTER_ID_SELECT_LEVEL,
1574     -1, -1,     // these values are not constant, but can change at runtime
1575     1,                                          100,
1576     GADGET_ID_SELECT_LEVEL_DOWN,                GADGET_ID_SELECT_LEVEL_UP,
1577     GADGET_ID_SELECT_LEVEL_TEXT,                GADGET_ID_NONE,
1578     &level_nr,
1579     NULL,                                       NULL, NULL
1580   },
1581
1582   // ---------- level and editor settings -------------------------------------
1583
1584   {
1585     ED_COUNTER_ID_LEVEL_XSIZE,
1586     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1587     MIN_LEV_FIELDX,                             MAX_LEV_FIELDX,
1588     GADGET_ID_LEVEL_XSIZE_DOWN,                 GADGET_ID_LEVEL_XSIZE_UP,
1589     GADGET_ID_LEVEL_XSIZE_TEXT,                 GADGET_ID_NONE,
1590     &level.fieldx,
1591     "Playfield size:",                          NULL, "Width",
1592   },
1593   {
1594     ED_COUNTER_ID_LEVEL_YSIZE,
1595     -1,                                         ED_LEVEL_SETTINGS_YPOS(4),
1596     MIN_LEV_FIELDY,                             MAX_LEV_FIELDY,
1597     GADGET_ID_LEVEL_YSIZE_DOWN,                 GADGET_ID_LEVEL_YSIZE_UP,
1598     GADGET_ID_LEVEL_YSIZE_TEXT,                 GADGET_ID_LEVEL_XSIZE_UP,
1599     &level.fieldy,
1600     NULL,                                       " ", "Height",
1601   },
1602   {
1603     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1604     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
1605     0,                                          999,
1606     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,             GADGET_ID_LEVEL_GEMSLIMIT_UP,
1607     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,             GADGET_ID_NONE,
1608     &level.gems_needed,
1609     NULL,                                       "Number of gems to collect:", NULL
1610   },
1611   {
1612     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1613     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
1614     0,                                          9999,
1615     GADGET_ID_LEVEL_TIMELIMIT_DOWN,             GADGET_ID_LEVEL_TIMELIMIT_UP,
1616     GADGET_ID_LEVEL_TIMELIMIT_TEXT,             GADGET_ID_NONE,
1617     &level.time,
1618     "Time or step limit to solve level:",       NULL, NULL
1619   },
1620   {
1621     ED_COUNTER_ID_LEVEL_TIMESCORE,
1622     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
1623     0,                                          999,
1624     GADGET_ID_LEVEL_TIMESCORE_DOWN,             GADGET_ID_LEVEL_TIMESCORE_UP,
1625     GADGET_ID_LEVEL_TIMESCORE_TEXT,             GADGET_ID_NONE,
1626     &level.score[SC_TIME_BONUS],
1627     "Score for time or steps left:",            NULL, NULL
1628   },
1629   {
1630     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1631     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(13),
1632     0,                                          9999,
1633     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,           GADGET_ID_LEVEL_RANDOM_SEED_UP,
1634     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,           GADGET_ID_NONE,
1635     &level.random_seed,
1636     NULL,                                       "Random seed:", "(0 => random)"
1637   },
1638   {
1639     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1640     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1641     1,                                          MAX_LEVELS,
1642     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,         GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1643     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,         GADGET_ID_NONE,
1644     &levelset_num_levels,
1645     "Number of levels:",                        NULL, NULL,
1646   },
1647   {
1648     ED_COUNTER_ID_LEVEL_RANDOM,
1649     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1650     1,                                          100,
1651     GADGET_ID_LEVEL_RANDOM_DOWN,                GADGET_ID_LEVEL_RANDOM_UP,
1652     GADGET_ID_LEVEL_RANDOM_TEXT,                GADGET_ID_NONE,
1653     &random_placement_value,
1654     "Random element placement:",                NULL, "in"
1655   },
1656   {
1657     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1658     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1659     50,                                         500,
1660     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,           GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1661     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,           GADGET_ID_NONE,
1662     &level.bd_cycle_delay_ms,
1663     NULL,                                       NULL, "Game cycle delay (ms)"
1664   },
1665   {
1666     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1667     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1668     0,                                          32,
1669     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,          GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1670     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,          GADGET_ID_NONE,
1671     &level.bd_cycle_delay_c64,
1672     NULL,                                       NULL, "Game cycle delay (C64-style)"
1673   },
1674   {
1675     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1676     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1677     1,                                          40,
1678     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1679     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1680     &level.bd_hatching_delay_cycles,
1681     NULL,                                       NULL, "Hatching delay (cycles)"
1682   },
1683   {
1684     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1685     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1686     1,                                          40,
1687     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1688     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1689     &level.bd_hatching_delay_seconds,
1690     NULL,                                       NULL, "Hatching delay (seconds)"
1691   },
1692
1693   // ---------- element settings: configure (various elements) ----------------
1694
1695   {
1696     ED_COUNTER_ID_BD_PUSHING_PROB,
1697     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1698     0,                                          100,
1699     GADGET_ID_BD_PUSHING_PROB_DOWN,             GADGET_ID_BD_PUSHING_PROB_UP,
1700     GADGET_ID_BD_PUSHING_PROB_TEXT,             GADGET_ID_NONE,
1701     &level.bd_pushing_prob,
1702     NULL,                                       NULL, "Push probability"
1703   },
1704   {
1705     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1706     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1707     0,                                          100,
1708     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1709     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1710     &level.bd_pushing_prob_with_sweet,
1711     NULL,                                       NULL, "Push probability with sweet"
1712   },
1713   {
1714     ED_COUNTER_ID_ELEMENT_VALUE1,
1715     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1716     MIN_SCORE,                                  MAX_SCORE,
1717     GADGET_ID_ELEMENT_VALUE1_DOWN,              GADGET_ID_ELEMENT_VALUE1_UP,
1718     GADGET_ID_ELEMENT_VALUE1_TEXT,              GADGET_ID_NONE,
1719     NULL,                                       // will be set when used
1720     NULL,                                       NULL, NULL
1721   },
1722   {
1723     ED_COUNTER_ID_ELEMENT_VALUE2,
1724     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
1725     MIN_SCORE,                                  MAX_SCORE,
1726     GADGET_ID_ELEMENT_VALUE2_DOWN,              GADGET_ID_ELEMENT_VALUE2_UP,
1727     GADGET_ID_ELEMENT_VALUE2_TEXT,              GADGET_ID_NONE,
1728     NULL,                                       // will be set when used
1729     NULL,                                       NULL, NULL
1730   },
1731   {
1732     ED_COUNTER_ID_ELEMENT_VALUE3,
1733     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1734     MIN_SCORE,                                  MAX_SCORE,
1735     GADGET_ID_ELEMENT_VALUE3_DOWN,              GADGET_ID_ELEMENT_VALUE3_UP,
1736     GADGET_ID_ELEMENT_VALUE3_TEXT,              GADGET_ID_NONE,
1737     NULL,                                       // will be set when used
1738     NULL,                                       NULL, NULL
1739   },
1740   {
1741     ED_COUNTER_ID_ELEMENT_VALUE4,
1742     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1743     MIN_SCORE,                                  MAX_SCORE,
1744     GADGET_ID_ELEMENT_VALUE4_DOWN,              GADGET_ID_ELEMENT_VALUE4_UP,
1745     GADGET_ID_ELEMENT_VALUE4_TEXT,              GADGET_ID_NONE,
1746     NULL,                                       // will be set when used
1747     NULL,                                       NULL, NULL
1748   },
1749   {
1750     ED_COUNTER_ID_YAMYAM_CONTENT,
1751     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1752     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1753     GADGET_ID_YAMYAM_CONTENT_DOWN,              GADGET_ID_YAMYAM_CONTENT_UP,
1754     GADGET_ID_YAMYAM_CONTENT_TEXT,              GADGET_ID_NONE,
1755     &level.num_yamyam_contents,
1756     NULL,                                       NULL, "Number of content areas"
1757   },
1758   {
1759     ED_COUNTER_ID_BALL_CONTENT,
1760     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1761     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1762     GADGET_ID_BALL_CONTENT_DOWN,                GADGET_ID_BALL_CONTENT_UP,
1763     GADGET_ID_BALL_CONTENT_TEXT,                GADGET_ID_NONE,
1764     &level.num_ball_contents,
1765     NULL,                                       NULL, "Number of content areas"
1766   },
1767   {
1768     ED_COUNTER_ID_ANDROID_CONTENT,
1769     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1770     MIN_ANDROID_ELEMENTS,                       MAX_ANDROID_ELEMENTS,
1771     GADGET_ID_ANDROID_CONTENT_DOWN,             GADGET_ID_ANDROID_CONTENT_UP,
1772     GADGET_ID_ANDROID_CONTENT_TEXT,             GADGET_ID_NONE,
1773     &level.num_android_clone_elements,
1774     NULL,                                       NULL, "Number of clonable elements"
1775   },
1776   {
1777     ED_COUNTER_ID_ENVELOPE_XSIZE,
1778     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1779     MIN_ENVELOPE_XSIZE,                         MAX_ENVELOPE_XSIZE,
1780     GADGET_ID_ENVELOPE_XSIZE_DOWN,              GADGET_ID_ENVELOPE_XSIZE_UP,
1781     GADGET_ID_ENVELOPE_XSIZE_TEXT,              GADGET_ID_NONE,
1782     NULL,                                       // will be set when used
1783     NULL,                                       NULL, "Width",
1784   },
1785   {
1786     ED_COUNTER_ID_ENVELOPE_YSIZE,
1787     -1,                                         ED_ELEMENT_SETTINGS_YPOS(0),
1788     MIN_ENVELOPE_YSIZE,                         MAX_ENVELOPE_YSIZE,
1789     GADGET_ID_ENVELOPE_YSIZE_DOWN,              GADGET_ID_ENVELOPE_YSIZE_UP,
1790     GADGET_ID_ENVELOPE_YSIZE_TEXT,              GADGET_ID_ENVELOPE_XSIZE_UP,
1791     NULL,                                       // will be set when used
1792     NULL,                                       " ", "Height",
1793   },
1794   {
1795     ED_COUNTER_ID_INVENTORY_SIZE,
1796     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1797     MIN_INITIAL_INVENTORY_SIZE,                 MAX_INITIAL_INVENTORY_SIZE,
1798     GADGET_ID_INVENTORY_SIZE_DOWN,              GADGET_ID_INVENTORY_SIZE_UP,
1799     GADGET_ID_INVENTORY_SIZE_TEXT,              GADGET_ID_NONE,
1800     &level.initial_inventory_size[0],
1801     NULL,                                       NULL, "Number of inventory elements"
1802   },
1803   {
1804     ED_COUNTER_ID_MM_BALL_CONTENT,
1805     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1806     MIN_ELEMENTS_IN_GROUP,                      MAX_MM_BALL_CONTENTS,
1807     GADGET_ID_MM_BALL_CONTENT_DOWN,             GADGET_ID_MM_BALL_CONTENT_UP,
1808     GADGET_ID_MM_BALL_CONTENT_TEXT,             GADGET_ID_NONE,
1809     &level.num_mm_ball_contents,
1810     NULL,                                       NULL, "Number of content elements"
1811   },
1812
1813   // ---------- element settings: configure 1 (custom elements) ---------------
1814
1815   {
1816     ED_COUNTER_ID_CUSTOM_SCORE,
1817     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1818     MIN_SCORE,                                  MAX_SCORE,
1819     GADGET_ID_CUSTOM_SCORE_DOWN,                GADGET_ID_CUSTOM_SCORE_UP,
1820     GADGET_ID_CUSTOM_SCORE_TEXT,                GADGET_ID_NONE,
1821     &custom_element.collect_score_initial,
1822     NULL,                                       "CE score", " "
1823   },
1824   {
1825     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1826     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1827     MIN_COLLECT_COUNT,                          MAX_COLLECT_COUNT,
1828     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,             GADGET_ID_CUSTOM_GEMCOUNT_UP,
1829     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,             GADGET_ID_CUSTOM_SCORE_UP,
1830     &custom_element.collect_count_initial,
1831     NULL,                                       "CE count", NULL
1832   },
1833   {
1834     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1835     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1836     0,                                          9999,
1837     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1838     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,            GADGET_ID_NONE,
1839     &custom_element.ce_value_fixed_initial,
1840     NULL,                                       "CE value", NULL
1841   },
1842   {
1843     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1844     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1845     0,                                          9999,
1846     GADGET_ID_CUSTOM_VALUE_RND_DOWN,            GADGET_ID_CUSTOM_VALUE_RND_UP,
1847     GADGET_ID_CUSTOM_VALUE_RND_TEXT,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1848     &custom_element.ce_value_random_initial,
1849     NULL,                                       "+random", NULL
1850   },
1851   {
1852     ED_COUNTER_ID_PUSH_DELAY_FIX,
1853     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1854     0,                                          999,
1855     GADGET_ID_PUSH_DELAY_FIX_DOWN,              GADGET_ID_PUSH_DELAY_FIX_UP,
1856     GADGET_ID_PUSH_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1857     &custom_element.push_delay_fixed,
1858     NULL,                                       "Push delay", NULL
1859   },
1860   {
1861     ED_COUNTER_ID_PUSH_DELAY_RND,
1862     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1863     0,                                          999,
1864     GADGET_ID_PUSH_DELAY_RND_DOWN,              GADGET_ID_PUSH_DELAY_RND_UP,
1865     GADGET_ID_PUSH_DELAY_RND_TEXT,              GADGET_ID_PUSH_DELAY_FIX_UP,
1866     &custom_element.push_delay_random,
1867     NULL,                                       "+random", NULL
1868   },
1869   {
1870     ED_COUNTER_ID_DROP_DELAY_FIX,
1871     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(7),
1872     0,                                          999,
1873     GADGET_ID_DROP_DELAY_FIX_DOWN,              GADGET_ID_DROP_DELAY_FIX_UP,
1874     GADGET_ID_DROP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1875     &custom_element.drop_delay_fixed,
1876     NULL,                                       "Drop delay", NULL
1877   },
1878   {
1879     ED_COUNTER_ID_DROP_DELAY_RND,
1880     -1,                                         ED_ELEMENT_SETTINGS_YPOS(7),
1881     0,                                          999,
1882     GADGET_ID_DROP_DELAY_RND_DOWN,              GADGET_ID_DROP_DELAY_RND_UP,
1883     GADGET_ID_DROP_DELAY_RND_TEXT,              GADGET_ID_DROP_DELAY_FIX_UP,
1884     &custom_element.drop_delay_random,
1885     NULL,                                       "+random", NULL
1886   },
1887
1888   // ---------- element settings: configure 2 (custom elements) ---------------
1889
1890   {
1891     ED_COUNTER_ID_MOVE_DELAY_FIX,
1892     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1893     0,                                          999,
1894     GADGET_ID_MOVE_DELAY_FIX_DOWN,              GADGET_ID_MOVE_DELAY_FIX_UP,
1895     GADGET_ID_MOVE_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1896     &custom_element.move_delay_fixed,
1897     NULL,                                       "Move delay", NULL
1898   },
1899   {
1900     ED_COUNTER_ID_MOVE_DELAY_RND,
1901     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1902     0,                                          999,
1903     GADGET_ID_MOVE_DELAY_RND_DOWN,              GADGET_ID_MOVE_DELAY_RND_UP,
1904     GADGET_ID_MOVE_DELAY_RND_TEXT,              GADGET_ID_MOVE_DELAY_FIX_UP,
1905     &custom_element.move_delay_random,
1906     NULL,                                       "+random", NULL
1907   },
1908   {
1909     ED_COUNTER_ID_STEP_DELAY_FIX,
1910     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1911     0,                                          999,
1912     GADGET_ID_STEP_DELAY_FIX_DOWN,              GADGET_ID_STEP_DELAY_FIX_UP,
1913     GADGET_ID_STEP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1914     &custom_element.step_delay_fixed,
1915     NULL,                                       "Step delay", NULL
1916   },
1917   {
1918     ED_COUNTER_ID_STEP_DELAY_RND,
1919     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1920     0,                                          999,
1921     GADGET_ID_STEP_DELAY_RND_DOWN,              GADGET_ID_STEP_DELAY_RND_UP,
1922     GADGET_ID_STEP_DELAY_RND_TEXT,              GADGET_ID_STEP_DELAY_FIX_UP,
1923     &custom_element.step_delay_random,
1924     NULL,                                       "+random", NULL
1925   },
1926   {
1927     ED_COUNTER_ID_EXPLOSION_DELAY,
1928     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
1929     0,                                          999,
1930     GADGET_ID_EXPLOSION_DELAY_DOWN,             GADGET_ID_EXPLOSION_DELAY_UP,
1931     GADGET_ID_EXPLOSION_DELAY_TEXT,             GADGET_ID_NONE,
1932     &custom_element.explosion_delay,
1933     NULL,                                       "Explosion delay", NULL
1934   },
1935   {
1936     ED_COUNTER_ID_IGNITION_DELAY,
1937     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
1938     0,                                          999,
1939     GADGET_ID_IGNITION_DELAY_DOWN,              GADGET_ID_IGNITION_DELAY_UP,
1940     GADGET_ID_IGNITION_DELAY_TEXT,              GADGET_ID_NONE,
1941     &custom_element.ignition_delay,
1942     NULL,                                       "Ignition delay", "(by fire)"
1943   },
1944
1945   // ---------- element settings: configure (group elements) ------------------
1946
1947   {
1948     ED_COUNTER_ID_GROUP_CONTENT,
1949     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1950     MIN_ELEMENTS_IN_GROUP,                      MAX_ELEMENTS_IN_GROUP,
1951     GADGET_ID_GROUP_CONTENT_DOWN,               GADGET_ID_GROUP_CONTENT_UP,
1952     GADGET_ID_GROUP_CONTENT_TEXT,               GADGET_ID_NONE,
1953     &group_element_info.num_elements,
1954     NULL,                                       NULL, "Number of elements in group"
1955   },
1956
1957   // ---------- element settings: advanced (custom elements) ------------------
1958
1959   {
1960     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1961     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(2),
1962     0,                                          999,
1963     GADGET_ID_CHANGE_DELAY_FIX_DOWN,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1964     GADGET_ID_CHANGE_DELAY_FIX_TEXT,            GADGET_ID_NONE,
1965     &custom_element_change.delay_fixed,
1966     NULL,                                       "CE delay", NULL,
1967   },
1968   {
1969     ED_COUNTER_ID_CHANGE_DELAY_RND,
1970     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
1971     0,                                          999,
1972     GADGET_ID_CHANGE_DELAY_RND_DOWN,            GADGET_ID_CHANGE_DELAY_RND_UP,
1973     GADGET_ID_CHANGE_DELAY_RND_TEXT,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1974     &custom_element_change.delay_random,
1975     NULL,                                       "+random", NULL
1976   },
1977   {
1978     ED_COUNTER_ID_CHANGE_CONT_RND,
1979     ED_ELEMENT_SETTINGS_XPOS(3),                ED_ELEMENT_SETTINGS_YPOS(12),
1980     0,                                          100,
1981     GADGET_ID_CHANGE_CONT_RND_DOWN,             GADGET_ID_CHANGE_CONT_RND_UP,
1982     GADGET_ID_CHANGE_CONT_RND_TEXT,             GADGET_ID_NONE,
1983     &custom_element_change.random_percentage,
1984     NULL,                                       "Use random replace:", "%"
1985   },
1986 };
1987
1988 static struct
1989 {
1990   int gadget_type_id;
1991   int x, y;
1992   int gadget_id;
1993   int size;
1994   char *value;
1995   char *text_above, *infotext;
1996 } textinput_info[ED_NUM_TEXTINPUT] =
1997 {
1998   {
1999     ED_TEXTINPUT_ID_LEVEL_NAME,
2000     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
2001     GADGET_ID_LEVEL_NAME,
2002     MAX_LEVEL_NAME_LEN,
2003     level.name,
2004     "Title:", "Title for this level"
2005   },
2006   {
2007     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
2008     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2009     GADGET_ID_LEVEL_AUTHOR,
2010     MAX_LEVEL_AUTHOR_LEN,
2011     level.author,
2012     "Author:", "Author for this level"
2013   },
2014   {
2015     ED_TEXTINPUT_ID_LEVELSET_NAME,
2016     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
2017     GADGET_ID_LEVELSET_NAME,
2018     MAX_LEVEL_NAME_LEN,
2019     levelset_name,
2020     "Title:", "Title for this or new level set"
2021   },
2022   {
2023     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
2024     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
2025     GADGET_ID_LEVELSET_AUTHOR,
2026     MAX_LEVEL_AUTHOR_LEN,
2027     levelset_author,
2028     "Author:", "Author for this or new level set"
2029   },
2030   {
2031     ED_TEXTINPUT_ID_ELEMENT_NAME,
2032     -1, -1,     // these values are not constant, but can change at runtime
2033     GADGET_ID_ELEMENT_NAME,
2034     MAX_ELEMENT_NAME_LEN - 2,                   // currently 2 chars less editable
2035     custom_element.description,
2036     NULL, "Element name"
2037   }
2038 };
2039
2040 static struct
2041 {
2042   int gadget_type_id;
2043   int x, y;
2044   int gadget_id;
2045   int xsize, ysize;
2046   char *value;
2047   char *text_above, *text_above_cropped, *infotext;
2048 } textarea_info[ED_NUM_TEXTAREAS] =
2049 {
2050   {
2051     ED_TEXTAREA_ID_ENVELOPE_INFO,
2052     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
2053     GADGET_ID_ENVELOPE_INFO,
2054     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2055     NULL,
2056     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2057   }
2058 };
2059
2060 static struct ValueTextInfo options_time_or_steps[] =
2061 {
2062   { 0,                                  "seconds"                       },
2063   { 1,                                  "steps"                         },
2064
2065   { -1,                                 NULL                            }
2066 };
2067
2068 static struct ValueTextInfo options_time_score_base[] =
2069 {
2070   { 1,                                  "per second/step"               },
2071   { 10,                                 "per 10 seconds/steps"          },
2072
2073   { -1,                                 NULL                            }
2074 };
2075
2076 static struct ValueTextInfo options_game_engine_type[] =
2077 {
2078   { GAME_ENGINE_TYPE_RND,               "Rocks'n'Diamonds"              },
2079   { GAME_ENGINE_TYPE_BD,                "Boulder Dash"                  },
2080   { GAME_ENGINE_TYPE_EM,                "Emerald Mine"                  },
2081   { GAME_ENGINE_TYPE_SP,                "Supaplex"                      },
2082   { GAME_ENGINE_TYPE_MM,                "Mirror Magic"                  },
2083
2084   { -1,                                 NULL                            }
2085 };
2086
2087 static struct ValueTextInfo options_levelset_save_mode[] =
2088 {
2089   { LEVELSET_SAVE_MODE_UPDATE,          "Update this level set"         },
2090   { LEVELSET_SAVE_MODE_CREATE,          "Create new level set"          },
2091
2092   { -1,                                 NULL                            }
2093 };
2094
2095 static struct ValueTextInfo options_bd_gravity_direction[] =
2096 {
2097   { GD_MV_DOWN,                         "down"                          },
2098   { GD_MV_UP,                           "up"                            },
2099   { GD_MV_LEFT,                         "left"                          },
2100   { GD_MV_RIGHT,                        "right"                         },
2101
2102   { -1,                                 NULL                            }
2103 };
2104
2105 static struct ValueTextInfo options_wind_direction[] =
2106 {
2107   { MV_START_NONE,                      "none"                          },
2108   { MV_START_LEFT,                      "left"                          },
2109   { MV_START_RIGHT,                     "right"                         },
2110   { MV_START_UP,                        "up"                            },
2111   { MV_START_DOWN,                      "down"                          },
2112
2113   { -1,                                 NULL                            }
2114 };
2115
2116 static struct ValueTextInfo options_player_speed[] =
2117 {
2118   { 0,                                  "frozen"                        },
2119   { 1,                                  "very slow"                     },
2120   { 2,                                  "slow"                          },
2121   { 4,                                  "normal"                        },
2122   { 8,                                  "fast"                          },
2123   { 16,                                 "very fast"                     },
2124   { 32,                                 "ultrafast"                     },
2125
2126   { -1,                                 NULL                            }
2127 };
2128
2129 static struct ValueTextInfo options_access_type[] =
2130 {
2131   { EP_WALKABLE,                        "walkable"                      },
2132   { EP_PASSABLE,                        "passable"                      },
2133
2134   { -1,                                 NULL                            }
2135 };
2136
2137 static struct ValueTextInfo options_access_layer[] =
2138 {
2139   { EP_ACCESSIBLE_OVER,                 "over"                          },
2140   { EP_ACCESSIBLE_INSIDE,               "inside"                        },
2141   { EP_ACCESSIBLE_UNDER,                "under"                         },
2142
2143   { -1,                                 NULL                            }
2144 };
2145
2146 static struct ValueTextInfo options_access_protected[] =
2147 {
2148   { 0,                                  "unprotected"                   },
2149   { 1,                                  "protected"                     },
2150
2151   { -1,                                 NULL                            }
2152 };
2153
2154 static struct ValueTextInfo options_access_direction[] =
2155 {
2156   { MV_NO_DIRECTION,                    "no direction"                  },
2157   { MV_LEFT,                            "left"                          },
2158   { MV_RIGHT,                           "right"                         },
2159   { MV_UP,                              "up"                            },
2160   { MV_DOWN,                            "down"                          },
2161   { MV_LEFT  | MV_UP,                   "left + up"                     },
2162   { MV_LEFT  | MV_DOWN,                 "left + down"                   },
2163   { MV_RIGHT | MV_UP,                   "right + up"                    },
2164   { MV_RIGHT | MV_DOWN,                 "right + down"                  },
2165   { MV_HORIZONTAL,                      "horizontal"                    },
2166   { MV_VERTICAL,                        "vertical"                      },
2167   { MV_HORIZONTAL | MV_UP,              "horizontal + up"               },
2168   { MV_HORIZONTAL | MV_DOWN,            "horizontal + down"             },
2169   { MV_VERTICAL   | MV_LEFT,            "vertical + left"               },
2170   { MV_VERTICAL   | MV_RIGHT,           "vertical + right"              },
2171   { MV_ALL_DIRECTIONS,                  "all directions"                },
2172
2173   { -1,                                 NULL                            }
2174 };
2175
2176 static struct ValueTextInfo options_walk_to_action[] =
2177 {
2178   { EP_DIGGABLE,                        "diggable"                      },
2179   { EP_COLLECTIBLE_ONLY,                "collectible"                   },
2180   { EP_DROPPABLE,                       "collectible & droppable"       },
2181   { EP_THROWABLE,                       "collectible & throwable"       },
2182   { EP_PUSHABLE,                        "pushable"                      },
2183
2184   { -1,                                 NULL                            }
2185 };
2186
2187 static struct ValueTextInfo options_move_pattern[] =
2188 {
2189   { MV_LEFT,                            "left"                          },
2190   { MV_RIGHT,                           "right"                         },
2191   { MV_UP,                              "up"                            },
2192   { MV_DOWN,                            "down"                          },
2193   { MV_HORIZONTAL,                      "horizontal"                    },
2194   { MV_VERTICAL,                        "vertical"                      },
2195   { MV_ALL_DIRECTIONS,                  "all directions"                },
2196   { MV_WIND_DIRECTION,                  "wind direction"                },
2197   { MV_TOWARDS_PLAYER,                  "towards player"                },
2198   { MV_AWAY_FROM_PLAYER,                "away from player"              },
2199   { MV_ALONG_LEFT_SIDE,                 "along left side"               },
2200   { MV_ALONG_RIGHT_SIDE,                "along right side"              },
2201   { MV_TURNING_LEFT,                    "turning left"                  },
2202   { MV_TURNING_RIGHT,                   "turning right"                 },
2203   { MV_TURNING_LEFT_RIGHT,              "turning left, right"           },
2204   { MV_TURNING_RIGHT_LEFT,              "turning right, left"           },
2205   { MV_TURNING_RANDOM,                  "turning random"                },
2206   { MV_MAZE_RUNNER,                     "maze runner style"             },
2207   { MV_MAZE_HUNTER,                     "maze hunter style"             },
2208   { MV_WHEN_PUSHED,                     "when pushed"                   },
2209   { MV_WHEN_DROPPED,                    "when dropped/thrown"           },
2210
2211   { -1,                                 NULL                            }
2212 };
2213
2214 static struct ValueTextInfo options_move_direction[] =
2215 {
2216   { MV_START_AUTOMATIC,                 "automatic"                     },
2217   { MV_START_LEFT,                      "left"                          },
2218   { MV_START_RIGHT,                     "right"                         },
2219   { MV_START_UP,                        "up"                            },
2220   { MV_START_DOWN,                      "down"                          },
2221   { MV_START_RANDOM,                    "random"                        },
2222   { MV_START_PREVIOUS,                  "previous"                      },
2223
2224   { -1,                                 NULL                            }
2225 };
2226
2227 static struct ValueTextInfo options_move_stepsize[] =
2228 {
2229   { 0,                                  "not moving"                    },
2230   { 1,                                  "very slow"                     },
2231   { 2,                                  "slow"                          },
2232   { 4,                                  "normal"                        },
2233   { 8,                                  "fast"                          },
2234   { 16,                                 "very fast"                     },
2235   { 32,                                 "even faster"                   },
2236
2237   { -1,                                 NULL                            }
2238 };
2239
2240 static struct ValueTextInfo options_move_leave_type[] =
2241 {
2242   { LEAVE_TYPE_UNLIMITED,               "leave behind"                  },
2243   { LEAVE_TYPE_LIMITED,                 "change it to"                  },
2244
2245   { -1,                                 NULL                            }
2246 };
2247
2248 static struct ValueTextInfo options_smash_targets[] =
2249 {
2250   { EP_CAN_SMASH_PLAYER,                "player"                        },
2251 #if 0
2252   { EP_CAN_SMASH_ENEMIES,               "enemies"                       },
2253 #endif
2254   { EP_CAN_SMASH_EVERYTHING,            "everything"                    },
2255
2256   { -1,                                 NULL                            }
2257 };
2258
2259 static struct ValueTextInfo options_slippery_type[] =
2260 {
2261   { SLIPPERY_ANY_RANDOM,                "random"                        },
2262   { SLIPPERY_ANY_LEFT_RIGHT,            "left, right"                   },
2263   { SLIPPERY_ANY_RIGHT_LEFT,            "right, left"                   },
2264   { SLIPPERY_ONLY_LEFT,                 "only left"                     },
2265   { SLIPPERY_ONLY_RIGHT,                "only right"                    },
2266
2267   { -1,                                 NULL                            }
2268 };
2269
2270 static struct ValueTextInfo options_deadliness[] =
2271 {
2272   { EP_DONT_RUN_INTO,                   "running into"                  },
2273   { EP_DONT_COLLIDE_WITH,               "colliding with"                },
2274   { EP_DONT_GET_HIT_BY,                 "getting hit by"                },
2275   { EP_DONT_TOUCH,                      "touching"                      },
2276
2277   { -1,                                 NULL                            }
2278 };
2279
2280 static struct ValueTextInfo options_explosion_type[] =
2281 {
2282   { EXPLODES_3X3,                       "3x3"                           },
2283   { EXPLODES_CROSS,                     "3+3"                           },
2284   { EXPLODES_1X1,                       "1x1"                           },
2285
2286   { -1,                                 NULL                            }
2287 };
2288
2289 static struct ValueTextInfo options_time_units[] =
2290 {
2291   { 1,                                  "frames"                        },
2292   { FRAMES_PER_SECOND,                  "seconds"                       },
2293
2294   { -1,                                 NULL                            }
2295 };
2296
2297 static struct ValueTextInfo options_change_direct_action[] =
2298 {
2299   { CE_TOUCHED_BY_PLAYER,               "touched by player"             },
2300   { CE_PRESSED_BY_PLAYER,               "pressed by player"             },
2301   { CE_SWITCHED_BY_PLAYER,              "switched by player"            },
2302   { CE_SNAPPED_BY_PLAYER,               "snapped by player"             },
2303   { CE_PUSHED_BY_PLAYER,                "pushed by player"              },
2304   { CE_ENTERED_BY_PLAYER,               "entered by player"             },
2305   { CE_LEFT_BY_PLAYER,                  "left by player"                },
2306   { CE_DROPPED_BY_PLAYER,               "dropped/thrown by player"      },
2307   { CE_SWITCHED,                        "switched"                      },
2308   { CE_HITTING_SOMETHING,               "hitting something"             },
2309   { CE_HIT_BY_SOMETHING,                "hit by something"              },
2310 #if 0
2311   { CE_BLOCKED,                         "blocked"                       },
2312 #endif
2313   { CE_IMPACT,                          "impact (on something)"         },
2314   { CE_SMASHED,                         "smashed (from above)"          },
2315 #if 0
2316   { CE_VALUE_CHANGES,                   "CE value changes"              },
2317   { CE_SCORE_CHANGES,                   "CE score changes"              },
2318 #endif
2319   { CE_VALUE_GETS_ZERO,                 "CE value gets 0"               },
2320   { CE_SCORE_GETS_ZERO,                 "CE score gets 0"               },
2321   { CE_UNDEFINED,                       " "                             },
2322   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2323   { CE_CLICKED_BY_MOUSE,                "clicked by mouse"              },
2324   { CE_PRESSED_BY_MOUSE,                "pressed by mouse"              },
2325   { CE_UNDEFINED,                       " "                             },
2326   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2327   { CE_NEXT_TO_PLAYER,                  "next to player"                },
2328
2329   { -1,                                 NULL                            }
2330 };
2331
2332 static struct ValueTextInfo options_change_other_action[] =
2333 {
2334   { CE_PLAYER_TOUCHES_X,                "player touches"                },
2335   { CE_PLAYER_PRESSES_X,                "player presses"                },
2336   { CE_PLAYER_SWITCHES_X,               "player switches"               },
2337   { CE_PLAYER_SNAPS_X,                  "player snaps"                  },
2338   { CE_PLAYER_PUSHES_X,                 "player pushes"                 },
2339   { CE_PLAYER_ENTERS_X,                 "player enters"                 },
2340   { CE_PLAYER_LEAVES_X,                 "player leaves"                 },
2341   { CE_PLAYER_DIGS_X,                   "player digs"                   },
2342   { CE_PLAYER_COLLECTS_X,               "player collects"               },
2343   { CE_PLAYER_DROPS_X,                  "player drops/throws"           },
2344   { CE_TOUCHING_X,                      "touching"                      },
2345   { CE_HITTING_X,                       "hitting"                       },
2346   { CE_DIGGING_X,                       "digging"                       },
2347   { CE_HIT_BY_X,                        "hit by"                        },
2348   { CE_SWITCH_OF_X,                     "switch of"                     },
2349   { CE_CHANGE_OF_X,                     "change by page of"             },
2350   { CE_EXPLOSION_OF_X,                  "explosion of"                  },
2351   { CE_MOVE_OF_X,                       "move of"                       },
2352   { CE_CREATION_OF_X,                   "creation of"                   },
2353   { CE_VALUE_CHANGES_OF_X,              "CE value changes of"           },
2354   { CE_SCORE_CHANGES_OF_X,              "CE score changes of"           },
2355   { CE_VALUE_GETS_ZERO_OF_X,            "CE value gets 0 of"            },
2356   { CE_SCORE_GETS_ZERO_OF_X,            "CE score gets 0 of"            },
2357   { CE_UNDEFINED,                       " "                             },
2358   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2359   { CE_MOUSE_CLICKED_ON_X,              "mouse clicked on"              },
2360   { CE_MOUSE_PRESSED_ON_X,              "mouse pressed on"              },
2361   { CE_UNDEFINED,                       " "                             },
2362   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2363   { CE_PLAYER_NEXT_TO_X,                "player next to"                },
2364   { CE_NEXT_TO_X,                       "next to"                       },
2365
2366   { -1,                                 NULL                            }
2367 };
2368
2369 static struct ValueTextInfo options_change_trigger_side[] =
2370 {
2371   { CH_SIDE_LEFT,                       "left"                          },
2372   { CH_SIDE_RIGHT,                      "right"                         },
2373   { CH_SIDE_TOP,                        "top"                           },
2374   { CH_SIDE_BOTTOM,                     "bottom"                        },
2375   { CH_SIDE_LEFT_RIGHT,                 "left/right"                    },
2376   { CH_SIDE_TOP_BOTTOM,                 "top/bottom"                    },
2377   { CH_SIDE_ANY,                        "any"                           },
2378
2379   { -1,                                 NULL                            }
2380 };
2381
2382 static struct ValueTextInfo options_change_trigger_player[] =
2383 {
2384   { CH_PLAYER_1,                        "1"                             },
2385   { CH_PLAYER_2,                        "2"                             },
2386   { CH_PLAYER_3,                        "3"                             },
2387   { CH_PLAYER_4,                        "4"                             },
2388   { CH_PLAYER_ANY,                      "any"                           },
2389
2390   { -1,                                 NULL                            }
2391 };
2392
2393 static struct ValueTextInfo options_change_trigger_page[] =
2394 {
2395   { (1u << 0),                          "1"                             },
2396   { (1u << 1),                          "2"                             },
2397   { (1u << 2),                          "3"                             },
2398   { (1u << 3),                          "4"                             },
2399   { (1u << 4),                          "5"                             },
2400   { (1u << 5),                          "6"                             },
2401   { (1u << 6),                          "7"                             },
2402   { (1u << 7),                          "8"                             },
2403   { (1u << 8),                          "9"                             },
2404   { (1u << 9),                          "10"                            },
2405   { (1u << 10),                         "11"                            },
2406   { (1u << 11),                         "12"                            },
2407   { (1u << 12),                         "13"                            },
2408   { (1u << 13),                         "14"                            },
2409   { (1u << 14),                         "15"                            },
2410   { (1u << 15),                         "16"                            },
2411   { (1u << 16),                         "17"                            },
2412   { (1u << 17),                         "18"                            },
2413   { (1u << 18),                         "19"                            },
2414   { (1u << 19),                         "20"                            },
2415   { (1u << 20),                         "21"                            },
2416   { (1u << 21),                         "22"                            },
2417   { (1u << 22),                         "23"                            },
2418   { (1u << 23),                         "24"                            },
2419   { (1u << 24),                         "25"                            },
2420   { (1u << 25),                         "26"                            },
2421   { (1u << 26),                         "27"                            },
2422   { (1u << 27),                         "28"                            },
2423   { (1u << 28),                         "29"                            },
2424   { (1u << 29),                         "30"                            },
2425   { (1u << 30),                         "31"                            },
2426   { (1u << 31),                         "32"                            },
2427   { CH_PAGE_ANY,                        "any"                           },
2428
2429   { -1,                                 NULL                            }
2430 };
2431
2432 static struct ValueTextInfo options_change_replace_when[] =
2433 {
2434   { CP_WHEN_EMPTY,                      "empty"                         },
2435   { CP_WHEN_WALKABLE,                   "walkable"                      },
2436   { CP_WHEN_DIGGABLE,                   "diggable"                      },
2437   { CP_WHEN_COLLECTIBLE,                "collectible"                   },
2438   { CP_WHEN_REMOVABLE,                  "removable"                     },
2439   { CP_WHEN_DESTRUCTIBLE,               "destructible"                  },
2440
2441   { -1,                                 NULL                            }
2442 };
2443
2444 static struct ValueTextInfo options_action_type[] =
2445 {
2446   { CA_NO_ACTION,                       "no action"                     },
2447   { CA_UNDEFINED,                       " "                             },
2448   { CA_HEADLINE_LEVEL_ACTIONS,          "[level]"                       },
2449   { CA_RESTART_LEVEL,                   "restart level"                 },
2450   { CA_SHOW_ENVELOPE,                   "show envelope"                 },
2451   { CA_SET_LEVEL_TIME,                  "set time"                      },
2452   { CA_SET_LEVEL_SCORE,                 "set score"                     },
2453   { CA_SET_LEVEL_GEMS,                  "set gems"                      },
2454   { CA_SET_LEVEL_WIND,                  "set wind dir."                 },
2455   { CA_SET_LEVEL_RANDOM_SEED,           "set random seed"               },
2456   { CA_UNDEFINED,                       " "                             },
2457   { CA_HEADLINE_PLAYER_ACTIONS,         "[player]"                      },
2458   { CA_MOVE_PLAYER,                     "move player"                   },
2459   { CA_MOVE_PLAYER_NEW,                 "move player new"               },
2460   { CA_EXIT_PLAYER,                     "exit player"                   },
2461   { CA_KILL_PLAYER,                     "kill player"                   },
2462   { CA_SET_PLAYER_KEYS,                 "set keys"                      },
2463   { CA_SET_PLAYER_SPEED,                "set speed"                     },
2464   { CA_SET_PLAYER_SHIELD,               "set shield"                    },
2465   { CA_SET_PLAYER_GRAVITY,              "set gravity"                   },
2466   { CA_SET_PLAYER_ARTWORK,              "set artwork"                   },
2467   { CA_SET_PLAYER_INVENTORY,            "set inventory"                 },
2468   { CA_UNDEFINED,                       " "                             },
2469   { CA_HEADLINE_CE_ACTIONS,             "[CE]"                          },
2470   { CA_SET_CE_VALUE,                    "set CE value"                  },
2471   { CA_SET_CE_SCORE,                    "set CE score"                  },
2472   { CA_SET_CE_ARTWORK,                  "set CE artwork"                },
2473   { CA_UNDEFINED,                       " "                             },
2474   { CA_HEADLINE_ENGINE_ACTIONS,         "[engine]"                      },
2475   { CA_SET_ENGINE_SCAN_MODE,            "set scan mode"                 },
2476
2477   { -1,                                 NULL                            }
2478 };
2479
2480 static struct ValueTextInfo options_action_mode_none[] =
2481 {
2482   { CA_MODE_UNDEFINED,                  " "                             },
2483
2484   { -1,                                 NULL                            }
2485 };
2486
2487 static struct ValueTextInfo options_action_mode_assign[] =
2488 {
2489   { CA_MODE_SET,                        "="                             },
2490
2491   { -1,                                 NULL                            }
2492 };
2493
2494 static struct ValueTextInfo options_action_mode_add_remove[] =
2495 {
2496   { CA_MODE_ADD,                        "+"                             },
2497   { CA_MODE_SUBTRACT,                   "-"                             },
2498
2499   { -1,                                 NULL                            }
2500 };
2501
2502 static struct ValueTextInfo options_action_mode_calculate[] =
2503 {
2504   { CA_MODE_SET,                        "="                             },
2505   { CA_MODE_ADD,                        "+"                             },
2506   { CA_MODE_SUBTRACT,                   "-"                             },
2507   { CA_MODE_MULTIPLY,                   "*"                             },
2508   { CA_MODE_DIVIDE,                     "/"                             },
2509   { CA_MODE_MODULO,                     "%"                             },
2510
2511   { -1,                                 NULL                            }
2512 };
2513
2514 static struct ValueTextInfo options_action_arg_none[] =
2515 {
2516   { CA_ARG_UNDEFINED,                   "         "                     },
2517
2518   { -1,                                 NULL                            }
2519 };
2520
2521 static struct ValueTextInfo options_action_arg_player[] =
2522 {
2523   { CA_ARG_PLAYER_HEADLINE,             "[player]"                      },
2524   { CA_ARG_PLAYER_1,                    "1"                             },
2525   { CA_ARG_PLAYER_2,                    "2"                             },
2526   { CA_ARG_PLAYER_3,                    "3"                             },
2527   { CA_ARG_PLAYER_4,                    "4"                             },
2528   { CA_ARG_PLAYER_ANY,                  "any"                           },
2529   { CA_ARG_PLAYER_TRIGGER,              "trigger"                       },
2530   { CA_ARG_PLAYER_ACTION,               "action ->"                     },
2531
2532   { -1,                                 NULL                            }
2533 };
2534
2535 static struct ValueTextInfo options_action_arg_number[] =
2536 {
2537   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2538   { CA_ARG_0,                           "0"                             },
2539   { CA_ARG_1,                           "1"                             },
2540   { CA_ARG_2,                           "2"                             },
2541   { CA_ARG_3,                           "3"                             },
2542   { CA_ARG_4,                           "4"                             },
2543   { CA_ARG_5,                           "5"                             },
2544   { CA_ARG_10,                          "10"                            },
2545   { CA_ARG_100,                         "100"                           },
2546   { CA_ARG_1000,                        "1000"                          },
2547   { CA_ARG_UNDEFINED,                   " "                             },
2548   { CA_ARG_NUMBER_MIN,                  "min"                           },
2549   { CA_ARG_NUMBER_MAX,                  "max"                           },
2550   { CA_ARG_UNDEFINED,                   " "                             },
2551   { CA_ARG_NUMBER_RESET,                "reset"                         },
2552   { CA_ARG_UNDEFINED,                   " "                             },
2553   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2554   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2555   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2556   { CA_ARG_UNDEFINED,                   " "                             },
2557   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2558   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2559   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2560   { CA_ARG_UNDEFINED,                   " "                             },
2561   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2562   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2563   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2564   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2565   { CA_ARG_UNDEFINED,                   " "                             },
2566   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2567   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2568   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2569   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2570
2571   { -1,                                 NULL                            }
2572 };
2573
2574 static struct ValueTextInfo options_action_arg_value[] =
2575 {
2576   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2577   { CA_ARG_0,                           "0"                             },
2578   { CA_ARG_1,                           "1"                             },
2579   { CA_ARG_2,                           "2"                             },
2580   { CA_ARG_3,                           "3"                             },
2581   { CA_ARG_4,                           "4"                             },
2582   { CA_ARG_5,                           "5"                             },
2583   { CA_ARG_10,                          "10"                            },
2584   { CA_ARG_100,                         "100"                           },
2585   { CA_ARG_1000,                        "1000"                          },
2586   { CA_ARG_UNDEFINED,                   " "                             },
2587   { CA_ARG_NUMBER_MIN,                  "min"                           },
2588   { CA_ARG_NUMBER_MAX,                  "max"                           },
2589   { CA_ARG_UNDEFINED,                   " "                             },
2590   { CA_ARG_NUMBER_RESET,                "reset"                         },
2591   { CA_ARG_UNDEFINED,                   " "                             },
2592   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2593   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2594   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2595   { CA_ARG_UNDEFINED,                   " "                             },
2596   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2597   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2598   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2599   { CA_ARG_UNDEFINED,                   " "                             },
2600   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2601   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2602   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2603   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2604   { CA_ARG_UNDEFINED,                   " "                             },
2605   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2606   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2607   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2608   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2609   { CA_ARG_UNDEFINED,                   " "                             },
2610   { CA_ARG_ELEMENT_NR_HEADLINE,         "[element]"                     },
2611   { CA_ARG_ELEMENT_NR_TARGET,           "target"                        },
2612   { CA_ARG_ELEMENT_NR_TRIGGER,          "trigger"                       },
2613   { CA_ARG_ELEMENT_NR_ACTION,           "action ->"                     },
2614
2615   { -1,                                 NULL                            }
2616 };
2617
2618 static struct ValueTextInfo options_action_arg_envelope[] =
2619 {
2620   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2621   { CA_ARG_1,                           "1"                             },
2622   { CA_ARG_2,                           "2"                             },
2623   { CA_ARG_3,                           "3"                             },
2624   { CA_ARG_4,                           "4"                             },
2625   { CA_ARG_UNDEFINED,                   " "                             },
2626   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2627   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2628   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2629   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2630
2631   { -1,                                 NULL                            }
2632 };
2633
2634 static struct ValueTextInfo options_action_arg_key[] =
2635 {
2636   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2637   { CA_ARG_1,                           "1"                             },
2638   { CA_ARG_2,                           "2"                             },
2639   { CA_ARG_3,                           "3"                             },
2640   { CA_ARG_4,                           "4"                             },
2641   { CA_ARG_5,                           "5"                             },
2642   { CA_ARG_6,                           "6"                             },
2643   { CA_ARG_7,                           "7"                             },
2644   { CA_ARG_8,                           "8"                             },
2645   { CA_ARG_UNDEFINED,                   " "                             },
2646   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2647   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2648   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2649   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2650
2651   { -1,                                 NULL                            }
2652 };
2653
2654 static struct ValueTextInfo options_action_arg_speed[] =
2655 {
2656   { CA_ARG_SPEED_HEADLINE,              "[speed]"                       },
2657   { CA_ARG_SPEED_NOT_MOVING,            "frozen"                        },
2658   { CA_ARG_SPEED_VERY_SLOW,             "very slow"                     },
2659   { CA_ARG_SPEED_SLOW,                  "slow"                          },
2660   { CA_ARG_SPEED_NORMAL,                "normal"                        },
2661   { CA_ARG_SPEED_FAST,                  "fast"                          },
2662   { CA_ARG_SPEED_VERY_FAST,             "very fast"                     },
2663   { CA_ARG_SPEED_EVEN_FASTER,           "ultrafast"                     },
2664   { CA_ARG_UNDEFINED,                   " "                             },
2665   { CA_ARG_SPEED_SLOWER,                "slower"                        },
2666   { CA_ARG_SPEED_FASTER,                "faster"                        },
2667   { CA_ARG_UNDEFINED,                   " "                             },
2668   { CA_ARG_SPEED_RESET,                 "reset"                         },
2669
2670   { -1,                                 NULL                            }
2671 };
2672
2673 static struct ValueTextInfo options_action_arg_shield[] =
2674 {
2675   { CA_ARG_SHIELD_HEADLINE,             "[shield]"                      },
2676   { CA_ARG_SHIELD_OFF,                  "off"                           },
2677   { CA_ARG_SHIELD_NORMAL,               "normal"                        },
2678   { CA_ARG_SHIELD_DEADLY,               "deadly"                        },
2679
2680   { -1,                                 NULL                            }
2681 };
2682
2683 static struct ValueTextInfo options_action_arg_artwork[] =
2684 {
2685   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2686   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2687   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2688   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2689   { CA_ARG_UNDEFINED,                   " "                             },
2690   { CA_ARG_ELEMENT_RESET,               "reset"                         },
2691
2692   { -1,                                 NULL                            }
2693 };
2694
2695 static struct ValueTextInfo options_action_arg_gravity[] =
2696 {
2697   { CA_ARG_GRAVITY_HEADLINE,            "[gravity]"                     },
2698   { CA_ARG_GRAVITY_ON,                  "on"                            },
2699   { CA_ARG_GRAVITY_OFF,                 "off"                           },
2700   { CA_ARG_GRAVITY_TOGGLE,              "toggle"                        },
2701
2702   { -1,                                 NULL                            }
2703 };
2704
2705 static struct ValueTextInfo options_action_arg_direction[] =
2706 {
2707   { CA_ARG_DIRECTION_HEADLINE,          "[dir.]"                        },
2708   { CA_ARG_DIRECTION_NONE,              "none"                          },
2709   { CA_ARG_DIRECTION_LEFT,              "left"                          },
2710   { CA_ARG_DIRECTION_RIGHT,             "right"                         },
2711   { CA_ARG_DIRECTION_UP,                "up"                            },
2712   { CA_ARG_DIRECTION_DOWN,              "down"                          },
2713   { CA_ARG_DIRECTION_TRIGGER,           "trigger"                       },
2714   { CA_ARG_DIRECTION_TRIGGER_BACK,      "-trigger"                      },
2715
2716   { -1,                                 NULL                            }
2717 };
2718
2719 static struct ValueTextInfo options_action_arg_scan_mode[] =
2720 {
2721   { CA_ARG_SCAN_MODE_HEADLINE,          "[mode]"                        },
2722   { CA_ARG_SCAN_MODE_NORMAL,            "normal"                        },
2723   { CA_ARG_SCAN_MODE_REVERSE,           "reverse"                       },
2724
2725   { -1,                                 NULL                            }
2726 };
2727
2728 static struct ValueTextInfo options_action_arg_inventory[] =
2729 {
2730   { CA_ARG_INVENTORY_HEADLINE,          "[add]"                         },
2731   { CA_ARG_ELEMENT_TARGET,              "+ target"                      },
2732   { CA_ARG_ELEMENT_TRIGGER,             "+ trigger"                     },
2733   { CA_ARG_ELEMENT_ACTION,              "+ action"                      },
2734   { CA_ARG_UNDEFINED,                   " "                             },
2735   { CA_ARG_INVENTORY_RM_HEADLINE,       "[remove]"                      },
2736   { CA_ARG_INVENTORY_RM_TARGET,         "- target"                      },
2737   { CA_ARG_INVENTORY_RM_TRIGGER,        "- trigger"                     },
2738   { CA_ARG_INVENTORY_RM_ACTION,         "- action"                      },
2739   { CA_ARG_INVENTORY_RM_FIRST,          "- first"                       },
2740   { CA_ARG_INVENTORY_RM_LAST,           "- last"                        },
2741   { CA_ARG_INVENTORY_RM_ALL,            "- all"                         },
2742   { CA_ARG_UNDEFINED,                   " "                             },
2743   { CA_ARG_INVENTORY_RESET,             "reset"                         },
2744
2745   { -1,                                 NULL                            }
2746 };
2747
2748 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2749 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2750 {
2751   { -1,                                 NULL                            }
2752 };
2753
2754 static struct ValueTextInfo options_group_choice_mode[] =
2755 {
2756   { ANIM_RANDOM,                        "random"                        },
2757   { ANIM_LOOP,                          "loop"                          },
2758   { ANIM_LINEAR,                        "linear"                        },
2759   { ANIM_PINGPONG,                      "pingpong"                      },
2760   { ANIM_PINGPONG2,                     "pingpong 2"                    },
2761   { ANIM_LEVEL_NR,                      "level number"                  },
2762
2763   { -1,                                 NULL                            }
2764 };
2765
2766 static struct ValueTextInfo options_bd_scheduling_type[] =
2767 {
2768   { GD_SCHEDULING_MILLISECONDS,         "Milliseconds"                  },
2769   { GD_SCHEDULING_BD1,                  "BD1"                           },
2770   { GD_SCHEDULING_BD2,                  "BD2"                           },
2771   { GD_SCHEDULING_PLCK,                 "Construction Kit"              },
2772   { GD_SCHEDULING_CRDR,                 "Crazy Dream 7"                 },
2773   { GD_SCHEDULING_BD1_ATARI,            "Atari BD1"                     },
2774   { GD_SCHEDULING_BD2_PLCK_ATARI,       "Atari BD2 / PLCK"              },
2775
2776   { -1,                                   NULL                          }
2777 };
2778
2779 static struct ValueTextInfo *action_arg_modes[] =
2780 {
2781   options_action_mode_none,
2782   options_action_mode_assign,
2783   options_action_mode_add_remove,
2784   options_action_mode_calculate,
2785 };
2786
2787 static struct
2788 {
2789   int value;
2790   int mode;
2791   struct ValueTextInfo *options;
2792 }
2793 action_arg_options[] =
2794 {
2795   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2796   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2797   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2798   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2799   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2800   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2801   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2802   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2803   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2804   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2805   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2806   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2807   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2808   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2809   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2810   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2811   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2812   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2813   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2814   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2815   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2816   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2817
2818   { -1,                         FALSE,  NULL                            }
2819 };
2820
2821 static struct
2822 {
2823   int gadget_type_id;
2824   int x, y;
2825   int gadget_id;
2826   int gadget_id_align;
2827   int size;     // char size of selectbox or '-1' (dynamically determined)
2828   struct ValueTextInfo *options;
2829   int *value;
2830   char *text_above, *text_left, *text_right, *infotext;
2831 } selectbox_info[ED_NUM_SELECTBOX] =
2832 {
2833   // ---------- level and editor settings -------------------------------------
2834
2835   {
2836     ED_SELECTBOX_ID_TIME_OR_STEPS,
2837     -1,                                         ED_LEVEL_SETTINGS_YPOS(8),
2838     GADGET_ID_TIME_OR_STEPS,                    GADGET_ID_LEVEL_TIMELIMIT_UP,
2839     -1,
2840     options_time_or_steps,
2841     &level.use_step_counter,
2842     NULL, NULL, "(0 => no limit)",              "Select time or step limit"
2843   },
2844   {
2845     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2846     -1,                                         ED_LEVEL_SETTINGS_YPOS(10),
2847     GADGET_ID_TIME_SCORE_BASE,                  GADGET_ID_LEVEL_TIMESCORE_UP,
2848     -1,
2849     options_time_score_base,
2850     &level.time_score_base,
2851     NULL, NULL, NULL,                           "Select time score for 1 or 10 seconds/steps"
2852   },
2853   {
2854     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2855     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(12),
2856     GADGET_ID_GAME_ENGINE_TYPE,                 GADGET_ID_NONE,
2857     -1,
2858     options_game_engine_type,
2859     &level.game_engine_type,
2860     NULL, "Game engine:", NULL,                 "Select game engine"
2861   },
2862   {
2863     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2864     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
2865     GADGET_ID_BD_SCHEDULING_TYPE,               GADGET_ID_NONE,
2866     -1,
2867     options_bd_scheduling_type,
2868     &level.bd_scheduling_type,
2869     NULL, "Scheduling type:", NULL,             "Select level timing"
2870   },
2871   {
2872     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2873     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
2874     GADGET_ID_LEVELSET_SAVE_MODE,               GADGET_ID_NONE,
2875     -1,
2876     options_levelset_save_mode,
2877     &levelset_save_mode,
2878     "Action:", NULL, NULL,                      "Select action when saving level set"
2879   },
2880
2881   // ---------- element settings: configure (several elements) ----------------
2882
2883   {
2884     ED_SELECTBOX_ID_WIND_DIRECTION,
2885     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2886     GADGET_ID_WIND_DIRECTION,                   GADGET_ID_NONE,
2887     -1,
2888     options_wind_direction,
2889     &level.wind_direction_initial,
2890     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2891   },
2892   {
2893     ED_SELECTBOX_ID_PLAYER_SPEED,
2894     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(7),
2895     GADGET_ID_PLAYER_SPEED,                     GADGET_ID_NONE,
2896     -1,
2897     options_player_speed,
2898     &level.initial_player_stepsize[0],
2899     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2900   },
2901   {
2902     ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
2903     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2904     GADGET_ID_BD_GRAVITY_DIRECTION,             GADGET_ID_NONE,
2905     -1,
2906     options_bd_gravity_direction,
2907     &level.bd_gravity_direction,
2908     NULL, "Gravity direction:", NULL,           "Select initial gravity direction"
2909   },
2910   {
2911     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2912     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
2913     GADGET_ID_MM_BALL_CHOICE_MODE,              GADGET_ID_NONE,
2914     -1,
2915     options_group_choice_mode,
2916     &level.mm_ball_choice_mode,
2917     NULL, "Choice type:", NULL,                 "Select type of content choice"
2918   },
2919
2920   // ---------- element settings: configure 1 (custom elements) ---------------
2921
2922   {
2923     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2924     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2925     GADGET_ID_CUSTOM_ACCESS_TYPE,               GADGET_ID_NONE,
2926     -1,
2927     options_access_type,
2928     &custom_element.access_type,
2929     NULL, NULL, NULL,                           "Select type of access to this field"
2930   },
2931   {
2932     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2933     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2934     GADGET_ID_CUSTOM_ACCESS_LAYER,              GADGET_ID_CUSTOM_ACCESS_TYPE,
2935     -1,
2936     options_access_layer,
2937     &custom_element.access_layer,
2938     NULL, NULL, NULL,                           "Select layer of access for this field"
2939   },
2940   {
2941     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2942     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2943     GADGET_ID_CUSTOM_ACCESS_PROTECTED,          GADGET_ID_CUSTOM_ACCESS_LAYER,
2944     -1,
2945     options_access_protected,
2946     &custom_element.access_protected,
2947     NULL, NULL, NULL,                           "Select protected access for this field"
2948   },
2949   {
2950     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2951     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2952     GADGET_ID_CUSTOM_ACCESS_DIRECTION,          GADGET_ID_NONE,
2953     -1,
2954     options_access_direction,
2955     &custom_element.access_direction,
2956     NULL, "from", NULL,                         "Select access direction for this field"
2957   },
2958   {
2959     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2960     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2961     GADGET_ID_CUSTOM_WALK_TO_ACTION,            GADGET_ID_NONE,
2962     -1,
2963     options_walk_to_action,
2964     &custom_element.walk_to_action,
2965     NULL, NULL, NULL,                           "Select diggable/collectible/pushable"
2966   },
2967
2968   // ---------- element settings: configure 2 (custom elements) ---------------
2969
2970   {
2971     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2972     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(1),
2973     GADGET_ID_CUSTOM_MOVE_PATTERN,              GADGET_ID_NONE,
2974     -1,
2975     options_move_pattern,
2976     &custom_element.move_pattern,
2977     NULL, "Can move", NULL,                     "Select element move pattern"
2978   },
2979   {
2980     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2981     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2982     GADGET_ID_CUSTOM_MOVE_DIRECTION,            GADGET_ID_NONE,
2983     -1,
2984     options_move_direction,
2985     &custom_element.move_direction_initial,
2986     NULL, "Starts moving", NULL,                "Select initial element move direction"
2987   },
2988   {
2989     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2990     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2991     GADGET_ID_CUSTOM_MOVE_STEPSIZE,             GADGET_ID_NONE,
2992     -1,
2993     options_move_stepsize,
2994     &custom_element.move_stepsize,
2995     NULL, "Move/fall speed", NULL,              "Select speed of element movement"
2996   },
2997   {
2998     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2999     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
3000     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,           GADGET_ID_NONE,
3001     -1,
3002     options_move_leave_type,
3003     &custom_element.move_leave_type,
3004     // left text with leading spaces to place gadget next to "can dig" gadget
3005     // (needed because drawing area gadgets created after selectbox gadgets)
3006     // NULL, "can dig:    can", ":",            "leave behind or change element"
3007     NULL, "            Can", ":",               "Select leave behind or change element"
3008   },
3009   {
3010     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
3011     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
3012     GADGET_ID_CUSTOM_SMASH_TARGETS,             GADGET_ID_CUSTOM_CAN_SMASH,
3013     -1,
3014     options_smash_targets,
3015     &custom_element.smash_targets,
3016     NULL, "Can smash", NULL,                    "Select elements that can be smashed"
3017   },
3018   {
3019     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
3020     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
3021     GADGET_ID_CUSTOM_SLIPPERY_TYPE,             GADGET_ID_NONE,
3022     -1,
3023     options_slippery_type,
3024     &custom_element.slippery_type,
3025     NULL, "Slippery", NULL,                     "Select where other elements fall down"
3026   },
3027   {
3028     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
3029     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(10),
3030     GADGET_ID_CUSTOM_DEADLINESS,                GADGET_ID_NONE,
3031     -1,
3032     options_deadliness,
3033     &custom_element.deadliness,
3034     NULL, "Deadly when", NULL,                  "Select deadliness of element"
3035   },
3036   {
3037     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
3038     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(11),
3039     GADGET_ID_CUSTOM_EXPLOSION_TYPE,            GADGET_ID_NONE,
3040     -1,
3041     options_explosion_type,
3042     &custom_element.explosion_type,
3043     NULL, "Can explode", NULL,                  "Select explosion type"
3044   },
3045
3046   // ---------- element settings: advanced (custom elements) ------------------
3047
3048   {
3049     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
3050     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(3),
3051     GADGET_ID_CHANGE_TIME_UNITS,                GADGET_ID_NONE,
3052     -1,
3053     options_time_units,
3054     &custom_element_change.delay_frames,
3055     NULL, "Delay time given in", NULL,          "Select delay time units for change"
3056   },
3057   {
3058     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
3059     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(4),
3060     GADGET_ID_CHANGE_DIRECT_ACTION,             GADGET_ID_NONE,
3061     -1,
3062     options_change_direct_action,
3063     &custom_element_change.direct_action,
3064     NULL, NULL, NULL,                           "Select type of direct action"
3065   },
3066   {
3067     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3068     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(5),
3069     GADGET_ID_CHANGE_OTHER_ACTION,              GADGET_ID_NONE,
3070     -1,
3071     options_change_other_action,
3072     &custom_element_change.other_action,
3073     NULL, NULL, "element:",                     "Select type of other element action"
3074   },
3075   {
3076     ED_SELECTBOX_ID_CHANGE_SIDE,
3077     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(6),
3078     GADGET_ID_CHANGE_SIDE,                      GADGET_ID_NONE,
3079     -1,
3080     options_change_trigger_side,
3081     &custom_element_change.trigger_side,
3082     NULL, "at", "side",                         "Select element side triggering change"
3083   },
3084   {
3085     ED_SELECTBOX_ID_CHANGE_PLAYER,
3086     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3087     GADGET_ID_CHANGE_PLAYER,                    GADGET_ID_NONE,
3088     -1,
3089     options_change_trigger_player,
3090     &custom_element_change.trigger_player,
3091     NULL, "Player:", " ",                       "Select player that causes change"
3092   },
3093   {
3094     ED_SELECTBOX_ID_CHANGE_PAGE,
3095     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3096     GADGET_ID_CHANGE_PAGE,                      GADGET_ID_CHANGE_PLAYER,
3097     -1,
3098     options_change_trigger_page,
3099     &custom_element_change.trigger_page,
3100     NULL, "Page:", NULL,                        "Select change page that causes change"
3101   },
3102   {
3103     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3104     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(10),
3105     GADGET_ID_CHANGE_REPLACE_WHEN,              GADGET_ID_NONE,
3106     -1,
3107     options_change_replace_when,
3108     &custom_element_change.replace_when,
3109     NULL, "Replace when", NULL,                 "Select which elements can be replaced"
3110   },
3111   {
3112     ED_SELECTBOX_ID_ACTION_TYPE,
3113     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
3114     GADGET_ID_ACTION_TYPE,                      GADGET_ID_NONE,
3115     15,
3116     options_action_type,
3117     &custom_element_change.action_type,
3118     NULL, NULL, NULL,                           "Select action on specified condition"
3119   },
3120   {
3121     ED_SELECTBOX_ID_ACTION_MODE,
3122     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3123     GADGET_ID_ACTION_MODE,                      GADGET_ID_ACTION_TYPE,
3124     -1,
3125     options_action_mode_none,
3126     &custom_element_change.action_mode,
3127     NULL, NULL, NULL,                           "Select action operator"
3128   },
3129   {
3130     ED_SELECTBOX_ID_ACTION_ARG,
3131     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3132     GADGET_ID_ACTION_ARG,                       GADGET_ID_ACTION_MODE,
3133     -1,
3134     options_action_arg_none,
3135     &custom_element_change.action_arg,
3136     NULL, NULL, NULL,                           "Select action parameter"
3137   },
3138   {
3139     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3140     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
3141     GADGET_ID_SELECT_CHANGE_PAGE,               GADGET_ID_NONE,
3142     3,
3143     options_change_page,
3144     &custom_element.current_change_page,
3145     NULL, NULL, NULL,                           "Select element change page"
3146   },
3147
3148   // ---------- element settings: configure (group elements) ------------------
3149
3150   {
3151     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3152     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3153     GADGET_ID_GROUP_CHOICE_MODE,                GADGET_ID_NONE,
3154     -1,
3155     options_group_choice_mode,
3156     &group_element_info.choice_mode,
3157     NULL, "Choice type:", NULL,                 "Select type of group element choice"
3158   },
3159 };
3160
3161 static struct
3162 {
3163   int gadget_type_id;
3164   int x, y;
3165   int gadget_id;
3166   int gadget_id_align;
3167   int size;
3168   char *text;
3169   char *text_above, *text_left, *text_right, *infotext;
3170 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3171 {
3172   // ---------- level and editor settings (tabs) ------------------------------
3173
3174   {
3175     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3176     ED_LEVEL_TABS_XPOS(0),                      ED_LEVEL_TABS_YPOS(0),
3177     GADGET_ID_LEVELCONFIG_LEVEL,                GADGET_ID_NONE,
3178     8,                                          "Level",
3179     NULL, NULL, NULL,                           "Configure level settings"
3180   },
3181   {
3182     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3183     -1,                                         -1,
3184     GADGET_ID_LEVELCONFIG_LEVELSET,             GADGET_ID_LEVELCONFIG_LEVEL,
3185     8,                                          "Levelset",
3186     NULL, NULL, NULL,                           "Update this or create new level set"
3187   },
3188   {
3189     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3190     -1,                                         -1,
3191     GADGET_ID_LEVELCONFIG_EDITOR,               GADGET_ID_LEVELCONFIG_LEVELSET,
3192     8,                                          "Editor",
3193     NULL, NULL, NULL,                           "Configure editor settings"
3194   },
3195   {
3196     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3197     -1,                                         -1,
3198     GADGET_ID_LEVELCONFIG_ENGINE,               GADGET_ID_LEVELCONFIG_EDITOR,
3199     8,                                          "Engine",
3200     NULL, NULL, NULL,                           "Configure engine settings"
3201   },
3202
3203   // ---------- element settings (tabs) ---------------------------------------
3204
3205   {
3206     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3207     ED_ELEMENT_TABS_XPOS(0),                    ED_ELEMENT_TABS_YPOS(0),
3208     GADGET_ID_PROPERTIES_INFO,                  GADGET_ID_NONE,
3209     8,                                          "Info",
3210     NULL, NULL, NULL,                           "Show information about element"
3211   },
3212   {
3213     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3214     -1,                                         -1,
3215     GADGET_ID_PROPERTIES_CONFIG,                GADGET_ID_PROPERTIES_INFO,
3216     8,                                          "Config",
3217     NULL, NULL, NULL,                           "Configure element properties"
3218   },
3219   {
3220     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3221     -1,                                         -1,
3222     GADGET_ID_PROPERTIES_CONFIG_1,              GADGET_ID_PROPERTIES_INFO,
3223     8,                                          "Config 1",
3224     NULL, NULL, NULL,                           "Configure element properties, part 1"
3225   },
3226   {
3227     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3228     -1,                                         -1,
3229     GADGET_ID_PROPERTIES_CONFIG_2,              GADGET_ID_PROPERTIES_CONFIG_1,
3230     8,                                          "Config 2",
3231     NULL, NULL, NULL,                           "Configure element properties, part 2"
3232   },
3233   {
3234     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3235     -1,                                         -1,
3236     GADGET_ID_PROPERTIES_CHANGE,                GADGET_ID_PROPERTIES_CONFIG_2,
3237     8,                                          "Change",
3238     NULL, NULL, NULL,                           "Configure custom element change pages"
3239   },
3240
3241   // ---------- level and editor settings (buttons) ---------------------------
3242
3243   {
3244     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3245     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
3246     GADGET_ID_SAVE_LEVELSET,                    GADGET_ID_LEVELSET_SAVE_MODE,
3247     -1,                                         "Save",
3248     NULL, NULL, NULL,                           "Update or create level set"
3249   },
3250   {
3251     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3252     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3253     GADGET_ID_SAVE_AS_TEMPLATE_2,               GADGET_ID_NONE,
3254     -1,                                         "Save",
3255     NULL, NULL,                                 "this level as level template",
3256     "Save current settings as new template"
3257   },
3258
3259   // ---------- element settings (buttons) ------------------------------------
3260
3261   {
3262     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3263     -1,                                         -1,
3264     GADGET_ID_SAVE_AS_TEMPLATE_1,               GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3265     -1,                                         "Save",
3266     NULL, " ",                                  "As Template",
3267     "Save current settings as new template"
3268   },
3269   {
3270     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3271     -1,                                         -1,
3272     GADGET_ID_ADD_CHANGE_PAGE,                  GADGET_ID_PASTE_CHANGE_PAGE,
3273     -1,                                         "New",
3274     NULL, NULL, NULL,                           "Add new change page"
3275   },
3276   {
3277     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3278     -1,                                         -1,
3279     GADGET_ID_DEL_CHANGE_PAGE,                  GADGET_ID_ADD_CHANGE_PAGE,
3280     -1,                                         "Delete",
3281     NULL, NULL, NULL,                           "Delete current change page"
3282   },
3283 };
3284
3285 static struct
3286 {
3287   int gadget_type_id;
3288   int graphic;
3289   int x, y;
3290   int gadget_id;
3291   int gadget_id_align;
3292   char *text_left, *text_right, *infotext;
3293 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3294 {
3295   {
3296     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3297     IMG_EDITOR_COUNTER_DOWN,
3298     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3299     GADGET_ID_PREV_CHANGE_PAGE,                 GADGET_ID_NONE,
3300     NULL, NULL,                                 "Select previous change page"
3301   },
3302   {
3303     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3304     IMG_EDITOR_COUNTER_UP,
3305     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3306     GADGET_ID_NEXT_CHANGE_PAGE,                 GADGET_ID_SELECT_CHANGE_PAGE,
3307     NULL, "Change page",                        "Select next change page"
3308   },
3309   {
3310     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3311     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3312     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3313     GADGET_ID_COPY_CHANGE_PAGE,                 GADGET_ID_NEXT_CHANGE_PAGE,
3314     " ", NULL,                                  "Copy settings from this change page"
3315   },
3316   {
3317     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3318     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3319     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3320     GADGET_ID_PASTE_CHANGE_PAGE,                GADGET_ID_COPY_CHANGE_PAGE,
3321     NULL, NULL,                                 "Paste settings to this change page"
3322   },
3323 };
3324
3325 static struct
3326 {
3327   int x, y;
3328 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3329
3330 static struct
3331 {
3332   int gadget_type_id;
3333   int graphic;
3334   int gadget_id;
3335   char *infotext;
3336 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3337 {
3338   {
3339     ED_SCROLLBUTTON_ID_AREA_UP,
3340     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3341     GADGET_ID_SCROLL_UP,
3342     "Scroll level editing area up"
3343   },
3344   {
3345     ED_SCROLLBUTTON_ID_AREA_DOWN,
3346     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3347     GADGET_ID_SCROLL_DOWN,
3348     "Scroll level editing area down"
3349   },
3350   {
3351     ED_SCROLLBUTTON_ID_AREA_LEFT,
3352     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3353     GADGET_ID_SCROLL_LEFT,
3354     "Scroll level editing area left"
3355   },
3356   {
3357     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3358     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3359     GADGET_ID_SCROLL_RIGHT,
3360     "Scroll level editing area right"
3361   },
3362   {
3363     ED_SCROLLBUTTON_ID_LIST_UP,
3364     IMG_EDITOR_PALETTE_SCROLL_UP,
3365     GADGET_ID_SCROLL_LIST_UP,
3366     "Scroll element list up ('Page Up')"
3367   },
3368   {
3369     ED_SCROLLBUTTON_ID_LIST_DOWN,
3370     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3371     GADGET_ID_SCROLL_LIST_DOWN,
3372     "Scroll element list down ('Page Down')"
3373   },
3374 };
3375
3376 static struct
3377 {
3378   int x, y;
3379   int width, height;
3380   int wheel_x, wheel_y;
3381   int wheel_width, wheel_height;
3382 } scrollbar_pos[ED_NUM_SCROLLBARS];
3383
3384 static struct
3385 {
3386   int gadget_type_id;
3387   int graphic;
3388   int type;
3389   int gadget_id;
3390   char *infotext;
3391 } scrollbar_info[ED_NUM_SCROLLBARS] =
3392 {
3393   {
3394     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3395     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3396     GD_TYPE_SCROLLBAR_HORIZONTAL,
3397     GADGET_ID_SCROLL_HORIZONTAL,
3398     "Scroll level editing area horizontally"
3399   },
3400   {
3401     ED_SCROLLBAR_ID_AREA_VERTICAL,
3402     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3403     GD_TYPE_SCROLLBAR_VERTICAL,
3404     GADGET_ID_SCROLL_VERTICAL,
3405     "Scroll level editing area vertically"
3406   },
3407   {
3408     ED_SCROLLBAR_ID_LIST_VERTICAL,
3409     IMG_EDITOR_PALETTE_SCROLLBAR,
3410     GD_TYPE_SCROLLBAR_VERTICAL,
3411     GADGET_ID_SCROLL_LIST_VERTICAL,
3412     "Scroll element list vertically"
3413   }
3414 };
3415
3416
3417 static struct
3418 {
3419   int gadget_type_id;
3420   int x, y;
3421   int gadget_id;
3422   int gadget_id_align;
3423   int radio_button_nr;
3424   int *value;
3425   int checked_value;
3426   char *text_left, *text_right, *infotext;
3427 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3428 {
3429   {
3430     ED_RADIOBUTTON_ID_PERCENTAGE,
3431     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3432     GADGET_ID_RANDOM_PERCENTAGE,                GADGET_ID_LEVEL_RANDOM_UP,
3433     RADIO_NR_RANDOM_ELEMENTS,
3434     &random_placement_method,                   RANDOM_USE_PERCENTAGE,
3435     " ", "percentage",                          "Use percentage for random elements"
3436   },
3437   {
3438     ED_RADIOBUTTON_ID_QUANTITY,
3439     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3440     GADGET_ID_RANDOM_QUANTITY,                  GADGET_ID_RANDOM_PERCENTAGE,
3441     RADIO_NR_RANDOM_ELEMENTS,
3442     &random_placement_method,                   RANDOM_USE_QUANTITY,
3443     " ", "quantity",                            "Use quantity for random elements"
3444   }
3445 };
3446
3447 static struct
3448 {
3449   int gadget_type_id;
3450   int x, y;
3451   int gadget_id;
3452   int gadget_id_align;
3453   boolean *value;
3454   char *text_above, *text_left, *text_right, *infotext;
3455 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3456 {
3457   // ---------- level and editor settings -------------------------------------
3458
3459   {
3460     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3461     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3462     GADGET_ID_AUTO_COUNT_GEMS,                  GADGET_ID_NONE,
3463     &level.auto_count_gems,
3464     NULL, NULL,
3465     "Automatically count gems needed",          "Set counter to number of gems"
3466   },
3467   {
3468     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3469     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(11),
3470     GADGET_ID_RATE_TIME_OVER_SCORE,             GADGET_ID_NONE,
3471     &level.rate_time_over_score,
3472     NULL, NULL,
3473     "Rate time/steps used over score",          "Sort high scores by playing time/steps"
3474   },
3475   {
3476     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3477     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3478     GADGET_ID_USE_LEVELSET_ARTWORK,             GADGET_ID_NONE,
3479     &levelset_use_levelset_artwork,
3480     NULL, NULL,
3481     "Use current custom artwork",               "Use custom artwork of this level set"
3482   },
3483   {
3484     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3485     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3486     GADGET_ID_COPY_LEVEL_TEMPLATE,              GADGET_ID_NONE,
3487     &levelset_copy_level_template,
3488     NULL, NULL,
3489     "Copy current level template",              "Copy level template of this level set"
3490   },
3491   {
3492     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3493     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
3494     GADGET_ID_RANDOM_RESTRICTED,                GADGET_ID_NONE,
3495     &random_placement_background_restricted,
3496     NULL, NULL,
3497     "Restrict random placement to:",            "Set random placement restriction"
3498   },
3499   {
3500     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3501     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
3502     GADGET_ID_CUSTOM_USE_TEMPLATE_3,            GADGET_ID_NONE,
3503     &setup.editor.use_template_for_new_levels,
3504     "Template for new levels and CE/GE:", NULL,
3505     "Use template for new levels",              "Use template for level properties"
3506   },
3507   {
3508     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3509     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
3510     GADGET_ID_CUSTOM_USE_TEMPLATE_2,            GADGET_ID_NONE,
3511     &level.use_custom_template,
3512     NULL, NULL,
3513     "Use template for custom elements",         "Use template for custom properties"
3514   },
3515   {
3516     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3517     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
3518     GADGET_ID_BD_INTERMISSION,                  GADGET_ID_NONE,
3519     &level.bd_intermission,
3520     "Boulder Dash game engine settings:", NULL,
3521     "Intermission",                             "Level is an intermission level"
3522   },
3523   {
3524     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3525     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
3526     GADGET_ID_BD_PAL_TIMING,                    GADGET_ID_NONE,
3527     &level.bd_pal_timing,
3528     NULL, NULL,
3529     "PAL timing",                               "Use slower timer (like PAL C64)"
3530   },
3531   {
3532     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3533     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3534     GADGET_ID_BD_LINE_SHIFTING_BORDERS,         GADGET_ID_NONE,
3535     &level.bd_line_shifting_borders,
3536     "Compatibility settings:", NULL,
3537     "Line-shifting borders",                    "Use line-shifting wrap-around"
3538   },
3539   {
3540     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3541     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3542     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,       GADGET_ID_NONE,
3543     &level.bd_scan_first_and_last_row,
3544     NULL, NULL,
3545     "Scan first and last row",                  "Also process top/bottom border rows"
3546   },
3547   {
3548     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3549     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3550     GADGET_ID_BD_SHORT_EXPLOSIONS,              GADGET_ID_NONE,
3551     &level.bd_short_explosions,
3552     NULL, NULL,
3553     "Short explosions",                         "Use four game cycles for explosions"
3554   },
3555
3556   // ---------- element settings: configure (various elements) ----------------
3557
3558   {
3559     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3560     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3561     GADGET_ID_STICK_ELEMENT,                    GADGET_ID_NONE,
3562     &stick_element_properties_window,
3563     NULL, NULL,
3564     "Stick this screen to edit content",        "Stick this screen to edit content"
3565   },
3566   {
3567     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3568     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3569     GADGET_ID_EM_SLIPPERY_GEMS,                 GADGET_ID_NONE,
3570     &level.em_slippery_gems,
3571     NULL, NULL,
3572     "Slip down from certain flat walls",        "Use EM/DC style slipping behaviour"
3573   },
3574   {
3575     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3576     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3577     GADGET_ID_EM_EXPLODES_BY_FIRE,              GADGET_ID_NONE,
3578     &level.em_explodes_by_fire,
3579     NULL, NULL,
3580     "Explodes with chain reaction",             "Use R'n'D style explosion behaviour"
3581   },
3582   {
3583     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3584     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3585     GADGET_ID_USE_SPRING_BUG,                   GADGET_ID_NONE,
3586     &level.use_spring_bug,
3587     NULL, NULL,
3588     "Use spring pushing bug",                   "Use odd spring pushing behaviour"
3589   },
3590   {
3591     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3592     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3593     GADGET_ID_USE_TIME_ORB_BUG,                 GADGET_ID_NONE,
3594     &level.use_time_orb_bug,
3595     NULL, NULL,
3596     "Use time orb bug",                         "Use odd time orb behaviour"
3597   },
3598   {
3599     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3600     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3601     GADGET_ID_USE_LIFE_BUGS,                    GADGET_ID_NONE,
3602     &level.use_life_bugs,
3603     NULL, NULL,
3604     "Use buggy element behaviour",              "Use odd (historic) element behaviour"
3605   },
3606   {
3607     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3608     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3609     GADGET_ID_RANDOM_BALL_CONTENT,              GADGET_ID_NONE,
3610     &level.ball_random,
3611     NULL, NULL,
3612     "Create single random element",             "Only create one element from content"
3613   },
3614   {
3615     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3616     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3617     GADGET_ID_INITIAL_BALL_ACTIVE,              GADGET_ID_NONE,
3618     &level.ball_active_initial,
3619     NULL, NULL,
3620     "Magic ball initially activated",           "Activate magic ball after level start"
3621   },
3622   {
3623     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3624     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3625     GADGET_ID_GROW_INTO_DIGGABLE,               GADGET_ID_NONE,
3626     &level.grow_into_diggable,
3627     NULL, NULL,
3628     "Can grow into anything diggable",          "Grow into more than just sand"
3629   },
3630   {
3631     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3632     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3633     GADGET_ID_SB_FIELDS_NEEDED,                 GADGET_ID_NONE,
3634     &level.sb_fields_needed,
3635     NULL, NULL,
3636     "All fields need to be filled",             "Require all SB fields to be solved"
3637   },
3638   {
3639     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3640     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3641     GADGET_ID_SB_OBJECTS_NEEDED,                GADGET_ID_NONE,
3642     &level.sb_objects_needed,
3643     NULL, NULL,
3644     "All objects need to be placed",            "Require all SB objects to be solved"
3645   },
3646   {
3647     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3648     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3649     GADGET_ID_AUTO_EXIT_SOKOBAN,                GADGET_ID_NONE,
3650     &level.auto_exit_sokoban,
3651     NULL, NULL,
3652     "Exit level if all tasks solved",           "Automatically finish Sokoban levels"
3653   },
3654   {
3655     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3656     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3657     GADGET_ID_SOLVED_BY_ONE_PLAYER,             GADGET_ID_NONE,
3658     &level.solved_by_one_player,
3659     NULL, NULL,
3660     "Only one player must enter exit",          "Level solved by first player in exit"
3661   },
3662   {
3663     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3664     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3665     GADGET_ID_FINISH_DIG_COLLECT,               GADGET_ID_NONE,
3666     &level.finish_dig_collect,
3667     NULL, NULL,
3668     "CE action on finished dig/collect",        "Only finished dig/collect triggers CE"
3669   },
3670   {
3671     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3672     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3673     GADGET_ID_KEEP_WALKABLE_CE,                 GADGET_ID_NONE,
3674     &level.keep_walkable_ce,
3675     NULL, NULL,
3676     "Keep walkable CE changed to player",       "Keep CE changing to player if walkable"
3677   },
3678   {
3679     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3680     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3681     GADGET_ID_CONTINUOUS_SNAPPING,              GADGET_ID_NONE,
3682     &level.continuous_snapping,
3683     NULL, NULL,
3684     "Continuous snapping",                      "Use snapping without releasing key"
3685   },
3686   {
3687     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3688     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
3689     GADGET_ID_BLOCK_SNAP_FIELD,                 GADGET_ID_NONE,
3690     &level.block_snap_field,
3691     NULL, NULL,
3692     "Block snapped field when snapping",        "Use snapping delay to show animation"
3693   },
3694   {
3695     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3696     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3697     GADGET_ID_BLOCK_LAST_FIELD,                 GADGET_ID_NONE,
3698     &level.block_last_field,
3699     NULL, NULL,
3700     "Block last field when moving",             "Player blocks last field when moving"
3701   },
3702   {
3703     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3704     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3705     GADGET_ID_SP_BLOCK_LAST_FIELD,              GADGET_ID_NONE,
3706     &level.sp_block_last_field,
3707     NULL, NULL,
3708     "Block last field when moving",             "Player blocks last field when moving"
3709   },
3710   {
3711     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3712     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3713     GADGET_ID_INSTANT_RELOCATION,               GADGET_ID_NONE,
3714     &level.instant_relocation,
3715     NULL, NULL,
3716     "No scrolling when relocating",             "Player gets relocated without delay"
3717   },
3718   {
3719     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3720     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3721     GADGET_ID_SHIFTED_RELOCATION,               GADGET_ID_NONE,
3722     &level.shifted_relocation,
3723     NULL, NULL,
3724     "No centering when relocating",             "Level not centered after relocation"
3725   },
3726   {
3727     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3728     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3729     GADGET_ID_LAZY_RELOCATION,                  GADGET_ID_NONE,
3730     &level.lazy_relocation,
3731     NULL, NULL,
3732     "Only redraw off-screen relocation",        "No redraw if relocation target visible"
3733   },
3734   {
3735     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3736     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
3737     GADGET_ID_USE_START_ELEMENT,                GADGET_ID_NONE,
3738     &level.use_start_element[0],
3739     NULL, NULL,
3740     "Use level start element:",                "Start level at this element's position"
3741   },
3742   {
3743     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3744     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
3745     GADGET_ID_USE_ARTWORK_ELEMENT,              GADGET_ID_NONE,
3746     &level.use_artwork_element[0],
3747     NULL, NULL,
3748     "Use artwork from element:",                "Use player artwork from other element"
3749   },
3750   {
3751     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3752     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(12),
3753     GADGET_ID_USE_EXPLOSION_ELEMENT,            GADGET_ID_NONE,
3754     &level.use_explosion_element[0],
3755     NULL, NULL,
3756     "Use explosion from element:",              "Use explosion properties from element"
3757   },
3758   {
3759     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3760     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
3761     GADGET_ID_INITIAL_GRAVITY,                  GADGET_ID_NONE,
3762     &level.initial_player_gravity[0],
3763     NULL, NULL,
3764     "Use initial gravity",                      "Set initial player gravity"
3765   },
3766   {
3767     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3768     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3769     GADGET_ID_USE_INITIAL_INVENTORY,            GADGET_ID_NONE,
3770     &level.use_initial_inventory[0],
3771     NULL, NULL,
3772     "Use initial inventory:",                   "Use collected elements on level start"
3773   },
3774   {
3775     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3776     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
3777     GADGET_ID_CAN_PASS_TO_WALKABLE,             GADGET_ID_NONE,
3778     &level.can_pass_to_walkable,
3779     NULL, NULL,
3780     "Can pass to walkable element",             "Player can pass to empty or walkable"
3781   },
3782   {
3783     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3784     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3785     GADGET_ID_CAN_FALL_INTO_ACID,               GADGET_ID_NONE,
3786     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3787     NULL, NULL,
3788     "Can fall into acid (with gravity)",        "Player can fall into acid pool"
3789   },
3790   {
3791     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3792     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3793     GADGET_ID_CAN_MOVE_INTO_ACID,               GADGET_ID_NONE,
3794     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3795     NULL, NULL,
3796     "Can move into acid",                       "Element can move into acid pool"
3797   },
3798   {
3799     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3800     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3801     GADGET_ID_DONT_COLLIDE_WITH,                GADGET_ID_NONE,
3802     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3803     NULL, NULL,
3804     "Deadly when colliding with",               "Element is deadly when hitting player"
3805   },
3806   {
3807     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3808     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3809     GADGET_ID_BD_DIAGONAL_MOVEMENTS,            GADGET_ID_NONE,
3810     &level.bd_diagonal_movements,
3811     NULL, NULL,
3812     "Can move diagonally",                      "Player can move diagonally"
3813   },
3814   {
3815     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3816     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3817     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,         GADGET_ID_NONE,
3818     &level.bd_topmost_player_active,
3819     NULL, NULL,
3820     "Topmost player is active",                 "Use first player found on playfield"
3821   },
3822   {
3823     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3824     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3825     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,     GADGET_ID_NONE,
3826     &level.bd_push_mega_rock_with_sweet,
3827     NULL, NULL,
3828     "Mega rocks pushable with sweet",           "Push mega rocks after eating sweet"
3829   },
3830   {
3831     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
3832     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3833     GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,      GADGET_ID_NONE,
3834     &level.bd_magic_wall_zero_infinite,
3835     NULL, NULL,
3836     "Run forever if duration is zero",          "Run infinitely if timer is zero"
3837   },
3838   {
3839     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3840     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3841     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,      GADGET_ID_NONE,
3842     &level.bd_magic_wall_wait_hatching,
3843     NULL, NULL,
3844     "Wait for player's birth",                  "Timer start waits for player's birth"
3845   },
3846   {
3847     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3848     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3849     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,       GADGET_ID_NONE,
3850     &level.bd_magic_wall_stops_amoeba,
3851     NULL, NULL,
3852     "Stop amoeba and turn to diamonds",         "Activation changes amoeba to diamonds"
3853   },
3854   {
3855     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
3856     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3857     GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,         GADGET_ID_NONE,
3858     &level.bd_magic_wall_break_scan,
3859     NULL, NULL,
3860     "Emulate amoeba bug in BD1",                "Use buggy BD1 behavior"
3861   },
3862   {
3863     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3864     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3865     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,      GADGET_ID_NONE,
3866     &level.bd_amoeba_wait_for_hatching,
3867     NULL, NULL,
3868     "Wait for player's birth",                  "Timer start waits for player's birth"
3869   },
3870   {
3871     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3872     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3873     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,      GADGET_ID_NONE,
3874     &level.bd_amoeba_start_immediately,
3875     NULL, NULL,
3876     "Start growing immediately",                "Start slow growth time immediately"
3877   },
3878   {
3879     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3880     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3881     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,    GADGET_ID_NONE,
3882     &level.bd_amoeba_2_explode_by_amoeba,
3883     NULL, NULL,
3884     "Explodes if touched by amoeba",            "Amoeba 2 explodes if touched by amoeba"
3885   },
3886   {
3887     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3888     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3889     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,      GADGET_ID_NONE,
3890     &level.bd_voodoo_collects_diamonds,
3891     NULL, NULL,
3892     "Can collect diamonds",                     "Can collect diamonds for the player"
3893   },
3894   {
3895     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3896     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3897     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,      GADGET_ID_NONE,
3898     &level.bd_voodoo_hurt_kills_player,
3899     NULL, NULL,
3900     "Player is killed if hurt",                 "If hurt in any way, player is killed"
3901   },
3902   {
3903     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3904     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3905     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,           GADGET_ID_NONE,
3906     &level.bd_voodoo_dies_by_rock,
3907     NULL, NULL,
3908     "Killed by falling rock",                   "Can be killed by a falling rock"
3909   },
3910   {
3911     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3912     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3913     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,    GADGET_ID_NONE,
3914     &level.bd_voodoo_vanish_by_explosion,
3915     NULL, NULL,
3916     "Disappears in explosions",                 "Can be destroyed by explosions"
3917   },
3918   {
3919     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3920     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3921     GADGET_ID_BD_SLIME_IS_PREDICTABLE,          GADGET_ID_NONE,
3922     &level.bd_slime_is_predictable,
3923     NULL, NULL,
3924     "Slime is predictable",                     "Use predictable random numbers"
3925   },
3926   {
3927     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3928     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3929     GADGET_ID_BD_CHANGE_EXPANDING_WALL,         GADGET_ID_NONE,
3930     &level.bd_change_expanding_wall,
3931     NULL, NULL,
3932     "Change direction",                         "Switch horizontal/vertical direction"
3933   },
3934   {
3935     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3936     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3937     GADGET_ID_BD_REPLICATORS_ACTIVE,            GADGET_ID_NONE,
3938     &level.bd_replicators_active,
3939     NULL, NULL,
3940     "Active at start",                          "Replicators start in active state"
3941   },
3942   {
3943     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3944     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3945     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,         GADGET_ID_NONE,
3946     &level.bd_conveyor_belts_active,
3947     NULL, NULL,
3948     "Active at start",                          "Conveyor belts start in active state"
3949   },
3950   {
3951     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3952     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3953     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,        GADGET_ID_NONE,
3954     &level.bd_conveyor_belts_changed,
3955     NULL, NULL,
3956     "Change direction",                         "Switch conveyor belt direction"
3957   },
3958   {
3959     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3960     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3961     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,        GADGET_ID_NONE,
3962     &level.bd_water_cannot_flow_down,
3963     NULL, NULL,
3964     "Does not flow downwards",                  "Water can only flow up, left and right"
3965   },
3966   {
3967     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3968     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3969     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,         GADGET_ID_NONE,
3970     &level.bd_hammer_walls_reappear,
3971     NULL, NULL,
3972     "Hammered walls reappear",                  "Hammered walls reappear after delay"
3973   },
3974   {
3975     ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
3976     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3977     GADGET_ID_BD_INFINITE_ROCKETS,              GADGET_ID_NONE,
3978     &level.bd_infinite_rockets,
3979     NULL, NULL,
3980     "Infinite rockets",                         "Rocket launcher has infinite rockets"
3981   },
3982   {
3983     ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
3984     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3985     GADGET_ID_BD_CREATURES_START_BACKWARDS,     GADGET_ID_NONE,
3986     &level.bd_creatures_start_backwards,
3987     NULL, NULL,
3988     "Creatures start moving backwards",         "Creatures start in opposite direction"
3989   },
3990   {
3991     ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
3992     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3993     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3994     &level.bd_creatures_turn_on_hatching,
3995     NULL, NULL,
3996     "Creatures auto turn on hatching",          "Creatures change direction on hatching"
3997   },
3998   {
3999     ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
4000     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4001     GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,         GADGET_ID_NONE,
4002     &level.bd_gravity_switch_active,
4003     NULL, NULL,
4004     "Gravity switch active at start",           "Gravity switch starts in active state"
4005   },
4006   {
4007     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
4008     ED_LEVEL_SETTINGS_XPOS(0),                  ED_ELEMENT_SETTINGS_YPOS(3),
4009     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,           GADGET_ID_NONE,
4010     &level.bd_gravity_affects_all,
4011     NULL, NULL,
4012     "Gravity change affects everything",        "Gravity affects all falling objects"
4013   },
4014   {
4015     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
4016     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4017     GADGET_ID_ENVELOPE_AUTOWRAP,                GADGET_ID_NONE,
4018     &level.envelope[0].autowrap,
4019     NULL, NULL,
4020     "Auto-wrap",                                "Automatically wrap envelope text"
4021   },
4022   {
4023     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
4024     -1,                                         ED_ELEMENT_SETTINGS_YPOS(1),
4025     GADGET_ID_ENVELOPE_CENTERED,                GADGET_ID_ENVELOPE_AUTOWRAP,
4026     &level.envelope[0].centered,
4027     NULL, " ",
4028     "Centered",                                 "Automatically center envelope text"
4029   },
4030   {
4031     ED_CHECKBUTTON_ID_MM_LASER_RED,
4032     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4033     GADGET_ID_MM_LASER_RED,                     GADGET_ID_NONE,
4034     &level.mm_laser_red,
4035     "Choose color components for laser:", NULL,
4036     "Red",                                      "Use red color components in laser"
4037   },
4038   {
4039     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
4040     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4041     GADGET_ID_MM_LASER_GREEN,                   GADGET_ID_NONE,
4042     &level.mm_laser_green,
4043     NULL, NULL,
4044     "Green",                                    "Use green color components in laser"
4045   },
4046   {
4047     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
4048     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4049     GADGET_ID_MM_LASER_BLUE,                    GADGET_ID_NONE,
4050     &level.mm_laser_blue,
4051     NULL, NULL,
4052     "Blue",                                     "Use blue color components in laser"
4053   },
4054   {
4055     ED_CHECKBUTTON_ID_DF_LASER_RED,
4056     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4057     GADGET_ID_DF_LASER_RED,                     GADGET_ID_NONE,
4058     &level.df_laser_red,
4059     "Choose color components for laser:", NULL,
4060     "Red",                                      "Use red color components in laser"
4061   },
4062   {
4063     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
4064     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4065     GADGET_ID_DF_LASER_GREEN,                   GADGET_ID_NONE,
4066     &level.df_laser_green,
4067     NULL, NULL,
4068     "Green",                                    "Use green color components in laser"
4069   },
4070   {
4071     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
4072     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4073     GADGET_ID_DF_LASER_BLUE,                    GADGET_ID_NONE,
4074     &level.df_laser_blue,
4075     NULL, NULL,
4076     "Blue",                                     "Use blue color components in laser"
4077   },
4078   {
4079     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
4080     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
4081     GADGET_ID_ROTATE_MM_BALL_CONTENT,           GADGET_ID_NONE,
4082     &level.rotate_mm_ball_content,
4083     NULL, NULL,
4084     "Randomly rotate created content",          "Randomly rotate newly created content"
4085   },
4086   {
4087     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
4088     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
4089     GADGET_ID_EXPLODE_MM_BALL,                  GADGET_ID_NONE,
4090     &level.explode_mm_ball,
4091     NULL, NULL,
4092     "Explode ball instead of melting",          "Use explosion to release ball content"
4093   },
4094
4095   // ---------- element settings: configure 1 (custom elements) ---------------
4096
4097   {
4098     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
4099     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4100     GADGET_ID_CUSTOM_USE_GRAPHIC,               GADGET_ID_NONE,
4101     &custom_element.use_gfx_element,
4102     NULL, NULL,
4103     "Use graphic of element:",                  "Use existing element graphic"
4104   },
4105   {
4106     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
4107     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
4108     GADGET_ID_CUSTOM_USE_TEMPLATE_1,            GADGET_ID_NONE,
4109     &level.use_custom_template,
4110     NULL, NULL,
4111     "Use template",                             "Use template for custom properties"
4112   },
4113   {
4114     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4115     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4116     GADGET_ID_CUSTOM_ACCESSIBLE,                GADGET_ID_NONE,
4117     &custom_element_properties[EP_ACCESSIBLE],
4118     NULL, NULL,
4119     NULL,                                       "Player can walk to or pass this field"
4120   },
4121   {
4122     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4123     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4124     GADGET_ID_CUSTOM_GRAV_REACHABLE,            GADGET_ID_NONE,
4125     &custom_element_properties[EP_GRAVITY_REACHABLE],
4126     NULL, NULL,
4127     "Reachable despite gravity",                "Player can walk/dig despite gravity"
4128   },
4129   {
4130     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4131     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4132     GADGET_ID_CUSTOM_USE_LAST_VALUE,            GADGET_ID_NONE,
4133     &custom_element.use_last_ce_value,
4134     NULL, NULL,
4135     "Use last CE value after change",           "Use last CE value after change"
4136   },
4137   {
4138     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4139     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
4140     GADGET_ID_CUSTOM_WALK_TO_OBJECT,            GADGET_ID_NONE,
4141     &custom_element_properties[EP_WALK_TO_OBJECT],
4142     NULL, NULL,
4143     NULL,                                       "Player can dig/collect/push element"
4144   },
4145   {
4146     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4147     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4148     GADGET_ID_CUSTOM_INDESTRUCTIBLE,            GADGET_ID_NONE,
4149     &custom_element_properties[EP_INDESTRUCTIBLE],
4150     NULL, NULL,
4151     "Indestructible",                           "Element is indestructible"
4152   },
4153
4154   // ---------- element settings: configure 2 (custom elements) ---------------
4155
4156   {
4157     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4158     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4159     GADGET_ID_CUSTOM_CAN_MOVE,                  GADGET_ID_NONE,
4160     &custom_element_properties[EP_CAN_MOVE],
4161     NULL, NULL,
4162     NULL,                                       "Element can move with some pattern"
4163   },
4164   {
4165     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4166     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4167     GADGET_ID_CUSTOM_CAN_FALL,                  GADGET_ID_NONE,
4168     &custom_element_properties[EP_CAN_FALL],
4169     NULL, NULL,
4170     "Can fall",                                 "Element can fall down"
4171   },
4172   {
4173     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4174     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
4175     GADGET_ID_CUSTOM_CAN_SMASH,                 GADGET_ID_CUSTOM_CAN_FALL,
4176     &custom_element_properties[EP_CAN_SMASH],
4177     NULL, " ",
4178     NULL,                                       "Element can smash other elements"
4179   },
4180   {
4181     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4182     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4183     GADGET_ID_CUSTOM_SLIPPERY,                  GADGET_ID_NONE,
4184     &custom_element_properties[EP_SLIPPERY],
4185     NULL, NULL,
4186     NULL,                                       "Other elements can fall down from it"
4187   },
4188   {
4189     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4190     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
4191     GADGET_ID_CUSTOM_DEADLY,                    GADGET_ID_NONE,
4192     &custom_element_properties[EP_DEADLY],
4193     NULL, NULL,
4194     NULL,                                       "Element can kill the player"
4195   },
4196   {
4197     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4198     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4199     GADGET_ID_CUSTOM_CAN_EXPLODE,               GADGET_ID_NONE,
4200     &custom_element_properties[EP_CAN_EXPLODE],
4201     NULL, NULL,
4202     NULL,                                       "Element can explode"
4203   },
4204   {
4205     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4206     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(12),
4207     GADGET_ID_CUSTOM_EXPLODE_FIRE,              GADGET_ID_NONE,
4208     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4209     NULL, NULL,
4210     "By fire",                                  "Element can explode by fire/explosion"
4211   },
4212   {
4213     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4214     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4215     GADGET_ID_CUSTOM_EXPLODE_SMASH,             GADGET_ID_CUSTOM_EXPLODE_FIRE,
4216     &custom_element_properties[EP_EXPLODES_SMASHED],
4217     NULL, " ",
4218     "Smashed",                                  "Element can explode when smashed"
4219   },
4220   {
4221     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4222     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4223     GADGET_ID_CUSTOM_EXPLODE_IMPACT,            GADGET_ID_CUSTOM_EXPLODE_SMASH,
4224     &custom_element_properties[EP_EXPLODES_IMPACT],
4225     NULL, " ",
4226     "Impact",                                   "Element can explode on impact"
4227   },
4228
4229   // ---------- element settings: advanced (custom elements) ------------------
4230
4231   {
4232     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4233     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4234     GADGET_ID_CUSTOM_CAN_CHANGE,                GADGET_ID_NONE,
4235     &custom_element_change.can_change,
4236     NULL, NULL,
4237     "Element changes to:",                      "Change element on specified condition"
4238   },
4239   {
4240     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4241     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
4242     GADGET_ID_CHANGE_DELAY,                     GADGET_ID_NONE,
4243     &custom_element_change_events[CE_DELAY],
4244     NULL, NULL,
4245     NULL,                                       "Element changes after delay"
4246   },
4247   {
4248     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4249     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
4250     GADGET_ID_CHANGE_BY_DIRECT_ACT,             GADGET_ID_NONE,
4251     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4252     NULL, NULL,
4253     NULL,                                       "Element changes by direct action"
4254   },
4255   {
4256     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4257     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
4258     GADGET_ID_CHANGE_BY_OTHER_ACT,              GADGET_ID_NONE,
4259     &custom_element_change_events[CE_BY_OTHER_ACTION],
4260     NULL, NULL,
4261     NULL,                                       "Element changes by other element"
4262   },
4263   {
4264     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4265     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(8),
4266     GADGET_ID_CHANGE_USE_EXPLOSION,             GADGET_ID_NONE,
4267     &custom_element_change.explode,
4268     NULL, NULL,
4269     "Explode instead of change",                "Element explodes instead of change"
4270   },
4271   {
4272     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4273     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
4274     GADGET_ID_CHANGE_USE_CONTENT,               GADGET_ID_NONE,
4275     &custom_element_change.use_target_content,
4276     NULL, NULL,
4277     "Use extended change target:",              "Element changes to more elements"
4278   },
4279   {
4280     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4281     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(11),
4282     GADGET_ID_CHANGE_ONLY_COMPLETE,             GADGET_ID_NONE,
4283     &custom_element_change.only_if_complete,
4284     NULL, NULL,
4285     "Replace all or nothing",                   "Only replace when all can be changed"
4286   },
4287   {
4288     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4289     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(12),
4290     GADGET_ID_CHANGE_USE_RANDOM,                GADGET_ID_NONE,
4291     &custom_element_change.use_random_replace,
4292     NULL, NULL,
4293     NULL,                                       "Use percentage for random replace"
4294   },
4295   {
4296     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4297     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
4298     GADGET_ID_CHANGE_HAS_ACTION,                GADGET_ID_NONE,
4299     &custom_element_change.has_action,
4300     NULL, NULL,
4301     NULL,                                       "Execute action on specified condition"
4302   },
4303 };
4304
4305 static struct
4306 {
4307   int gadget_type_id;
4308   int x, y;
4309   int xoffset, yoffset;
4310   int gadget_id;
4311   int gadget_id_align;
4312   int *value;
4313   int area_xsize, area_ysize;
4314   char *text_left, *text_right, *text_above, *text_below, *infotext;
4315 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4316 {
4317   // ---------- level playfield content ---------------------------------------
4318
4319   {
4320     ED_DRAWING_ID_DRAWING_LEVEL,
4321     0,                                          0,
4322     0,                                          0,
4323     GADGET_ID_DRAWING_LEVEL,                    GADGET_ID_NONE,
4324     NULL,
4325     -1, -1,     // these values are not constant, but can change at runtime
4326     NULL, NULL, NULL, NULL,                     NULL
4327   },
4328
4329   // ---------- yam yam content -----------------------------------------------
4330
4331   {
4332     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4333     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4334     ED_AREA_YAMYAM_CONTENT_XOFF(0),             ED_AREA_YAMYAM_CONTENT_YOFF(0),
4335     GADGET_ID_YAMYAM_CONTENT_0,                 GADGET_ID_NONE,
4336     &level.yamyam_content[0].e[0][0],           3, 3,
4337     NULL, NULL, NULL, "1",                      NULL
4338   },
4339   {
4340     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4341     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4342     ED_AREA_YAMYAM_CONTENT_XOFF(1),             ED_AREA_YAMYAM_CONTENT_YOFF(1),
4343     GADGET_ID_YAMYAM_CONTENT_1,                 GADGET_ID_NONE,
4344     &level.yamyam_content[1].e[0][0],           3, 3,
4345     NULL, NULL, NULL, "2",                      NULL
4346   },
4347   {
4348     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4349     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4350     ED_AREA_YAMYAM_CONTENT_XOFF(2),             ED_AREA_YAMYAM_CONTENT_YOFF(2),
4351     GADGET_ID_YAMYAM_CONTENT_2,                 GADGET_ID_NONE,
4352     &level.yamyam_content[2].e[0][0],           3, 3,
4353     NULL, NULL, NULL, "3",                      NULL
4354   },
4355   {
4356     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4357     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4358     ED_AREA_YAMYAM_CONTENT_XOFF(3),             ED_AREA_YAMYAM_CONTENT_YOFF(3),
4359     GADGET_ID_YAMYAM_CONTENT_3,                 GADGET_ID_NONE,
4360     &level.yamyam_content[3].e[0][0],           3, 3,
4361     NULL, NULL, NULL, "4",                      NULL
4362   },
4363   {
4364     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4365     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4366     ED_AREA_YAMYAM_CONTENT_XOFF(4),             ED_AREA_YAMYAM_CONTENT_YOFF(4),
4367     GADGET_ID_YAMYAM_CONTENT_4,                 GADGET_ID_NONE,
4368     &level.yamyam_content[4].e[0][0],           3, 3,
4369     NULL, NULL, NULL, "5",                      NULL
4370   },
4371   {
4372     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4373     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4374     ED_AREA_YAMYAM_CONTENT_XOFF(5),             ED_AREA_YAMYAM_CONTENT_YOFF(5),
4375     GADGET_ID_YAMYAM_CONTENT_5,                 GADGET_ID_NONE,
4376     &level.yamyam_content[5].e[0][0],           3, 3,
4377     NULL, NULL, NULL, "6",                      NULL
4378   },
4379   {
4380     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4381     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4382     ED_AREA_YAMYAM_CONTENT_XOFF(6),             ED_AREA_YAMYAM_CONTENT_YOFF(6),
4383     GADGET_ID_YAMYAM_CONTENT_6,                 GADGET_ID_NONE,
4384     &level.yamyam_content[6].e[0][0],           3, 3,
4385     NULL, NULL, NULL, "7",                      NULL
4386   },
4387   {
4388     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4389     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4390     ED_AREA_YAMYAM_CONTENT_XOFF(7),             ED_AREA_YAMYAM_CONTENT_YOFF(7),
4391     GADGET_ID_YAMYAM_CONTENT_7,                 GADGET_ID_NONE,
4392     &level.yamyam_content[7].e[0][0],           3, 3,
4393     NULL, NULL, NULL, "8",                      NULL
4394   },
4395
4396   // ---------- magic ball content --------------------------------------------
4397
4398   {
4399     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4400     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4401     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4402     GADGET_ID_MAGIC_BALL_CONTENT_0,             GADGET_ID_NONE,
4403     &level.ball_content[0].e[0][0],             3, 3,
4404     NULL, NULL, NULL, "1",                      NULL
4405   },
4406   {
4407     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4408     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4409     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4410     GADGET_ID_MAGIC_BALL_CONTENT_1,             GADGET_ID_NONE,
4411     &level.ball_content[1].e[0][0],             3, 3,
4412     NULL, NULL, NULL, "2",                      NULL
4413   },
4414   {
4415     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4416     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4417     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4418     GADGET_ID_MAGIC_BALL_CONTENT_2,             GADGET_ID_NONE,
4419     &level.ball_content[2].e[0][0],             3, 3,
4420     NULL, NULL, NULL, "3",                      NULL
4421   },
4422   {
4423     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4424     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4425     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4426     GADGET_ID_MAGIC_BALL_CONTENT_3,             GADGET_ID_NONE,
4427     &level.ball_content[3].e[0][0],             3, 3,
4428     NULL, NULL, NULL, "4",                      NULL
4429   },
4430   {
4431     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4432     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4433     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4434     GADGET_ID_MAGIC_BALL_CONTENT_4,             GADGET_ID_NONE,
4435     &level.ball_content[4].e[0][0],             3, 3,
4436     NULL, NULL, NULL, "5",                      NULL
4437   },
4438   {
4439     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4440     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4441     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4442     GADGET_ID_MAGIC_BALL_CONTENT_5,             GADGET_ID_NONE,
4443     &level.ball_content[5].e[0][0],             3, 3,
4444     NULL, NULL, NULL, "6",                      NULL
4445   },
4446   {
4447     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4448     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4449     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4450     GADGET_ID_MAGIC_BALL_CONTENT_6,             GADGET_ID_NONE,
4451     &level.ball_content[6].e[0][0],             3, 3,
4452     NULL, NULL, NULL, "7",                      NULL
4453   },
4454   {
4455     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4456     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4457     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4458     GADGET_ID_MAGIC_BALL_CONTENT_7,             GADGET_ID_NONE,
4459     &level.ball_content[7].e[0][0],             3, 3,
4460     NULL, NULL, NULL, "8",                      NULL
4461   },
4462
4463   // ---------- android content -----------------------------------------------
4464
4465   {
4466     ED_DRAWING_ID_ANDROID_CONTENT,
4467     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4468     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4469     GADGET_ID_ANDROID_CONTENT,                  GADGET_ID_NONE,
4470     &level.android_clone_element[0],            MAX_ANDROID_ELEMENTS, 1,
4471     NULL, NULL, "Elements:", NULL,              "Elements android can clone"
4472   },
4473
4474   // ---------- amoeba content ------------------------------------------------
4475
4476   {
4477     ED_DRAWING_ID_AMOEBA_CONTENT,
4478     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4479     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4480     GADGET_ID_AMOEBA_CONTENT,                   GADGET_ID_NONE,
4481     &level.amoeba_content,                      1, 1,
4482     "Content:", NULL, NULL, NULL,               "Amoeba content"
4483   },
4484
4485   // ---------- BD snap element -----------------------------------------------
4486
4487   {
4488     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4489     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4490     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4491     GADGET_ID_BD_SNAP_ELEMENT,                  GADGET_ID_NONE,
4492     &level.bd_snap_element,                     1, 1,
4493     "Snap element:", NULL, NULL, NULL,          "Element created when snapping"
4494   },
4495
4496   // ---------- BD magic wall elements ----------------------------------------
4497
4498   {
4499     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4500     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4501     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4502     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,         GADGET_ID_NONE,
4503     &level.bd_magic_wall_diamond_to,            1, 1,
4504     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4505   },
4506   {
4507     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4508     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4509     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4510     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,            GADGET_ID_NONE,
4511     &level.bd_magic_wall_rock_to,               1, 1,
4512     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4513   },
4514   {
4515     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4516     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4517     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4518     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,       GADGET_ID_NONE,
4519     &level.bd_magic_wall_mega_rock_to,          1, 1,
4520     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4521   },
4522   {
4523     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4524     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(9),
4525     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4526     GADGET_ID_BD_MAGIC_WALL_NUT_TO,             GADGET_ID_NONE,
4527     &level.bd_magic_wall_nut_to,                1, 1,
4528     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4529   },
4530   {
4531     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4532     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4533     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4534     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,      GADGET_ID_NONE,
4535     &level.bd_magic_wall_nitro_pack_to,         1, 1,
4536     "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
4537   },
4538   {
4539     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4540     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4541     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4542     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,  GADGET_ID_NONE,
4543     &level.bd_magic_wall_flying_diamond_to,     1, 1,
4544     "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
4545   },
4546   {
4547     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4548     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(12),
4549     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4550     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,     GADGET_ID_NONE,
4551     &level.bd_magic_wall_flying_rock_to,        1, 1,
4552     "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
4553   },
4554
4555   // ---------- BD amoeba content ---------------------------------------------
4556
4557   {
4558     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4559     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4560     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4561     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,        GADGET_ID_NONE,
4562     &level.bd_amoeba_content_too_big,           1, 1,
4563     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba content if too big"
4564   },
4565   {
4566     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4567     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4568     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4569     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,       GADGET_ID_NONE,
4570     &level.bd_amoeba_content_enclosed,          1, 1,
4571     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba content if enclosed"
4572   },
4573
4574   // ---------- BD amoeba 2 content -------------------------------------------
4575
4576   {
4577     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4578     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4579     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4580     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,      GADGET_ID_NONE,
4581     &level.bd_amoeba_2_content_too_big,         1, 1,
4582     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if too big"
4583   },
4584   {
4585     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4586     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4587     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4588     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,     GADGET_ID_NONE,
4589     &level.bd_amoeba_2_content_enclosed,        1, 1,
4590     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if enclosed"
4591   },
4592   {
4593     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4594     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4595     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4596     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,    GADGET_ID_NONE,
4597     &level.bd_amoeba_2_content_exploding,       1, 1,
4598     "If exploding, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if exploding"
4599   },
4600   {
4601     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4602     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4603     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4604     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4605     &level.bd_amoeba_2_content_looks_like,      1, 1,
4606     "Use graphic of element:", NULL, NULL, NULL, "BD amoeba 2 looks like this element"
4607   },
4608   {
4609     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4610     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4611     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4612     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,          GADGET_ID_NONE,
4613     &level.bd_slime_eats_element_1,             1, 1,
4614     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4615   },
4616   {
4617     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4618     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4619     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4620     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4621     &level.bd_slime_converts_to_element_1,      1, 1,
4622     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4623   },
4624   {
4625     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4626     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4627     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4628     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,          GADGET_ID_NONE,
4629     &level.bd_slime_eats_element_2,             1, 1,
4630     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4631   },
4632   {
4633     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4634     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4635     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4636     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4637     &level.bd_slime_converts_to_element_2,      1, 1,
4638     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4639   },
4640   {
4641     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4642     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4643     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4644     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,          GADGET_ID_NONE,
4645     &level.bd_slime_eats_element_3,             1, 1,
4646     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4647   },
4648   {
4649     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4650     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4651     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4652     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4653     &level.bd_slime_converts_to_element_3,      1, 1,
4654     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4655   },
4656   {
4657     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4658     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4659     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4660     GADGET_ID_BD_ACID_EATS_ELEMENT,             GADGET_ID_NONE,
4661     &level.bd_acid_eats_element,                1, 1,
4662     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4663   },
4664   {
4665     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4666     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4667     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4668     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,         GADGET_ID_NONE,
4669     &level.bd_acid_turns_to_element,            1, 1,
4670     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4671   },
4672   {
4673     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4674     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4675     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4676     GADGET_ID_BD_BITER_EATS_ELEMENT,            GADGET_ID_NONE,
4677     &level.bd_biter_eats_element,               1, 1,
4678     "Can eat:", NULL, NULL, NULL,               "Eats this element when moving"
4679   },
4680   {
4681     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4682     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4683     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4684     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
4685     &level.bd_bladder_converts_by_element,      1, 1,
4686     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
4687   },
4688   {
4689     ED_DRAWING_ID_BD_NUT_CONTENT,
4690     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4691     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4692     GADGET_ID_BD_NUT_CONTENT,                   GADGET_ID_NONE,
4693     &level.bd_nut_content,                      1, 1,
4694     "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
4695   },
4696   {
4697     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4698     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4699     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4700     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,     GADGET_ID_NONE,
4701     &level.bd_expanding_wall_looks_like,        1, 1,
4702     "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
4703   },
4704   {
4705     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4706     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4707     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4708     GADGET_ID_BD_SAND_LOOKS_LIKE,               GADGET_ID_NONE,
4709     &level.bd_sand_looks_like,                  1, 1,
4710     "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
4711   },
4712   {
4713     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
4714     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4715     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4716     GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,      GADGET_ID_NONE,
4717     &level.bd_rock_turns_to_on_falling,         1, 1,
4718     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4719   },
4720   {
4721     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
4722     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4723     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4724     GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,       GADGET_ID_NONE,
4725     &level.bd_rock_turns_to_on_impact,          1, 1,
4726     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4727   },
4728   {
4729     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
4730     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4731     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4732     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,   GADGET_ID_NONE,
4733     &level.bd_diamond_turns_to_on_falling,      1, 1,
4734     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4735   },
4736   {
4737     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
4738     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4739     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4740     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,    GADGET_ID_NONE,
4741     &level.bd_diamond_turns_to_on_impact,       1, 1,
4742     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4743   },
4744   {
4745     ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO,
4746     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4747     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4748     GADGET_ID_BD_FIREFLY_EXPLODES_TO,           GADGET_ID_NONE,
4749     &level.bd_firefly_explodes_to,              1, 1,
4750     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4751   },
4752   {
4753     ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
4754     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4755     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4756     GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,         GADGET_ID_NONE,
4757     &level.bd_firefly_2_explodes_to,            1, 1,
4758     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4759   },
4760   {
4761     ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO,
4762     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4763     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4764     GADGET_ID_BD_BUTTERFLY_EXPLODES_TO,         GADGET_ID_NONE,
4765     &level.bd_butterfly_explodes_to,            1, 1,
4766     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4767   },
4768   {
4769     ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
4770     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4771     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4772     GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,       GADGET_ID_NONE,
4773     &level.bd_butterfly_2_explodes_to,          1, 1,
4774     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4775   },
4776   {
4777     ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
4778     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4779     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4780     GADGET_ID_BD_STONEFLY_EXPLODES_TO,          GADGET_ID_NONE,
4781     &level.bd_stonefly_explodes_to,             1, 1,
4782     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4783   },
4784   {
4785     ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
4786     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4787     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4788     GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,         GADGET_ID_NONE,
4789     &level.bd_dragonfly_explodes_to,            1, 1,
4790     "Explodes to:", NULL, NULL, NULL,           "Changes to this when exploding"
4791   },
4792   {
4793     ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
4794     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4795     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4796     GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,        GADGET_ID_NONE,
4797     &level.bd_diamond_birth_turns_to,           1, 1,
4798     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4799   },
4800   {
4801     ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
4802     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4803     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4804     GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,       GADGET_ID_NONE,
4805     &level.bd_bomb_explosion_turns_to,          1, 1,
4806     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4807   },
4808   {
4809     ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
4810     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4811     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4812     GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,      GADGET_ID_NONE,
4813     &level.bd_nitro_explosion_turns_to,         1, 1,
4814     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4815   },
4816   {
4817     ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
4818     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4819     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4820     GADGET_ID_BD_EXPLOSION_TURNS_TO,            GADGET_ID_NONE,
4821     &level.bd_explosion_turns_to,               1, 1,
4822     "Explosion ends in:", NULL, NULL, NULL,     "Changes to this after explosion"
4823   },
4824
4825   // ---------- level start element -------------------------------------------
4826
4827   {
4828     ED_DRAWING_ID_START_ELEMENT,
4829     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(10),
4830     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4831     GADGET_ID_START_ELEMENT,                    GADGET_ID_USE_START_ELEMENT,
4832     &level.start_element[0],                    1, 1,
4833     NULL, NULL, NULL, NULL,                     "Level start element"
4834   },
4835
4836   // ---------- player artwork element ----------------------------------------
4837
4838   {
4839     ED_DRAWING_ID_ARTWORK_ELEMENT,
4840     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(11),
4841     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4842     GADGET_ID_ARTWORK_ELEMENT,                  GADGET_ID_USE_ARTWORK_ELEMENT,
4843     &level.artwork_element[0],                  1, 1,
4844     NULL, NULL, NULL, NULL,                     "Element for player artwork"
4845   },
4846
4847   // ---------- player explosion element --------------------------------------
4848
4849   {
4850     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4851     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(12),
4852     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4853     GADGET_ID_EXPLOSION_ELEMENT,                GADGET_ID_USE_EXPLOSION_ELEMENT,
4854     &level.explosion_element[0],                1, 1,
4855     NULL, NULL, NULL, NULL,                     "Element for player explosion"
4856   },
4857
4858   // ---------- player initial inventory --------------------------------------
4859
4860   {
4861     ED_DRAWING_ID_INVENTORY_CONTENT,
4862     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4863     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4864     GADGET_ID_INVENTORY_CONTENT,                GADGET_ID_USE_INITIAL_INVENTORY,
4865     &level.initial_inventory_content[0][0],     MAX_INITIAL_INVENTORY_SIZE, 1,
4866     NULL, NULL, NULL, NULL,                     "Content for initial inventory"
4867   },
4868
4869   // ---------- gray ball content -----------------------------------------
4870
4871   {
4872     ED_DRAWING_ID_MM_BALL_CONTENT,
4873     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4874     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4875     GADGET_ID_MM_BALL_CONTENT,                  GADGET_ID_NONE,
4876     &level.mm_ball_content[0],                  MAX_MM_BALL_CONTENTS, 1,
4877     "Content:", NULL, NULL, NULL,               "Content for gray ball"
4878   },
4879
4880   // ---------- element settings: configure 1 (custom elements) ---------------
4881
4882   // ---------- custom graphic ------------------------------------------------
4883
4884   {
4885     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4886     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4887     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4888     GADGET_ID_CUSTOM_GRAPHIC,                   GADGET_ID_CUSTOM_USE_GRAPHIC,
4889     &custom_element.gfx_element_initial,        1, 1,
4890     NULL, NULL, NULL, NULL,                     "Custom graphic element"
4891   },
4892
4893   // ---------- element settings: configure 2 (custom elements) ---------------
4894
4895   // ---------- custom content (when exploding) -------------------------------
4896
4897   {
4898     ED_DRAWING_ID_CUSTOM_CONTENT,
4899     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(11),
4900     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4901     GADGET_ID_CUSTOM_CONTENT,                   GADGET_ID_NONE,         // align three rows
4902     &custom_element.content.e[0][0],            3, 3,
4903     "Content:", NULL, NULL, NULL,               NULL
4904   },
4905
4906   // ---------- custom enter and leave element (when moving) ------------------
4907
4908   {
4909     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4910     ED_AREA_1X1_SETTINGS_XPOS(1),               ED_AREA_1X1_SETTINGS_YPOS(3),
4911     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4912     GADGET_ID_CUSTOM_MOVE_ENTER,                GADGET_ID_NONE,
4913     &custom_element.move_enter_element,         1, 1,
4914     "Can dig:", " ", NULL, NULL,                "Element that can be digged/collected"
4915   },
4916   {
4917     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4918     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(3),
4919     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4920     GADGET_ID_CUSTOM_MOVE_LEAVE,                GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4921     &custom_element.move_leave_element,         1, 1,
4922     NULL, NULL, NULL, NULL,                     "Element that will be left behind"
4923   },
4924
4925   // ---------- element settings: advanced (custom elements) ------------------
4926
4927   // ---------- custom change target ------------------------------------------
4928
4929   {
4930     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4931     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4932     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4933     GADGET_ID_CUSTOM_CHANGE_TARGET,             GADGET_ID_CUSTOM_CAN_CHANGE,
4934     &custom_element_change.target_element,      1, 1,
4935     NULL, "after/when:", NULL, NULL,            "New target element after change"
4936   },
4937
4938   // ---------- custom change content (extended change target) ----------------
4939
4940   {
4941     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4942     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(9),
4943     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4944     GADGET_ID_CUSTOM_CHANGE_CONTENT,            GADGET_ID_NONE,         // align three rows
4945     &custom_element_change.target_content.e[0][0], 3, 3,
4946     NULL, NULL, NULL, NULL,                     "New extended elements after change"
4947   },
4948
4949   // ---------- custom change trigger (element causing change) ----------------
4950
4951   {
4952     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4953     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(5),
4954     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4955     GADGET_ID_CUSTOM_CHANGE_TRIGGER,            GADGET_ID_CHANGE_OTHER_ACTION,
4956     &custom_element_change.initial_trigger_element, 1, 1,
4957     NULL, NULL, NULL, NULL,                     "Other element triggering change"
4958   },
4959
4960   // ---------- custom change action (element used for action) ----------------
4961
4962   {
4963     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4964     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(13),
4965     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4966     GADGET_ID_CUSTOM_CHANGE_ACTION,             GADGET_ID_ACTION_ARG,
4967     &custom_element_change.action_element,      1, 1,
4968     NULL, NULL, NULL, NULL,                     "Element used as action parameter"
4969   },
4970
4971   // ---------- group element content -----------------------------------------
4972
4973   {
4974     ED_DRAWING_ID_GROUP_CONTENT,
4975     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4976     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4977     GADGET_ID_GROUP_CONTENT,                    GADGET_ID_NONE,
4978     &group_element_info.element[0],             MAX_ELEMENTS_IN_GROUP, 1,
4979     "Content:", NULL, NULL, NULL,               NULL
4980   },
4981
4982   // ---------- random background (for random painting) -----------------------
4983
4984   {
4985     ED_DRAWING_ID_RANDOM_BACKGROUND,
4986     -1,                                         ED_AREA_1X1_LSETTINGS_YPOS(1),
4987     0,                                          ED_AREA_1X1_LSETTINGS_YOFF,
4988     GADGET_ID_RANDOM_BACKGROUND,                GADGET_ID_RANDOM_RESTRICTED,
4989     &random_placement_background_element,       1, 1,
4990     NULL, NULL, NULL, NULL,                     "Random placement background"
4991   },
4992 };
4993
4994
4995 // ----------------------------------------------------------------------------
4996 // some internally used variables
4997 // ----------------------------------------------------------------------------
4998
4999 // maximal size of level editor drawing area
5000 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
5001
5002 // actual size of level editor drawing area
5003 static int ed_fieldx, ed_fieldy;
5004
5005 // actual position of level editor drawing area in level playfield
5006 static int level_xpos = -1, level_ypos = -1;
5007
5008 // actual tile size used to display playfield drawing area
5009 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
5010 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
5011
5012 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
5013
5014 // drawing elements on the three mouse buttons
5015 static int new_element1 = EL_WALL;
5016 static int new_element2 = EL_EMPTY;
5017 static int new_element3 = EL_SAND;
5018
5019 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
5020 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
5021                                 (button) == 2 ? new_element2 : \
5022                                 (button) == 3 ? new_element3 : EL_EMPTY)
5023
5024 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
5025
5026 static int use_permanent_palette = TRUE;
5027
5028 #define PX              (use_permanent_palette ? DX : SX)
5029 #define PY              (use_permanent_palette ? DY : SY)
5030 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
5031 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
5032
5033 // forward declaration for internal use
5034 static void CopyBrushToCursor(int, int);
5035 static void DeleteBrushFromCursor(void);
5036 static void ModifyEditorCounterValue(int, int);
5037 static void ModifyEditorCounterLimits(int, int, int);
5038 static void ModifyEditorSelectboxValue(int, int);
5039 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
5040 static void ModifyEditorDrawingArea(int, int, int);
5041 static void ModifyEditorElementList(void);
5042 static void AdjustElementListScrollbar(void);
5043 static void RedrawDrawingElements(void);
5044 static void DrawDrawingWindowExt(boolean);
5045 static void DrawDrawingWindow(void);
5046 static void DrawLevelConfigWindow(void);
5047 static void DrawPropertiesWindow(void);
5048 static void DrawPaletteWindow(void);
5049 static void UpdateCustomElementGraphicGadgets(void);
5050 static boolean checkPropertiesConfig(int);
5051 static void SetAutomaticNumberOfGemsNeeded(void);
5052 static void ClearEditorGadgetInfoText(void);
5053 static void CopyLevelToUndoBuffer(int);
5054 static void HandleDrawingAreas(struct GadgetInfo *);
5055 static void HandleCounterButtons(struct GadgetInfo *);
5056 static void HandleTextInputGadgets(struct GadgetInfo *);
5057 static void HandleTextAreaGadgets(struct GadgetInfo *);
5058 static void HandleSelectboxGadgets(struct GadgetInfo *);
5059 static void HandleTextbuttonGadgets(struct GadgetInfo *);
5060 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
5061 static void HandleRadiobuttons(struct GadgetInfo *);
5062 static void HandleCheckbuttons(struct GadgetInfo *);
5063 static void HandleControlButtons(struct GadgetInfo *);
5064 static void HandleDrawingAreaInfo(struct GadgetInfo *);
5065 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
5066 static boolean AskToCopyAndModifyLevelTemplate(void);
5067 static boolean getDrawModeHiRes(void);
5068 static int getTabulatorBarWidth(void);
5069 static int getTabulatorBarHeight(void);
5070 static Pixel getTabulatorBarColor(void);
5071 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
5072 static int numHiresTiles(int);
5073
5074 static int num_editor_gadgets = 0;      // dynamically determined
5075
5076 static struct GadgetInfo **level_editor_gadget = NULL;
5077 static int *right_gadget_border = NULL;
5078
5079 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
5080 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
5081 static boolean draw_with_brush = FALSE;
5082 static int properties_element = 0;
5083
5084 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5085 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5086 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
5087 static int undo_buffer_position = 0;
5088 static int undo_buffer_steps = 0;
5089 static int redo_buffer_steps = 0;
5090
5091 static int edit_mode;
5092 static int edit_mode_levelconfig;
5093 static int edit_mode_properties;
5094
5095 static int element_shift = 0;
5096
5097 static int editor_el_players[] =
5098 {
5099   EL_PLAYER_1,
5100   EL_PLAYER_2,
5101   EL_PLAYER_3,
5102   EL_PLAYER_4
5103 };
5104 static int *editor_el_players_ptr = editor_el_players;
5105 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
5106
5107 static int editor_hl_boulderdash[] =
5108 {
5109   EL_INTERNAL_CASCADE_BD_ACTIVE,
5110   EL_CHAR('B'),
5111   EL_CHAR('D'),
5112   EL_EMPTY,
5113 };
5114
5115 static int editor_el_boulderdash[] =
5116 {
5117   EL_EMPTY,
5118   EL_SAND,
5119   EL_BD_ROCK,
5120   EL_BD_DIAMOND,
5121
5122   EL_STEELWALL,
5123   EL_BD_WALL,
5124   EL_BD_EXPANDABLE_WALL,
5125   EL_BD_MAGIC_WALL,
5126
5127   EL_BD_AMOEBA,
5128   EL_BD_BUTTERFLY_UP,
5129   EL_BD_FIREFLY_UP,
5130   EL_EXIT_CLOSED,
5131
5132   EL_BD_BUTTERFLY_LEFT,
5133   EL_BD_FIREFLY_LEFT,
5134   EL_BD_BUTTERFLY_RIGHT,
5135   EL_BD_FIREFLY_RIGHT,
5136
5137   EL_EMPTY,
5138   EL_BD_BUTTERFLY_DOWN,
5139   EL_BD_FIREFLY_DOWN,
5140   EL_EXIT_OPEN,
5141 };
5142 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
5143 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
5144 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
5145 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
5146
5147 static int editor_hl_boulderdash_native[] =
5148 {
5149   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
5150   EL_CHAR('B'),
5151   EL_CHAR('D'),
5152   EL_EMPTY,
5153 };
5154
5155 static int editor_el_boulderdash_native[] =
5156 {
5157   EL_EMPTY,
5158   EL_BD_SAND,
5159   EL_BD_ROCK,
5160   EL_BD_DIAMOND,
5161
5162   EL_BD_INBOX,
5163   EL_BD_STEELWALL,
5164   EL_BD_WALL,
5165   EL_BD_MAGIC_WALL,
5166
5167   EL_BD_AMOEBA,
5168   EL_BD_BUTTERFLY_UP,
5169   EL_BD_FIREFLY_UP,
5170   EL_BD_EXIT_CLOSED,
5171
5172   EL_BD_BUTTERFLY_LEFT,
5173   EL_BD_FIREFLY_LEFT,
5174   EL_BD_BUTTERFLY_RIGHT,
5175   EL_BD_FIREFLY_RIGHT,
5176
5177   EL_BD_SAND_2,
5178   EL_BD_BUTTERFLY_DOWN,
5179   EL_BD_FIREFLY_DOWN,
5180   EL_BD_EXIT_OPEN,
5181
5182   EL_BD_AMOEBA_2,
5183   EL_BD_BUTTERFLY_2_UP,
5184   EL_BD_FIREFLY_2_UP,
5185   EL_BD_SLIME,
5186
5187   EL_BD_BUTTERFLY_2_LEFT,
5188   EL_BD_FIREFLY_2_LEFT,
5189   EL_BD_BUTTERFLY_2_RIGHT,
5190   EL_BD_FIREFLY_2_RIGHT,
5191
5192   EL_BD_BOMB,
5193   EL_BD_BUTTERFLY_2_DOWN,
5194   EL_BD_FIREFLY_2_DOWN,
5195   EL_BD_FLYING_DIAMOND,
5196
5197   EL_BD_NITRO_PACK,
5198   EL_BD_DRAGONFLY_UP,
5199   EL_BD_STONEFLY_UP,
5200   EL_BD_DIAMOND_GLUED,
5201
5202   EL_BD_DRAGONFLY_LEFT,
5203   EL_BD_STONEFLY_LEFT,
5204   EL_BD_DRAGONFLY_RIGHT,
5205   EL_BD_STONEFLY_RIGHT,
5206
5207   EL_BD_NUT,
5208   EL_BD_DRAGONFLY_DOWN,
5209   EL_BD_STONEFLY_DOWN,
5210   EL_EMPTY,
5211
5212   EL_BD_BITER_SWITCH_1,
5213   EL_BD_BITER_UP,
5214   EL_BD_COW_UP,
5215   EL_EMPTY,
5216
5217   EL_BD_BITER_LEFT,
5218   EL_BD_COW_LEFT,
5219   EL_BD_BITER_RIGHT,
5220   EL_BD_COW_RIGHT,
5221
5222   EL_BD_VOODOO_DOLL,
5223   EL_BD_BITER_DOWN,
5224   EL_BD_COW_DOWN,
5225   EL_BD_GHOST,
5226
5227   EL_BD_SAND_GLUED,
5228   EL_BD_SAND_BALL,
5229   EL_BD_SAND_LOOSE,
5230   EL_BD_WALL_NON_SLOPED,
5231
5232   EL_BD_SAND_SLOPED_UP_LEFT,
5233   EL_BD_SAND_SLOPED_UP_RIGHT,
5234   EL_BD_WALL_SLOPED_UP_LEFT,
5235   EL_BD_WALL_SLOPED_UP_RIGHT,
5236
5237   EL_BD_SAND_SLOPED_DOWN_LEFT,
5238   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5239   EL_BD_WALL_SLOPED_DOWN_LEFT,
5240   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5241
5242   EL_BD_FLYING_ROCK,
5243   EL_BD_ROCK_GLUED,
5244   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5245   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5246
5247   EL_BD_WAITING_ROCK,
5248   EL_BD_CHASING_ROCK,
5249   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5250   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5251
5252   EL_BD_MEGA_ROCK,
5253   EL_BD_SWEET,
5254   EL_BD_INVISIBLE_EXIT_CLOSED,
5255   EL_BD_INVISIBLE_EXIT_OPEN,
5256
5257   EL_BD_STEELWALL_EXPLODABLE,
5258   EL_BD_STEELWALL_DIGGABLE,
5259   EL_BD_WALL_DIGGABLE,
5260   EL_BD_FALLING_WALL,
5261
5262   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5263   EL_BD_EXPANDABLE_WALL_VERTICAL,
5264   EL_BD_EXPANDABLE_WALL_ANY,
5265   EL_BD_EXPANDABLE_WALL_SWITCH,
5266
5267   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5268   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5269   EL_BD_EXPANDABLE_STEELWALL_ANY,
5270   EL_BD_CREATURE_SWITCH,
5271
5272   EL_BD_BLADDER,
5273   EL_BD_BLADDER_SPENDER,
5274   EL_BD_REPLICATOR,
5275   EL_BD_REPLICATOR_SWITCH,
5276
5277   EL_BD_CONVEYOR_LEFT,
5278   EL_BD_CONVEYOR_RIGHT,
5279   EL_BD_CONVEYOR_SWITCH,
5280   EL_BD_CONVEYOR_DIR_SWITCH,
5281
5282   EL_BD_CLOCK,
5283   EL_BD_TIME_PENALTY,
5284   EL_BD_GRAVESTONE,
5285   EL_BD_SKELETON,
5286
5287   EL_BD_WATER,
5288   EL_BD_ACID,
5289   EL_BD_LAVA,
5290   EL_BD_BOX,
5291
5292   EL_BD_GATE_1,
5293   EL_BD_GATE_2,
5294   EL_BD_GATE_3,
5295   EL_BD_TRAPPED_DIAMOND,
5296
5297   EL_BD_KEY_1,
5298   EL_BD_KEY_2,
5299   EL_BD_KEY_3,
5300   EL_BD_DIAMOND_KEY,
5301
5302   EL_BD_WALL_KEY_1,
5303   EL_BD_WALL_KEY_2,
5304   EL_BD_WALL_KEY_3,
5305   EL_BD_WALL_DIAMOND,
5306
5307   EL_BD_POT,
5308   EL_BD_GRAVITY_SWITCH,
5309   EL_BD_PNEUMATIC_HAMMER,
5310   EL_BD_TELEPORTER,
5311
5312   EL_BD_PLAYER,
5313   EL_BD_PLAYER_WITH_BOMB,
5314   EL_BD_PLAYER_WITH_ROCKET_LAUNCHER,
5315   EL_BD_ROCKET_LAUNCHER,
5316
5317   EL_BD_PLAYER_GLUED,
5318   EL_BD_PLAYER_STIRRING,
5319   EL_EMPTY,
5320   EL_EMPTY,
5321 };
5322 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5323 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5324 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5325 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5326
5327 static int editor_hl_boulderdash_effects[] =
5328 {
5329   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5330   EL_CHAR('B'),
5331   EL_CHAR('D'),
5332   EL_CHAR('E'),
5333 };
5334
5335 static int editor_el_boulderdash_effects[] =
5336 {
5337   EL_BD_DIAMOND_FALLING,
5338   EL_BD_ROCK_FALLING,
5339   EL_BD_MEGA_ROCK_FALLING,
5340   EL_BD_FLYING_DIAMOND_FLYING,
5341
5342   EL_BD_FALLING_WALL_FALLING,
5343   EL_BD_NITRO_PACK_FALLING,
5344   EL_BD_NUT_FALLING,
5345   EL_BD_FLYING_ROCK_FLYING,
5346
5347   EL_BD_PLAYER_GROWING_1,
5348   EL_BD_PLAYER_GROWING_2,
5349   EL_BD_PLAYER_GROWING_3,
5350   EL_BD_PLAYER,
5351
5352   EL_BD_PLAYER_WITH_BOMB,
5353   EL_BD_PLAYER_STIRRING,
5354   EL_BD_EXIT_OPEN,
5355   EL_BD_INVISIBLE_EXIT_OPEN,
5356
5357   EL_BD_BLADDER_1,
5358   EL_BD_BLADDER_2,
5359   EL_BD_BLADDER_3,
5360   EL_BD_BLADDER_4,
5361
5362   EL_BD_BLADDER_5,
5363   EL_BD_BLADDER_6,
5364   EL_BD_BLADDER_7,
5365   EL_BD_BLADDER_8,
5366
5367   EL_BD_SAND_2,
5368   EL_BD_COW_ENCLOSED_1,
5369   EL_BD_COW_ENCLOSED_2,
5370   EL_BD_COW_ENCLOSED_3,
5371
5372   EL_BD_COW_ENCLOSED_4,
5373   EL_BD_COW_ENCLOSED_5,
5374   EL_BD_COW_ENCLOSED_6,
5375   EL_BD_COW_ENCLOSED_7,
5376
5377   EL_BD_WATER_1,
5378   EL_BD_WATER_2,
5379   EL_BD_WATER_3,
5380   EL_BD_WATER_4,
5381
5382   EL_BD_WATER_5,
5383   EL_BD_WATER_6,
5384   EL_BD_WATER_7,
5385   EL_BD_WATER_8,
5386
5387   EL_BD_WATER_9,
5388   EL_BD_WATER_10,
5389   EL_BD_WATER_11,
5390   EL_BD_WATER_12,
5391
5392   EL_BD_WATER_13,
5393   EL_BD_WATER_14,
5394   EL_BD_WATER_15,
5395   EL_BD_WATER_16,
5396
5397   EL_BD_BOMB_TICKING_1,
5398   EL_BD_BOMB_TICKING_2,
5399   EL_BD_BOMB_TICKING_3,
5400   EL_BD_BOMB_TICKING_4,
5401
5402   EL_BD_BOMB_TICKING_5,
5403   EL_BD_BOMB_TICKING_6,
5404   EL_BD_BOMB_TICKING_7,
5405   EL_EMPTY,
5406
5407   EL_BD_BOMB_EXPLODING_1,
5408   EL_BD_BOMB_EXPLODING_2,
5409   EL_BD_BOMB_EXPLODING_3,
5410   EL_BD_BOMB_EXPLODING_4,
5411
5412   EL_BD_NUT_BREAKING_1,
5413   EL_BD_NUT_BREAKING_2,
5414   EL_BD_NUT_BREAKING_3,
5415   EL_BD_NUT_BREAKING_4,
5416
5417   EL_BD_EXPLODING_1,
5418   EL_BD_EXPLODING_2,
5419   EL_BD_EXPLODING_3,
5420   EL_BD_EXPLODING_4,
5421
5422   EL_BD_EXPLODING_5,
5423   EL_BD_TIME_PENALTY,
5424   EL_BD_DIAMOND_GROWING_1,
5425   EL_BD_DIAMOND_GROWING_2,
5426
5427   EL_BD_DIAMOND_GROWING_3,
5428   EL_BD_DIAMOND_GROWING_4,
5429   EL_BD_DIAMOND_GROWING_5,
5430   EL_BD_NITRO_PACK_EXPLODING,
5431
5432   EL_BD_NITRO_PACK_EXPLODING_1,
5433   EL_BD_NITRO_PACK_EXPLODING_2,
5434   EL_BD_NITRO_PACK_EXPLODING_3,
5435   EL_BD_NITRO_PACK_EXPLODING_4,
5436
5437   EL_BD_ROCK_GROWING_1,
5438   EL_BD_ROCK_GROWING_2,
5439   EL_BD_ROCK_GROWING_3,
5440   EL_BD_ROCK_GROWING_4,
5441
5442   EL_BD_STEELWALL_GROWING_1,
5443   EL_BD_STEELWALL_GROWING_2,
5444   EL_BD_STEELWALL_GROWING_3,
5445   EL_BD_STEELWALL_GROWING_4,
5446
5447   EL_BD_CLOCK_GROWING_1,
5448   EL_BD_CLOCK_GROWING_2,
5449   EL_BD_CLOCK_GROWING_3,
5450   EL_BD_CLOCK_GROWING_4,
5451
5452   EL_BD_GHOST_EXPLODING_1,
5453   EL_BD_GHOST_EXPLODING_2,
5454   EL_BD_GHOST_EXPLODING_3,
5455   EL_BD_GHOST_EXPLODING_4,
5456 };
5457 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5458 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5459 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5460 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5461
5462 static int editor_hl_emerald_mine[] =
5463 {
5464   EL_INTERNAL_CASCADE_EM_ACTIVE,
5465   EL_CHAR('E'),
5466   EL_CHAR('M'),
5467   EL_EMPTY,
5468 };
5469
5470 static int editor_el_emerald_mine[] =
5471 {
5472   EL_SAND,
5473   EL_ROCK,
5474   EL_QUICKSAND_EMPTY,
5475   EL_QUICKSAND_FULL,
5476
5477   EL_STEELWALL,
5478   EL_WALL,
5479   EL_WALL_SLIPPERY,
5480   EL_MAGIC_WALL,
5481
5482   EL_EMERALD,
5483   EL_DIAMOND,
5484   EL_NUT,
5485   EL_BOMB,
5486
5487   EL_EM_DYNAMITE,
5488   EL_EM_DYNAMITE_ACTIVE,
5489   EL_EM_EXIT_CLOSED,
5490   EL_EM_EXIT_OPEN,
5491
5492   EL_YAMYAM_UP,
5493   EL_BUG_UP,
5494   EL_SPACESHIP_UP,
5495   EL_ROBOT,
5496
5497   EL_BUG_LEFT,
5498   EL_SPACESHIP_LEFT,
5499   EL_BUG_RIGHT,
5500   EL_SPACESHIP_RIGHT,
5501
5502   EL_ROBOT_WHEEL,
5503   EL_BUG_DOWN,
5504   EL_SPACESHIP_DOWN,
5505   EL_INVISIBLE_WALL,
5506
5507   EL_ACID_POOL_TOPLEFT,
5508   EL_ACID,
5509   EL_ACID_POOL_TOPRIGHT,
5510   EL_AMOEBA_DROP,
5511
5512   EL_ACID_POOL_BOTTOMLEFT,
5513   EL_ACID_POOL_BOTTOM,
5514   EL_ACID_POOL_BOTTOMRIGHT,
5515   EL_AMOEBA_WET,
5516
5517   EL_EM_KEY_1,
5518   EL_EM_KEY_2,
5519   EL_EM_KEY_3,
5520   EL_EM_KEY_4,
5521
5522   EL_EM_GATE_1,
5523   EL_EM_GATE_2,
5524   EL_EM_GATE_3,
5525   EL_EM_GATE_4,
5526
5527   EL_EM_GATE_1_GRAY,
5528   EL_EM_GATE_2_GRAY,
5529   EL_EM_GATE_3_GRAY,
5530   EL_EM_GATE_4_GRAY,
5531 };
5532 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5533 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5534 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5535 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5536
5537 static int editor_hl_emerald_mine_club[] =
5538 {
5539   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5540   EL_CHAR('E'),
5541   EL_CHAR('M'),
5542   EL_CHAR('C'),
5543 };
5544
5545 static int editor_el_emerald_mine_club[] =
5546 {
5547   EL_EMC_KEY_5,
5548   EL_EMC_KEY_6,
5549   EL_EMC_KEY_7,
5550   EL_EMC_KEY_8,
5551
5552   EL_EMC_GATE_5,
5553   EL_EMC_GATE_6,
5554   EL_EMC_GATE_7,
5555   EL_EMC_GATE_8,
5556
5557   EL_EMC_GATE_5_GRAY,
5558   EL_EMC_GATE_6_GRAY,
5559   EL_EMC_GATE_7_GRAY,
5560   EL_EMC_GATE_8_GRAY,
5561
5562   EL_EMC_STEELWALL_1,
5563   EL_EMC_STEELWALL_2,
5564   EL_EMC_STEELWALL_3,
5565   EL_EMC_STEELWALL_4,
5566
5567   EL_EMC_WALL_13,
5568   EL_EMC_WALL_14,
5569   EL_EMC_WALL_15,
5570   EL_EMC_WALL_16,
5571
5572   EL_EMC_WALL_SLIPPERY_1,
5573   EL_EMC_WALL_SLIPPERY_2,
5574   EL_EMC_WALL_SLIPPERY_3,
5575   EL_EMC_WALL_SLIPPERY_4,
5576
5577   EL_EMC_WALL_1,
5578   EL_EMC_WALL_2,
5579   EL_EMC_WALL_3,
5580   EL_EMC_WALL_4,
5581
5582   EL_EMC_WALL_5,
5583   EL_EMC_WALL_6,
5584   EL_EMC_WALL_7,
5585   EL_EMC_WALL_8,
5586
5587   EL_EMC_WALL_9,
5588   EL_EMC_WALL_10,
5589   EL_EMC_WALL_11,
5590   EL_EMC_WALL_12,
5591
5592   EL_EMC_GRASS,
5593   EL_EMC_FAKE_GRASS,
5594   EL_EMC_PLANT,
5595   EL_EMC_DRIPPER,
5596
5597   EL_EMC_MAGIC_BALL,
5598   EL_EMC_MAGIC_BALL_SWITCH,
5599   EL_EMC_LENSES,
5600   EL_EMC_MAGNIFIER,
5601
5602   EL_SPRING_LEFT,
5603   EL_SPRING,
5604   EL_SPRING_RIGHT,
5605   EL_EMC_SPRING_BUMPER,
5606
5607   EL_BALLOON,
5608   EL_YAMYAM_UP,
5609   EL_BALLOON_SWITCH_UP,
5610   EL_BALLOON_SWITCH_ANY,
5611
5612   EL_YAMYAM_LEFT,
5613   EL_BALLOON_SWITCH_LEFT,
5614   EL_YAMYAM_RIGHT,
5615   EL_BALLOON_SWITCH_RIGHT,
5616
5617   EL_EMC_ANDROID,
5618   EL_YAMYAM_DOWN,
5619   EL_BALLOON_SWITCH_DOWN,
5620   EL_BALLOON_SWITCH_NONE,
5621 };
5622 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5623 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5624 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5625 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5626
5627 static int editor_hl_rnd[] =
5628 {
5629   EL_INTERNAL_CASCADE_RND_ACTIVE,
5630   EL_CHAR('R'),
5631   EL_CHAR('N'),
5632   EL_CHAR('D'),
5633 };
5634
5635 static int editor_el_rnd[] =
5636 {
5637   EL_DYNAMITE,                  // RND
5638   EL_DYNAMITE_ACTIVE,           // RND
5639   EL_EMPTY,
5640   EL_EMPTY,
5641
5642   EL_KEY_1,
5643   EL_KEY_2,
5644   EL_KEY_3,
5645   EL_KEY_4,
5646
5647   EL_GATE_1,
5648   EL_GATE_2,
5649   EL_GATE_3,
5650   EL_GATE_4,
5651
5652   EL_GATE_1_GRAY,
5653   EL_GATE_2_GRAY,
5654   EL_GATE_3_GRAY,
5655   EL_GATE_4_GRAY,
5656
5657   EL_ARROW_LEFT,
5658   EL_ARROW_RIGHT,
5659   EL_ARROW_UP,
5660   EL_ARROW_DOWN,
5661
5662   EL_AMOEBA_DEAD,
5663   EL_AMOEBA_DRY,
5664   EL_AMOEBA_FULL,
5665   EL_GAME_OF_LIFE,
5666
5667   EL_EMERALD_YELLOW,
5668   EL_EMERALD_RED,
5669   EL_EMERALD_PURPLE,
5670   EL_BIOMAZE,
5671
5672   EL_WALL_EMERALD_YELLOW,
5673   EL_WALL_EMERALD_RED,
5674   EL_WALL_EMERALD_PURPLE,
5675   EL_WALL_BD_DIAMOND,
5676
5677   EL_SPEED_PILL,
5678   EL_PACMAN_UP,
5679   EL_TIME_ORB_FULL,
5680   EL_TIME_ORB_EMPTY,
5681
5682   EL_PACMAN_LEFT,
5683   EL_DARK_YAMYAM,
5684   EL_PACMAN_RIGHT,
5685   EL_YAMYAM,                    // RND
5686
5687   EL_BLACK_ORB,
5688   EL_PACMAN_DOWN,
5689   EL_LAMP,
5690   EL_LAMP_ACTIVE,
5691
5692   EL_DYNABOMB_INCREASE_NUMBER,
5693   EL_DYNABOMB_INCREASE_SIZE,
5694   EL_DYNABOMB_INCREASE_POWER,
5695   EL_STONEBLOCK,
5696
5697   EL_MOLE,
5698   EL_PENGUIN,
5699   EL_PIG,
5700   EL_DRAGON,
5701
5702   EL_BUG,
5703   EL_MOLE_UP,
5704   EL_BD_BUTTERFLY,
5705   EL_BD_FIREFLY,
5706
5707   EL_MOLE_LEFT,
5708   EL_SATELLITE,
5709   EL_MOLE_RIGHT,
5710   EL_PACMAN,
5711
5712   EL_SPACESHIP,
5713   EL_MOLE_DOWN,
5714   EL_INVISIBLE_STEELWALL,
5715   EL_INVISIBLE_WALL,
5716
5717   EL_EXPANDABLE_WALL,
5718   EL_EXPANDABLE_WALL_HORIZONTAL,
5719   EL_EXPANDABLE_WALL_VERTICAL,
5720   EL_EXPANDABLE_WALL_ANY,
5721 };
5722 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5723 static int *editor_el_rnd_ptr = editor_el_rnd;
5724 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5725 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5726
5727 static int editor_hl_sokoban[] =
5728 {
5729   EL_INTERNAL_CASCADE_SB_ACTIVE,
5730   EL_CHAR('S'),
5731   EL_CHAR('B'),
5732   EL_EMPTY,
5733 };
5734
5735 static int editor_el_sokoban[] =
5736 {
5737   EL_SOKOBAN_OBJECT,
5738   EL_SOKOBAN_FIELD_EMPTY,
5739   EL_SOKOBAN_FIELD_FULL,
5740   EL_SOKOBAN_FIELD_PLAYER,
5741 };
5742 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5743 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5744 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5745 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5746
5747 static int editor_hl_supaplex[] =
5748 {
5749   EL_INTERNAL_CASCADE_SP_ACTIVE,
5750   EL_CHAR('S'),
5751   EL_CHAR('P'),
5752   EL_EMPTY,
5753 };
5754
5755 static int editor_el_supaplex[] =
5756 {
5757   EL_SP_MURPHY,
5758   EL_EMPTY,
5759   EL_SP_BASE,
5760   EL_SP_BUGGY_BASE,
5761
5762   EL_SP_INFOTRON,
5763   EL_SP_ZONK,
5764   EL_SP_SNIKSNAK,
5765   EL_SP_ELECTRON,
5766
5767   EL_SP_DISK_RED,
5768   EL_SP_DISK_ORANGE,
5769   EL_SP_DISK_YELLOW,
5770   EL_SP_TERMINAL,
5771
5772   EL_SP_EXIT_CLOSED,
5773   EL_SP_PORT_HORIZONTAL,
5774   EL_SP_PORT_VERTICAL,
5775   EL_SP_PORT_ANY,
5776
5777   EL_SP_PORT_LEFT,
5778   EL_SP_PORT_RIGHT,
5779   EL_SP_PORT_UP,
5780   EL_SP_PORT_DOWN,
5781
5782   EL_SP_GRAVITY_PORT_LEFT,
5783   EL_SP_GRAVITY_PORT_RIGHT,
5784   EL_SP_GRAVITY_PORT_UP,
5785   EL_SP_GRAVITY_PORT_DOWN,
5786
5787   EL_SP_GRAVITY_ON_PORT_LEFT,
5788   EL_SP_GRAVITY_ON_PORT_RIGHT,
5789   EL_SP_GRAVITY_ON_PORT_UP,
5790   EL_SP_GRAVITY_ON_PORT_DOWN,
5791
5792   EL_SP_GRAVITY_OFF_PORT_LEFT,
5793   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5794   EL_SP_GRAVITY_OFF_PORT_UP,
5795   EL_SP_GRAVITY_OFF_PORT_DOWN,
5796
5797   EL_SP_HARDWARE_GRAY,
5798   EL_SP_HARDWARE_GREEN,
5799   EL_SP_HARDWARE_BLUE,
5800   EL_SP_HARDWARE_RED,
5801
5802   EL_SP_HARDWARE_BASE_1,
5803   EL_SP_HARDWARE_BASE_2,
5804   EL_SP_HARDWARE_BASE_3,
5805   EL_SP_HARDWARE_BASE_4,
5806
5807   EL_SP_HARDWARE_BASE_5,
5808   EL_SP_HARDWARE_BASE_6,
5809   EL_SP_HARDWARE_YELLOW,
5810   EL_SP_CHIP_TOP,
5811
5812   EL_SP_CHIP_SINGLE,
5813   EL_SP_CHIP_LEFT,
5814   EL_SP_CHIP_RIGHT,
5815   EL_SP_CHIP_BOTTOM,
5816 };
5817 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5818 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5819 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5820 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5821
5822 static int editor_hl_diamond_caves[] =
5823 {
5824   EL_INTERNAL_CASCADE_DC_ACTIVE,
5825   EL_CHAR('D'),
5826   EL_CHAR('C'),
5827   EL_CHAR('2'),
5828 };
5829
5830 static int editor_el_diamond_caves[] =
5831 {
5832   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5833   EL_EM_STEEL_EXIT_OPEN,        // DC2
5834   EL_WALL_EMERALD,              // DC2
5835   EL_WALL_DIAMOND,              // DC2
5836
5837   EL_PEARL,
5838   EL_CRYSTAL,
5839   EL_WALL_PEARL,
5840   EL_WALL_CRYSTAL,
5841
5842   EL_CONVEYOR_BELT_1_LEFT,
5843   EL_CONVEYOR_BELT_1_MIDDLE,
5844   EL_CONVEYOR_BELT_1_RIGHT,
5845   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5846
5847   EL_CONVEYOR_BELT_2_LEFT,
5848   EL_CONVEYOR_BELT_2_MIDDLE,
5849   EL_CONVEYOR_BELT_2_RIGHT,
5850   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5851
5852   EL_CONVEYOR_BELT_3_LEFT,
5853   EL_CONVEYOR_BELT_3_MIDDLE,
5854   EL_CONVEYOR_BELT_3_RIGHT,
5855   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5856
5857   EL_CONVEYOR_BELT_4_LEFT,
5858   EL_CONVEYOR_BELT_4_MIDDLE,
5859   EL_CONVEYOR_BELT_4_RIGHT,
5860   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5861
5862   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5863   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5864   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5865   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5866
5867   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5868   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5869   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5870   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5871
5872   EL_TIMEGATE_CLOSED,
5873   EL_TIMEGATE_OPEN,
5874   EL_TIMEGATE_SWITCH,
5875   EL_DC_TIMEGATE_SWITCH,
5876
5877   EL_SWITCHGATE_CLOSED,
5878   EL_SWITCHGATE_OPEN,
5879   EL_SWITCHGATE_SWITCH_UP,
5880   EL_SWITCHGATE_SWITCH_DOWN,
5881
5882   EL_LIGHT_SWITCH,
5883   EL_LIGHT_SWITCH_ACTIVE,
5884   EL_DC_SWITCHGATE_SWITCH_UP,
5885   EL_DC_SWITCHGATE_SWITCH_DOWN,
5886
5887   EL_STEEL_EXIT_CLOSED,
5888   EL_STEEL_EXIT_OPEN,
5889   EL_STEELWALL_SLIPPERY,
5890   EL_INVISIBLE_SAND,
5891
5892   EL_QUICKSAND_FAST_EMPTY,
5893   EL_QUICKSAND_FAST_FULL,
5894   EL_LANDMINE,
5895   EL_DC_LANDMINE,
5896
5897   EL_SHIELD_NORMAL,
5898   EL_SHIELD_DEADLY,
5899   EL_EXTRA_TIME,
5900   EL_DC_MAGIC_WALL,
5901
5902   EL_ENVELOPE_1,
5903   EL_ENVELOPE_2,
5904   EL_ENVELOPE_3,
5905   EL_ENVELOPE_4,
5906
5907   EL_SIGN_RADIOACTIVITY,
5908   EL_SIGN_WHEELCHAIR,
5909   EL_SIGN_PARKING,
5910   EL_SIGN_NO_ENTRY,
5911
5912   EL_SIGN_GIVE_WAY,
5913   EL_SIGN_ENTRY_FORBIDDEN,
5914   EL_SIGN_EMERGENCY_EXIT,
5915   EL_SIGN_YIN_YANG,
5916
5917 #if 0
5918   EL_SIGN_SPERMS,
5919   EL_SIGN_BULLET,
5920   EL_SIGN_HEART,
5921   EL_SIGN_CROSS,
5922
5923   EL_SIGN_FRANKIE,
5924   EL_EMPTY,
5925   EL_EMPTY,
5926   EL_EMPTY,
5927
5928   EL_SPERMS,
5929   EL_BULLET,
5930   EL_HEART,
5931   EL_CROSS,
5932
5933   EL_FRANKIE,
5934   EL_EMPTY,
5935   EL_EMPTY,
5936   EL_EMPTY,
5937 #endif
5938
5939   EL_DC_STEELWALL_2_SINGLE,
5940   EL_DC_STEELWALL_2_TOP,
5941   EL_SIGN_EXCLAMATION,
5942   EL_SIGN_STOP,
5943
5944   EL_DC_STEELWALL_2_LEFT,
5945   EL_DC_STEELWALL_2_MIDDLE,
5946   EL_DC_STEELWALL_2_HORIZONTAL,
5947   EL_DC_STEELWALL_2_RIGHT,
5948
5949   EL_DC_STEELWALL_1_TOPLEFT,
5950   EL_DC_STEELWALL_2_VERTICAL,
5951   EL_DC_STEELWALL_1_TOPRIGHT,
5952   EL_DC_GATE_WHITE,
5953
5954   EL_DC_STEELWALL_1_VERTICAL,
5955   EL_DC_STEELWALL_2_BOTTOM,
5956   EL_DC_KEY_WHITE,
5957   EL_DC_GATE_WHITE_GRAY,
5958
5959   EL_DC_STEELWALL_1_BOTTOMLEFT,
5960   EL_DC_STEELWALL_1_HORIZONTAL,
5961   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5962   EL_DC_GATE_FAKE_GRAY,
5963
5964   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5965   EL_DC_STEELWALL_1_BOTTOM,
5966   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5967   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5968
5969   EL_DC_STEELWALL_1_RIGHT,
5970   EL_EMPTY,
5971   EL_DC_STEELWALL_1_LEFT,
5972   EL_EXPANDABLE_STEELWALL_VERTICAL,
5973
5974   EL_DC_STEELWALL_1_TOPRIGHT_2,
5975   EL_DC_STEELWALL_1_TOP,
5976   EL_DC_STEELWALL_1_TOPLEFT_2,
5977   EL_EXPANDABLE_STEELWALL_ANY,
5978 };
5979 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5980 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5981 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5982 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5983
5984 static int editor_hl_dx_boulderdash[] =
5985 {
5986   EL_INTERNAL_CASCADE_DX_ACTIVE,
5987   EL_CHAR('D'),
5988   EL_CHAR('X'),
5989   EL_EMPTY,
5990 };
5991
5992 static int editor_el_dx_boulderdash[] =
5993 {
5994   EL_EMPTY,
5995   EL_TUBE_RIGHT_DOWN,
5996   EL_TUBE_HORIZONTAL_DOWN,
5997   EL_TUBE_LEFT_DOWN,
5998
5999   EL_TUBE_HORIZONTAL,
6000   EL_TUBE_VERTICAL_RIGHT,
6001   EL_TUBE_ANY,
6002   EL_TUBE_VERTICAL_LEFT,
6003
6004   EL_TUBE_VERTICAL,
6005   EL_TUBE_RIGHT_UP,
6006   EL_TUBE_HORIZONTAL_UP,
6007   EL_TUBE_LEFT_UP,
6008
6009   EL_TRAP,
6010   EL_DX_SUPABOMB,
6011   EL_EMPTY,
6012   EL_EMPTY
6013 };
6014 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
6015 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
6016 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
6017 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
6018
6019 static int editor_hl_mirror_magic[] =
6020 {
6021   EL_INTERNAL_CASCADE_MM_ACTIVE,
6022   EL_CHAR('M'),
6023   EL_CHAR('M'),
6024   EL_EMPTY,
6025 };
6026
6027 static int editor_el_mirror_magic[] =
6028 {
6029   EL_MM_MCDUFFIN_RIGHT,
6030   EL_MM_MCDUFFIN_UP,
6031   EL_MM_MCDUFFIN_LEFT,
6032   EL_MM_MCDUFFIN_DOWN,
6033
6034   EL_MM_MIRROR_START,
6035   EL_MM_MIRROR_FIXED_START,
6036   EL_MM_POLARIZER_START,
6037   EL_MM_POLARIZER_CROSS_START,
6038
6039   EL_MM_TELEPORTER_RED_START,
6040   EL_MM_TELEPORTER_YELLOW_START,
6041   EL_MM_TELEPORTER_GREEN_START,
6042   EL_MM_TELEPORTER_BLUE_START,
6043
6044   EL_MM_PRISM,
6045   EL_MM_FUSE_ACTIVE,
6046   EL_MM_PACMAN_RIGHT,
6047   EL_MM_EXIT_CLOSED,
6048
6049   EL_MM_KETTLE,
6050   EL_MM_BOMB,
6051   EL_MM_KEY,
6052   EL_MM_FUEL_FULL,
6053
6054   EL_MM_LIGHTBULB,
6055   EL_MM_LIGHTBULB_ACTIVE,
6056   EL_MM_GRAY_BALL,
6057   EL_MM_LIGHTBALL,
6058
6059   EL_MM_STEEL_WALL,
6060   EL_MM_WOODEN_WALL,
6061   EL_MM_ICE_WALL,
6062   EL_MM_AMOEBA_WALL,
6063
6064   EL_MM_STEEL_LOCK,
6065   EL_MM_WOODEN_LOCK,
6066   EL_MM_STEEL_BLOCK,
6067   EL_MM_WOODEN_BLOCK,
6068
6069   EL_MM_STEEL_GRID_FIXED_1,
6070   EL_MM_STEEL_GRID_FIXED_2,
6071   EL_MM_STEEL_GRID_FIXED_3,
6072   EL_MM_STEEL_GRID_FIXED_4,
6073
6074   EL_MM_WOODEN_GRID_FIXED_1,
6075   EL_MM_WOODEN_GRID_FIXED_2,
6076   EL_MM_WOODEN_GRID_FIXED_3,
6077   EL_MM_WOODEN_GRID_FIXED_4,
6078
6079   EL_MM_ENVELOPE_1,
6080   EL_MM_ENVELOPE_2,
6081   EL_MM_ENVELOPE_3,
6082   EL_MM_ENVELOPE_4
6083 };
6084 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
6085 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
6086 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
6087 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
6088
6089 static int editor_hl_deflektor[] =
6090 {
6091   EL_INTERNAL_CASCADE_DF_ACTIVE,
6092   EL_CHAR('D'),
6093   EL_CHAR('F'),
6094   EL_EMPTY,
6095 };
6096
6097 static int editor_el_deflektor[] =
6098 {
6099   EL_DF_LASER_RIGHT,
6100   EL_DF_LASER_UP,
6101   EL_DF_LASER_LEFT,
6102   EL_DF_LASER_DOWN,
6103
6104   EL_DF_RECEIVER_RIGHT,
6105   EL_DF_RECEIVER_UP,
6106   EL_DF_RECEIVER_LEFT,
6107   EL_DF_RECEIVER_DOWN,
6108
6109   EL_DF_MIRROR_START,
6110   EL_DF_MIRROR_ROTATING_START,
6111   EL_DF_MIRROR_FIXED_START,
6112   EL_DF_CELL,
6113
6114   EL_DF_FIBRE_OPTIC_RED_1,
6115   EL_DF_FIBRE_OPTIC_YELLOW_1,
6116   EL_DF_FIBRE_OPTIC_GREEN_1,
6117   EL_DF_FIBRE_OPTIC_BLUE_1,
6118
6119   EL_DF_STEEL_GRID_FIXED_START,
6120   EL_DF_STEEL_GRID_ROTATING_START,
6121   EL_DF_WOODEN_GRID_FIXED_START,
6122   EL_DF_WOODEN_GRID_ROTATING_START,
6123
6124   EL_DF_STEEL_WALL,
6125   EL_DF_WOODEN_WALL,
6126   EL_DF_REFRACTOR,
6127   EL_DF_MINE,
6128
6129   EL_DF_SLOPE_1,
6130   EL_DF_SLOPE_2,
6131   EL_DF_SLOPE_3,
6132   EL_DF_SLOPE_4
6133 };
6134 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
6135 static int *editor_el_deflektor_ptr = editor_el_deflektor;
6136 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
6137 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
6138
6139 static int editor_hl_chars[] =
6140 {
6141   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
6142   EL_CHAR('T'),
6143   EL_CHAR('X'),
6144   EL_CHAR('T'),
6145 };
6146
6147 static int editor_el_chars[] =
6148 {
6149   EL_CHAR(' '),
6150   EL_CHAR('!'),
6151   EL_CHAR('"'),
6152   EL_CHAR('#'),
6153
6154   EL_CHAR('$'),
6155   EL_CHAR('%'),
6156   EL_CHAR('&'),
6157   EL_CHAR('\''),
6158
6159   EL_CHAR('('),
6160   EL_CHAR(')'),
6161   EL_CHAR('*'),
6162   EL_CHAR('+'),
6163
6164   EL_CHAR(','),
6165   EL_CHAR('-'),
6166   EL_CHAR('.'),
6167   EL_CHAR('/'),
6168
6169   EL_CHAR('0'),
6170   EL_CHAR('1'),
6171   EL_CHAR('2'),
6172   EL_CHAR('3'),
6173
6174   EL_CHAR('4'),
6175   EL_CHAR('5'),
6176   EL_CHAR('6'),
6177   EL_CHAR('7'),
6178
6179   EL_CHAR('8'),
6180   EL_CHAR('9'),
6181   EL_CHAR(':'),
6182   EL_CHAR(';'),
6183
6184   EL_CHAR('<'),
6185   EL_CHAR('='),
6186   EL_CHAR('>'),
6187   EL_CHAR('?'),
6188
6189   EL_CHAR('@'),
6190   EL_CHAR('A'),
6191   EL_CHAR('B'),
6192   EL_CHAR('C'),
6193
6194   EL_CHAR('D'),
6195   EL_CHAR('E'),
6196   EL_CHAR('F'),
6197   EL_CHAR('G'),
6198
6199   EL_CHAR('H'),
6200   EL_CHAR('I'),
6201   EL_CHAR('J'),
6202   EL_CHAR('K'),
6203
6204   EL_CHAR('L'),
6205   EL_CHAR('M'),
6206   EL_CHAR('N'),
6207   EL_CHAR('O'),
6208
6209   EL_CHAR('P'),
6210   EL_CHAR('Q'),
6211   EL_CHAR('R'),
6212   EL_CHAR('S'),
6213
6214   EL_CHAR('T'),
6215   EL_CHAR('U'),
6216   EL_CHAR('V'),
6217   EL_CHAR('W'),
6218
6219   EL_CHAR('X'),
6220   EL_CHAR('Y'),
6221   EL_CHAR('Z'),
6222   EL_CHAR('['),
6223
6224   EL_CHAR('\\'),
6225   EL_CHAR(']'),
6226   EL_CHAR('^'),
6227   EL_CHAR('_'),
6228
6229   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6230   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6231   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6232   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6233
6234   EL_CHAR(CHAR_BYTE_DEGREE),
6235   EL_CHAR(CHAR_BYTE_REGISTERED),
6236   EL_CHAR(FONT_ASCII_CURSOR),
6237   EL_CHAR(FONT_ASCII_BUTTON),
6238
6239   EL_CHAR(FONT_ASCII_UP),
6240   EL_CHAR(FONT_ASCII_DOWN),
6241   EL_CHAR(' '),
6242   EL_CHAR(' ')
6243 };
6244 static int *editor_hl_chars_ptr = editor_hl_chars;
6245 static int *editor_el_chars_ptr = editor_el_chars;
6246 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6247 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6248
6249 static int editor_hl_steel_chars[] =
6250 {
6251   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6252   EL_STEEL_CHAR('T'),
6253   EL_STEEL_CHAR('X'),
6254   EL_STEEL_CHAR('T'),
6255 };
6256
6257 static int editor_el_steel_chars[] =
6258 {
6259   EL_STEEL_CHAR(' '),
6260   EL_STEEL_CHAR('!'),
6261   EL_STEEL_CHAR('"'),
6262   EL_STEEL_CHAR('#'),
6263
6264   EL_STEEL_CHAR('$'),
6265   EL_STEEL_CHAR('%'),
6266   EL_STEEL_CHAR('&'),
6267   EL_STEEL_CHAR('\''),
6268
6269   EL_STEEL_CHAR('('),
6270   EL_STEEL_CHAR(')'),
6271   EL_STEEL_CHAR('*'),
6272   EL_STEEL_CHAR('+'),
6273
6274   EL_STEEL_CHAR(','),
6275   EL_STEEL_CHAR('-'),
6276   EL_STEEL_CHAR('.'),
6277   EL_STEEL_CHAR('/'),
6278
6279   EL_STEEL_CHAR('0'),
6280   EL_STEEL_CHAR('1'),
6281   EL_STEEL_CHAR('2'),
6282   EL_STEEL_CHAR('3'),
6283
6284   EL_STEEL_CHAR('4'),
6285   EL_STEEL_CHAR('5'),
6286   EL_STEEL_CHAR('6'),
6287   EL_STEEL_CHAR('7'),
6288
6289   EL_STEEL_CHAR('8'),
6290   EL_STEEL_CHAR('9'),
6291   EL_STEEL_CHAR(':'),
6292   EL_STEEL_CHAR(';'),
6293
6294   EL_STEEL_CHAR('<'),
6295   EL_STEEL_CHAR('='),
6296   EL_STEEL_CHAR('>'),
6297   EL_STEEL_CHAR('?'),
6298
6299   EL_STEEL_CHAR('@'),
6300   EL_STEEL_CHAR('A'),
6301   EL_STEEL_CHAR('B'),
6302   EL_STEEL_CHAR('C'),
6303
6304   EL_STEEL_CHAR('D'),
6305   EL_STEEL_CHAR('E'),
6306   EL_STEEL_CHAR('F'),
6307   EL_STEEL_CHAR('G'),
6308
6309   EL_STEEL_CHAR('H'),
6310   EL_STEEL_CHAR('I'),
6311   EL_STEEL_CHAR('J'),
6312   EL_STEEL_CHAR('K'),
6313
6314   EL_STEEL_CHAR('L'),
6315   EL_STEEL_CHAR('M'),
6316   EL_STEEL_CHAR('N'),
6317   EL_STEEL_CHAR('O'),
6318
6319   EL_STEEL_CHAR('P'),
6320   EL_STEEL_CHAR('Q'),
6321   EL_STEEL_CHAR('R'),
6322   EL_STEEL_CHAR('S'),
6323
6324   EL_STEEL_CHAR('T'),
6325   EL_STEEL_CHAR('U'),
6326   EL_STEEL_CHAR('V'),
6327   EL_STEEL_CHAR('W'),
6328
6329   EL_STEEL_CHAR('X'),
6330   EL_STEEL_CHAR('Y'),
6331   EL_STEEL_CHAR('Z'),
6332   EL_STEEL_CHAR('['),
6333
6334   EL_STEEL_CHAR('\\'),
6335   EL_STEEL_CHAR(']'),
6336   EL_STEEL_CHAR('^'),
6337   EL_STEEL_CHAR('_'),
6338
6339   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6340   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6341   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6342   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6343
6344   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6345   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6346   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6347   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6348
6349   EL_STEEL_CHAR(FONT_ASCII_UP),
6350   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6351   EL_STEEL_CHAR(' '),
6352   EL_STEEL_CHAR(' ')
6353 };
6354 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6355 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6356 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6357 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6358
6359 static int editor_hl_custom[] =
6360 {
6361   EL_INTERNAL_CASCADE_CE_ACTIVE,
6362   EL_CHAR('C'),
6363   EL_CHAR('E'),
6364   EL_EMPTY,
6365 };
6366
6367 static int editor_el_custom[] =
6368 {
6369   EL_CUSTOM_START + 0,
6370   EL_CUSTOM_START + 1,
6371   EL_CUSTOM_START + 2,
6372   EL_CUSTOM_START + 3,
6373
6374   EL_CUSTOM_START + 4,
6375   EL_CUSTOM_START + 5,
6376   EL_CUSTOM_START + 6,
6377   EL_CUSTOM_START + 7,
6378
6379   EL_CUSTOM_START + 8,
6380   EL_CUSTOM_START + 9,
6381   EL_CUSTOM_START + 10,
6382   EL_CUSTOM_START + 11,
6383
6384   EL_CUSTOM_START + 12,
6385   EL_CUSTOM_START + 13,
6386   EL_CUSTOM_START + 14,
6387   EL_CUSTOM_START + 15,
6388
6389   EL_CUSTOM_START + 16,
6390   EL_CUSTOM_START + 17,
6391   EL_CUSTOM_START + 18,
6392   EL_CUSTOM_START + 19,
6393
6394   EL_CUSTOM_START + 20,
6395   EL_CUSTOM_START + 21,
6396   EL_CUSTOM_START + 22,
6397   EL_CUSTOM_START + 23,
6398
6399   EL_CUSTOM_START + 24,
6400   EL_CUSTOM_START + 25,
6401   EL_CUSTOM_START + 26,
6402   EL_CUSTOM_START + 27,
6403
6404   EL_CUSTOM_START + 28,
6405   EL_CUSTOM_START + 29,
6406   EL_CUSTOM_START + 30,
6407   EL_CUSTOM_START + 31,
6408
6409   EL_CUSTOM_START + 32,
6410   EL_CUSTOM_START + 33,
6411   EL_CUSTOM_START + 34,
6412   EL_CUSTOM_START + 35,
6413
6414   EL_CUSTOM_START + 36,
6415   EL_CUSTOM_START + 37,
6416   EL_CUSTOM_START + 38,
6417   EL_CUSTOM_START + 39,
6418
6419   EL_CUSTOM_START + 40,
6420   EL_CUSTOM_START + 41,
6421   EL_CUSTOM_START + 42,
6422   EL_CUSTOM_START + 43,
6423
6424   EL_CUSTOM_START + 44,
6425   EL_CUSTOM_START + 45,
6426   EL_CUSTOM_START + 46,
6427   EL_CUSTOM_START + 47,
6428
6429   EL_CUSTOM_START + 48,
6430   EL_CUSTOM_START + 49,
6431   EL_CUSTOM_START + 50,
6432   EL_CUSTOM_START + 51,
6433
6434   EL_CUSTOM_START + 52,
6435   EL_CUSTOM_START + 53,
6436   EL_CUSTOM_START + 54,
6437   EL_CUSTOM_START + 55,
6438
6439   EL_CUSTOM_START + 56,
6440   EL_CUSTOM_START + 57,
6441   EL_CUSTOM_START + 58,
6442   EL_CUSTOM_START + 59,
6443
6444   EL_CUSTOM_START + 60,
6445   EL_CUSTOM_START + 61,
6446   EL_CUSTOM_START + 62,
6447   EL_CUSTOM_START + 63,
6448
6449   EL_CUSTOM_START + 64,
6450   EL_CUSTOM_START + 65,
6451   EL_CUSTOM_START + 66,
6452   EL_CUSTOM_START + 67,
6453
6454   EL_CUSTOM_START + 68,
6455   EL_CUSTOM_START + 69,
6456   EL_CUSTOM_START + 70,
6457   EL_CUSTOM_START + 71,
6458
6459   EL_CUSTOM_START + 72,
6460   EL_CUSTOM_START + 73,
6461   EL_CUSTOM_START + 74,
6462   EL_CUSTOM_START + 75,
6463
6464   EL_CUSTOM_START + 76,
6465   EL_CUSTOM_START + 77,
6466   EL_CUSTOM_START + 78,
6467   EL_CUSTOM_START + 79,
6468
6469   EL_CUSTOM_START + 80,
6470   EL_CUSTOM_START + 81,
6471   EL_CUSTOM_START + 82,
6472   EL_CUSTOM_START + 83,
6473
6474   EL_CUSTOM_START + 84,
6475   EL_CUSTOM_START + 85,
6476   EL_CUSTOM_START + 86,
6477   EL_CUSTOM_START + 87,
6478
6479   EL_CUSTOM_START + 88,
6480   EL_CUSTOM_START + 89,
6481   EL_CUSTOM_START + 90,
6482   EL_CUSTOM_START + 91,
6483
6484   EL_CUSTOM_START + 92,
6485   EL_CUSTOM_START + 93,
6486   EL_CUSTOM_START + 94,
6487   EL_CUSTOM_START + 95,
6488
6489   EL_CUSTOM_START + 96,
6490   EL_CUSTOM_START + 97,
6491   EL_CUSTOM_START + 98,
6492   EL_CUSTOM_START + 99,
6493
6494   EL_CUSTOM_START + 100,
6495   EL_CUSTOM_START + 101,
6496   EL_CUSTOM_START + 102,
6497   EL_CUSTOM_START + 103,
6498
6499   EL_CUSTOM_START + 104,
6500   EL_CUSTOM_START + 105,
6501   EL_CUSTOM_START + 106,
6502   EL_CUSTOM_START + 107,
6503
6504   EL_CUSTOM_START + 108,
6505   EL_CUSTOM_START + 109,
6506   EL_CUSTOM_START + 110,
6507   EL_CUSTOM_START + 111,
6508
6509   EL_CUSTOM_START + 112,
6510   EL_CUSTOM_START + 113,
6511   EL_CUSTOM_START + 114,
6512   EL_CUSTOM_START + 115,
6513
6514   EL_CUSTOM_START + 116,
6515   EL_CUSTOM_START + 117,
6516   EL_CUSTOM_START + 118,
6517   EL_CUSTOM_START + 119,
6518
6519   EL_CUSTOM_START + 120,
6520   EL_CUSTOM_START + 121,
6521   EL_CUSTOM_START + 122,
6522   EL_CUSTOM_START + 123,
6523
6524   EL_CUSTOM_START + 124,
6525   EL_CUSTOM_START + 125,
6526   EL_CUSTOM_START + 126,
6527   EL_CUSTOM_START + 127,
6528
6529   EL_CUSTOM_START + 128,
6530   EL_CUSTOM_START + 129,
6531   EL_CUSTOM_START + 130,
6532   EL_CUSTOM_START + 131,
6533
6534   EL_CUSTOM_START + 132,
6535   EL_CUSTOM_START + 133,
6536   EL_CUSTOM_START + 134,
6537   EL_CUSTOM_START + 135,
6538
6539   EL_CUSTOM_START + 136,
6540   EL_CUSTOM_START + 137,
6541   EL_CUSTOM_START + 138,
6542   EL_CUSTOM_START + 139,
6543
6544   EL_CUSTOM_START + 140,
6545   EL_CUSTOM_START + 141,
6546   EL_CUSTOM_START + 142,
6547   EL_CUSTOM_START + 143,
6548
6549   EL_CUSTOM_START + 144,
6550   EL_CUSTOM_START + 145,
6551   EL_CUSTOM_START + 146,
6552   EL_CUSTOM_START + 147,
6553
6554   EL_CUSTOM_START + 148,
6555   EL_CUSTOM_START + 149,
6556   EL_CUSTOM_START + 150,
6557   EL_CUSTOM_START + 151,
6558
6559   EL_CUSTOM_START + 152,
6560   EL_CUSTOM_START + 153,
6561   EL_CUSTOM_START + 154,
6562   EL_CUSTOM_START + 155,
6563
6564   EL_CUSTOM_START + 156,
6565   EL_CUSTOM_START + 157,
6566   EL_CUSTOM_START + 158,
6567   EL_CUSTOM_START + 159,
6568
6569   EL_CUSTOM_START + 160,
6570   EL_CUSTOM_START + 161,
6571   EL_CUSTOM_START + 162,
6572   EL_CUSTOM_START + 163,
6573
6574   EL_CUSTOM_START + 164,
6575   EL_CUSTOM_START + 165,
6576   EL_CUSTOM_START + 166,
6577   EL_CUSTOM_START + 167,
6578
6579   EL_CUSTOM_START + 168,
6580   EL_CUSTOM_START + 169,
6581   EL_CUSTOM_START + 170,
6582   EL_CUSTOM_START + 171,
6583
6584   EL_CUSTOM_START + 172,
6585   EL_CUSTOM_START + 173,
6586   EL_CUSTOM_START + 174,
6587   EL_CUSTOM_START + 175,
6588
6589   EL_CUSTOM_START + 176,
6590   EL_CUSTOM_START + 177,
6591   EL_CUSTOM_START + 178,
6592   EL_CUSTOM_START + 179,
6593
6594   EL_CUSTOM_START + 180,
6595   EL_CUSTOM_START + 181,
6596   EL_CUSTOM_START + 182,
6597   EL_CUSTOM_START + 183,
6598
6599   EL_CUSTOM_START + 184,
6600   EL_CUSTOM_START + 185,
6601   EL_CUSTOM_START + 186,
6602   EL_CUSTOM_START + 187,
6603
6604   EL_CUSTOM_START + 188,
6605   EL_CUSTOM_START + 189,
6606   EL_CUSTOM_START + 190,
6607   EL_CUSTOM_START + 191,
6608
6609   EL_CUSTOM_START + 192,
6610   EL_CUSTOM_START + 193,
6611   EL_CUSTOM_START + 194,
6612   EL_CUSTOM_START + 195,
6613
6614   EL_CUSTOM_START + 196,
6615   EL_CUSTOM_START + 197,
6616   EL_CUSTOM_START + 198,
6617   EL_CUSTOM_START + 199,
6618
6619   EL_CUSTOM_START + 200,
6620   EL_CUSTOM_START + 201,
6621   EL_CUSTOM_START + 202,
6622   EL_CUSTOM_START + 203,
6623
6624   EL_CUSTOM_START + 204,
6625   EL_CUSTOM_START + 205,
6626   EL_CUSTOM_START + 206,
6627   EL_CUSTOM_START + 207,
6628
6629   EL_CUSTOM_START + 208,
6630   EL_CUSTOM_START + 209,
6631   EL_CUSTOM_START + 210,
6632   EL_CUSTOM_START + 211,
6633
6634   EL_CUSTOM_START + 212,
6635   EL_CUSTOM_START + 213,
6636   EL_CUSTOM_START + 214,
6637   EL_CUSTOM_START + 215,
6638
6639   EL_CUSTOM_START + 216,
6640   EL_CUSTOM_START + 217,
6641   EL_CUSTOM_START + 218,
6642   EL_CUSTOM_START + 219,
6643
6644   EL_CUSTOM_START + 220,
6645   EL_CUSTOM_START + 221,
6646   EL_CUSTOM_START + 222,
6647   EL_CUSTOM_START + 223,
6648
6649   EL_CUSTOM_START + 224,
6650   EL_CUSTOM_START + 225,
6651   EL_CUSTOM_START + 226,
6652   EL_CUSTOM_START + 227,
6653
6654   EL_CUSTOM_START + 228,
6655   EL_CUSTOM_START + 229,
6656   EL_CUSTOM_START + 230,
6657   EL_CUSTOM_START + 231,
6658
6659   EL_CUSTOM_START + 232,
6660   EL_CUSTOM_START + 233,
6661   EL_CUSTOM_START + 234,
6662   EL_CUSTOM_START + 235,
6663
6664   EL_CUSTOM_START + 236,
6665   EL_CUSTOM_START + 237,
6666   EL_CUSTOM_START + 238,
6667   EL_CUSTOM_START + 239,
6668
6669   EL_CUSTOM_START + 240,
6670   EL_CUSTOM_START + 241,
6671   EL_CUSTOM_START + 242,
6672   EL_CUSTOM_START + 243,
6673
6674   EL_CUSTOM_START + 244,
6675   EL_CUSTOM_START + 245,
6676   EL_CUSTOM_START + 246,
6677   EL_CUSTOM_START + 247,
6678
6679   EL_CUSTOM_START + 248,
6680   EL_CUSTOM_START + 249,
6681   EL_CUSTOM_START + 250,
6682   EL_CUSTOM_START + 251,
6683
6684   EL_CUSTOM_START + 252,
6685   EL_CUSTOM_START + 253,
6686   EL_CUSTOM_START + 254,
6687   EL_CUSTOM_START + 255
6688 };
6689 static int *editor_hl_custom_ptr = editor_hl_custom;
6690 static int *editor_el_custom_ptr = editor_el_custom;
6691 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6692 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6693
6694 static int editor_hl_group[] =
6695 {
6696   EL_INTERNAL_CASCADE_GE_ACTIVE,
6697   EL_CHAR('G'),
6698   EL_CHAR('E'),
6699   EL_EMPTY,
6700 };
6701
6702 static int editor_el_group[] =
6703 {
6704   EL_GROUP_START + 0,
6705   EL_GROUP_START + 1,
6706   EL_GROUP_START + 2,
6707   EL_GROUP_START + 3,
6708
6709   EL_GROUP_START + 4,
6710   EL_GROUP_START + 5,
6711   EL_GROUP_START + 6,
6712   EL_GROUP_START + 7,
6713
6714   EL_GROUP_START + 8,
6715   EL_GROUP_START + 9,
6716   EL_GROUP_START + 10,
6717   EL_GROUP_START + 11,
6718
6719   EL_GROUP_START + 12,
6720   EL_GROUP_START + 13,
6721   EL_GROUP_START + 14,
6722   EL_GROUP_START + 15,
6723
6724   EL_GROUP_START + 16,
6725   EL_GROUP_START + 17,
6726   EL_GROUP_START + 18,
6727   EL_GROUP_START + 19,
6728
6729   EL_GROUP_START + 20,
6730   EL_GROUP_START + 21,
6731   EL_GROUP_START + 22,
6732   EL_GROUP_START + 23,
6733
6734   EL_GROUP_START + 24,
6735   EL_GROUP_START + 25,
6736   EL_GROUP_START + 26,
6737   EL_GROUP_START + 27,
6738
6739   EL_GROUP_START + 28,
6740   EL_GROUP_START + 29,
6741   EL_GROUP_START + 30,
6742   EL_GROUP_START + 31
6743 };
6744 static int *editor_hl_group_ptr = editor_hl_group;
6745 static int *editor_el_group_ptr = editor_el_group;
6746 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6747 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6748
6749 static int editor_hl_empty_space[] =
6750 {
6751   EL_INTERNAL_CASCADE_ES_ACTIVE,
6752   EL_CHAR('E'),
6753   EL_CHAR('S'),
6754   EL_EMPTY,
6755 };
6756
6757 static int editor_el_empty_space[] =
6758 {
6759   EL_EMPTY_SPACE_1,
6760   EL_EMPTY_SPACE_2,
6761   EL_EMPTY_SPACE_3,
6762   EL_EMPTY_SPACE_4,
6763
6764   EL_EMPTY_SPACE_5,
6765   EL_EMPTY_SPACE_6,
6766   EL_EMPTY_SPACE_7,
6767   EL_EMPTY_SPACE_8,
6768
6769   EL_EMPTY_SPACE_9,
6770   EL_EMPTY_SPACE_10,
6771   EL_EMPTY_SPACE_11,
6772   EL_EMPTY_SPACE_12,
6773
6774   EL_EMPTY_SPACE_13,
6775   EL_EMPTY_SPACE_14,
6776   EL_EMPTY_SPACE_15,
6777   EL_EMPTY_SPACE_16
6778 };
6779 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6780 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6781 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6782 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6783
6784 static int editor_hl_reference[] =
6785 {
6786   EL_INTERNAL_CASCADE_REF_ACTIVE,
6787   EL_CHAR('R'),
6788   EL_CHAR('E'),
6789   EL_CHAR('F')
6790 };
6791
6792 static int editor_el_reference[] =
6793 {
6794   EL_TRIGGER_PLAYER,
6795   EL_TRIGGER_ELEMENT,
6796   EL_TRIGGER_CE_VALUE,
6797   EL_TRIGGER_CE_SCORE,
6798
6799   EL_SELF,
6800   EL_ANY_ELEMENT,
6801   EL_CURRENT_CE_VALUE,
6802   EL_CURRENT_CE_SCORE,
6803
6804   EL_PREV_CE_8,
6805   EL_PREV_CE_7,
6806   EL_PREV_CE_6,
6807   EL_PREV_CE_5,
6808
6809   EL_PREV_CE_4,
6810   EL_PREV_CE_3,
6811   EL_PREV_CE_2,
6812   EL_PREV_CE_1,
6813
6814   EL_NEXT_CE_1,
6815   EL_NEXT_CE_2,
6816   EL_NEXT_CE_3,
6817   EL_NEXT_CE_4,
6818
6819   EL_NEXT_CE_5,
6820   EL_NEXT_CE_6,
6821   EL_NEXT_CE_7,
6822   EL_NEXT_CE_8,
6823 };
6824 static int *editor_hl_reference_ptr = editor_hl_reference;
6825 static int *editor_el_reference_ptr = editor_el_reference;
6826 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6827 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6828
6829 static int editor_hl_user_defined[] =
6830 {
6831   EL_INTERNAL_CASCADE_USER_ACTIVE,
6832   EL_CHAR('M'),
6833   EL_CHAR('Y'),
6834   EL_EMPTY,
6835 };
6836
6837 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6838 static int *editor_el_user_defined_ptr = NULL;
6839 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6840 static int num_editor_el_user_defined = 0;
6841
6842 static int editor_hl_dynamic[] =
6843 {
6844   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6845   EL_CHAR('U'),
6846   EL_CHAR('S'),
6847   EL_CHAR('E'),
6848 };
6849
6850 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6851 static int *editor_el_dynamic_ptr = NULL;
6852 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6853 static int num_editor_el_dynamic = 0;
6854
6855 static int editor_hl_empty[] = { EL_EMPTY };
6856 static int *editor_el_empty = NULL;     // dynamically allocated
6857
6858 static int *editor_hl_empty_ptr = editor_hl_empty;
6859 static int *editor_el_empty_ptr = NULL;
6860 static int num_editor_hl_empty = 0;
6861 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6862
6863 static boolean use_el_empty = FALSE;
6864
6865 static int *editor_elements = NULL;     // dynamically allocated
6866 static int num_editor_elements = 0;     // dynamically determined
6867
6868 static boolean setup_editor_cascade_never = FALSE;
6869
6870 static boolean setup_editor_el_players                  = TRUE;
6871 static boolean setup_editor_el_boulderdash              = TRUE;
6872 static boolean setup_editor_el_boulderdash_native       = TRUE;
6873 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6874 static boolean setup_editor_el_emerald_mine             = TRUE;
6875 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6876 static boolean setup_editor_el_more                     = TRUE;
6877 static boolean setup_editor_el_sokoban                  = TRUE;
6878 static boolean setup_editor_el_supaplex                 = TRUE;
6879 static boolean setup_editor_el_diamond_caves            = TRUE;
6880 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6881 static boolean setup_editor_el_mirror_magic             = TRUE;
6882 static boolean setup_editor_el_deflektor                = TRUE;
6883 static boolean setup_editor_el_chars                    = TRUE;
6884 static boolean setup_editor_el_steel_chars              = TRUE;
6885 static boolean setup_editor_el_custom                   = TRUE;
6886 static boolean setup_editor_el_user_defined             = TRUE;
6887 static boolean setup_editor_el_dynamic                  = TRUE;
6888
6889 static int editor_hl_unused[] = { EL_EMPTY };
6890 static int *editor_hl_unused_ptr = editor_hl_unused;
6891 static int num_editor_hl_unused = 0;
6892
6893 static struct
6894 {
6895   boolean *setup_value;
6896   boolean *setup_cascade_value;
6897
6898   int **headline_list;
6899   int *headline_list_size;
6900
6901   int **element_list;
6902   int *element_list_size;
6903
6904   boolean last_setup_value;
6905 }
6906 editor_elements_info[] =
6907 {
6908   {
6909     &setup_editor_el_players,
6910     &setup_editor_cascade_never,
6911     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6912     &editor_el_players_ptr,             &num_editor_el_players
6913   },
6914   {
6915     &setup_editor_el_boulderdash,
6916     &setup.editor_cascade.el_bd,
6917     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6918     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6919   },
6920   {
6921     &setup_editor_el_boulderdash_native,
6922     &setup.editor_cascade.el_bd_native,
6923     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6924     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6925   },
6926   {
6927     &setup_editor_el_boulderdash_effects,
6928     &setup.editor_cascade.el_bd_effects,
6929     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6930     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6931   },
6932   {
6933     &setup_editor_el_emerald_mine,
6934     &setup.editor_cascade.el_em,
6935     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6936     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6937   },
6938   {
6939     &setup_editor_el_emerald_mine_club,
6940     &setup.editor_cascade.el_emc,
6941     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6942     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6943   },
6944   {
6945     &setup_editor_el_more,
6946     &setup.editor_cascade.el_rnd,
6947     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6948     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6949   },
6950   {
6951     &setup_editor_el_sokoban,
6952     &setup.editor_cascade.el_sb,
6953     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6954     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6955   },
6956   {
6957     &setup_editor_el_supaplex,
6958     &setup.editor_cascade.el_sp,
6959     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6960     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6961   },
6962   {
6963     &setup_editor_el_diamond_caves,
6964     &setup.editor_cascade.el_dc,
6965     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6966     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6967   },
6968   {
6969     &setup_editor_el_dx_boulderdash,
6970     &setup.editor_cascade.el_dx,
6971     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6972     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6973   },
6974   {
6975     &setup_editor_el_mirror_magic,
6976     &setup.editor_cascade.el_mm,
6977     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6978     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6979   },
6980   {
6981     &setup_editor_el_deflektor,
6982     &setup.editor_cascade.el_df,
6983     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6984     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6985   },
6986   {
6987     &setup_editor_el_chars,
6988     &setup.editor_cascade.el_chars,
6989     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6990     &editor_el_chars_ptr,               &num_editor_el_chars
6991   },
6992   {
6993     &setup_editor_el_steel_chars,
6994     &setup.editor_cascade.el_steel_chars,
6995     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6996     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6997   },
6998   {
6999     &setup_editor_el_custom,
7000     &setup.editor_cascade.el_ce,
7001     &editor_hl_custom_ptr,              &num_editor_hl_custom,
7002     &editor_el_custom_ptr,              &num_editor_el_custom
7003   },
7004   {
7005     &setup_editor_el_custom,
7006     &setup.editor_cascade.el_ge,
7007     &editor_hl_group_ptr,               &num_editor_hl_group,
7008     &editor_el_group_ptr,               &num_editor_el_group
7009   },
7010   {
7011     &setup_editor_el_custom,
7012     &setup.editor_cascade.el_es,
7013     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
7014     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
7015   },
7016   {
7017     &setup_editor_el_custom,
7018     &setup.editor_cascade.el_ref,
7019     &editor_hl_reference_ptr,           &num_editor_hl_reference,
7020     &editor_el_reference_ptr,           &num_editor_el_reference
7021   },
7022   {
7023     &setup_editor_el_user_defined,
7024     &setup.editor_cascade.el_user,
7025     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
7026     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
7027   },
7028   {
7029     &setup_editor_el_dynamic,
7030     &setup.editor_cascade.el_dynamic,
7031     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
7032     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
7033   },
7034   {
7035     &use_el_empty,
7036     &use_el_empty,
7037     &editor_hl_empty_ptr,               &num_editor_hl_empty,
7038     &editor_el_empty_ptr,               &num_editor_el_empty,
7039   },
7040   {
7041     NULL,
7042     NULL,
7043     NULL,                               NULL,
7044     NULL,                               NULL
7045   }
7046 };
7047
7048 static struct XY xy_directions[] =
7049 {
7050   { -1,  0 },
7051   { +1,  0 },
7052   {  0, -1 },
7053   {  0, +1 }
7054 };
7055
7056
7057 // ----------------------------------------------------------------------------
7058 // functions
7059 // ----------------------------------------------------------------------------
7060
7061 static int getMaxInfoTextLength(void)
7062 {
7063   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
7064 }
7065
7066 static int getTextWidthForGadget(char *text)
7067 {
7068   if (text == NULL)
7069     return 0;
7070
7071   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
7072 }
7073
7074 static int getTextWidthForDrawingArea(char *text)
7075 {
7076   if (text == NULL)
7077     return 0;
7078
7079   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
7080 }
7081
7082 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
7083 {
7084   return (gi->x + gi->width + getTextWidthForGadget(text));
7085 }
7086
7087 static char *getElementInfoText(int element)
7088 {
7089   char *info_text = NULL;
7090
7091   if (element < MAX_NUM_ELEMENTS)
7092   {
7093     if (strlen(element_info[element].description) > 0)
7094       info_text = element_info[element].description;
7095     else if (element_info[element].custom_description != NULL)
7096       info_text = element_info[element].custom_description;
7097     else if (element_info[element].editor_description != NULL)
7098       info_text = element_info[element].editor_description;
7099   }
7100
7101   if (info_text == NULL)
7102     info_text = INFOTEXT_UNKNOWN_ELEMENT;
7103
7104   return info_text;
7105 }
7106
7107 static char *getElementDescriptionFilenameExt(char *basename)
7108 {
7109   char *elements_subdir = ELEMENTS_DIRECTORY;
7110   static char *elements_subdir2 = NULL;
7111   static char *filename = NULL;
7112
7113   if (elements_subdir2 == NULL)
7114     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
7115
7116   checked_free(filename);
7117
7118   // 1st try: look for element description in current level set directory
7119   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
7120   if (fileExists(filename))
7121     return filename;
7122
7123   free(filename);
7124
7125   // 2nd try: look for element description in the game's base directory
7126   filename = getPath3(options.docs_directory, elements_subdir, basename);
7127   if (fileExists(filename))
7128     return filename;
7129
7130   return NULL;
7131 }
7132
7133 static char *getElementDescriptionFilename(int element)
7134 {
7135   char basename[MAX_FILENAME_LEN];
7136   char *filename;
7137
7138   // 1st try: look for element description file for exactly this element
7139   sprintf(basename, "%s.txt", element_info[element].token_name);
7140   filename = getElementDescriptionFilenameExt(basename);
7141   if (filename != NULL)
7142     return filename;
7143
7144   // 2nd try: look for element description file for this element's class
7145   sprintf(basename, "%s.txt", element_info[element].class_name);
7146   filename = getElementDescriptionFilenameExt(basename);
7147   if (filename != NULL)
7148     return filename;
7149
7150   // 3rd try: look for generic fallback text file for any element
7151   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
7152   if (filename != NULL)
7153     return filename;
7154
7155   return NULL;
7156 }
7157
7158 static boolean suppressBorderElement(void)
7159 {
7160   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
7161           lev_fieldx <= MAX_ED_FIELDX &&
7162           lev_fieldy <= MAX_ED_FIELDY);
7163 }
7164
7165 static void InitDynamicEditorElementList(int **elements, int *num_elements)
7166 {
7167   boolean element_found[NUM_FILE_ELEMENTS];
7168   int i, x, y;
7169
7170   // initialize list of used elements to "not used"
7171   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7172     element_found[i] = FALSE;
7173
7174   // find all elements used in current level
7175   for (y = 0; y < lev_fieldy; y++)
7176   {
7177     for (x = 0; x < lev_fieldx; x++)
7178     {
7179       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
7180         continue;
7181
7182       if (IS_MM_WALL(Tile[x][y]))
7183         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
7184       else
7185         element_found[Tile[x][y]] = TRUE;
7186     }
7187   }
7188
7189   *num_elements = 0;
7190
7191   // count number of elements used in current level
7192   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7193     if (element_found[i])
7194       (*num_elements)++;
7195
7196   // add space for up to 3 more elements for padding that may be needed
7197   *num_elements += 3;
7198
7199   // free memory for old list of elements, if needed
7200   checked_free(*elements);
7201
7202   // allocate memory for new list of elements
7203   *elements = checked_malloc(*num_elements * sizeof(int));
7204
7205   *num_elements = 0;
7206
7207   // add all elements used in current level (non-custom/group/empty elements)
7208   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7209     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
7210                               IS_GROUP_ELEMENT(i) ||
7211                               IS_EMPTY_ELEMENT(i)))
7212       (*elements)[(*num_elements)++] = i;
7213
7214   // add all elements used in current level (custom/group/empty elements)
7215   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7216     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
7217                              IS_GROUP_ELEMENT(i) ||
7218                              IS_EMPTY_ELEMENT(i)))
7219       (*elements)[(*num_elements)++] = i;
7220
7221   while (*num_elements % 4)     // pad with empty elements, if needed
7222     (*elements)[(*num_elements)++] = EL_EMPTY;
7223 }
7224
7225 static void ReinitializeElementList_EnableSections(void)
7226 {
7227   // default: enable all element sections
7228
7229   setup_editor_el_players               = TRUE;
7230   setup_editor_el_boulderdash           = TRUE;
7231   setup_editor_el_boulderdash_native    = TRUE;
7232   setup_editor_el_boulderdash_effects   = TRUE;
7233   setup_editor_el_emerald_mine          = TRUE;
7234   setup_editor_el_emerald_mine_club     = TRUE;
7235   setup_editor_el_more                  = TRUE;
7236   setup_editor_el_sokoban               = TRUE;
7237   setup_editor_el_supaplex              = TRUE;
7238   setup_editor_el_diamond_caves         = TRUE;
7239   setup_editor_el_dx_boulderdash        = TRUE;
7240   setup_editor_el_mirror_magic          = TRUE;
7241   setup_editor_el_deflektor             = TRUE;
7242   setup_editor_el_chars                 = TRUE;
7243   setup_editor_el_steel_chars           = TRUE;
7244
7245   setup_editor_el_custom                = TRUE;
7246   setup_editor_el_user_defined          = TRUE;
7247   setup_editor_el_dynamic               = TRUE;
7248
7249   // now disable all element sections not to be displayed
7250
7251   if (!setup.editor.el_classic)
7252   {
7253     setup_editor_el_players             = FALSE;
7254     setup_editor_el_boulderdash         = FALSE;
7255     setup_editor_el_boulderdash_native  = FALSE;
7256     setup_editor_el_boulderdash_effects = FALSE;
7257     setup_editor_el_emerald_mine        = FALSE;
7258     setup_editor_el_emerald_mine_club   = FALSE;
7259     setup_editor_el_more                = FALSE;
7260     setup_editor_el_sokoban             = FALSE;
7261     setup_editor_el_supaplex            = FALSE;
7262     setup_editor_el_diamond_caves       = FALSE;
7263     setup_editor_el_dx_boulderdash      = FALSE;
7264     setup_editor_el_mirror_magic        = FALSE;
7265     setup_editor_el_deflektor           = FALSE;
7266     setup_editor_el_chars               = FALSE;
7267     setup_editor_el_steel_chars         = FALSE;
7268   }
7269
7270   if (!setup.editor.el_custom)
7271   {
7272     setup_editor_el_custom              = FALSE;
7273   }
7274
7275   if (!setup.editor.el_user_defined)
7276   {
7277     setup_editor_el_user_defined        = FALSE;
7278   }
7279
7280   if (!setup.editor.el_dynamic)
7281   {
7282     setup_editor_el_dynamic             = FALSE;
7283   }
7284
7285   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7286   {
7287     setup_editor_el_boulderdash_native  = FALSE;
7288     setup_editor_el_boulderdash_effects = FALSE;
7289     setup_editor_el_mirror_magic        = FALSE;
7290     setup_editor_el_deflektor           = FALSE;
7291   }
7292   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7293   {
7294     setup_editor_el_players             = FALSE;
7295     setup_editor_el_boulderdash         = FALSE;
7296     setup_editor_el_emerald_mine        = FALSE;
7297     setup_editor_el_emerald_mine_club   = FALSE;
7298     setup_editor_el_more                = FALSE;
7299     setup_editor_el_sokoban             = FALSE;
7300     setup_editor_el_supaplex            = 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_EM)
7311   {
7312     setup_editor_el_boulderdash         = FALSE;
7313     setup_editor_el_boulderdash_native  = FALSE;
7314     setup_editor_el_boulderdash_effects = FALSE;
7315     setup_editor_el_more                = FALSE;
7316     setup_editor_el_sokoban             = FALSE;
7317     setup_editor_el_supaplex            = FALSE;
7318     setup_editor_el_diamond_caves       = FALSE;
7319     setup_editor_el_dx_boulderdash      = FALSE;
7320     setup_editor_el_mirror_magic        = FALSE;
7321     setup_editor_el_deflektor           = FALSE;
7322     setup_editor_el_steel_chars         = FALSE;
7323
7324     setup_editor_el_custom              = FALSE;
7325   }
7326   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7327   {
7328     setup_editor_el_players             = FALSE;
7329     setup_editor_el_boulderdash         = FALSE;
7330     setup_editor_el_boulderdash_native  = FALSE;
7331     setup_editor_el_boulderdash_effects = FALSE;
7332     setup_editor_el_emerald_mine        = FALSE;
7333     setup_editor_el_emerald_mine_club   = FALSE;
7334     setup_editor_el_more                = FALSE;
7335     setup_editor_el_sokoban             = FALSE;
7336     setup_editor_el_diamond_caves       = FALSE;
7337     setup_editor_el_dx_boulderdash      = FALSE;
7338     setup_editor_el_mirror_magic        = FALSE;
7339     setup_editor_el_deflektor           = FALSE;
7340     setup_editor_el_chars               = FALSE;
7341     setup_editor_el_steel_chars         = FALSE;
7342
7343     setup_editor_el_custom              = FALSE;
7344   }
7345   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7346   {
7347     setup_editor_el_players             = FALSE;
7348     setup_editor_el_boulderdash         = FALSE;
7349     setup_editor_el_boulderdash_native  = FALSE;
7350     setup_editor_el_boulderdash_effects = FALSE;
7351     setup_editor_el_emerald_mine        = FALSE;
7352     setup_editor_el_emerald_mine_club   = FALSE;
7353     setup_editor_el_more                = FALSE;
7354     setup_editor_el_sokoban             = FALSE;
7355     setup_editor_el_supaplex            = FALSE;
7356     setup_editor_el_diamond_caves       = FALSE;
7357     setup_editor_el_dx_boulderdash      = FALSE;
7358     setup_editor_el_steel_chars         = FALSE;
7359
7360     setup_editor_el_custom              = FALSE;
7361   }
7362 }
7363
7364 static void ReinitializeElementList(void)
7365 {
7366   static boolean initialization_needed = TRUE;
7367   int pos = 0;
7368   int i, j;
7369
7370   ReinitializeElementList_EnableSections();
7371
7372   if (initialization_needed)
7373   {
7374     LoadSetup_EditorCascade();          // load last editor cascade state
7375
7376     // initialize editor cascade element from saved cascade state
7377     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7378     {
7379       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7380       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7381
7382       if (IS_EDITOR_CASCADE(*cascade_element))
7383         *cascade_element =
7384           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7385            EL_CASCADE_INACTIVE(*cascade_element));
7386     }
7387
7388     initialization_needed = FALSE;
7389   }
7390
7391   checked_free(editor_elements);
7392
7393   // reload optional user defined element list for each invocation of editor
7394   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7395                                    &num_editor_el_user_defined);
7396
7397   // initialize dynamic level element list for each invocation of editor
7398   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7399                                &num_editor_el_dynamic);
7400
7401   // initialize list of empty elements (used for padding, if needed)
7402   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7403     editor_el_empty[i] = EL_EMPTY;
7404
7405   // do some sanity checks for each element from element list
7406   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7407   {
7408     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7409     {
7410       int element = (*editor_elements_info[i].element_list)[j];
7411
7412       if (element >= NUM_FILE_ELEMENTS)
7413         Warn("editor element %d is runtime element", element);
7414
7415       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7416         Warn("no element description text for element %d", element);
7417     }
7418   }
7419
7420   num_editor_elements = 0;
7421   use_el_empty = FALSE;
7422
7423   // determine size of element list
7424   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7425   {
7426     if (*editor_elements_info[i].setup_value)
7427     {
7428       boolean found_inactive_cascade = FALSE;
7429
7430       if (setup.editor.el_headlines)
7431       {
7432         // required for correct padding of palette headline buttons
7433         if (*editor_elements_info[i].headline_list_size > 0)
7434           num_editor_elements += ED_ELEMENTLIST_COLS;
7435
7436         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7437         {
7438           int element = (*editor_elements_info[i].headline_list)[j];
7439
7440           if (IS_EDITOR_CASCADE_INACTIVE(element))
7441             found_inactive_cascade = TRUE;
7442         }
7443       }
7444
7445       if (found_inactive_cascade)
7446         continue;
7447
7448       // required for correct padding of palette element buttons
7449       int element_list_size = *editor_elements_info[i].element_list_size;
7450       int element_rows =
7451         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7452       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7453
7454       num_editor_elements += element_buttons;
7455     }
7456   }
7457
7458   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7459   {
7460     // offer at least as many elements as element buttons exist
7461     use_el_empty = TRUE;
7462     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7463
7464     num_editor_elements += num_editor_el_empty;
7465   }
7466   else
7467   {
7468     num_editor_el_empty = 0;
7469   }
7470
7471   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7472
7473   // fill element list
7474   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7475   {
7476     boolean found_inactive_cascade = FALSE;
7477
7478     if (*editor_elements_info[i].setup_value)
7479     {
7480       if (setup.editor.el_headlines)
7481       {
7482         // required for correct padding of palette headline buttons
7483         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7484                              ED_ELEMENTLIST_COLS : 0);
7485
7486         for (j = 0; j < headline_size; j++)
7487         {
7488           // use empty elements for padding of palette headline buttons
7489           int element = (j < *editor_elements_info[i].headline_list_size ?
7490                          (*editor_elements_info[i].headline_list)[j] :
7491                          editor_el_empty[0]);
7492
7493           editor_elements[pos++] = element;
7494
7495           if (IS_EDITOR_CASCADE_INACTIVE(element))
7496             found_inactive_cascade = TRUE;
7497         }
7498       }
7499
7500       if (found_inactive_cascade)
7501         continue;
7502
7503       // required for correct padding of palette element buttons
7504       int element_list_size = *editor_elements_info[i].element_list_size;
7505       int element_rows =
7506         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7507       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7508
7509       // copy all elements from element list
7510       for (j = 0; j < element_list_size; j++)
7511         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7512
7513       // use empty elements for padding of palette element buttons
7514       for (j = 0; j < element_buttons - element_list_size; j++)
7515         editor_elements[pos++] = editor_el_empty[0];
7516     }
7517   }
7518
7519   // (this function is also called before editor gadgets are initialized!)
7520   AdjustElementListScrollbar();
7521 }
7522
7523 void PrintEditorElementList(void)
7524 {
7525   boolean *stop = &setup_editor_el_user_defined;
7526   int i, j;
7527
7528   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7529   {
7530     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7531
7532     if (IS_EDITOR_CASCADE(cascade_element))
7533     {
7534       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7535       char *headline = element_info[cascade_element_show].editor_description;
7536
7537       PrintLineWithPrefix("# ", "-", 77);
7538       Print("# %s\n", headline);
7539       PrintLineWithPrefix("# ", "-", 77);
7540     }
7541
7542     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7543     {
7544       int element = (*editor_elements_info[i].headline_list)[j];
7545
7546       if (IS_EDITOR_CASCADE(element))
7547         element = EL_CHAR_MINUS;
7548
7549       Print("# %s\n", element_info[element].token_name);
7550     }
7551
7552     if (j > 0)
7553       Print("#\n");
7554
7555     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7556     {
7557       int element = (*editor_elements_info[i].element_list)[j];
7558
7559       Print("# %s\n", element_info[element].token_name);
7560     }
7561
7562     if (j > 0)
7563       Print("#\n");
7564   }
7565 }
7566
7567 static void ReinitializeElementListButtons(void)
7568 {
7569   static boolean last_setup_value_headlines = FALSE;
7570   static boolean initialization_needed = TRUE;
7571   int i;
7572
7573   if (!initialization_needed)   // check if editor element setup has changed
7574   {
7575     if (last_setup_value_headlines != setup.editor.el_headlines)
7576       initialization_needed = TRUE;
7577
7578     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7579       if (editor_elements_info[i].last_setup_value !=
7580           *editor_elements_info[i].setup_value)
7581         initialization_needed = TRUE;
7582   }
7583
7584   if (!initialization_needed)
7585     return;
7586
7587   FreeLevelEditorGadgets();
7588   CreateLevelEditorGadgets();
7589
7590   // store current setup values for next invocation of this function
7591   last_setup_value_headlines = setup.editor.el_headlines;
7592   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7593     editor_elements_info[i].last_setup_value =
7594       *editor_elements_info[i].setup_value;
7595
7596   initialization_needed = FALSE;
7597 }
7598
7599 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7600                               boolean input)
7601 {
7602   int border_graphic =
7603     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7604   struct GraphicInfo *g = &graphic_info[border_graphic];
7605   Bitmap *src_bitmap = g->bitmap;
7606   int src_x = g->src_x;
7607   int src_y = g->src_y;
7608   int border_size = g->border_size;
7609   int border_xpos = g->width  - border_size;
7610   int border_ypos = g->height - border_size;
7611   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7612   int i;
7613
7614   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7615              border_size, border_size,
7616              dest_x - border_size, dest_y - border_size);
7617   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7618              border_size, border_size,
7619              dest_x + width, dest_y - border_size);
7620   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7621              border_size, border_size,
7622              dest_x - border_size, dest_y + height);
7623   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7624              border_size, border_size,
7625              dest_x + width, dest_y + height);
7626
7627   for (i = 0; i < width / tilesize; i++)
7628   {
7629     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7630                tilesize, border_size,
7631                dest_x + i * tilesize, dest_y - border_size);
7632     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7633                tilesize, border_size,
7634                dest_x + i * tilesize, dest_y + height);
7635   }
7636
7637   for (i = 0; i < height / tilesize; i++)
7638   {
7639     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7640                border_size, tilesize,
7641                dest_x - border_size, dest_y + i * tilesize);
7642     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7643                border_size, tilesize,
7644                dest_x + width, dest_y + i * tilesize);
7645   }
7646
7647   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7648 }
7649
7650 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7651 {
7652   int xsize_tile = MAX(ed_tilesize, xsize);
7653   int ysize_tile = MAX(ed_tilesize, ysize);
7654   int xsize_full = xsize + 1;
7655   int ysize_full = ysize + 1;
7656   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7657   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7658   Pixel line_color = getTabulatorBarColor();
7659
7660   if (line_color == BLACK_PIXEL)                // black => transparent
7661     return;
7662
7663   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7664   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7665   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7666 }
7667
7668 static void DrawEditorLevelBorderLinesIfNeeded(void)
7669 {
7670   int xsize = lev_fieldx * ed_tilesize;
7671   int ysize = lev_fieldy * ed_tilesize;
7672   int line_size = getTabulatorBarHeight();
7673
7674   if (!suppressBorderElement())
7675     return;
7676
7677   // draw little border line around editable level playfield
7678
7679   if (xsize < SXSIZE)
7680     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7681
7682   if (ysize < SYSIZE)
7683     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7684
7685   if (xsize < SXSIZE && ysize < SYSIZE)
7686     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7687 }
7688
7689 static void DrawEditorElement(int x, int y, int element)
7690 {
7691   DrawSizedElement(x, y, element, ed_tilesize);
7692 }
7693
7694 static void DrawEditorElementThruMask(int x, int y, int element)
7695 {
7696   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7697 }
7698
7699 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7700 {
7701   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7702 }
7703
7704 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7705 {
7706   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7707   DrawEditorLevelBorderLinesIfNeeded();
7708 }
7709
7710 static void DrawDrawingArea(int id)
7711 {
7712   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7713   int x, y;
7714
7715   int *value = drawingarea_info[id].value;
7716   int area_xsize = drawingarea_info[id].area_xsize;
7717   int area_ysize = drawingarea_info[id].area_ysize;
7718   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7719
7720   for (x = 0; x < area_xsize; x++)
7721   {
7722     for (y = 0; y < area_ysize; y++)
7723     {
7724       int element = value[x * area_ysize + y];
7725       int graphic;
7726       int frame;
7727
7728       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7729
7730       DrawSizedGraphicExt(drawto,
7731                           gi->x + x * tilesize,
7732                           gi->y + y * tilesize,
7733                           graphic, frame, tilesize);
7734     }
7735   }
7736 }
7737
7738 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7739 {
7740   int x, y;
7741   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7742   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7743
7744   BlitBitmap(drawto, drawto,
7745              SX + (dx == -1 ? ed_tilesize : 0),
7746              SY + (dy == -1 ? ed_tilesize : 0),
7747              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7748              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7749              SX + (dx == +1 ? ed_tilesize : 0),
7750              SY + (dy == +1 ? ed_tilesize : 0));
7751
7752   if (dx)
7753   {
7754     x = (dx == 1 ? 0 : ed_fieldx - 1);
7755     for (y = 0; y < ed_fieldy; y++)
7756       DrawEditorElementOrWall(x, y, from_x, from_y);
7757   }
7758   else if (dy)
7759   {
7760     y = (dy == 1 ? 0 : ed_fieldy - 1);
7761     for (x = 0; x < ed_fieldx; x++)
7762       DrawEditorElementOrWall(x, y, from_x, from_y);
7763   }
7764
7765   redraw_mask |= REDRAW_FIELD;
7766   BackToFront();
7767 }
7768
7769 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7770 {
7771   if (use_editor_gfx)
7772   {
7773     *graphic = el2edimg(element);
7774     *frame = 0;
7775   }
7776   else
7777   {
7778     *graphic = el2img(element);
7779     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7780               custom_element.ce_value_fixed_initial :
7781               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7782               custom_element.collect_score_initial : FrameCounter);
7783   }
7784
7785   if (*graphic == IMG_UNKNOWN)
7786   {
7787     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7788     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7789     int element_bd = map_element_RND_to_BD_cave(element);
7790
7791     if (element_bd != O_UNKNOWN)
7792     {
7793       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7794
7795       *graphic = g_bd->graphic;
7796       *frame   = g_bd->frame;
7797     }
7798   }
7799 }
7800
7801 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7802                                    int *x, int *y)
7803 {
7804   int graphic;
7805   int frame;
7806
7807   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7808
7809   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7810 }
7811
7812 static void CreateControlButtons(void)
7813 {
7814   struct GadgetInfo *gi;
7815   int i;
7816
7817   // create toolbox buttons
7818   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7819   {
7820     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7821     int id = controlbutton_info[i].gadget_id;
7822     int type = controlbutton_info[i].gadget_type;
7823     int graphic = controlbutton_info[i].graphic;
7824     struct XYTileSize *pos = controlbutton_info[i].pos;
7825     struct GraphicInfo *gd = &graphic_info[graphic];
7826     Bitmap *deco_bitmap = NULL;
7827     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7828     int tile_size = 0, deco_shift = 0;
7829     boolean deco_masked = FALSE;
7830     int gd_x1 = gd->src_x;
7831     int gd_y1 = gd->src_y;
7832     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7833     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7834     int gd_x1a = gd->src_x + gd->active_xoffset;
7835     int gd_y1a = gd->src_y + gd->active_yoffset;
7836     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7837     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7838     int x = pos->x;
7839     int y = pos->y;
7840     unsigned int event_mask;
7841     int radio_button_nr = RADIO_NR_NONE;
7842     boolean checked = FALSE;
7843
7844     if (type_id != i)
7845       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7846
7847     if (type == GD_TYPE_RADIO_BUTTON)
7848     {
7849       event_mask = GD_EVENT_PRESSED;
7850       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7851
7852       if (id == drawing_function)
7853         checked = TRUE;
7854     }
7855     else
7856     {
7857       if (id == GADGET_ID_WRAP_LEFT ||
7858           id == GADGET_ID_WRAP_RIGHT ||
7859           id == GADGET_ID_WRAP_UP ||
7860           id == GADGET_ID_WRAP_DOWN)
7861         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7862       else
7863         event_mask = GD_EVENT_RELEASED;
7864     }
7865
7866     if (id == GADGET_ID_PROPERTIES ||
7867         id == GADGET_ID_PALETTE)
7868     {
7869       x += DX;
7870       y += DY;
7871     }
7872     else if (id == GADGET_ID_ELEMENT_LEFT ||
7873              id == GADGET_ID_ELEMENT_MIDDLE ||
7874              id == GADGET_ID_ELEMENT_RIGHT)
7875     {
7876       x += DX;
7877       y += DY;
7878
7879       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7880                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7881                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7882
7883       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7884                                    editor.button.element_left.tile_size :
7885                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7886                                    editor.button.element_middle.tile_size :
7887                                    id == GADGET_ID_ELEMENT_RIGHT ?
7888                                    editor.button.element_right.tile_size : 0);
7889
7890       // make sure that decoration does not overlap gadget border
7891       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7892
7893       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7894
7895       deco_xpos = (gd->width  - tile_size) / 2;
7896       deco_ypos = (gd->height - tile_size) / 2;
7897       deco_shift = 1;
7898       deco_masked = gd->draw_masked;
7899     }
7900     else
7901     {
7902       x += EX;
7903       y += EY;
7904     }
7905
7906     gi = CreateGadget(GDI_CUSTOM_ID, id,
7907                       GDI_CUSTOM_TYPE_ID, type_id,
7908                       GDI_IMAGE_ID, graphic,
7909                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7910                       GDI_X, x,
7911                       GDI_Y, y,
7912                       GDI_WIDTH, gd->width,
7913                       GDI_HEIGHT, gd->height,
7914                       GDI_TYPE, type,
7915                       GDI_STATE, GD_BUTTON_UNPRESSED,
7916                       GDI_RADIO_NR, radio_button_nr,
7917                       GDI_CHECKED, checked,
7918                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7919                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7920                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7921                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7922                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7923                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7924                       GDI_DECORATION_SIZE, tile_size, tile_size,
7925                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7926                       GDI_DECORATION_MASKED, deco_masked,
7927                       GDI_EVENT_MASK, event_mask,
7928                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7929                       GDI_CALLBACK_ACTION, HandleControlButtons,
7930                       GDI_END);
7931
7932     if (gi == NULL)
7933       Fail("cannot create gadget");
7934
7935     level_editor_gadget[id] = gi;
7936   }
7937
7938   // these values are not constant, but can change at runtime
7939   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7940   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7941   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7942   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7943   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7944   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7945   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7946   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7947   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7948   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7949   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7950   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7951
7952   // create buttons for scrolling of drawing area and element list
7953   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7954   {
7955     int id = scrollbutton_info[i].gadget_id;
7956     int type_id = scrollbutton_info[i].gadget_type_id;
7957     int graphic = scrollbutton_info[i].graphic;
7958     struct GraphicInfo *gd = &graphic_info[graphic];
7959     Bitmap *gd_bitmap = gd->bitmap;
7960     int gd_x1 = gd->src_x;
7961     int gd_y1 = gd->src_y;
7962     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7963     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7964     int width  = gd->width;
7965     int height = gd->height;
7966     int x = scrollbutton_pos[i].x;
7967     int y = scrollbutton_pos[i].y;
7968     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7969
7970     if (type_id != i)
7971       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7972
7973     if (id == GADGET_ID_SCROLL_LIST_UP ||
7974         id == GADGET_ID_SCROLL_LIST_DOWN)
7975     {
7976       x += PX;
7977       y += PY;
7978     }
7979     else
7980     {
7981       x += SX;
7982       y += SY;
7983     }
7984
7985     gi = CreateGadget(GDI_CUSTOM_ID, id,
7986                       GDI_CUSTOM_TYPE_ID, type_id,
7987                       GDI_IMAGE_ID, graphic,
7988                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7989                       GDI_X, x,
7990                       GDI_Y, y,
7991                       GDI_WIDTH, width,
7992                       GDI_HEIGHT, height,
7993                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7994                       GDI_STATE, GD_BUTTON_UNPRESSED,
7995                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7996                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7997                       GDI_EVENT_MASK, event_mask,
7998                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7999                       GDI_CALLBACK_ACTION, HandleControlButtons,
8000                       GDI_END);
8001
8002     if (gi == NULL)
8003       Fail("cannot create gadget");
8004
8005     level_editor_gadget[id] = gi;
8006   }
8007
8008   // create buttons for element list
8009   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8010   {
8011     int type_id = i;
8012     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
8013     int graphic = IMG_EDITOR_PALETTE_BUTTON;
8014     struct GraphicInfo *gd = &graphic_info[graphic];
8015     Bitmap *gd_bitmap = gd->bitmap;
8016     Bitmap *deco_bitmap;
8017     int deco_x, deco_y, deco_xpos, deco_ypos;
8018     int gd_x1 = gd->src_x;
8019     int gd_y1 = gd->src_y;
8020     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8021     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8022     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
8023     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
8024     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
8025     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
8026     int element = editor_elements[i];
8027     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
8028     unsigned int event_mask = GD_EVENT_RELEASED;
8029
8030     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
8031
8032     deco_xpos = (gd->width  - tile_size) / 2;
8033     deco_ypos = (gd->height - tile_size) / 2;
8034
8035     gi = CreateGadget(GDI_CUSTOM_ID, id,
8036                       GDI_CUSTOM_TYPE_ID, type_id,
8037                       GDI_IMAGE_ID, graphic,
8038                       GDI_INFO_TEXT, getElementInfoText(element),
8039                       GDI_X, x,
8040                       GDI_Y, y,
8041                       GDI_WIDTH, gd->width,
8042                       GDI_HEIGHT, gd->height,
8043                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8044                       GDI_STATE, GD_BUTTON_UNPRESSED,
8045                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
8046                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
8047                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
8048                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
8049                       GDI_DECORATION_SIZE, tile_size, tile_size,
8050                       GDI_DECORATION_SHIFTING, 1, 1,
8051                       GDI_EVENT_MASK, event_mask,
8052                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8053                       GDI_CALLBACK_ACTION, HandleControlButtons,
8054                       GDI_END);
8055
8056     if (gi == NULL)
8057       Fail("cannot create gadget");
8058
8059     level_editor_gadget[id] = gi;
8060   }
8061 }
8062
8063 static void CreateCounterButtons(void)
8064 {
8065   int max_infotext_len = getMaxInfoTextLength();
8066   int i;
8067
8068   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
8069   {
8070     int type_id = counterbutton_info[i].gadget_type_id;
8071     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
8072     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
8073     int j;
8074
8075     if (type_id != i)
8076       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
8077
8078     // determine horizontal position to the right of specified gadget
8079     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8080       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
8081            ED_GADGET_TEXT_DISTANCE);
8082
8083     // determine horizontal offset for leading text
8084     if (counterbutton_info[i].text_left != NULL)
8085       x += getTextWidthForGadget(counterbutton_info[i].text_left);
8086
8087     for (j = 0; j < 2; j++)
8088     {
8089       struct GadgetInfo *gi;
8090       int id = (j == 0 ?
8091                 counterbutton_info[i].gadget_id_down :
8092                 counterbutton_info[i].gadget_id_up);
8093       int graphic;
8094       struct GraphicInfo *gd;
8095       int gd_x1, gd_x2, gd_y1, gd_y2;
8096       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
8097       char infotext[max_infotext_len + 1];
8098
8099       if (i == ED_COUNTER_ID_SELECT_LEVEL)
8100       {
8101         graphic = (j == 0 ?
8102                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
8103                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
8104
8105         event_mask |= GD_EVENT_RELEASED;
8106
8107         if (j == 0)
8108         {
8109           x = DX + editor.button.prev_level.x;
8110           y = DY + editor.button.prev_level.y;
8111         }
8112         else
8113         {
8114           x = DX + editor.button.next_level.x;
8115           y = DY + editor.button.next_level.y;
8116         }
8117       }
8118       else
8119       {
8120         graphic = (j == 0 ?
8121                    IMG_EDITOR_COUNTER_DOWN :
8122                    IMG_EDITOR_COUNTER_UP);
8123       }
8124
8125       gd = &graphic_info[graphic];
8126
8127       gd_x1 = gd->src_x;
8128       gd_y1 = gd->src_y;
8129       gd_x2 = gd->src_x + gd->pressed_xoffset;
8130       gd_y2 = gd->src_y + gd->pressed_yoffset;
8131
8132       sprintf(infotext, "%s counter value by 1, 5 or 10",
8133               (j == 0 ? "Decrease" : "Increase"));
8134
8135       gi = CreateGadget(GDI_CUSTOM_ID, id,
8136                         GDI_CUSTOM_TYPE_ID, type_id,
8137                         GDI_IMAGE_ID, graphic,
8138                         GDI_INFO_TEXT, infotext,
8139                         GDI_X, x,
8140                         GDI_Y, y,
8141                         GDI_WIDTH, gd->width,
8142                         GDI_HEIGHT, gd->height,
8143                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8144                         GDI_STATE, GD_BUTTON_UNPRESSED,
8145                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8146                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8147                         GDI_EVENT_MASK, event_mask,
8148                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8149                         GDI_CALLBACK_ACTION, HandleCounterButtons,
8150                         GDI_END);
8151
8152       if (gi == NULL)
8153         Fail("cannot create gadget");
8154
8155       level_editor_gadget[id] = gi;
8156       right_gadget_border[id] =
8157         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8158
8159       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
8160
8161       if (j == 0)
8162       {
8163         int font_type = FONT_INPUT_1;
8164         int font_type_active = FONT_INPUT_1_ACTIVE;
8165
8166         id = counterbutton_info[i].gadget_id_text;
8167
8168         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8169
8170         if (i == ED_COUNTER_ID_SELECT_LEVEL)
8171         {
8172           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
8173
8174           font_type = FONT_LEVEL_NUMBER;
8175           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
8176
8177           x = DX + editor.input.level_number.x;
8178           y = DY + editor.input.level_number.y;
8179         }
8180         else
8181         {
8182           graphic = IMG_EDITOR_COUNTER_INPUT;
8183         }
8184
8185         gd = &graphic_info[graphic];
8186
8187         gd_x1 = gd->src_x;
8188         gd_y1 = gd->src_y;
8189         gd_x2 = gd->src_x + gd->active_xoffset;
8190         gd_y2 = gd->src_y + gd->active_yoffset;
8191
8192         gi = CreateGadget(GDI_CUSTOM_ID, id,
8193                           GDI_CUSTOM_TYPE_ID, type_id,
8194                           GDI_IMAGE_ID, graphic,
8195                           GDI_INFO_TEXT, "Enter counter value",
8196                           GDI_X, x,
8197                           GDI_Y, y,
8198                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
8199                           GDI_NUMBER_VALUE, 0,
8200                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
8201                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
8202                           GDI_TEXT_SIZE, 3,     // minimal counter text size
8203                           GDI_TEXT_FONT, font_type,
8204                           GDI_TEXT_FONT_ACTIVE, font_type_active,
8205                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8206                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8207                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8208                           GDI_DESIGN_WIDTH, gd->width,
8209                           GDI_EVENT_MASK, event_mask,
8210                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8211                           GDI_CALLBACK_ACTION, HandleCounterButtons,
8212                           GDI_END);
8213
8214         if (gi == NULL)
8215           Fail("cannot create gadget");
8216
8217         level_editor_gadget[id] = gi;
8218         right_gadget_border[id] =
8219           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8220
8221         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
8222       }
8223     }
8224   }
8225 }
8226
8227 static void CreateDrawingAreas(void)
8228 {
8229   int i;
8230
8231   // these values are not constant, but can change at runtime
8232   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8233   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8234
8235   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8236   {
8237     struct GadgetInfo *gi;
8238     int id = drawingarea_info[i].gadget_id;
8239     int type_id = drawingarea_info[i].gadget_type_id;
8240     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8241     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8242     int area_xsize = drawingarea_info[i].area_xsize;
8243     int area_ysize = drawingarea_info[i].area_ysize;
8244     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8245                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8246     unsigned int event_mask =
8247       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8248       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8249
8250     if (type_id != i)
8251       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8252
8253     // determine horizontal position to the right of specified gadget
8254     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8255       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8256            ED_DRAWINGAREA_TEXT_DISTANCE);
8257
8258     // determine horizontal offset for leading text
8259     if (drawingarea_info[i].text_left != NULL)
8260       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8261
8262     gi = CreateGadget(GDI_CUSTOM_ID, id,
8263                       GDI_CUSTOM_TYPE_ID, type_id,
8264                       GDI_X, x,
8265                       GDI_Y, y,
8266                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8267                       GDI_AREA_SIZE, area_xsize, area_ysize,
8268                       GDI_ITEM_SIZE, item_size, item_size,
8269                       GDI_EVENT_MASK, event_mask,
8270                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8271                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8272                       GDI_END);
8273
8274     if (gi == NULL)
8275       Fail("cannot create gadget");
8276
8277     level_editor_gadget[id] = gi;
8278     right_gadget_border[id] =
8279       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8280   }
8281 }
8282
8283 static void CreateTextInputGadgets(void)
8284 {
8285   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8286   int max_infotext_len = getMaxInfoTextLength();
8287   int i;
8288
8289   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8290   {
8291     int gd_x1 = gd->src_x;
8292     int gd_y1 = gd->src_y;
8293     int gd_x2 = gd->src_x + gd->active_xoffset;
8294     int gd_y2 = gd->src_y + gd->active_yoffset;
8295     struct GadgetInfo *gi;
8296     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8297     char infotext[MAX_OUTPUT_LINESIZE + 1];
8298     int id = textinput_info[i].gadget_id;
8299     int type_id = textinput_info[i].gadget_type_id;
8300     int x, y;
8301
8302     if (type_id != i)
8303       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8304
8305     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8306     {
8307       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8308       int border_size = gd->border_size;
8309       int font_nr = FONT_INPUT_1;
8310       int font_height = getFontHeight(font_nr);
8311       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8312       int yoffset = element_border + (TILEY - font_height) / 2;
8313
8314       x = (editor.settings.element_name.x != -1 ?
8315            editor.settings.element_name.x :
8316            editor.settings.element_graphic.x + xoffset) - border_size;
8317       y = (editor.settings.element_name.y != -1 ?
8318            editor.settings.element_name.y :
8319            editor.settings.element_graphic.y + yoffset) - border_size;
8320     }
8321     else
8322     {
8323       x = ED_SETTINGS_X(textinput_info[i].x);
8324       y = ED_SETTINGS_Y(textinput_info[i].y);
8325     }
8326
8327     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8328     infotext[max_infotext_len] = '\0';
8329
8330     gi = CreateGadget(GDI_CUSTOM_ID, id,
8331                       GDI_CUSTOM_TYPE_ID, type_id,
8332                       GDI_INFO_TEXT, infotext,
8333                       GDI_X, SX + x,
8334                       GDI_Y, SY + y,
8335                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8336                       GDI_TEXT_VALUE, textinput_info[i].value,
8337                       GDI_TEXT_SIZE, textinput_info[i].size,
8338                       GDI_TEXT_FONT, FONT_INPUT_1,
8339                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8340                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8341                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8342                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8343                       GDI_DESIGN_WIDTH, gd->width,
8344                       GDI_EVENT_MASK, event_mask,
8345                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8346                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
8347                       GDI_END);
8348
8349     if (gi == NULL)
8350       Fail("cannot create gadget");
8351
8352     level_editor_gadget[id] = gi;
8353   }
8354 }
8355
8356 static void CreateTextAreaGadgets(void)
8357 {
8358   int max_infotext_len = getMaxInfoTextLength();
8359   int i;
8360
8361   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8362   {
8363     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8364     int gd_x1 = gd->src_x;
8365     int gd_y1 = gd->src_y;
8366     int gd_x2 = gd->src_x + gd->active_xoffset;
8367     int gd_y2 = gd->src_y + gd->active_yoffset;
8368     struct GadgetInfo *gi;
8369     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8370     char infotext[MAX_OUTPUT_LINESIZE + 1];
8371     int id = textarea_info[i].gadget_id;
8372     int type_id = textarea_info[i].gadget_type_id;
8373     int area_xsize = textarea_info[i].xsize;
8374     int area_ysize = textarea_info[i].ysize;
8375
8376     if (type_id != i)
8377       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8378
8379     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8380     infotext[max_infotext_len] = '\0';
8381
8382     gi = CreateGadget(GDI_CUSTOM_ID, id,
8383                       GDI_CUSTOM_TYPE_ID, type_id,
8384                       GDI_INFO_TEXT, infotext,
8385                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8386                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8387                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8388                       GDI_AREA_SIZE, area_xsize, area_ysize,
8389                       GDI_TEXT_FONT, FONT_INPUT_1,
8390                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8391                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8392                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8393                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8394                       GDI_DESIGN_WIDTH, gd->width,
8395                       GDI_EVENT_MASK, event_mask,
8396                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8397                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8398                       GDI_END);
8399
8400     if (gi == NULL)
8401       Fail("cannot create gadget");
8402
8403     level_editor_gadget[id] = gi;
8404   }
8405 }
8406
8407 static void CreateSelectboxGadgets(void)
8408 {
8409   int max_infotext_len = getMaxInfoTextLength();
8410
8411   int i, j;
8412
8413   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8414   {
8415     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8416     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8417     int gd_x1 = gd->src_x;
8418     int gd_y1 = gd->src_y;
8419     int gd_x2 = gd->src_x + gd->active_xoffset;
8420     int gd_y2 = gd->src_y + gd->active_yoffset;
8421     int selectbox_button_xsize = gd2->width;
8422     struct GadgetInfo *gi;
8423     char infotext[MAX_OUTPUT_LINESIZE + 1];
8424     int id = selectbox_info[i].gadget_id;
8425     int type_id = selectbox_info[i].gadget_type_id;
8426     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8427     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8428     unsigned int event_mask =
8429       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8430
8431     if (type_id != i)
8432       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8433
8434     if (selectbox_info[i].size == -1)   // dynamically determine size
8435     {
8436       // (we cannot use -1 for uninitialized values if we directly compare
8437       // with results from strlen(), because the '<' and '>' operation will
8438       // implicitely cast -1 to an unsigned integer value!)
8439       selectbox_info[i].size = 0;
8440
8441       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8442         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8443           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8444
8445       selectbox_info[i].size++;         // add one character empty space
8446     }
8447
8448     // determine horizontal position to the right of specified gadget
8449     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8450       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8451            ED_GADGET_TEXT_DISTANCE);
8452
8453     // determine horizontal offset for leading text
8454     if (selectbox_info[i].text_left != NULL)
8455       x += getTextWidthForGadget(selectbox_info[i].text_left);
8456
8457     sprintf(infotext, "%s", selectbox_info[i].infotext);
8458     infotext[max_infotext_len] = '\0';
8459
8460     gi = CreateGadget(GDI_CUSTOM_ID, id,
8461                       GDI_CUSTOM_TYPE_ID, type_id,
8462                       GDI_INFO_TEXT, infotext,
8463                       GDI_X, x,
8464                       GDI_Y, y,
8465                       GDI_TYPE, GD_TYPE_SELECTBOX,
8466                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8467                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8468                       GDI_TEXT_SIZE, selectbox_info[i].size,
8469                       GDI_TEXT_FONT, FONT_INPUT_1,
8470                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8471                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8472                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8473                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8474                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8475                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8476                       GDI_DESIGN_WIDTH, gd->width,
8477                       GDI_EVENT_MASK, event_mask,
8478                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8479                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8480                       GDI_END);
8481
8482     if (gi == NULL)
8483       Fail("cannot create gadget");
8484
8485     level_editor_gadget[id] = gi;
8486     right_gadget_border[id] =
8487       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8488   }
8489 }
8490
8491 static void CreateTextbuttonGadgets(void)
8492 {
8493   int max_infotext_len = getMaxInfoTextLength();
8494   int i;
8495
8496   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8497   {
8498     int id = textbutton_info[i].gadget_id;
8499     int type_id = textbutton_info[i].gadget_type_id;
8500     int is_tab_button =
8501       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8502        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8503     int graphic =
8504       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8505     int gadget_distance =
8506       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8507     struct GraphicInfo *gd = &graphic_info[graphic];
8508     int gd_x1 = gd->src_x;
8509     int gd_y1 = gd->src_y;
8510     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8511     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8512     int gd_x1a = gd->src_x + gd->active_xoffset;
8513     int gd_y1a = gd->src_y + gd->active_yoffset;
8514     int border_xsize = gd->border_size + gd->draw_xoffset;
8515     int border_ysize = gd->border_size;
8516     struct GadgetInfo *gi;
8517     unsigned int event_mask = GD_EVENT_RELEASED;
8518     char infotext[MAX_OUTPUT_LINESIZE + 1];
8519     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8520     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8521
8522     if (type_id != i)
8523       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8524
8525     if (textbutton_info[i].size == -1)  // dynamically determine size
8526       textbutton_info[i].size = strlen(textbutton_info[i].text);
8527
8528     sprintf(infotext, "%s", textbutton_info[i].infotext);
8529     infotext[max_infotext_len] = '\0';
8530
8531     // determine horizontal position to the right of specified gadget
8532     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8533     {
8534       int gadget_id_align = textbutton_info[i].gadget_id_align;
8535
8536       x = right_gadget_border[gadget_id_align] + gadget_distance;
8537
8538       if (textbutton_info[i].y == -1)
8539         y = level_editor_gadget[gadget_id_align]->y;
8540     }
8541
8542     // determine horizontal offset for leading text
8543     if (textbutton_info[i].text_left != NULL)
8544       x += getTextWidthForGadget(textbutton_info[i].text_left);
8545
8546     gi = CreateGadget(GDI_CUSTOM_ID, id,
8547                       GDI_CUSTOM_TYPE_ID, type_id,
8548                       GDI_IMAGE_ID, graphic,
8549                       GDI_INFO_TEXT, infotext,
8550                       GDI_X, x,
8551                       GDI_Y, y,
8552                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8553                       GDI_TEXT_VALUE, textbutton_info[i].text,
8554                       GDI_TEXT_SIZE, textbutton_info[i].size,
8555                       GDI_TEXT_FONT, FONT_INPUT_2,
8556                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8557                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8558                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8559                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8560                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8561                       GDI_DESIGN_WIDTH, gd->width,
8562                       GDI_DECORATION_SHIFTING, 1, 1,
8563                       GDI_EVENT_MASK, event_mask,
8564                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8565                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8566                       GDI_END);
8567
8568     if (gi == NULL)
8569       Fail("cannot create gadget");
8570
8571     level_editor_gadget[id] = gi;
8572     right_gadget_border[id] =
8573       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8574   }
8575 }
8576
8577 static void CreateGraphicbuttonGadgets(void)
8578 {
8579   struct GadgetInfo *gi;
8580   int i;
8581
8582   // create buttons for scrolling of drawing area and element list
8583   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8584   {
8585     int id = graphicbutton_info[i].gadget_id;
8586     int type_id = graphicbutton_info[i].gadget_type_id;
8587     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8588     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8589     int graphic = graphicbutton_info[i].graphic;
8590     struct GraphicInfo *gd = &graphic_info[graphic];
8591     int gd_x1 = gd->src_x;
8592     int gd_y1 = gd->src_y;
8593     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8594     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8595     unsigned int event_mask = GD_EVENT_RELEASED;
8596
8597     if (type_id != i)
8598       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8599
8600     // determine horizontal position to the right of specified gadget
8601     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8602       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8603            ED_GADGET_TEXT_DISTANCE);
8604
8605     // determine horizontal offset for leading text
8606     if (graphicbutton_info[i].text_left != NULL)
8607       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8608
8609     gi = CreateGadget(GDI_CUSTOM_ID, id,
8610                       GDI_CUSTOM_TYPE_ID, type_id,
8611                       GDI_IMAGE_ID, graphic,
8612                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8613                       GDI_X, x,
8614                       GDI_Y, y,
8615                       GDI_WIDTH, gd->width,
8616                       GDI_HEIGHT, gd->height,
8617                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8618                       GDI_STATE, GD_BUTTON_UNPRESSED,
8619                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8620                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8621                       GDI_EVENT_MASK, event_mask,
8622                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8623                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8624                       GDI_END);
8625
8626     if (gi == NULL)
8627       Fail("cannot create gadget");
8628
8629     level_editor_gadget[id] = gi;
8630     right_gadget_border[id] =
8631       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8632   }
8633 }
8634
8635 static void CreateScrollbarGadgets(void)
8636 {
8637   int i;
8638
8639   // these values are not constant, but can change at runtime
8640   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8641     SX + ED_SCROLL_HORIZONTAL_XPOS;
8642   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8643     SY + ED_SCROLL_HORIZONTAL_YPOS;
8644   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8645     ED_SCROLL_HORIZONTAL_XSIZE;
8646   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8647     ED_SCROLL_HORIZONTAL_YSIZE;
8648   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8649   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8650   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8651   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8652
8653   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8654     SX + ED_SCROLL_VERTICAL_XPOS;
8655   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8656     SY + ED_SCROLL_VERTICAL_YPOS;
8657   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8658     ED_SCROLL_VERTICAL_XSIZE;
8659   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8660     ED_SCROLL_VERTICAL_YSIZE;
8661   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8662   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8663   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8664   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8665
8666   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8667     PX + ED_SCROLL2_VERTICAL_XPOS;
8668   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8669     PY + ED_SCROLL2_VERTICAL_YPOS;
8670   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8671     ED_SCROLL2_VERTICAL_XSIZE;
8672   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8673     ED_SCROLL2_VERTICAL_YSIZE;
8674   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8675   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8676   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8677   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8678
8679   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8680   {
8681     int id = scrollbar_info[i].gadget_id;
8682     int type_id = scrollbar_info[i].gadget_type_id;
8683     int graphic = scrollbar_info[i].graphic;
8684     struct GraphicInfo *gd = &graphic_info[graphic];
8685     int gd_x1 = gd->src_x;
8686     int gd_y1 = gd->src_y;
8687     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8688     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8689     struct GadgetInfo *gi;
8690     int items_max, items_visible, item_position;
8691     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8692
8693     if (type_id != i)
8694       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8695
8696     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8697     {
8698       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8699       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8700       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8701     }
8702     else        // drawing area scrollbars
8703     {
8704       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8705       {
8706         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8707         items_visible = ed_fieldx;
8708         item_position = 0;
8709       }
8710       else
8711       {
8712         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8713         items_visible = ed_fieldy;
8714         item_position = 0;
8715       }
8716     }
8717
8718     gi = CreateGadget(GDI_CUSTOM_ID, id,
8719                       GDI_CUSTOM_TYPE_ID, type_id,
8720                       GDI_IMAGE_ID, graphic,
8721                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8722                       GDI_X, scrollbar_pos[i].x,
8723                       GDI_Y, scrollbar_pos[i].y,
8724                       GDI_WIDTH, scrollbar_pos[i].width,
8725                       GDI_HEIGHT, scrollbar_pos[i].height,
8726                       GDI_TYPE, scrollbar_info[i].type,
8727                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8728                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8729                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8730                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8731                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8732                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8733                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8734                       GDI_STATE, GD_BUTTON_UNPRESSED,
8735                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8736                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8737                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8738                       GDI_EVENT_MASK, event_mask,
8739                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8740                       GDI_CALLBACK_ACTION, HandleControlButtons,
8741                       GDI_END);
8742
8743     if (gi == NULL)
8744       Fail("cannot create gadget");
8745
8746     level_editor_gadget[id] = gi;
8747   }
8748 }
8749
8750 static void CreateCheckbuttonGadgets(void)
8751 {
8752   struct GadgetInfo *gi;
8753   int i;
8754
8755   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8756   {
8757     int id = checkbutton_info[i].gadget_id;
8758     int type_id = checkbutton_info[i].gadget_type_id;
8759     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8760                    IMG_EDITOR_CHECKBOX);
8761     struct GraphicInfo *gd = &graphic_info[graphic];
8762     int gd_x1 = gd->src_x;
8763     int gd_y1 = gd->src_y;
8764     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8765     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8766     int gd_x1a = gd->src_x + gd->active_xoffset;
8767     int gd_y1a = gd->src_y + gd->active_yoffset;
8768     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8769     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8770     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8771     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8772     unsigned int event_mask = GD_EVENT_PRESSED;
8773
8774     if (type_id != i)
8775       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8776
8777     // determine horizontal position to the right of specified gadget
8778     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8779       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8780            ED_GADGET_TEXT_DISTANCE);
8781
8782     // determine horizontal offset for leading text
8783     if (checkbutton_info[i].text_left != NULL)
8784       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8785
8786     gi = CreateGadget(GDI_CUSTOM_ID, id,
8787                       GDI_CUSTOM_TYPE_ID, type_id,
8788                       GDI_IMAGE_ID, graphic,
8789                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8790                       GDI_X, x,
8791                       GDI_Y, y,
8792                       GDI_WIDTH, gd->width,
8793                       GDI_HEIGHT, gd->height,
8794                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8795                       GDI_CHECKED, *checkbutton_info[i].value,
8796                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8797                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8798                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8799                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8800                       GDI_EVENT_MASK, event_mask,
8801                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8802                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8803                       GDI_END);
8804
8805     if (gi == NULL)
8806       Fail("cannot create gadget");
8807
8808     level_editor_gadget[id] = gi;
8809     right_gadget_border[id] =
8810       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8811   }
8812 }
8813
8814 static void CreateRadiobuttonGadgets(void)
8815 {
8816   int graphic = IMG_EDITOR_RADIOBUTTON;
8817   struct GraphicInfo *gd = &graphic_info[graphic];
8818   int gd_x1 = gd->src_x;
8819   int gd_y1 = gd->src_y;
8820   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8821   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8822   int gd_x1a = gd->src_x + gd->active_xoffset;
8823   int gd_y1a = gd->src_y + gd->active_yoffset;
8824   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8825   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8826   struct GadgetInfo *gi;
8827   int i;
8828
8829   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8830   {
8831     int id = radiobutton_info[i].gadget_id;
8832     int type_id = radiobutton_info[i].gadget_type_id;
8833     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8834     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8835     unsigned int event_mask = GD_EVENT_PRESSED;
8836
8837     if (type_id != i)
8838       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8839
8840     int checked =
8841       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8842
8843     // determine horizontal position to the right of specified gadget
8844     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8845       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8846            ED_GADGET_TEXT_DISTANCE);
8847
8848     // determine horizontal offset for leading text
8849     if (radiobutton_info[i].text_left != NULL)
8850       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8851
8852     gi = CreateGadget(GDI_CUSTOM_ID, id,
8853                       GDI_CUSTOM_TYPE_ID, type_id,
8854                       GDI_IMAGE_ID, graphic,
8855                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8856                       GDI_X, x,
8857                       GDI_Y, y,
8858                       GDI_WIDTH, gd->width,
8859                       GDI_HEIGHT, gd->height,
8860                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8861                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8862                       GDI_CHECKED, checked,
8863                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8864                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8865                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8866                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8867                       GDI_EVENT_MASK, event_mask,
8868                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8869                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8870                       GDI_END);
8871
8872     if (gi == NULL)
8873       Fail("cannot create gadget");
8874
8875     level_editor_gadget[id] = gi;
8876     right_gadget_border[id] =
8877       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8878   }
8879 }
8880
8881 void CreateLevelEditorGadgets(void)
8882 {
8883   // force EDITOR font inside level editor
8884   SetFontStatus(GAME_MODE_EDITOR);
8885
8886   // these values are not constant, but can change at runtime
8887   ed_fieldx = MAX_ED_FIELDX - 1;
8888   ed_fieldy = MAX_ED_FIELDY - 1;
8889
8890   num_editor_gadgets = NUM_EDITOR_GADGETS;
8891
8892   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8893
8894   level_editor_gadget =
8895     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8896   right_gadget_border =
8897     checked_calloc(num_editor_gadgets * sizeof(int));
8898
8899   // set number of empty (padding) element buttons to maximum number of buttons
8900   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8901
8902   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8903   editor_el_empty_ptr = editor_el_empty;
8904
8905   use_permanent_palette = !editor.palette.show_as_separate_screen;
8906
8907   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8908
8909   ReinitializeElementList();
8910
8911   CreateControlButtons();
8912   CreateScrollbarGadgets();
8913
8914   // order of function calls is important because of cross-references
8915   CreateCheckbuttonGadgets();
8916   CreateCounterButtons();
8917   CreateRadiobuttonGadgets();
8918   CreateTextInputGadgets();
8919   CreateTextAreaGadgets();
8920   CreateSelectboxGadgets();
8921   CreateGraphicbuttonGadgets();
8922   CreateTextbuttonGadgets();
8923   CreateDrawingAreas();
8924
8925   ResetFontStatus();
8926 }
8927
8928 void FreeLevelEditorGadgets(void)
8929 {
8930   int i;
8931
8932   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8933
8934   for (i = 0; i < num_editor_gadgets; i++)
8935   {
8936     FreeGadget(level_editor_gadget[i]);
8937
8938     level_editor_gadget[i] = NULL;
8939   }
8940
8941   checked_free(level_editor_gadget);
8942   checked_free(right_gadget_border);
8943
8944   checked_free(editor_el_empty);
8945 }
8946
8947 static void MapCounterButtons(int id)
8948 {
8949   int font_nr = FONT_TEXT_1;
8950   int font_height = getFontHeight(font_nr);
8951   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8952   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8953   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8954   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8955   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8956   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8957   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8958   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8959   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8960   int yoffset = (gi_down->height - font_height) / 2;
8961   int x_left = gi_down->x - xoffset_left;
8962   int x_right;  // set after gadget position was modified
8963   int y_above = gi_down->y - yoffset_above;
8964   int x = gi_down->x;
8965   int y;        // set after gadget position was modified
8966
8967   // counter limits must be changed first to prevent value truncation
8968   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8969                             counterbutton_info[id].max_value);
8970
8971   // right text position might have changed after setting position above
8972   x_right = gi_up->x + gi_up->width + xoffset_right;
8973
8974   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8975
8976   // set position for counter gadgets with dynamically determined position
8977   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8978   {
8979     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8980     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8981     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8982   }
8983
8984   // vertical position might have changed after setting position above
8985   y = gi_up->y + yoffset;
8986
8987   if (counterbutton_info[id].text_above)
8988     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8989
8990   if (counterbutton_info[id].text_left)
8991     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8992
8993   if (counterbutton_info[id].text_right)
8994     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8995
8996   MapGadget(gi_down);
8997   MapGadget(gi_text);
8998   MapGadget(gi_up);
8999 }
9000
9001 static void MapControlButtons(void)
9002 {
9003   int counter_id;
9004   int i;
9005
9006   // map toolbox buttons (excluding special CE toolbox buttons)
9007   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
9008     MapGadget(level_editor_gadget[i]);
9009
9010   // map toolbox buttons (element properties buttons)
9011   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
9012     MapGadget(level_editor_gadget[i]);
9013
9014   if (use_permanent_palette)
9015   {
9016     // map buttons to select elements
9017     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
9018       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
9019     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
9020     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
9021     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
9022   }
9023
9024   // map buttons to select level
9025   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
9026   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
9027   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
9028   MapCounterButtons(counter_id);
9029 }
9030
9031 static void MapDrawingArea(int id)
9032 {
9033   int font_nr = FONT_TEXT_1;
9034   int font_height = getFontHeight(font_nr);
9035   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9036   int area_xsize = gi->drawing.area_xsize;
9037   int area_ysize = gi->drawing.area_ysize;
9038   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9039   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
9040   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
9041   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
9042   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
9043   int x_below = gi->x + (gi->width - xoffset_below) / 2;
9044   int y_side  = gi->y + (gi->height - font_height) / 2;
9045   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
9046   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
9047
9048   if (drawingarea_info[id].text_left)
9049     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
9050
9051   if (drawingarea_info[id].text_right)
9052     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
9053
9054   if (drawingarea_info[id].text_above)
9055     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
9056
9057   if (drawingarea_info[id].text_below)
9058     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
9059
9060   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
9061   {
9062     DrawElementBorder(gi->x, gi->y,
9063                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
9064                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
9065
9066     DrawDrawingArea(id);
9067   }
9068
9069   MapGadget(gi);
9070 }
9071
9072 static void MapTextInputGadget(int id)
9073 {
9074   int font_nr = FONT_TEXT_1;
9075   int font_height = getFontHeight(font_nr);
9076   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
9077   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9078   int x_above = ED_SETTINGS_X(textinput_info[id].x);
9079   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
9080
9081   if (textinput_info[id].text_above)
9082     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
9083
9084   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
9085
9086   MapGadget(gi);
9087 }
9088
9089 static void MapTextAreaGadget(int id)
9090 {
9091   int font_nr = FONT_TEXT_1;
9092   int font_height = getFontHeight(font_nr);
9093   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
9094   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9095   int x_above = ED_SETTINGS_X(textarea_info[id].x);
9096   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
9097   char *text_above = textarea_info[id].text_above;
9098
9099   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
9100     text_above = textarea_info[id].text_above_cropped;
9101
9102   if (text_above)
9103     DrawTextS(x_above, y_above, font_nr, text_above);
9104
9105   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
9106
9107   MapGadget(gi);
9108 }
9109
9110 static void MapSelectboxGadget(int id)
9111 {
9112   int font_nr = FONT_TEXT_1;
9113   int font_height = getFontHeight(font_nr);
9114   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
9115   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
9116   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9117   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9118   int yoffset = (gi->height - font_height) / 2;
9119   int x_left = gi->x - xoffset_left;
9120   int x_right = gi->x + gi->width + xoffset_right;
9121   int y_above = gi->y - yoffset_above;
9122   int x = gi->x;
9123   int y = gi->y + yoffset;
9124
9125   if (selectbox_info[id].text_above)
9126     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
9127
9128   if (selectbox_info[id].text_left)
9129     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
9130
9131   if (selectbox_info[id].text_right)
9132     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
9133
9134   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
9135
9136   MapGadget(gi);
9137 }
9138
9139 static void MapTextbuttonGadget(int id)
9140 {
9141   int font_nr = FONT_TEXT_1;
9142   int font_height = getFontHeight(font_nr);
9143   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
9144   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
9145   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9146   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9147   int yoffset = (gi->height - font_height) / 2;
9148   int x_left = gi->x - xoffset_left;
9149   int x_right = gi->x + gi->width + xoffset_right;
9150   int y_above = gi->y - yoffset_above;
9151   int x = gi->x;
9152   int y = gi->y + yoffset;
9153
9154   // only show button to delete change pages when more than minimum pages
9155   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
9156       custom_element.num_change_pages == MIN_CHANGE_PAGES)
9157     return;
9158
9159   if (textbutton_info[id].text_above)
9160     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
9161
9162   if (textbutton_info[id].text_left)
9163     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
9164
9165   if (textbutton_info[id].text_right)
9166     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
9167
9168   MapGadget(gi);
9169 }
9170
9171 static void MapGraphicbuttonGadget(int id)
9172 {
9173   int font_nr = FONT_TEXT_1;
9174   int font_height = getFontHeight(font_nr);
9175   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
9176   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
9177   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9178   int yoffset = (gi->height - font_height) / 2;
9179   int x_left = gi->x - xoffset_left;
9180   int x_right = gi->x + gi->width + xoffset_right;
9181   int y = gi->y + yoffset;
9182
9183   if (graphicbutton_info[id].text_left)
9184     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
9185
9186   if (graphicbutton_info[id].text_right)
9187     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
9188
9189   MapGadget(gi);
9190 }
9191
9192 static void MapRadiobuttonGadget(int id)
9193 {
9194   int font_nr = FONT_TEXT_1;
9195   int font_height = getFontHeight(font_nr);
9196   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
9197   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9198   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9199   int yoffset = (gi->height - font_height) / 2;
9200   int x_left = gi->x - xoffset_left;
9201   int x_right = gi->x + gi->width + xoffset_right;
9202   int y = gi->y + yoffset;
9203   boolean checked =
9204     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
9205
9206   if (radiobutton_info[id].text_left)
9207     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
9208
9209   if (radiobutton_info[id].text_right)
9210     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
9211
9212   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
9213
9214   MapGadget(gi);
9215 }
9216
9217 static void MapCheckbuttonGadget(int id)
9218 {
9219   int font_nr = FONT_TEXT_1;
9220   int font_height = getFontHeight(font_nr);
9221   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
9222   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9223   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9224   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9225   int yoffset = (gi->height - font_height) / 2;
9226   int y_above = gi->y - yoffset_above;
9227   int x = gi->x;
9228   int x_left, x_right, y;       // set after gadget position was modified
9229
9230   // set position for gadgets with dynamically determined position
9231   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9232     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9233   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9234
9235   x_left = gi->x - xoffset_left;
9236   x_right = gi->x + gi->width + xoffset_right;
9237   y = gi->y + yoffset;
9238
9239   if (checkbutton_info[id].text_above)
9240     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9241
9242   if (checkbutton_info[id].text_left)
9243     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9244
9245   if (checkbutton_info[id].text_right)
9246     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9247
9248   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9249
9250   MapGadget(gi);
9251 }
9252
9253 static void MapMainDrawingArea(void)
9254 {
9255   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9256   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9257   int i;
9258
9259   if (suppressBorderElement())
9260   {
9261     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9262     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9263   }
9264
9265   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9266   {
9267     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9268           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9269          no_horizontal_scrollbar) ||
9270         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9271           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9272          no_vertical_scrollbar))
9273       continue;
9274
9275     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9276   }
9277
9278   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9279   {
9280     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9281         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9282       continue;
9283
9284     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9285   }
9286
9287   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9288 }
9289
9290 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9291 {
9292   int i;
9293
9294   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9295   {
9296     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9297         i == GADGET_ID_CUSTOM_COPY_TO ||
9298         i == GADGET_ID_CUSTOM_EXCHANGE ||
9299         i == GADGET_ID_CUSTOM_COPY ||
9300         i == GADGET_ID_CUSTOM_PASTE)
9301     {
9302       if (map)
9303         MapGadget(level_editor_gadget[i]);
9304       else
9305         UnmapGadget(level_editor_gadget[i]);
9306     }
9307   }
9308 }
9309
9310 static void MapLevelEditorToolboxCustomGadgets(void)
9311 {
9312   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9313 }
9314
9315 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9316 {
9317   if (IS_CUSTOM_ELEMENT(properties_element) ||
9318       IS_GROUP_ELEMENT(properties_element) ||
9319       IS_EMPTY_ELEMENT(properties_element))
9320     MapLevelEditorToolboxCustomGadgets();
9321 }
9322
9323 static void UnmapLevelEditorToolboxCustomGadgets(void)
9324 {
9325   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9326 }
9327
9328 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9329 {
9330   int i;
9331
9332   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9333   {
9334     if (i != GADGET_ID_SINGLE_ITEMS &&
9335         i != GADGET_ID_PICK_ELEMENT)
9336     {
9337       struct GadgetInfo *gi = level_editor_gadget[i];
9338
9339       if (map)
9340       {
9341         MapGadget(gi);
9342       }
9343       else
9344       {
9345         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9346         struct GraphicInfo *gd = &graphic_info[graphic];
9347
9348         UnmapGadget(gi);
9349
9350         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9351                    gi->width, gi->height, gi->x, gi->y);
9352
9353         redraw_mask |= REDRAW_DOOR_3;
9354       }
9355     }
9356   }
9357 }
9358
9359 static void MapLevelEditorToolboxDrawingGadgets(void)
9360 {
9361   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9362 }
9363
9364 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9365 {
9366   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9367 }
9368
9369 static void UnmapDrawingArea(int id)
9370 {
9371   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9372 }
9373
9374 static void UnmapLevelEditorFieldGadgets(void)
9375 {
9376   int i;
9377
9378   for (i = 0; i < num_editor_gadgets; i++)
9379     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9380                           level_editor_gadget[i]->y))
9381       UnmapGadget(level_editor_gadget[i]);
9382 }
9383
9384 void UnmapLevelEditorGadgets(void)
9385 {
9386   int i;
9387
9388   for (i = 0; i < num_editor_gadgets; i++)
9389     UnmapGadget(level_editor_gadget[i]);
9390 }
9391
9392 static void ResetUndoBuffer(void)
9393 {
9394   undo_buffer_position = -1;
9395   undo_buffer_steps = -1;
9396   redo_buffer_steps = 0;
9397
9398   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9399
9400   level.changed = FALSE;
9401 }
9402
9403 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9404 {
9405   if (remap_toolbox_gadgets)
9406   {
9407     ModifyEditorElementList();
9408     RedrawDrawingElements();
9409   }
9410
9411   if (edit_mode == ED_MODE_LEVELCONFIG)
9412     DrawLevelConfigWindow();
9413   else if (edit_mode == ED_MODE_PROPERTIES)
9414     DrawPropertiesWindow();
9415   else if (edit_mode == ED_MODE_PALETTE)
9416     DrawPaletteWindow();
9417   else  // edit_mode == ED_MODE_DRAWING
9418     DrawDrawingWindowExt(remap_toolbox_gadgets);
9419 }
9420
9421 static void DrawEditModeWindow(void)
9422 {
9423   DrawEditModeWindowExt(TRUE);
9424 }
9425
9426 static void DrawEditModeWindow_PlayfieldOnly(void)
9427 {
9428   DrawEditModeWindowExt(FALSE);
9429 }
9430
9431 static void ChangeEditModeWindow(int new_edit_mode)
9432 {
9433   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9434
9435   DrawEditModeWindow();
9436 }
9437
9438 static boolean LevelChanged(void)
9439 {
9440   boolean field_changed = FALSE;
9441   int x, y;
9442
9443   for (y = 0; y < lev_fieldy; y++) 
9444     for (x = 0; x < lev_fieldx; x++)
9445       if (Tile[x][y] != level.field[x][y])
9446         field_changed = TRUE;
9447
9448   return (level.changed || field_changed);
9449 }
9450
9451 static boolean PrepareSavingIntoPersonalLevelSet(void)
9452 {
9453   static LevelDirTree *last_copied_leveldir = NULL;
9454   static LevelDirTree *last_written_leveldir = NULL;
9455   static int last_copied_level_nr = -1;
9456   static int last_written_level_nr = -1;
9457   LevelDirTree *leveldir_former = leveldir_current;
9458   int level_nr_former = level_nr;
9459   int new_level_nr;
9460
9461   // remember last mod/save so that for current session, we write
9462   // back to the same personal copy, asking only about overwrite.
9463   if (leveldir_current == last_copied_leveldir &&
9464       level_nr == last_copied_level_nr)
9465   {
9466     // "cd" to personal level set dir (as used when writing last copy)
9467     leveldir_current = last_written_leveldir;
9468     level_nr = last_written_level_nr;
9469
9470     return TRUE;
9471   }
9472
9473   if (!Request("This level is read-only! "
9474                "Save into personal level set?", REQ_ASK))
9475     return FALSE;
9476
9477   // "cd" to personal level set dir (for writing copy the first time)
9478   leveldir_current =
9479     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9480
9481   // this may happen if "setup.internal.create_user_levelset" is FALSE
9482   // or if file "levelinfo.conf" is missing in personal user level set
9483   if (leveldir_current == NULL)
9484   {
9485     Request("Cannot find personal level set?!", REQ_CONFIRM);
9486
9487     leveldir_current = leveldir_former;
9488
9489     return FALSE;
9490   }
9491
9492   // find unused level number
9493   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9494   {
9495     static char *level_filename = NULL;
9496
9497     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9498
9499     if (!fileExists(level_filename))
9500       break;
9501   }
9502
9503   last_copied_leveldir = leveldir_former;
9504   last_copied_level_nr = level_nr_former;
9505
9506   last_written_leveldir = leveldir_current;
9507   last_written_level_nr = level_nr = new_level_nr;
9508
9509   return TRUE;
9510 }
9511
9512 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9513 {
9514   static char *filename_levelinfo = NULL, *mod_name = NULL;
9515   FILE *file;
9516
9517   // annotate this copy-and-mod in personal levelinfo.conf
9518   setString(&filename_levelinfo,
9519             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9520
9521   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9522   {
9523     fprintf(file, "\n");
9524     fprintf(file, "# level %d was modified from:\n", level_nr);
9525     fprintf(file, "# - previous level set name:    %s\n",
9526             former_name);
9527     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9528             level.file_info.nr, level.name);
9529     fprintf(file, "# - previous author:            %s\n",
9530             level.author);
9531     fprintf(file, "# - previous save date:         ");
9532
9533     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9534     {
9535       fprintf(file, "%04d-%02d-%02d\n",
9536               level.creation_date.year,
9537               level.creation_date.month,
9538               level.creation_date.day);
9539     }
9540     else
9541     {
9542       fprintf(file, "not recorded\n");
9543     }
9544
9545     fclose(file);
9546   }
9547
9548   if (level_nr > leveldir_current->last_level)
9549     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9550
9551   // else: allow the save even if annotation failed
9552
9553   // now... spray graffiti on the old level vital statistics
9554   // user can change these; just trying to set a good baseline
9555
9556   // don't truncate names for fear of making offensive or silly:
9557   // long-named original author only recorded in levelinfo.conf.
9558   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9559   if (!strEqual(level.author, leveldir_current->author))
9560   {
9561     setString(&mod_name, getStringCat3(leveldir_current->author,
9562                                        " after ", level.author));
9563
9564     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9565       setString(&mod_name,
9566                 getStringCat2(leveldir_current->author, " (ed.)"));
9567
9568     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9569       setString(&mod_name, leveldir_current->author);
9570
9571     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9572
9573     // less worried about truncation here
9574     setString(&mod_name, getStringCat2("Mod: ", level.name));
9575     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9576   }
9577 }
9578
9579 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9580                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9581 {
9582   int x, y;
9583
9584   for (x = 0; x < lev_fieldx; x++)
9585     for (y = 0; y < lev_fieldy; y++) 
9586       dst[x][y] = src[x][y];
9587 }
9588
9589 static int setSelectboxValue(int selectbox_id, int new_value)
9590 {
9591   int new_index_value = 0;
9592   int i;
9593
9594   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9595     if (selectbox_info[selectbox_id].options[i].value == new_value)
9596       new_index_value = i;
9597
9598   *selectbox_info[selectbox_id].value =
9599     selectbox_info[selectbox_id].options[new_index_value].value;
9600
9601   return new_index_value;
9602 }
9603
9604 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9605 {
9606   int i;
9607
9608   // change action mode and arg variables according to action type variable
9609   for (i = 0; action_arg_options[i].value != -1; i++)
9610   {
9611     if (action_arg_options[i].value == custom_element_change.action_type)
9612     {
9613       int mode = action_arg_options[i].mode;
9614
9615       // only change if corresponding selectbox has changed
9616       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9617           action_arg_modes[mode])
9618         custom_element_change.action_mode = -1;
9619
9620       // only change if corresponding selectbox has changed
9621       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9622           action_arg_options[i].options)
9623         custom_element_change.action_arg = -1;
9624
9625       break;
9626     }
9627   }
9628 }
9629
9630 static void setSelectboxSpecialActionOptions(void)
9631 {
9632   int i;
9633
9634   // change action mode and arg selectbox according to action type selectbox
9635   for (i = 0; action_arg_options[i].value != -1; i++)
9636   {
9637     if (action_arg_options[i].value == custom_element_change.action_type)
9638     {
9639       int mode = action_arg_options[i].mode;
9640
9641       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9642                                    action_arg_modes[mode]);
9643       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9644                                  custom_element_change.action_mode);
9645
9646       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9647                                    action_arg_options[i].options);
9648       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9649                                  custom_element_change.action_arg);
9650       break;
9651     }
9652   }
9653 }
9654
9655 static void copy_custom_element_settings(int element_from, int element_to)
9656 {
9657   struct ElementInfo *ei_from = &element_info[element_from];
9658   struct ElementInfo *ei_to = &element_info[element_to];
9659
9660   copyElementInfo(ei_from, ei_to);
9661 }
9662
9663 static void replace_custom_element_in_settings(int element_from,
9664                                                int element_to)
9665 {
9666   int i, j, x, y;
9667
9668   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9669   {
9670     struct ElementInfo *ei = &element_info[i];
9671
9672     for (y = 0; y < 3; y++)
9673       for (x = 0; x < 3; x++)
9674         if (ei->content.e[x][y] == element_from)
9675           ei->content.e[x][y] = element_to;
9676
9677     for (j = 0; j < ei->num_change_pages; j++)
9678     {
9679       struct ElementChangeInfo *change = &ei->change_page[j];
9680
9681       if (change->target_element == element_from)
9682         change->target_element = element_to;
9683
9684       if (change->initial_trigger_element == element_from)
9685         change->initial_trigger_element = element_to;
9686
9687       if (change->action_element == element_from)
9688         change->action_element = element_to;
9689
9690       for (y = 0; y < 3; y++)
9691         for (x = 0; x < 3; x++)
9692           if (change->target_content.e[x][y] == element_from)
9693             change->target_content.e[x][y] = element_to;
9694     }
9695
9696     if (ei->group != NULL)                              // group or internal
9697       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9698         if (ei->group->element[j] == element_from)
9699           ei->group->element[j] = element_to;
9700   }
9701 }
9702
9703 static void replace_custom_element_in_playfield(int element_from,
9704                                                 int element_to)
9705 {
9706   int x, y;
9707
9708   for (x = 0; x < lev_fieldx; x++)
9709     for (y = 0; y < lev_fieldy; y++)
9710       if (Tile[x][y] == element_from)
9711         Tile[x][y] = element_to;
9712 }
9713
9714 static boolean CopyCustomElement(int element_old, int element_new,
9715                                  int copy_mode)
9716 {
9717   int copy_mode_orig = copy_mode;
9718
9719   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9720   {
9721     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9722                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9723     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9724   }
9725   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9726   {
9727     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9728                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9729     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9730
9731     level.changed = TRUE;
9732   }
9733   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9734   {
9735     Request("Please choose custom element!", REQ_CONFIRM);
9736
9737     return FALSE;
9738   }
9739   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9740   {
9741     Request("Please choose group element!", REQ_CONFIRM);
9742
9743     return FALSE;
9744   }
9745   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9746   {
9747     Request("Please choose empty element!", REQ_CONFIRM);
9748
9749     return FALSE;
9750   }
9751   else
9752   {
9753     level.changed = TRUE;
9754   }
9755
9756   // when modifying custom/group element, ask for copying level template
9757   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9758   {
9759     if (!AskToCopyAndModifyLevelTemplate())
9760       return FALSE;
9761   }
9762
9763   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9764   {
9765     copy_custom_element_settings(element_new, element_old);
9766   }
9767   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9768   {
9769     copy_custom_element_settings(element_old, element_new);
9770   }
9771   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9772   {
9773     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9774     copy_custom_element_settings(element_new, element_old);
9775     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9776
9777     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9778     replace_custom_element_in_settings(element_new, element_old);
9779     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9780
9781     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9782     replace_custom_element_in_playfield(element_new, element_old);
9783     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9784   }
9785
9786   UpdateCustomElementGraphicGadgets();
9787   DrawPropertiesWindow();
9788
9789   return TRUE;
9790 }
9791
9792 static void CopyCustomElementPropertiesToEditor(int element)
9793 {
9794   int i;
9795   int current_change_page = element_info[element].current_change_page;
9796
9797   // dynamically (re)build selectbox for selecting change page
9798   for (i = 0; i < element_info[element].num_change_pages; i++)
9799   {
9800     sprintf(options_change_page_strings[i], "%d", i + 1);
9801
9802     options_change_page[i].value = i;
9803     options_change_page[i].text = options_change_page_strings[i];
9804   }
9805
9806   options_change_page[i].value = -1;
9807   options_change_page[i].text = NULL;
9808
9809   // needed here to initialize combined element properties
9810   InitElementPropertiesEngine(level.game_version);
9811
9812   element_info[element].change =
9813     &element_info[element].change_page[current_change_page];
9814
9815   custom_element = element_info[element];
9816   custom_element_change = *element_info[element].change;
9817
9818   // needed to initially set selectbox options for special action options
9819   setSelectboxSpecialActionOptions();
9820
9821   // needed to initially set selectbox value variables to reliable defaults
9822   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9823     setSelectboxValue(i, *selectbox_info[i].value);
9824
9825   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9826     custom_element_properties[i] = HAS_PROPERTY(element, i);
9827
9828   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9829     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9830
9831   // ---------- element settings: configure (custom elements) -----------------
9832
9833   // set accessible layer selectbox help value
9834   custom_element.access_type =
9835     (IS_WALKABLE(element) ? EP_WALKABLE :
9836      IS_PASSABLE(element) ? EP_PASSABLE :
9837      custom_element.access_type);
9838   custom_element.access_layer =
9839     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9840      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9841      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9842      custom_element.access_layer);
9843   custom_element.access_protected =
9844     (IS_PROTECTED(element) ? 1 : 0);
9845   custom_element_properties[EP_ACCESSIBLE] =
9846     (IS_ACCESSIBLE_OVER(element) ||
9847      IS_ACCESSIBLE_INSIDE(element) ||
9848      IS_ACCESSIBLE_UNDER(element));
9849
9850   // set walk-to-object action selectbox help value
9851   custom_element.walk_to_action =
9852     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9853      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9854      IS_DROPPABLE(element) ? EP_DROPPABLE :
9855      IS_THROWABLE(element) ? EP_THROWABLE :
9856      IS_PUSHABLE(element) ? EP_PUSHABLE :
9857      custom_element.walk_to_action);
9858   custom_element_properties[EP_WALK_TO_OBJECT] =
9859     (IS_DIGGABLE(element) ||
9860      IS_COLLECTIBLE_ONLY(element) ||
9861      IS_DROPPABLE(element) ||
9862      IS_THROWABLE(element) ||
9863      IS_PUSHABLE(element));
9864
9865   // set smash targets selectbox help value
9866   custom_element.smash_targets =
9867     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9868      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9869      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9870      custom_element.smash_targets);
9871   custom_element_properties[EP_CAN_SMASH] =
9872     (CAN_SMASH_EVERYTHING(element) ||
9873      CAN_SMASH_ENEMIES(element) ||
9874      CAN_SMASH_PLAYER(element));
9875
9876   // set deadliness selectbox help value
9877   custom_element.deadliness =
9878     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9879      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9880      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9881      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9882      custom_element.deadliness);
9883   custom_element_properties[EP_DEADLY] =
9884     (DONT_TOUCH(element) ||
9885      DONT_GET_HIT_BY(element) ||
9886      DONT_COLLIDE_WITH(element) ||
9887      DONT_RUN_INTO(element));
9888
9889   // ---------- element settings: advanced (custom elements) ------------------
9890
9891   // set "change by direct action" selectbox help value
9892   custom_element_change.direct_action =
9893     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9894      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9895      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9896      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9897      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9898      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9899      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9900      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9901      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9902      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9903      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9904      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9905      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9906      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9907      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9908      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9909      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9910      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9911      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9912      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9913      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9914      custom_element_change.direct_action);
9915
9916   // set "change by other element action" selectbox help value
9917   custom_element_change.other_action =
9918     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9919      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9920      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9921      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9922      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9923      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9924      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9925      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9926      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9927      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9928      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9929      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9930      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9931      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9932      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9933      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9934      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9935      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9936      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9937      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9938      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9939      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9940      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9941      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9942      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9943      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9944      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9945      custom_element_change.other_action);
9946 }
9947
9948 static void CopyGroupElementPropertiesToEditor(int element)
9949 {
9950   group_element_info = *element_info[element].group;
9951   custom_element = element_info[element];       // needed for description
9952 }
9953
9954 static void CopyEmptyElementPropertiesToEditor(int element)
9955 {
9956   custom_element = element_info[element];
9957 }
9958
9959 static void CopyClassicElementPropertiesToEditor(int element)
9960 {
9961   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9962     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9963       getMoveIntoAcidProperty(&level, element);
9964
9965   if (MAYBE_DONT_COLLIDE_WITH(element))
9966     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9967       getDontCollideWithProperty(&level, element);
9968 }
9969
9970 static void CopyElementPropertiesToEditor(int element)
9971 {
9972   if (IS_CUSTOM_ELEMENT(element))
9973     CopyCustomElementPropertiesToEditor(element);
9974   else if (IS_GROUP_ELEMENT(element))
9975     CopyGroupElementPropertiesToEditor(element);
9976   else if (IS_EMPTY_ELEMENT(element))
9977     CopyEmptyElementPropertiesToEditor(element);
9978   else
9979     CopyClassicElementPropertiesToEditor(element);
9980 }
9981
9982 static boolean AskToCopyAndModifyLevelTemplate(void)
9983 {
9984   if (Request("Copy and modify settings from level template?", REQ_ASK))
9985   {
9986     level.use_custom_template = FALSE;
9987
9988     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9989                  GDI_CHECKED, FALSE, GDI_END);
9990     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9991                  GDI_CHECKED, FALSE, GDI_END);
9992
9993     return TRUE;
9994   }
9995   else
9996   {
9997     LoadLevelTemplate(-1);      // this resets all element modifications ...
9998
9999     DrawEditModeWindow();       // ... and copies them to 'custom_element'
10000
10001     return FALSE;
10002   }
10003 }
10004
10005 static void CopyCustomElementPropertiesToGame(int element)
10006 {
10007   int i;
10008   int access_type_and_layer;
10009
10010   // mark that this custom element has been modified
10011   custom_element.modified_settings = TRUE;
10012   level.changed = TRUE;
10013
10014   if (level.use_custom_template)
10015     AskToCopyAndModifyLevelTemplate();
10016
10017   element_info[element] = custom_element;
10018   *element_info[element].change = custom_element_change;
10019
10020   // ---------- element settings: configure (custom elements) -----------------
10021
10022   // set accessible property from checkbox and selectbox
10023   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
10024   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
10025   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
10026   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
10027   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
10028   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
10029   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
10030                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
10031                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
10032   custom_element_properties[access_type_and_layer] =
10033     custom_element_properties[EP_ACCESSIBLE];
10034   custom_element_properties[EP_PROTECTED] =
10035     (custom_element.access_protected != 0 &&
10036      custom_element_properties[EP_ACCESSIBLE]);
10037
10038   // set walk-to-object property from checkbox and selectbox
10039   custom_element_properties[EP_DIGGABLE] = FALSE;
10040   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
10041   custom_element_properties[EP_DROPPABLE] = FALSE;
10042   custom_element_properties[EP_THROWABLE] = FALSE;
10043   custom_element_properties[EP_PUSHABLE] = FALSE;
10044   custom_element_properties[custom_element.walk_to_action] =
10045     custom_element_properties[EP_WALK_TO_OBJECT];
10046
10047   // set smash property from checkbox and selectbox
10048   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
10049   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
10050   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
10051   custom_element_properties[custom_element.smash_targets] =
10052     custom_element_properties[EP_CAN_SMASH];
10053
10054   // set deadliness property from checkbox and selectbox
10055   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
10056   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
10057   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
10058   custom_element_properties[EP_DONT_TOUCH] = FALSE;
10059   custom_element_properties[custom_element.deadliness] =
10060     custom_element_properties[EP_DEADLY];
10061
10062   // ---------- element settings: advanced (custom elements) ------------------
10063
10064   // set player change event from checkbox and selectbox
10065   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
10066   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
10067   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
10068   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
10069   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
10070   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
10071   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
10072   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
10073   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
10074   custom_element_change_events[CE_SWITCHED] = FALSE;
10075   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
10076   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
10077   custom_element_change_events[CE_BLOCKED] = FALSE;
10078   custom_element_change_events[CE_IMPACT] = FALSE;
10079   custom_element_change_events[CE_SMASHED] = FALSE;
10080   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
10081   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
10082   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
10083   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
10084   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
10085   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
10086   custom_element_change_events[custom_element_change.direct_action] =
10087     custom_element_change_events[CE_BY_DIRECT_ACTION];
10088
10089   // set other element action change event from checkbox and selectbox
10090   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
10091   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
10092   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
10093   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
10094   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
10095   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
10096   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
10097   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
10098   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
10099   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
10100   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
10101   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
10102   custom_element_change_events[CE_TOUCHING_X] = FALSE;
10103   custom_element_change_events[CE_HITTING_X] = FALSE;
10104   custom_element_change_events[CE_DIGGING_X] = FALSE;
10105   custom_element_change_events[CE_HIT_BY_X] = FALSE;
10106   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
10107   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
10108   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
10109   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
10110   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
10111   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
10112   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
10113   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
10114   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
10115   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
10116   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
10117   custom_element_change_events[custom_element_change.other_action] =
10118     custom_element_change_events[CE_BY_OTHER_ACTION];
10119
10120   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
10121     SET_PROPERTY(element, i, custom_element_properties[i]);
10122
10123   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
10124     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
10125
10126   // copy change events also to special level editor variable
10127   custom_element = element_info[element];
10128   custom_element_change = *element_info[element].change;
10129
10130   // needed here to restore runtime value "element_info[element].gfx_element"
10131   InitElementPropertiesGfxElement();
10132 }
10133
10134 static void CopyGroupElementPropertiesToGame(int element)
10135 {
10136   // mark that this group element has been modified
10137   custom_element.modified_settings = TRUE;
10138   level.changed = TRUE;
10139
10140   if (level.use_custom_template)
10141     AskToCopyAndModifyLevelTemplate();
10142
10143   element_info[element] = custom_element;
10144   *element_info[element].group = group_element_info;
10145
10146   // needed here to restore runtime value "element_info[element].gfx_element"
10147   InitElementPropertiesGfxElement();
10148 }
10149
10150 static void CopyEmptyElementPropertiesToGame(int element)
10151 {
10152   // mark that this empty element has been modified
10153   custom_element.modified_settings = TRUE;
10154   level.changed = TRUE;
10155
10156   if (level.use_custom_template)
10157     AskToCopyAndModifyLevelTemplate();
10158
10159   element_info[element] = custom_element;
10160
10161   // needed here to restore runtime value "element_info[element].gfx_element"
10162   InitElementPropertiesGfxElement();
10163 }
10164
10165 static void CopyClassicElementPropertiesToGame(int element)
10166 {
10167   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
10168     setMoveIntoAcidProperty(&level, element,
10169                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
10170
10171   if (MAYBE_DONT_COLLIDE_WITH(element))
10172     setDontCollideWithProperty(&level, element,
10173                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
10174 }
10175
10176 static void CopyElementPropertiesToGame(int element)
10177 {
10178   if (IS_CUSTOM_ELEMENT(element))
10179     CopyCustomElementPropertiesToGame(element);
10180   else if (IS_GROUP_ELEMENT(element))
10181     CopyGroupElementPropertiesToGame(element);
10182   else if (IS_EMPTY_ELEMENT(element))
10183     CopyEmptyElementPropertiesToGame(element);
10184   else
10185     CopyClassicElementPropertiesToGame(element);
10186 }
10187
10188 #if DEBUG
10189 static void CheckElementDescriptions(void)
10190 {
10191   int i;
10192
10193   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10194     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
10195       Warn("no element description file for element '%s'", EL_NAME(i));
10196 }
10197 #endif
10198
10199 static int getMaxEdFieldX(boolean has_scrollbar)
10200 {
10201   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
10202   int sxsize = SXSIZE - scrollbar_width;
10203   int max_ed_fieldx = sxsize / ed_tilesize;
10204
10205   return max_ed_fieldx;
10206 }
10207
10208 static int getMaxEdFieldY(boolean has_scrollbar)
10209 {
10210   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
10211                          INFOTEXT_YSIZE_FULL : 0);
10212   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
10213   int sysize = SYSIZE - scrollbar_height - infotext_height;
10214   int max_ed_fieldy = sysize / ed_tilesize;
10215
10216   return max_ed_fieldy;
10217 }
10218
10219 static void InitZoomLevelSettings(int zoom_tilesize)
10220 {
10221   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
10222
10223   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
10224   {
10225     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10226     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10227
10228     // make sure that tile size is always a power of 2
10229     ed_tilesize = (1 << log_2(ed_tilesize));
10230
10231     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10232     {
10233       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10234       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10235     }
10236   }
10237
10238   last_game_engine_type = level.game_engine_type;
10239
10240   // limit zoom tilesize by upper and lower bound
10241   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10242
10243   // store zoom tilesize in auto setup file only if it was manually changed
10244   if (zoom_tilesize != -1)
10245     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10246
10247   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10248   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10249 }
10250
10251 static void InitDrawingElements(void)
10252 {
10253   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10254
10255   if (level.game_engine_type == game_engine_type_last)
10256     return;
10257
10258   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10259   {
10260     new_element1 = EL_BD_WALL;
10261     new_element2 = EL_EMPTY;
10262     new_element3 = EL_BD_SAND;
10263   }
10264   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10265   {
10266     new_element1 = EL_SP_CHIP_SINGLE;
10267     new_element2 = EL_EMPTY;
10268     new_element3 = EL_SP_BASE;
10269   }
10270   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10271   {
10272     new_element1 = EL_MM_MIRROR_START;
10273     new_element2 = EL_EMPTY;
10274     new_element3 = EL_MM_WOODEN_WALL;
10275   }
10276   else
10277   {
10278     new_element1 = EL_WALL;
10279     new_element2 = EL_EMPTY;
10280     new_element3 = EL_SAND;
10281   }
10282
10283   game_engine_type_last = level.game_engine_type;
10284 }
10285
10286 static void InitLevelSetInfo(void)
10287 {
10288   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10289            "%s", leveldir_current->name);
10290   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10291            "%s", leveldir_current->author);
10292
10293   levelset_num_levels = leveldir_current->levels;
10294
10295   levelset_use_levelset_artwork = FALSE;
10296   levelset_copy_level_template = FALSE;
10297
10298   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10299 }
10300
10301 static void ChangeEditorToLevelSet(char *levelset_subdir)
10302 {
10303   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10304
10305   // the previous level set might have used custom artwork
10306   ReloadCustomArtwork(0);
10307
10308   LoadLevelSetup_SeriesInfo();
10309
10310   SaveLevelSetup_LastSeries();
10311   SaveLevelSetup_SeriesInfo();
10312
10313   TapeErase();
10314
10315   LoadLevel(level_nr);
10316   LoadScore(level_nr);
10317
10318   DrawLevelEd();
10319 }
10320
10321 static boolean useEditorDoorAnimation(void)
10322 {
10323   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10324   boolean door_1_viewport_unchanged =
10325     (vp_door_1->x      == DX     &&
10326      vp_door_1->y      == DY     &&
10327      vp_door_1->width  == DXSIZE &&
10328      vp_door_1->height == DYSIZE);
10329   boolean door_1_contains_toolbox =
10330     (EX >= DX &&
10331      EY >= DY &&
10332      EX + EXSIZE <= DX + DXSIZE &&
10333      EY + EYSIZE <= DY + DYSIZE);
10334
10335   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10336 }
10337
10338 static void DrawEditorDoorBackground(int graphic, int x, int y,
10339                                      int width, int height)
10340 {
10341   struct GraphicInfo *g = &graphic_info[graphic];
10342
10343   if (g->bitmap != NULL)
10344     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10345                MIN(width, g->width), MIN(height, g->height), x, y);
10346   else
10347     ClearRectangle(drawto, x, y, width, height);
10348 }
10349
10350 static void DrawEditorDoorContent(void)
10351 {
10352   // needed for gadgets drawn on background (like palette scrollbar)
10353   SetDoorBackgroundImage(IMG_UNDEFINED);
10354
10355   // copy default editor door content to main double buffer
10356   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10357
10358   // draw bigger door
10359   DrawSpecialEditorDoor();
10360
10361   // draw new control window
10362   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10363
10364   // draw all toolbox gadgets to editor doors
10365   MapControlButtons();
10366
10367   // when returning from test game to properties page, redraw toolbox gadgets
10368   if (edit_mode == ED_MODE_PROPERTIES)
10369   {
10370     UnmapLevelEditorToolboxDrawingGadgets();
10371     UnmapLevelEditorToolboxCustomGadgets();
10372
10373     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10374   }
10375
10376   // draw all palette gadgets to editor doors
10377   ModifyEditorElementList();
10378   RedrawDrawingElements();
10379
10380   // copy actual editor door content to door double buffer for OpenDoor()
10381   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10382 }
10383
10384 void DrawLevelEd(void)
10385 {
10386   int fade_mask = REDRAW_FIELD;
10387
10388   FadeSoundsAndMusic();
10389
10390   if (CheckFadeAll())
10391     fade_mask = REDRAW_ALL;
10392
10393   FadeOut(fade_mask);
10394
10395   // needed if different viewport properties defined for editor
10396   ChangeViewportPropertiesIfNeeded();
10397
10398   ClearField();
10399
10400   InitZoomLevelSettings(-1);
10401   InitDrawingElements();
10402   InitLevelSetInfo();
10403
10404 #if DEBUG
10405   CheckElementDescriptions();
10406 #endif
10407
10408   if (level_editor_test_game)
10409   {
10410     CopyPlayfield(level.field, Tile);
10411     CopyPlayfield(TileBackup, level.field);
10412
10413     level_editor_test_game = FALSE;
10414   }
10415   else
10416   {
10417     edit_mode = ED_MODE_DRAWING;
10418     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10419     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10420
10421     ResetUndoBuffer();
10422
10423     level_xpos = -1;
10424     level_ypos = -1;
10425   }
10426
10427   // redraw_mask |= REDRAW_ALL;
10428
10429   FreeLevelEditorGadgets();
10430   CreateLevelEditorGadgets();
10431
10432   ReinitializeElementList();            // update dynamic level element list
10433   ReinitializeElementListButtons();     // custom element may look different
10434
10435   InitElementPropertiesGfxElement();
10436
10437   UnmapAllGadgets();
10438
10439   DrawEditModeWindow_PlayfieldOnly();
10440
10441   DrawMaskedBorder(fade_mask);
10442
10443   // use door animation if door 1 viewport is unchanged and contains toolbox
10444   if (useEditorDoorAnimation())
10445   {
10446     FadeIn(fade_mask);
10447
10448     DrawEditorDoorContent();
10449
10450     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10451   }
10452   else
10453   {
10454     DrawEditorDoorContent();
10455
10456     FadeIn(fade_mask);
10457   }
10458
10459   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10460 }
10461
10462 static void AdjustDrawingAreaGadgets(void)
10463 {
10464   int ed_xsize = lev_fieldx + 2;
10465   int ed_ysize = lev_fieldy + 2;
10466   int max_ed_fieldx = MAX_ED_FIELDX;
10467   int max_ed_fieldy = MAX_ED_FIELDY;
10468   boolean horizontal_scrollbar_needed;
10469   boolean vertical_scrollbar_needed;
10470   int x, y, width, height;
10471
10472   if (suppressBorderElement())
10473   {
10474     ed_xsize = lev_fieldx;
10475     ed_ysize = lev_fieldy;
10476   }
10477
10478   // check if we need any scrollbars
10479   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10480   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10481
10482   // check if we have a smaller editor field because of scrollbars
10483   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10484   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10485
10486   // check again if we now need more scrollbars because of less space
10487   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10488   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10489
10490   // check if editor field gets even smaller after adding new scrollbars
10491   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10492   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10493
10494   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10495   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10496
10497   x = SX + ed_fieldx * ed_tilesize;
10498   y = SY + ed_fieldy * ed_tilesize;
10499
10500   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10501   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10502
10503   // adjust drawing area gadget
10504   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10505                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10506                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10507                GDI_END);
10508
10509   // adjust horizontal scrollbar gadgets
10510   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10511                GDI_Y, y,
10512                GDI_END);
10513   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10514                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10515                GDI_Y, y,
10516                GDI_END);
10517   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10518                GDI_Y, y,
10519                GDI_WIDTH, width,
10520                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10521                GDI_END);
10522
10523   // adjust vertical scrollbar gadgets
10524   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10525                GDI_X, x,
10526                GDI_END);
10527   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10528                GDI_X, x,
10529                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10530                GDI_END);
10531   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10532                GDI_X, x,
10533                GDI_HEIGHT, height,
10534                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10535                GDI_END);
10536 }
10537
10538 static void AdjustLevelScrollPosition(void)
10539 {
10540   if (level_xpos < -1)
10541     level_xpos = -1;
10542   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10543     level_xpos = lev_fieldx - ed_fieldx + 1;
10544   if (lev_fieldx < ed_fieldx - 2)
10545     level_xpos = -1;
10546
10547   if (level_ypos < -1)
10548     level_ypos = -1;
10549   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10550     level_ypos = lev_fieldy - ed_fieldy + 1;
10551   if (lev_fieldy < ed_fieldy - 2)
10552     level_ypos = -1;
10553
10554   if (suppressBorderElement())
10555   {
10556     level_xpos = 0;
10557     level_ypos = 0;
10558   }
10559 }
10560
10561 static void AdjustEditorScrollbar(int id)
10562 {
10563   struct GadgetInfo *gi = level_editor_gadget[id];
10564   int items_max, items_visible, item_position;
10565
10566   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10567   {
10568     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10569     items_visible = ed_fieldx;
10570     item_position = level_xpos + 1;
10571   }
10572   else
10573   {
10574     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10575     items_visible = ed_fieldy;
10576     item_position = level_ypos + 1;
10577   }
10578
10579   if (item_position > items_max - items_visible)
10580     item_position = items_max - items_visible;
10581
10582   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10583                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10584 }
10585
10586 static void AdjustElementListScrollbar(void)
10587 {
10588   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10589   int items_max, items_visible, item_position;
10590
10591   // correct position of element list scrollbar
10592   if (element_shift < 0)
10593     element_shift = 0;
10594   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10595     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10596
10597   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10598   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10599   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10600
10601   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10602                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10603                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10604 }
10605
10606 static void ModifyEditorCounterValue(int counter_id, int new_value)
10607 {
10608   int *counter_value = counterbutton_info[counter_id].value;
10609   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10610   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10611
10612   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10613
10614   if (counter_value != NULL)
10615     *counter_value = gi->textinput.number_value;
10616 }
10617
10618 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10619 {
10620   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10621   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10622
10623   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10624
10625   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10626       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10627   {
10628     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10629     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10630
10631     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10632     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10633                  GDI_END);
10634   }
10635 }
10636
10637 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10638 {
10639   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10640   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10641   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10642
10643   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10644 }
10645
10646 static void ModifyEditorSelectboxOptions(int selectbox_id,
10647                                          struct ValueTextInfo *options)
10648 {
10649   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10650   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10651
10652   selectbox_info[selectbox_id].options = options;
10653
10654   // set index to zero -- list may be shorter now (correct later, if needed)
10655   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10656                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10657 }
10658
10659 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10660 {
10661   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10662   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10663
10664   drawingarea_info[drawingarea_id].area_xsize = xsize;
10665   drawingarea_info[drawingarea_id].area_ysize = ysize;
10666
10667   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10668 }
10669
10670 static void ModifyEditorElementList(void)
10671 {
10672   int i;
10673
10674   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10675     return;
10676
10677   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10678   {
10679     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10680     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10681     struct GadgetDesign *gd = &gi->deco.design;
10682     int element = editor_elements[element_shift + i];
10683     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10684
10685     UnmapGadget(gi);
10686
10687     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10688
10689     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10690
10691     MapGadget(gi);
10692   }
10693 }
10694
10695 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10696 {
10697   int graphic = el2edimg(element);
10698   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10699
10700   if (pos->x == -1 &&
10701       pos->y == -1)
10702     return;
10703
10704   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10705 }
10706
10707 static void ModifyDrawingElementButton(int element, int id)
10708 {
10709   struct GadgetInfo *gi = level_editor_gadget[id];
10710   Bitmap *deco_bitmap;
10711   int deco_x, deco_y;
10712   int tile_size = gi->deco.width;
10713
10714   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10715
10716   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10717 }
10718
10719 static void PickDrawingElement(int button, int element)
10720 {
10721   struct
10722   {
10723     int *new_element;
10724     struct XYTileSize *pos;
10725     int id;
10726   } de, drawing_elements[] =
10727   {
10728     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10729     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10730     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10731   };
10732
10733   if (button < 1 || button > 3)
10734     return;
10735
10736   if (IS_MM_WALL(element))
10737     element = map_mm_wall_element(element);
10738
10739   de = drawing_elements[button - 1];
10740
10741   *de.new_element = element;    // update global drawing element variable
10742
10743   DrawDrawingElementGraphic(element, de.pos);
10744   ModifyDrawingElementButton(element, de.id);
10745
10746   redraw_mask |= REDRAW_DOOR_1;
10747 }
10748
10749 static void RedrawDrawingElements(void)
10750 {
10751   PickDrawingElement(1, new_element1);
10752   PickDrawingElement(2, new_element2);
10753   PickDrawingElement(3, new_element3);
10754 }
10755
10756 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10757 {
10758   stick_element_properties_window = FALSE;
10759
10760   SetMainBackgroundImage(IMG_UNDEFINED);
10761   ClearField();
10762
10763   UnmapLevelEditorFieldGadgets();
10764
10765   AdjustDrawingAreaGadgets();
10766   AdjustLevelScrollPosition();
10767   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10768   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10769
10770   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10771
10772   MapMainDrawingArea();
10773
10774   if (remap_toolbox_gadgets)
10775   {
10776     UnmapLevelEditorToolboxCustomGadgets();
10777     MapLevelEditorToolboxDrawingGadgets();
10778   }
10779 }
10780
10781 static void DrawDrawingWindow(void)
10782 {
10783   DrawDrawingWindowExt(TRUE);
10784 }
10785
10786 static int getTabulatorBarWidth(void)
10787 {
10788   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10789   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10790
10791   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10792 }
10793
10794 static int getTabulatorBarHeight(void)
10795 {
10796   return ED_TAB_BAR_HEIGHT;
10797 }
10798
10799 static Pixel getTabulatorBarColor(void)
10800 {
10801   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10802   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10803   int gd_x = gd->x + gd_gi1->border.width / 2;
10804   int gd_y = gd->y + gd_gi1->height - 1;
10805
10806   return GetPixel(gd->bitmap, gd_x, gd_y);
10807 }
10808
10809 static void DrawLevelConfigTabulatorGadgets(void)
10810 {
10811   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10812   Pixel tab_color = getTabulatorBarColor();
10813   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10814   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10815   int i;
10816
10817   // draw additional "engine" tabulator when using native BD engine
10818   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10819     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10820
10821   for (i = id_first; i <= id_last; i++)
10822   {
10823     int gadget_id = textbutton_info[i].gadget_id;
10824     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10825     boolean active = (i != edit_mode_levelconfig);
10826
10827     // draw background line below tabulator button
10828     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10829
10830     // draw solid line below inactive tabulator buttons
10831     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10832       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10833                     ED_GADGET_TINY_DISTANCE, tab_color);
10834
10835     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10836     MapTextbuttonGadget(i);
10837   }
10838
10839   // draw little border line below tabulator buttons
10840   if (tab_color != BLACK_PIXEL)                 // black => transparent
10841     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10842                   ED_GADGET_TINY_DISTANCE,
10843                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10844 }
10845
10846 static void DrawPropertiesTabulatorGadgets(void)
10847 {
10848   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10849   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10850   int gd_x = gd->x + gd_gi1->border.width / 2;
10851   int gd_y = gd->y + gd_gi1->height - 1;
10852   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10853   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10854   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10855   int i;
10856
10857   // draw two config tabulators for player elements
10858   if (IS_PLAYER_ELEMENT(properties_element))
10859     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10860
10861   // draw two config and one "change" tabulator for custom elements
10862   if (IS_CUSTOM_ELEMENT(properties_element))
10863     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10864
10865   for (i = id_first; i <= id_last; i++)
10866   {
10867     int gadget_id = textbutton_info[i].gadget_id;
10868     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10869     boolean active = (i != edit_mode_properties);
10870
10871     // use "config 1" and "config 2" instead of "config" for players and CEs
10872     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10873         (IS_PLAYER_ELEMENT(properties_element) ||
10874          IS_CUSTOM_ELEMENT(properties_element)))
10875       continue;
10876
10877     // draw background line below tabulator button
10878     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10879
10880     // draw solid line below inactive tabulator buttons
10881     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10882       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10883                     ED_GADGET_TINY_DISTANCE, tab_color);
10884
10885     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10886     MapTextbuttonGadget(i);
10887   }
10888
10889   // draw little border line below tabulator buttons
10890   if (tab_color != BLACK_PIXEL)                 // black => transparent
10891     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10892                   ED_GADGET_TINY_DISTANCE,
10893                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10894 }
10895
10896 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10897 {
10898   DrawText(SX + xpos, SY + ypos, text, font_nr);
10899 }
10900
10901 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10902                                            int xpos, int ypos)
10903 {
10904   int font_width = getFontWidth(font_nr);
10905   int font_height = getFontHeight(font_nr);
10906   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10907   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10908
10909   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10910                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10911                       TRUE, FALSE, FALSE);
10912 }
10913
10914 static void DrawLevelConfigLevel(void)
10915 {
10916   int i;
10917
10918   // draw counter gadgets
10919   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10920     MapCounterButtons(i);
10921
10922   // draw checkbutton gadgets
10923   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10924     MapCheckbuttonGadget(i);
10925
10926   // draw selectbox gadgets
10927   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10928     MapSelectboxGadget(i);
10929
10930   // draw text input gadgets
10931   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10932     MapTextInputGadget(i);
10933 }
10934
10935 static char *getLevelSubdirFromSaveMode(int save_mode)
10936 {
10937   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10938     return getNewUserLevelSubdir();
10939
10940   return leveldir_current->subdir;
10941 }
10942
10943 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10944 {
10945   char *directory_text = "Level set directory:";
10946   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10947   int font1_nr = FONT_TEXT_1;
10948   int font2_nr = FONT_TEXT_2;
10949   int font1_height = getFontHeight(font1_nr);
10950   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10951   int x = ED_LEVEL_SETTINGS_X(0);
10952   int y = ED_LEVEL_SETTINGS_Y(6);
10953
10954   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10955   PrintInfoText(directory_name, font2_nr, x, y);
10956 }
10957
10958 static void DrawLevelConfigLevelSet(void)
10959 {
10960   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10961   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10962   int i;
10963
10964   // draw counter gadgets
10965   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10966     MapCounterButtons(i);
10967
10968   // draw checkbutton gadgets
10969   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10970   {
10971     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10972         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10973         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10974       continue;
10975
10976     MapCheckbuttonGadget(i);
10977   }
10978
10979   // draw selectbox gadgets
10980   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10981     MapSelectboxGadget(i);
10982
10983   // draw text input gadgets
10984   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10985     MapTextInputGadget(i);
10986
10987   // draw textbutton gadgets
10988   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10989
10990   // draw info text
10991   DrawLevelConfigLevelSet_DirectoryInfo();
10992 }
10993
10994 static void DrawLevelConfigEditor(void)
10995 {
10996   int i;
10997
10998   // draw counter gadgets
10999   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
11000     MapCounterButtons(i);
11001
11002   // draw checkbutton gadgets
11003   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
11004     MapCheckbuttonGadget(i);
11005
11006   // draw radiobutton gadgets
11007   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
11008     MapRadiobuttonGadget(i);
11009
11010   // draw drawing area
11011   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
11012
11013   // draw textbutton gadgets
11014   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
11015 }
11016
11017 static void DrawLevelConfigEngine(void)
11018 {
11019   int i;
11020
11021   // draw counter gadgets
11022   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
11023   {
11024     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
11025     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
11026   }
11027   else
11028   {
11029     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
11030     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
11031   }
11032
11033   // draw checkbutton gadgets
11034   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
11035     MapCheckbuttonGadget(i);
11036
11037   // draw selectbox gadgets
11038   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
11039     MapSelectboxGadget(i);
11040 }
11041
11042 static void DrawLevelConfigWindow(void)
11043 {
11044   char *text = "Global Settings";
11045   int font_nr = FONT_TITLE_1;
11046   struct MenuPosInfo *pos = &editor.settings.headline;
11047   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
11048   int sy = SY + pos->y;
11049
11050   stick_element_properties_window = FALSE;
11051
11052   SetAutomaticNumberOfGemsNeeded();
11053
11054   UnmapLevelEditorFieldGadgets();
11055
11056   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
11057   ClearField();
11058
11059   DrawText(sx, sy, text, font_nr);
11060
11061   DrawLevelConfigTabulatorGadgets();
11062
11063   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
11064     DrawLevelConfigLevel();
11065   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
11066     DrawLevelConfigLevelSet();
11067   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
11068     DrawLevelConfigEditor();
11069   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
11070     DrawLevelConfigEngine();
11071 }
11072
11073 static void DrawCustomContentArea(void)
11074 {
11075   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
11076   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11077   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
11078   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
11079   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
11080   int xoffset = ED_GADGET_SPACE_DISTANCE;
11081
11082   // add distance for potential left text (without drawing area border)
11083   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
11084
11085   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11086
11087   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
11088 }
11089
11090 static void DrawCustomChangeContentArea(void)
11091 {
11092   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
11093   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
11094   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
11095   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
11096   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
11097   int xoffset = ED_GADGET_SPACE_DISTANCE;
11098
11099   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
11100
11101   MapDrawingArea(id);
11102 }
11103
11104 static void RemoveElementContentArea(int id, int font_height)
11105 {
11106   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11107
11108   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
11109                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
11110                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11111                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
11112                  ED_GADGET_TEXT_DISTANCE + font_height);
11113 }
11114
11115 static void DrawYamYamContentAreas(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_YAMYAM_CONTENT_X(3) + 4 * tilesize;
11122   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
11123   int i;
11124
11125   // display counter to choose number of element content areas
11126   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
11127
11128   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11129   {
11130     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
11131
11132     if (i < level.num_yamyam_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, "content", font_nr);
11146   DrawText(x, y + 1 * tilesize, "when",    font_nr);
11147   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
11148 }
11149
11150 static void DrawMagicBallContentAreas(void)
11151 {
11152   int font_nr = FONT_TEXT_1;
11153   int font_height = getFontHeight(font_nr);
11154   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11155   int yoffset = (tilesize - font_height) / 2;
11156   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
11157   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
11158   int i;
11159
11160   // display counter to choose number of element content areas
11161   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
11162
11163   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11164   {
11165     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
11166
11167     if (i < level.num_ball_contents)
11168     {
11169       MapDrawingArea(id);
11170     }
11171     else
11172     {
11173       UnmapDrawingArea(id);
11174
11175       // delete content areas in case of reducing number of them
11176       RemoveElementContentArea(id, font_height);
11177     }
11178   }
11179
11180   DrawText(x, y + 0 * tilesize, "generated", font_nr);
11181   DrawText(x, y + 1 * tilesize, "when",      font_nr);
11182   DrawText(x, y + 2 * tilesize, "active",    font_nr);
11183 }
11184
11185 static void DrawAndroidElementArea(void)
11186 {
11187   int id = ED_DRAWING_ID_ANDROID_CONTENT;
11188   int num_elements = level.num_android_clone_elements;
11189   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11190   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11191   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11192   int xsize = MAX_ANDROID_ELEMENTS;
11193   int ysize = 1;
11194
11195   // display counter to choose number of element areas
11196   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
11197
11198   if (drawingarea_info[id].text_left != NULL)
11199     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11200
11201   UnmapDrawingArea(id);
11202
11203   ModifyEditorDrawingArea(id, num_elements, 1);
11204
11205   // delete content areas in case of reducing number of them
11206   DrawBackground(sx, sy,
11207                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11208                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11209
11210   MapDrawingArea(id);
11211 }
11212
11213 static void DrawGroupElementArea(void)
11214 {
11215   int id = ED_DRAWING_ID_GROUP_CONTENT;
11216   int num_elements = group_element_info.num_elements;
11217   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11218   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11219   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11220   int xsize = MAX_ELEMENTS_IN_GROUP;
11221   int ysize = 1;
11222
11223   if (drawingarea_info[id].text_left != NULL)
11224     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11225
11226   UnmapDrawingArea(id);
11227
11228   ModifyEditorDrawingArea(id, num_elements, 1);
11229
11230   // delete content areas in case of reducing number of them
11231   DrawBackground(sx, sy,
11232                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11233                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11234
11235   MapDrawingArea(id);
11236 }
11237
11238 static void DrawPlayerInitialInventoryArea(int element)
11239 {
11240   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11241   int player_nr = GET_PLAYER_NR(element);
11242   int num_elements = level.initial_inventory_size[player_nr];
11243   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11244   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11245   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11246   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11247   int ysize = 1;
11248
11249   // determine horizontal position to the right of specified gadget
11250   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11251     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11252           ED_DRAWINGAREA_TEXT_DISTANCE);
11253
11254   // determine horizontal offset for leading text
11255   if (drawingarea_info[id].text_left != NULL)
11256     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11257
11258   UnmapDrawingArea(id);
11259
11260   ModifyEditorDrawingArea(id, num_elements, 1);
11261
11262   // delete content areas in case of reducing number of them
11263   DrawBackground(sx, sy,
11264                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11265                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11266
11267   MapDrawingArea(id);
11268 }
11269
11270 static void DrawMMBallContentArea(void)
11271 {
11272   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11273   int num_elements = level.num_mm_ball_contents;
11274   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11275   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11276   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11277   int xsize = MAX_MM_BALL_CONTENTS;
11278   int ysize = 1;
11279
11280   if (drawingarea_info[id].text_left != NULL)
11281     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11282
11283   UnmapDrawingArea(id);
11284
11285   ModifyEditorDrawingArea(id, num_elements, 1);
11286
11287   // delete content areas in case of reducing number of them
11288   DrawBackground(sx, sy,
11289                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11290                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11291
11292   MapDrawingArea(id);
11293 }
11294
11295 static void DrawEnvelopeTextArea(int envelope_nr)
11296 {
11297   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11298   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11299
11300   UnmapGadget(gi);
11301
11302   DrawBackground(gi->x, gi->y,
11303                  gi->textarea.crop_width, gi->textarea.crop_height);
11304
11305   if (envelope_nr != -1)
11306     textarea_info[id].value = level.envelope[envelope_nr].text;
11307
11308   ModifyGadget(gi, GDI_AREA_SIZE,
11309                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11310                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11311                GDI_END);
11312
11313   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11314 }
11315
11316 static void DrawPropertiesInfo(void)
11317 {
11318   static struct
11319   {
11320     int value;
11321     char *text;
11322   }
11323   properties[] =
11324   {
11325     // configurable properties
11326
11327     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11328     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11329     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11330     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11331     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11332     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11333     { EP_PROTECTED,             "- player is protected by it"           },
11334
11335     { EP_DIGGABLE,              "- can be digged away"                  },
11336     { EP_COLLECTIBLE,           "- can be collected"                    },
11337     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11338     { EP_THROWABLE,             "- can be thrown after collecting"      },
11339     { EP_PUSHABLE,              "- can be pushed"                       },
11340
11341     { EP_CAN_FALL,              "- can fall"                            },
11342     { EP_CAN_MOVE,              "- can move"                            },
11343
11344     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11345 #if 0
11346     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11347 #endif
11348     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11349
11350     { EP_SLIPPERY,              "- slippery for falling elements"       },
11351     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11352
11353     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11354     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11355     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11356     { EP_DONT_TOUCH,            "- deadly when touching"                },
11357
11358     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11359
11360     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11361     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11362     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11363
11364     { EP_CAN_CHANGE,            "- can change to other element"         },
11365
11366     // pre-defined properties
11367     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11368     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11369     { EP_SWITCHABLE,            "- can be switched"                     },
11370 #if 0
11371     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11372 #endif
11373
11374     { -1,                       NULL                                    }
11375   };
11376   char *filename = getElementDescriptionFilename(properties_element);
11377   char *num_elements_text = "In this level: ";
11378   char *num_similar_text = "Similar tiles: ";
11379   char *properties_text = "Standard properties: ";
11380   char *description_text = "Description:";
11381   char *no_description_text = "No description available.";
11382   char *none_text = "None";
11383   float percentage;
11384   int num_elements_in_level = 0;
11385   int num_similar_in_level = 0;
11386   int num_hires_tiles_in_level = 0;
11387   int num_standard_properties = 0;
11388   int font1_nr = FONT_TEXT_1;
11389   int font2_nr = FONT_TEXT_2;
11390   int font1_width = getFontWidth(font1_nr);
11391   int font1_height = getFontHeight(font1_nr);
11392   int font2_height = getFontHeight(font2_nr);
11393   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11394   int font2_yoffset = (font1_height - font2_height) / 2;
11395   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11396   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11397   int properties_text_len = strlen(properties_text) * font1_width;
11398   int xpos = ED_ELEMENT_SETTINGS_X(0);
11399   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11400   int i, x, y;
11401
11402   if (setup.editor.show_element_token)
11403   {
11404     int font3_nr = FONT_TEXT_3;
11405     int font3_height = getFontHeight(font3_nr);
11406
11407     DrawTextF(xpos, ypos, font3_nr,
11408               "[%s]", element_info[properties_element].token_name);
11409
11410     ypos += 2 * font3_height;
11411   }
11412
11413   // ----- print number of elements / percentage of this element in level
11414
11415   for (y = 0; y < lev_fieldy; y++)
11416   {
11417     for (x = 0; x < lev_fieldx; x++)
11418     {
11419       if (Tile[x][y] == properties_element)
11420       {
11421         num_elements_in_level++;
11422       }
11423       else if (IS_MM_WALL(Tile[x][y]) &&
11424                map_mm_wall_element(Tile[x][y]) == properties_element)
11425       {
11426         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11427       }
11428     }
11429   }
11430
11431   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11432
11433   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11434
11435   if (num_hires_tiles_in_level > 0)
11436     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11437               "%d wall tiles", num_hires_tiles_in_level);
11438   else if (num_elements_in_level > 0)
11439     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11440               "%d (%.2f %%)", num_elements_in_level, percentage);
11441   else
11442     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11443               none_text);
11444
11445   // ----- print number of similar elements / percentage of them in level
11446
11447   for (y = 0; y < lev_fieldy; y++)
11448   {
11449     for (x = 0; x < lev_fieldx; x++)
11450     {
11451       if (strEqual(element_info[Tile[x][y]].class_name,
11452                    element_info[properties_element].class_name))
11453       {
11454         num_similar_in_level++;
11455       }
11456     }
11457   }
11458
11459   if (num_similar_in_level != num_elements_in_level)
11460   {
11461     ypos += 1 * MAX(font1_height, font2_height);
11462
11463     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11464
11465     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11466
11467     if (num_similar_in_level > 0)
11468       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11469                 "%d (%.2f %%)", num_similar_in_level, percentage);
11470     else
11471       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11472                 none_text);
11473   }
11474
11475   ypos += 2 * MAX(font1_height, font2_height);
11476
11477   // ----- print standard properties of this element
11478
11479   DrawTextS(xpos, ypos, font1_nr, properties_text);
11480
11481   ypos += line1_height;
11482
11483   for (i = 0; properties[i].value != -1; i++)
11484   {
11485     if (!HAS_PROPERTY(properties_element, properties[i].value))
11486       continue;
11487
11488     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11489
11490     ypos += font2_height;
11491
11492     num_standard_properties++;
11493   }
11494
11495   if (num_standard_properties == 0)
11496   {
11497     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11498               font2_nr, none_text);
11499
11500     ypos -= (line1_height - font1_height);
11501   }
11502
11503   ypos += MAX(font1_height, font2_height);
11504
11505   // ----- print special description of this element
11506
11507   PrintInfoText(description_text, font1_nr, xpos, ypos);
11508
11509   ypos += line1_height;
11510
11511   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11512     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11513 }
11514
11515 #define TEXT_COLLECTING                 "Score for collecting"
11516 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11517 #define TEXT_SMASHING                   "Score for smashing"
11518 #define TEXT_SLURPING                   "Score for slurping robot"
11519 #define TEXT_CRACKING                   "Score for cracking"
11520 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11521 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11522 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11523 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11524 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11525 #define TEXT_DURATION                   "Duration when activated"
11526 #define TEXT_DELAY_ON                   "Delay before activating"
11527 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11528 #define TEXT_DELAY_CHANGING             "Delay before changing"
11529 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11530 #define TEXT_DELAY_MOVING               "Delay before moving"
11531 #define TEXT_BALL_DELAY                 "Element generation delay"
11532 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11533 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11534 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11535 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11536 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11537 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11538 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11539 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11540 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11541 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11542 #define TEXT_RANDOM_SEED                "slime random number seed"
11543 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11544 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11545 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11546 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11547 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11548 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11549 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11550 #define TEXT_AUTO_TURN_DELAY            "Creatures auto turn delay"
11551 #define TEXT_GRAVITY_DELAY              "Gravity switch change delay"
11552
11553 static struct
11554 {
11555   int element;
11556   int *value;
11557   char *text;
11558   int min_value;
11559   int max_value;
11560 } elements_with_counter[] =
11561 {
11562   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11563   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11564   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11565   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11566   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11567   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11568   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11569   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11570   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11571   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11572   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11573   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11574   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11575   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11576   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11577   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11578   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11579   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11580   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11581   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11582   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11583   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11584   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11585   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11586   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11587   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11588   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11589   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11590   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11591   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11592   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11593   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11594   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11595   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11596   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11597   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11598   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11599   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11600   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11601   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11602   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11603   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11604   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11605   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11606   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11607   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11608   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11609   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11610   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11611   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11612   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11613   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11614   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11615   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11616   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11617   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11618   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11619   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11620   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11621   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11622   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11623   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11624   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11625   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11626   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11627   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11628   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11629   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11630   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11631   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11632   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11633   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11634   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11635   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11636   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11637   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11638   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11639   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11640   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11641   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11642   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11643   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11644   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11645                                 0, 100                                                          },
11646   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11647                                 0, 100                                                          },
11648   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11649   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11650   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11651                                 0, 100                                                          },
11652   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11653                                 0, 100                                                          },
11654   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11655   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11656   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11657   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11658   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11659   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11660   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11661   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11662   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11663   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11664   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11665                                 -100, 100                                                       },
11666   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11667                                 0, 100                                                          },
11668   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11669                                 0, 100                                                          },
11670   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11671                                 0, 255                                                          },
11672   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11673                                 -1, 65535                                                       },
11674   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11675                                 0, 100                                                          },
11676   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11677                                 0, 3                                                            },
11678   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11679                                 0, 3                                                            },
11680   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11681                                 0, 3                                                            },
11682   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11683                                 0, 3                                                            },
11684   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11685                                 0, 3                                                            },
11686   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11687                                 0, 100                                                          },
11688   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11689                                 1, 100                                                          },
11690   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11691                                 1, 200                                                          },
11692   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11693                                 0, 50                                                           },
11694   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11695                                 0, 50                                                           },
11696   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11697                                 0, 10                                                           },
11698   { EL_BD_CREATURE_SWITCH,      &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
11699   { EL_BD_GRAVITY_SWITCH,       &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
11700                                 1, 60                                                           },
11701   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11702   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11703   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11704   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11705   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11706   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11707   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11708   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11709   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11710   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11711   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11712   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11713   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11714   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11715   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11716   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11717   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11718   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11719   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11720   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11721   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11722   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11723   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11724   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11725   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11726
11727   { -1,                         NULL,                                   NULL                    }
11728 };
11729
11730 static boolean checkPropertiesConfig(int element)
11731 {
11732   int i;
11733
11734   // special case: empty space customization only available in R'n'D game engine
11735   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11736     return FALSE;
11737
11738   // special case: BD style rock customization only available in BD game engine
11739   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11740     return FALSE;
11741
11742   if (IS_GEM(element) ||
11743       IS_CUSTOM_ELEMENT(element) ||
11744       IS_GROUP_ELEMENT(element) ||
11745       IS_EMPTY_ELEMENT(element) ||
11746       IS_BALLOON_ELEMENT(element) ||
11747       IS_ENVELOPE(element) ||
11748       IS_MM_ENVELOPE(element) ||
11749       IS_MM_MCDUFFIN(element) ||
11750       IS_DF_LASER(element) ||
11751       IS_PLAYER_ELEMENT(element) ||
11752       IS_BD_PLAYER_ELEMENT(element) ||
11753       IS_BD_FIREFLY(properties_element) ||
11754       IS_BD_FIREFLY_2(properties_element) ||
11755       IS_BD_BUTTERFLY(properties_element) ||
11756       IS_BD_BUTTERFLY_2(properties_element) ||
11757       IS_BD_STONEFLY(properties_element) ||
11758       IS_BD_DRAGONFLY(properties_element) ||
11759       IS_BD_EXPANDABLE_WALL(properties_element) ||
11760       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11761       IS_BD_CONVEYOR_BELT(properties_element) ||
11762       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11763       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11764       HAS_EDITOR_CONTENT(element) ||
11765       CAN_GROW(element) ||
11766       COULD_MOVE_INTO_ACID(element) ||
11767       MAYBE_DONT_COLLIDE_WITH(element) ||
11768       element == EL_BD_SAND ||
11769       element == EL_BD_ROCK ||
11770       element == EL_BD_MEGA_ROCK ||
11771       element == EL_BD_BOMB ||
11772       element == EL_BD_ROCKET_LAUNCHER ||
11773       element == EL_BD_NITRO_PACK ||
11774       element == EL_BD_SWEET ||
11775       element == EL_BD_VOODOO_DOLL ||
11776       element == EL_BD_WATER ||
11777       element == EL_BD_GRAVITY_SWITCH)
11778   {
11779     return TRUE;
11780   }
11781   else
11782   {
11783     for (i = 0; elements_with_counter[i].element != -1; i++)
11784       if (elements_with_counter[i].element == element)
11785         return TRUE;
11786   }
11787
11788   return FALSE;
11789 }
11790
11791 static void SetAutomaticNumberOfGemsNeeded(void)
11792 {
11793   int x, y;
11794
11795   if (!level.auto_count_gems)
11796     return;
11797
11798   level.gems_needed = 0;
11799
11800   for (x = 0; x < lev_fieldx; x++)
11801   {
11802     for (y = 0; y < lev_fieldy; y++)
11803     {
11804       int element = Tile[x][y];
11805
11806       switch (element)
11807       {
11808         case EL_EMERALD:
11809         case EL_EMERALD_YELLOW:
11810         case EL_EMERALD_RED:
11811         case EL_EMERALD_PURPLE:
11812         case EL_BD_DIAMOND:
11813         case EL_WALL_EMERALD:
11814         case EL_WALL_EMERALD_YELLOW:
11815         case EL_WALL_EMERALD_RED:
11816         case EL_WALL_EMERALD_PURPLE:
11817         case EL_WALL_BD_DIAMOND:
11818         case EL_NUT:
11819         case EL_SP_INFOTRON:
11820         case EL_MM_KETTLE:
11821         case EL_DF_CELL:
11822           level.gems_needed++;
11823           break;
11824
11825         case EL_DIAMOND:
11826         case EL_WALL_DIAMOND:
11827           level.gems_needed += 3;
11828           break;
11829
11830         case EL_PEARL:
11831         case EL_WALL_PEARL:
11832           level.gems_needed += 5;
11833           break;
11834
11835         case EL_CRYSTAL:
11836         case EL_WALL_CRYSTAL:
11837           level.gems_needed += 8;
11838           break;
11839
11840         default:
11841           break;
11842       }
11843     }
11844   }
11845
11846   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11847 }
11848
11849 static void DrawPropertiesConfig(void)
11850 {
11851   boolean draw_footer_line = FALSE;
11852   int max_num_element_counters = 4;
11853   int num_element_counters = 0;
11854   int i;
11855
11856   if (!checkPropertiesConfig(properties_element))
11857   {
11858     int xpos = ED_ELEMENT_SETTINGS_X(0);
11859     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11860
11861     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11862
11863     return;
11864   }
11865
11866   // check if there are elements where a value can be chosen for
11867   for (i = 0; elements_with_counter[i].element != -1; i++)
11868   {
11869     if (elements_with_counter[i].element != properties_element)
11870       continue;
11871
11872     // special case: score for extra diamonds only available in BD game engine
11873     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11874         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11875         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11876       continue;
11877
11878     // special case: some amoeba counters only available in BD game engine
11879     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11880         elements_with_counter[i].value != &level.amoeba_speed &&
11881         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11882       continue;
11883
11884     // special case: score for smashing only available in R'n'D game engine
11885     if ((IS_BD_FIREFLY(elements_with_counter[i].element) ||
11886          IS_BD_BUTTERFLY(elements_with_counter[i].element)) &&
11887         (elements_with_counter[i].value == &level.score[SC_BUG] ||
11888          elements_with_counter[i].value == &level.score[SC_SPACESHIP]) &&
11889         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11890       continue;
11891
11892     // special case: some amoeba counters only available in R'n'D game engine
11893     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11894         elements_with_counter[i].value == &level.amoeba_speed &&
11895         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11896       continue;
11897
11898     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11899
11900     counterbutton_info[counter_id].y =
11901       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11902                                (CAN_GROW(properties_element)                ? 1 : 0) +
11903                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11904                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11905                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11906                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11907                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11908                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11909                                (properties_element == EL_BD_CREATURE_SWITCH ? 1 : 0) +
11910                                (properties_element == EL_BD_GRAVITY_SWITCH  ? 2 : 0) +
11911                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11912                                num_element_counters);
11913
11914     // special case: set magic wall counter for BD game engine separately
11915     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11916       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11917
11918     // special case: set amoeba counters for BD game engine separately
11919     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11920         (properties_element == EL_BD_AMOEBA_2))
11921       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11922
11923     // special case: set position for delay counter for reappearing hammered walls
11924     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11925       counterbutton_info[counter_id].y += 1;
11926
11927     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11928     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11929     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11930     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11931
11932     // default: counter values between 0 and 999
11933     if (counterbutton_info[counter_id].max_value == 0)
11934       counterbutton_info[counter_id].max_value = 999;
11935
11936     MapCounterButtons(counter_id);
11937
11938     num_element_counters++;
11939     if (num_element_counters >= max_num_element_counters)
11940       break;
11941   }
11942
11943   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11944   {
11945     // draw stickybutton gadget
11946     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11947
11948     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE);
11949     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11950     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11951     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN);
11952
11953     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11954     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11955     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11956     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11957     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11958     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11959     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11960   }
11961
11962   if (HAS_EDITOR_CONTENT(properties_element))
11963   {
11964     // draw stickybutton gadget
11965     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11966
11967     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11968     {
11969       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11970       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11971
11972       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11973       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11974     }
11975     else if (properties_element == EL_BD_AMOEBA_2)
11976     {
11977       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11978       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11979       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11980
11981       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11982       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11983       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11984       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11985     }
11986     else if (IS_AMOEBOID(properties_element))
11987     {
11988       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11989     }
11990     else if (properties_element == EL_BD_ACID)
11991     {
11992       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11993       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11994     }
11995     else if (IS_BD_BITER(properties_element))
11996     {
11997       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11998     }
11999     else if (properties_element == EL_BD_BLADDER)
12000     {
12001       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
12002     }
12003     else if (properties_element == EL_YAMYAM ||
12004              properties_element == EL_YAMYAM_LEFT ||
12005              properties_element == EL_YAMYAM_RIGHT ||
12006              properties_element == EL_YAMYAM_UP ||
12007              properties_element == EL_YAMYAM_DOWN)
12008     {
12009       DrawYamYamContentAreas();
12010     }
12011     else if (properties_element == EL_EMC_MAGIC_BALL)
12012     {
12013       DrawMagicBallContentAreas();
12014
12015       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
12016       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
12017     }
12018     else if (properties_element == EL_EMC_ANDROID)
12019     {
12020       DrawAndroidElementArea();
12021     }
12022     else if (properties_element == EL_MM_GRAY_BALL)
12023     {
12024       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
12025       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
12026       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
12027       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
12028
12029       DrawMMBallContentArea();
12030     }
12031   }
12032
12033   if (IS_PLAYER_ELEMENT(properties_element))
12034   {
12035     int player_nr = GET_PLAYER_NR(properties_element);
12036
12037     // these properties can be set for every player individually
12038
12039     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12040     {
12041       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
12042         &level.start_element[player_nr];
12043       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
12044         &level.artwork_element[player_nr];
12045       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
12046         &level.explosion_element[player_nr];
12047
12048       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
12049         &level.use_start_element[player_nr];
12050       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
12051         &level.use_artwork_element[player_nr];
12052       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
12053         &level.use_explosion_element[player_nr];
12054       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
12055         &level.initial_player_gravity[player_nr];
12056
12057       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
12058         &level.initial_player_stepsize[player_nr];
12059
12060       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
12061       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
12062                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
12063                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
12064       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
12065       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
12066       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
12067       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
12068       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
12069       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
12070       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
12071       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
12072       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
12073       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
12074       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
12075
12076       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
12077       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
12078       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
12079
12080       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
12081     }
12082     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12083     {
12084       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
12085         &level.initial_inventory_content[player_nr][0];
12086
12087       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
12088         &level.initial_inventory_size[player_nr];
12089
12090       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
12091         &level.use_initial_inventory[player_nr];
12092
12093       // draw checkbutton gadgets
12094       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
12095       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
12096       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
12097
12098       // draw counter gadgets
12099       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
12100
12101       // draw drawing area gadgets
12102       DrawPlayerInitialInventoryArea(properties_element);
12103     }
12104   }
12105
12106   if (IS_BD_PLAYER_ELEMENT(properties_element))
12107   {
12108     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12109       ED_ELEMENT_SETTINGS_YPOS(2);
12110     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12111       ED_ELEMENT_SETTINGS_YPOS(3);
12112     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12113       ED_ELEMENT_SETTINGS_YPOS(4);
12114
12115     // draw checkbutton gadgets
12116     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
12117     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
12118     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12119
12120     // draw counter gadgets
12121     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12122     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12123
12124     // draw drawing area gadgets
12125     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
12126   }
12127
12128   if (properties_element == EL_BD_SAND)
12129   {
12130     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
12131   }
12132
12133   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12134   {
12135     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
12136       ED_ELEMENT_SETTINGS_YPOS(0);
12137     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12138       ED_ELEMENT_SETTINGS_YPOS(1);
12139
12140     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
12141     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12142
12143     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
12144     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
12145   }
12146
12147   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
12148   {
12149     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
12150     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
12151   }
12152
12153   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
12154   {
12155     if (IS_BD_FIREFLY(properties_element))
12156     {
12157       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_EXPLODES_TO);
12158       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12159     }
12160     else if (IS_BD_FIREFLY_2(properties_element))
12161     {
12162       MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
12163       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12164     }
12165     else if (IS_BD_BUTTERFLY(properties_element))
12166     {
12167       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_EXPLODES_TO);
12168       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12169     }
12170     else if (IS_BD_BUTTERFLY_2(properties_element))
12171     {
12172       MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
12173       MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
12174     }
12175     else if (IS_BD_STONEFLY(properties_element))
12176     {
12177       MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
12178     }
12179     else if (IS_BD_DRAGONFLY(properties_element))
12180     {
12181       MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
12182       MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
12183     }
12184     else if (properties_element == EL_BD_BOMB)
12185     {
12186       MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
12187     }
12188     else if (properties_element == EL_BD_NITRO_PACK)
12189     {
12190       MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
12191     }
12192   }
12193
12194   if (properties_element == EL_BD_MEGA_ROCK ||
12195       properties_element == EL_BD_SWEET)
12196   {
12197     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
12198       ED_ELEMENT_SETTINGS_YPOS(0);
12199     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
12200       ED_ELEMENT_SETTINGS_YPOS(1);
12201
12202     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12203     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12204   }
12205
12206   if (properties_element == EL_BD_VOODOO_DOLL)
12207   {
12208     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12209     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12210     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12211     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12212   }
12213
12214   if (properties_element == EL_BD_SLIME)
12215   {
12216     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12217
12218     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12219     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12220     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12221     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12222     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12223     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12224   }
12225
12226   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12227       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12228   {
12229     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12230
12231     if (IS_BD_EXPANDABLE_WALL(properties_element))
12232       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12233   }
12234
12235   if (properties_element == EL_BD_REPLICATOR)
12236   {
12237     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12238   }
12239
12240   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12241       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12242   {
12243     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12244     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12245   }
12246
12247   if (properties_element == EL_BD_WATER)
12248   {
12249     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12250   }
12251
12252   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12253   {
12254     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12255   }
12256
12257   if (properties_element == EL_BD_ROCKET_LAUNCHER)
12258   {
12259     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS);
12260   }
12261
12262   if (properties_element == EL_BD_CREATURE_SWITCH)
12263   {
12264     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12265     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12266   }
12267
12268   if (properties_element == EL_BD_GRAVITY_SWITCH)
12269   {
12270     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12271
12272     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12273     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12274   }
12275
12276   if (properties_element == EL_BD_NUT)
12277   {
12278     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12279   }
12280
12281   // special case: slippery walls option for gems only available in R'n'D game engine
12282   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12283     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12284
12285   if (properties_element == EL_EM_DYNAMITE)
12286     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12287
12288   if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
12289       COULD_MOVE_INTO_ACID(properties_element) &&
12290       !IS_PLAYER_ELEMENT(properties_element) &&
12291       (!IS_CUSTOM_ELEMENT(properties_element) ||
12292        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12293   {
12294     // set position for checkbutton for "can move into acid"
12295     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12296       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12297     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12298       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12299                                IS_BALLOON_ELEMENT(properties_element) ||
12300                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12301
12302     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12303   }
12304
12305   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12306     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12307
12308   if (properties_element == EL_SPRING ||
12309       properties_element == EL_SPRING_LEFT ||
12310       properties_element == EL_SPRING_RIGHT)
12311     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12312
12313   if (properties_element == EL_TIME_ORB_FULL)
12314     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12315
12316   if (properties_element == EL_GAME_OF_LIFE ||
12317       properties_element == EL_BIOMAZE)
12318     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12319
12320   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12321   {
12322     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12323       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12324
12325     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12326   }
12327
12328   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12329     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12330
12331   if (properties_element == EL_SOKOBAN_OBJECT)
12332     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12333
12334   if (properties_element == EL_SOKOBAN_OBJECT ||
12335       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12336       properties_element == EL_SOKOBAN_FIELD_FULL)
12337   {
12338     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12339       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12340                                0 : 1);
12341
12342     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12343   }
12344
12345   if (IS_BALLOON_ELEMENT(properties_element))
12346     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12347
12348   if (IS_ENVELOPE(properties_element) ||
12349       IS_MM_ENVELOPE(properties_element))
12350   {
12351     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12352     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12353     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12354     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12355     int envelope_nr = ENVELOPE_NR(properties_element);
12356
12357     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12358     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12359
12360     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12361     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12362
12363     // display counter to choose size of envelope text area
12364     MapCounterButtons(counter1_id);
12365     MapCounterButtons(counter2_id);
12366
12367     // display checkbuttons to choose auto-wrap and alignment properties
12368     MapCheckbuttonGadget(button1_id);
12369     MapCheckbuttonGadget(button2_id);
12370
12371     DrawEnvelopeTextArea(envelope_nr);
12372   }
12373
12374   if (IS_MM_MCDUFFIN(properties_element))
12375   {
12376     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12377     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12378     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12379   }
12380
12381   if (IS_DF_LASER(properties_element))
12382   {
12383     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12384     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12385     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12386   }
12387
12388   if (IS_CUSTOM_ELEMENT(properties_element))
12389   {
12390     // draw stickybutton gadget
12391     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12392
12393     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12394     {
12395       // draw checkbutton gadgets
12396       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12397            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12398         MapCheckbuttonGadget(i);
12399
12400       // draw counter gadgets
12401       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12402            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12403         MapCounterButtons(i);
12404
12405       // draw selectbox gadgets
12406       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12407            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12408         MapSelectboxGadget(i);
12409
12410       // draw textbutton gadgets
12411       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12412
12413       // draw text input gadgets
12414       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12415
12416       // draw drawing area gadgets
12417       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12418
12419       draw_footer_line = TRUE;
12420     }
12421     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12422     {
12423       // draw checkbutton gadgets
12424       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12425            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12426         MapCheckbuttonGadget(i);
12427
12428       // draw counter gadgets
12429       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12430            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12431         MapCounterButtons(i);
12432
12433       // draw selectbox gadgets
12434       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12435            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12436         MapSelectboxGadget(i);
12437
12438       // draw drawing area gadgets
12439       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12440       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12441       DrawCustomContentArea();
12442     }
12443   }
12444   else if (IS_GROUP_ELEMENT(properties_element))
12445   {
12446     // draw stickybutton gadget
12447     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12448
12449     // draw checkbutton gadgets
12450     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12451     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12452
12453     // draw counter gadgets
12454     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12455
12456     // draw selectbox gadgets
12457     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12458
12459     // draw textbutton gadgets
12460     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12461
12462     // draw drawing area gadgets
12463     DrawGroupElementArea();
12464
12465     // draw text input gadgets
12466     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12467
12468     // draw drawing area gadgets
12469     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12470
12471     draw_footer_line = TRUE;
12472   }
12473   else if (IS_EMPTY_ELEMENT(properties_element))
12474   {
12475     // draw stickybutton gadget
12476     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12477
12478     // draw checkbutton gadgets
12479     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12480     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12481
12482     // draw textbutton gadgets
12483     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12484
12485     // draw drawing area gadgets
12486     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12487
12488     draw_footer_line = TRUE;
12489   }
12490
12491   // draw little footer border line above CE/GE use/save template gadgets
12492   if (draw_footer_line)
12493   {
12494     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12495     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12496     int gd_x = gd->x + gd_gi1->border.width / 2;
12497     int gd_y = gd->y + gd_gi1->height - 1;
12498     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12499
12500     if (tab_color != BLACK_PIXEL)               // black => transparent
12501       FillRectangle(drawto,
12502                     SX + ED_ELEMENT_SETTINGS_X(0),
12503                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12504                     ED_TAB_BAR_HEIGHT,
12505                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12506   }
12507 }
12508
12509 static void DrawPropertiesChangeDrawingAreas(void)
12510 {
12511   if (IS_CUSTOM_ELEMENT(properties_element))
12512   {
12513     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12514     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12515     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12516
12517     DrawCustomChangeContentArea();
12518   }
12519
12520   redraw_mask |= REDRAW_FIELD;
12521 }
12522
12523 static void DrawPropertiesChange(void)
12524 {
12525   int i;
12526
12527   // needed to initially set selectbox options for special action options
12528   setSelectboxSpecialActionOptions();
12529
12530   // draw stickybutton gadget
12531   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12532
12533   // draw checkbutton gadgets
12534   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12535        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12536     MapCheckbuttonGadget(i);
12537
12538   // draw counter gadgets
12539   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12540        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12541     MapCounterButtons(i);
12542
12543   // draw selectbox gadgets
12544   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12545        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12546     MapSelectboxGadget(i);
12547
12548   // draw textbutton gadgets
12549   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12550        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12551     MapTextbuttonGadget(i);
12552
12553   // draw graphicbutton gadgets
12554   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12555        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12556     MapGraphicbuttonGadget(i);
12557
12558   // draw drawing area gadgets
12559   DrawPropertiesChangeDrawingAreas();
12560 }
12561
12562 static void DrawEditorElementAnimation(int x, int y)
12563 {
12564   int graphic;
12565   int frame;
12566
12567   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12568
12569   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12570 }
12571
12572 static void DrawEditorElementName(int x, int y, int font_nr)
12573 {
12574   char *element_name = getElementInfoText(properties_element);
12575   int font_width = getFontWidth(font_nr);
12576   int font_height = getFontHeight(font_nr);
12577   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12578   int max_chars_per_line = max_text_width / font_width;
12579
12580   if (strlen(element_name) <= max_chars_per_line)
12581     DrawTextS(x, y, font_nr, element_name);
12582   else
12583   {
12584     char buffer[max_chars_per_line + 1];
12585     int next_pos = max_chars_per_line;
12586
12587     strncpy(buffer, element_name, max_chars_per_line);
12588     buffer[max_chars_per_line] = '\0';
12589
12590     if (element_name[max_chars_per_line] == ' ')
12591       next_pos++;
12592     else
12593     {
12594       int i;
12595
12596       for (i = max_chars_per_line - 1; i >= 0; i--)
12597         if (buffer[i] == ' ')
12598           break;
12599
12600       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12601       {
12602         buffer[i] = '\0';
12603         next_pos = i + 1;
12604       }
12605     }
12606
12607     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12608
12609     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12610     buffer[max_chars_per_line] = '\0';
12611
12612     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12613   }
12614 }
12615
12616 static void DrawPropertiesWindow(void)
12617 {
12618   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12619   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12620   int border_size = gd->border_size;
12621   int font_nr = FONT_TEXT_1;
12622   int font_height = getFontHeight(font_nr);
12623   int xoffset = TILEX + element_border + 3 * border_size;
12624   int yoffset = (TILEY - font_height) / 2;
12625   int x1 = editor.settings.element_graphic.x + element_border;
12626   int y1 = editor.settings.element_graphic.y + element_border;
12627   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12628             editor.settings.element_name.x);
12629   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12630             editor.settings.element_name.y);
12631   char *text = "Element Settings";
12632   int font2_nr = FONT_TITLE_1;
12633   struct MenuPosInfo *pos = &editor.settings.headline;
12634   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12635   int sy = SY + pos->y;
12636
12637   stick_element_properties_window = FALSE;
12638
12639   // make sure that previous properties edit mode exists for this element
12640   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12641       !IS_CUSTOM_ELEMENT(properties_element))
12642     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12643
12644   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12645       !IS_PLAYER_ELEMENT(properties_element) &&
12646       !IS_CUSTOM_ELEMENT(properties_element))
12647     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12648
12649   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12650       (IS_PLAYER_ELEMENT(properties_element) ||
12651        IS_CUSTOM_ELEMENT(properties_element)))
12652     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12653
12654   CopyElementPropertiesToEditor(properties_element);
12655
12656   UnmapLevelEditorFieldGadgets();
12657   UnmapLevelEditorToolboxDrawingGadgets();
12658   UnmapLevelEditorToolboxCustomGadgets();
12659
12660   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12661
12662   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12663   ClearField();
12664
12665   DrawText(sx, sy, text, font2_nr);
12666
12667   FrameCounter = 0;     // restart animation frame counter
12668
12669   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12670   DrawEditorElementAnimation(SX + x1, SY + y1);
12671   DrawEditorElementName(x2, y2, font_nr);
12672
12673   DrawPropertiesTabulatorGadgets();
12674
12675   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12676     DrawPropertiesInfo();
12677   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12678     DrawPropertiesChange();
12679   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12680     DrawPropertiesConfig();
12681 }
12682
12683 static void DrawPaletteWindow(void)
12684 {
12685   int i;
12686
12687   UnmapLevelEditorFieldGadgets();
12688
12689   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12690   ClearField();
12691
12692   // map buttons to select elements
12693   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12694     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12695   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12696   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12697   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12698 }
12699
12700 static void UpdateCustomElementGraphicGadgets(void)
12701 {
12702   int i;
12703
12704   InitElementPropertiesGfxElement();
12705
12706   ModifyEditorElementList();
12707   RedrawDrawingElements();
12708
12709   // force redraw of all mapped drawing area gadgets
12710   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12711   {
12712     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12713
12714     if (gi->mapped)
12715       MapDrawingArea(i);
12716   }
12717 }
12718
12719 static int getOpenDirectionFromTube(int element)
12720 {
12721   switch (element)
12722   {
12723     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12724     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12725     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12726     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12727     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12728     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12729     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12730     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12731     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12732     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12733     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12734   }
12735
12736   return MV_NONE;
12737 }
12738
12739 static int getTubeFromOpenDirection(int direction)
12740 {
12741   switch (direction)
12742   {
12743     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12744     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12745     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12746     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12747     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12748     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12749     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12750     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12751     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12752     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12753     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12754
12755     // if only one direction, fall back to simple tube with that direction
12756     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12757     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12758     case (MV_UP):                       return EL_TUBE_VERTICAL;
12759     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12760   }
12761
12762   return EL_EMPTY;
12763 }
12764
12765 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12766 {
12767   int element_new = getTubeFromOpenDirection(direction);
12768
12769   return (element_new != EL_EMPTY ? element_new : element_old);
12770 }
12771
12772 static int getOpenDirectionFromBelt(int element)
12773 {
12774   int belt_dir = getBeltDirFromBeltElement(element);
12775
12776   return (belt_dir == MV_LEFT ? MV_RIGHT :
12777           belt_dir == MV_RIGHT ? MV_LEFT :
12778           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12779 }
12780
12781 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12782 {
12783   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12784                   direction == MV_RIGHT ? MV_LEFT :
12785                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12786
12787   if (direction == MV_NONE)
12788     return EL_EMPTY;
12789
12790   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12791 }
12792
12793 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12794                                                  int element_old)
12795 {
12796   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12797
12798   return (element_new != EL_EMPTY ? element_new : element_old);
12799 }
12800
12801 static int getOpenDirectionFromPool(int element)
12802 {
12803   switch (element)
12804   {
12805     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12806     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12807     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12808     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12809     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12810     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12811   }
12812
12813   return MV_NONE;
12814 }
12815
12816 static int getPoolFromOpenDirection(int direction)
12817 {
12818   switch (direction)
12819   {
12820     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12821     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12822     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12823     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12824     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12825     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12826   }
12827
12828   return EL_EMPTY;
12829 }
12830
12831 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12832 {
12833   int element = getPoolFromOpenDirection(direction);
12834   int help_direction = getOpenDirectionFromPool(help_element);
12835
12836   if (element == EL_EMPTY)
12837   {
12838     int help_direction_vertical = help_direction & MV_VERTICAL;
12839
12840     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12841   }
12842
12843   if (element == EL_EMPTY)
12844   {
12845     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12846
12847     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12848   }
12849
12850   return element;
12851 }
12852
12853 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12854 {
12855   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12856
12857   return (element_new != EL_EMPTY ? element_new : element_old);
12858 }
12859
12860 static int getOpenDirectionFromPillar(int element)
12861 {
12862   switch (element)
12863   {
12864     case EL_EMC_WALL_1:                 return (MV_DOWN);
12865     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12866     case EL_EMC_WALL_3:                 return (MV_UP);
12867   }
12868
12869   return MV_NONE;
12870 }
12871
12872 static int getPillarFromOpenDirection(int direction)
12873 {
12874   switch (direction)
12875   {
12876     case (MV_DOWN):                     return EL_EMC_WALL_1;
12877     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12878     case (MV_UP):                       return EL_EMC_WALL_3;
12879   }
12880
12881   return EL_EMPTY;
12882 }
12883
12884 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12885 {
12886   int element_new = getPillarFromOpenDirection(direction);
12887
12888   return (element_new != EL_EMPTY ? element_new : element_old);
12889 }
12890
12891 static int getOpenDirectionFromSteel2(int element)
12892 {
12893   switch (element)
12894   {
12895     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12896     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12897     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12898     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12899     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12900     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12901     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12902     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12903   }
12904
12905   return MV_NONE;
12906 }
12907
12908 static int getSteel2FromOpenDirection(int direction)
12909 {
12910   switch (direction)
12911   {
12912     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12913     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12914     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12915     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12916     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12917     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12918     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12919     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12920   }
12921
12922   return EL_EMPTY;
12923 }
12924
12925 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12926 {
12927   int element_new = getSteel2FromOpenDirection(direction);
12928
12929   return (element_new != EL_EMPTY ? element_new : element_old);
12930 }
12931
12932 static int getOpenDirectionFromChip(int element)
12933 {
12934   switch (element)
12935   {
12936     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12937     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12938     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12939     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12940     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12941   }
12942
12943   return MV_NONE;
12944 }
12945
12946 static int getChipFromOpenDirection(int direction)
12947 {
12948   switch (direction)
12949   {
12950     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12951     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12952     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12953     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12954     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12955   }
12956
12957   return EL_EMPTY;
12958 }
12959
12960 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12961 {
12962   int element_new = getChipFromOpenDirection(direction);
12963
12964   return (element_new != EL_EMPTY ? element_new : element_old);
12965 }
12966
12967 static int getClosedTube(int x, int y)
12968 {
12969   struct XY *xy = xy_directions;
12970   int element_old = IntelliDrawBuffer[x][y];
12971   int direction_old = getOpenDirectionFromTube(element_old);
12972   int direction_new = MV_NONE;
12973   int i;
12974
12975   for (i = 0; i < NUM_DIRECTIONS; i++)
12976   {
12977     int xx = x + xy[i].x;
12978     int yy = y + xy[i].y;
12979     int dir = MV_DIR_FROM_BIT(i);
12980     int dir_opposite = MV_DIR_OPPOSITE(dir);
12981
12982     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12983         (direction_old & dir) &&
12984         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12985       direction_new |= dir;
12986   }
12987
12988   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12989 }
12990
12991 static int getClosedBelt(int x, int y)
12992 {
12993   struct XY *xy = xy_directions;
12994   int element_old = IntelliDrawBuffer[x][y];
12995   int nr = getBeltNrFromBeltElement(element_old);
12996   int direction_old = getOpenDirectionFromBelt(element_old);
12997   int direction_new = MV_NONE;
12998   int i;
12999
13000   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13001   {
13002     int xx = x + xy[i].x;
13003     int yy = y + xy[i].y;
13004     int dir = MV_DIR_FROM_BIT(i);
13005     int dir_opposite = MV_DIR_OPPOSITE(dir);
13006
13007     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
13008         (direction_old & dir) &&
13009         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13010       direction_new |= dir;
13011   }
13012
13013   return getBeltFromNrAndOpenDirection(nr, direction_new);
13014 }
13015
13016 static int getClosedPool(int x, int y)
13017 {
13018   struct XY *xy = xy_directions;
13019   int element_old = IntelliDrawBuffer[x][y];
13020   int direction_old = getOpenDirectionFromPool(element_old);
13021   int direction_new = MV_NONE;
13022   int i;
13023
13024   for (i = 0; i < NUM_DIRECTIONS; i++)
13025   {
13026     int xx = x + xy[i].x;
13027     int yy = y + xy[i].y;
13028     int dir = MV_DIR_FROM_BIT(i);
13029     int dir_opposite = MV_DIR_OPPOSITE(dir);
13030
13031     if (IN_LEV_FIELD(xx, yy) &&
13032         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
13033         (direction_old & dir) &&
13034         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13035       direction_new |= dir;
13036   }
13037
13038   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
13039 }
13040
13041 static int getClosedPillar(int x, int y)
13042 {
13043   struct XY *xy = xy_directions;
13044   int element_old = IntelliDrawBuffer[x][y];
13045   int direction_old = getOpenDirectionFromPillar(element_old);
13046   int direction_new = MV_NONE;
13047   int i;
13048
13049   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13050   {
13051     int xx = x + xy[i].x;
13052     int yy = y + xy[i].y;
13053     int dir = MV_DIR_FROM_BIT(i);
13054     int dir_opposite = MV_DIR_OPPOSITE(dir);
13055
13056     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
13057         (direction_old & dir) &&
13058         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13059       direction_new |= dir;
13060   }
13061
13062   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
13063 }
13064
13065 static int getClosedSteel2(int x, int y)
13066 {
13067   struct XY *xy = xy_directions;
13068   int element_old = IntelliDrawBuffer[x][y];
13069   int direction_old = getOpenDirectionFromSteel2(element_old);
13070   int direction_new = MV_NONE;
13071   int i;
13072
13073   for (i = 0; i < NUM_DIRECTIONS; i++)
13074   {
13075     int xx = x + xy[i].x;
13076     int yy = y + xy[i].y;
13077     int dir = MV_DIR_FROM_BIT(i);
13078     int dir_opposite = MV_DIR_OPPOSITE(dir);
13079
13080     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
13081         (direction_old & dir) &&
13082         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13083       direction_new |= dir;
13084   }
13085
13086   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
13087 }
13088
13089 static int getClosedChip(int x, int y)
13090 {
13091   struct XY *xy = xy_directions;
13092   int element_old = IntelliDrawBuffer[x][y];
13093   int direction_old = getOpenDirectionFromChip(element_old);
13094   int direction_new = MV_NONE;
13095   int i;
13096
13097   for (i = 0; i < NUM_DIRECTIONS; i++)
13098   {
13099     int xx = x + xy[i].x;
13100     int yy = y + xy[i].y;
13101     int dir = MV_DIR_FROM_BIT(i);
13102     int dir_opposite = MV_DIR_OPPOSITE(dir);
13103
13104     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
13105         (direction_old & dir) &&
13106         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
13107       direction_new |= dir;
13108   }
13109
13110   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
13111 }
13112
13113 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
13114                                 boolean change_level)
13115 {
13116   int sx = x - level_xpos;
13117   int sy = y - level_ypos;
13118   int old_element = Tile[x][y];
13119   int new_element = element;
13120   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
13121   boolean draw_masked = FALSE;
13122
13123   if (IS_MM_WALL_EDITOR(element))
13124   {
13125     element = map_mm_wall_element_editor(element) | new_bitmask;
13126
13127     if (IS_MM_WALL(old_element))
13128       element |= MM_WALL_BITS(old_element);
13129
13130     if (!change_level)
13131       draw_masked = TRUE;
13132   }
13133   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
13134   {
13135     int element_changed = old_element & ~new_bitmask;
13136
13137     if (MM_WALL_BITS(element_changed) != 0)
13138       element = element_changed;
13139   }
13140
13141   IntelliDrawBuffer[x][y] = element;
13142
13143   if (change_level)
13144     Tile[x][y] = element;
13145
13146   if (IN_ED_FIELD(sx, sy))
13147   {
13148     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
13149       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
13150     else if (draw_masked)
13151       DrawEditorElementThruMask(sx, sy, element);
13152     else
13153       DrawEditorElement(sx, sy, element);
13154   }
13155 }
13156
13157 static void SetElementSimple(int x, int y, int element, boolean change_level)
13158 {
13159   SetElementSimpleExt(x, y, 0, 0, element, change_level);
13160 }
13161
13162 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
13163                                            int x2, int y2, int *element2,
13164                                            int (*close_function)(int, int),
13165                                            boolean change_level)
13166 {
13167   // set neighbour elements to newly determined connections
13168   SetElementSimple(x1, y1, *element1, change_level);
13169   SetElementSimple(x2, y2, *element2, change_level);
13170
13171   // remove all open connections of neighbour elements
13172   *element1 = close_function(x1, y1);
13173   *element2 = close_function(x2, y2);
13174
13175   // set neighbour elements to new, minimized connections
13176   SetElementSimple(x1, y1, *element1, change_level);
13177   SetElementSimple(x2, y2, *element2, change_level);
13178 }
13179
13180 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
13181                                   boolean change_level, int button)
13182 {
13183   struct XY *xy = xy_directions;
13184   static int last_x = -1;
13185   static int last_y = -1;
13186
13187   if (new_element == EL_UNDEFINED)
13188   {
13189     last_x = -1;
13190     last_y = -1;
13191
13192     return;
13193   }
13194
13195   int old_element = IntelliDrawBuffer[x][y];
13196
13197   if (IS_TUBE(new_element))
13198   {
13199     int last_element_new = EL_UNDEFINED;
13200     int direction = MV_NONE;
13201     int i;
13202
13203     // if old element is of same kind, keep all existing directions
13204     if (IS_TUBE(old_element))
13205       direction |= getOpenDirectionFromTube(old_element);
13206
13207     for (i = 0; i < NUM_DIRECTIONS; i++)
13208     {
13209       int xx = x + xy[i].x;
13210       int yy = y + xy[i].y;
13211
13212       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13213           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13214       {
13215         int dir = MV_DIR_FROM_BIT(i);
13216         int dir_opposite = MV_DIR_OPPOSITE(dir);
13217         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13218         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13219         int last_direction_new = last_direction_old | dir_opposite;
13220
13221         last_element_new = getTubeFromOpenDirection(last_direction_new);
13222
13223         direction |= dir;
13224       }
13225     }
13226
13227     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13228
13229     if (last_element_new != EL_UNDEFINED)
13230       MergeAndCloseNeighbourElements(x, y, &new_element,
13231                                      last_x, last_y, &last_element_new,
13232                                      getClosedTube, change_level);
13233   }
13234   else if (IS_BELT(new_element))
13235   {
13236     int belt_nr = getBeltNrFromBeltElement(new_element);
13237     int last_element_new = EL_UNDEFINED;
13238     int direction = MV_NONE;
13239     int i;
13240
13241     // if old element is of same kind, keep all existing directions
13242     if (IS_BELT(old_element))
13243       direction |= getOpenDirectionFromBelt(old_element);
13244
13245     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13246     {
13247       int xx = x + xy[i].x;
13248       int yy = y + xy[i].y;
13249
13250       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13251           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
13252       {
13253         int dir = MV_DIR_FROM_BIT(i);
13254         int dir_opposite = MV_DIR_OPPOSITE(dir);
13255         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13256         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
13257         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13258         int last_direction_new = last_direction_old | dir_opposite;
13259
13260         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13261                                                          last_direction_new);
13262         direction |= dir;
13263       }
13264     }
13265
13266     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13267                                                         new_element);
13268     if (last_element_new != EL_UNDEFINED)
13269       MergeAndCloseNeighbourElements(x, y, &new_element,
13270                                      last_x, last_y, &last_element_new,
13271                                      getClosedBelt, change_level);
13272   }
13273   else if (IS_ACID_POOL_OR_ACID(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_ACID_POOL_OR_ACID(old_element))
13281       direction |= getOpenDirectionFromPool(old_element);
13282
13283     for (i = 0; i < NUM_DIRECTIONS; 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_ACID_POOL_OR_ACID(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 = getOpenDirectionFromPool(last_element_old);
13295         int last_direction_new = last_direction_old | dir_opposite;
13296
13297         last_element_new = getPoolFromOpenDirection(last_direction_new);
13298
13299         direction |= dir;
13300       }
13301     }
13302
13303     // special corrections needed for intuitively correct acid pool drawing
13304     if (last_element_new == EL_EMPTY)
13305       last_element_new = new_element;
13306     else if (last_element_new != EL_UNDEFINED)
13307       new_element = last_element_new;
13308
13309     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13310
13311     if (last_element_new != EL_UNDEFINED)
13312       MergeAndCloseNeighbourElements(x, y, &new_element,
13313                                      last_x, last_y, &last_element_new,
13314                                      getClosedPool, change_level);
13315   }
13316   else if (IS_EMC_PILLAR(new_element))
13317   {
13318     int last_element_new = EL_UNDEFINED;
13319     int direction = MV_NONE;
13320     int i;
13321
13322     // if old element is of same kind, keep all existing directions
13323     if (IS_EMC_PILLAR(old_element))
13324       direction |= getOpenDirectionFromPillar(old_element);
13325
13326     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13327     {
13328       int xx = x + xy[i].x;
13329       int yy = y + xy[i].y;
13330
13331       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13332           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13333       {
13334         int dir = MV_DIR_FROM_BIT(i);
13335         int dir_opposite = MV_DIR_OPPOSITE(dir);
13336         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13337         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13338         int last_direction_new = last_direction_old | dir_opposite;
13339
13340         last_element_new = getPillarFromOpenDirection(last_direction_new);
13341
13342         direction |= dir;
13343       }
13344     }
13345
13346     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13347
13348     if (last_element_new != EL_UNDEFINED)
13349       MergeAndCloseNeighbourElements(x, y, &new_element,
13350                                      last_x, last_y, &last_element_new,
13351                                      getClosedPillar, change_level);
13352   }
13353   else if (IS_DC_STEELWALL_2(new_element))
13354   {
13355     int last_element_new = EL_UNDEFINED;
13356     int direction = MV_NONE;
13357     int i;
13358
13359     // if old element is of same kind, keep all existing directions
13360     if (IS_DC_STEELWALL_2(old_element))
13361       direction |= getOpenDirectionFromSteel2(old_element);
13362
13363     for (i = 0; i < NUM_DIRECTIONS; i++)
13364     {
13365       int xx = x + xy[i].x;
13366       int yy = y + xy[i].y;
13367
13368       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13369           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13370       {
13371         int dir = MV_DIR_FROM_BIT(i);
13372         int dir_opposite = MV_DIR_OPPOSITE(dir);
13373         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13374         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13375         int last_direction_new = last_direction_old | dir_opposite;
13376
13377         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13378
13379         direction |= dir;
13380       }
13381     }
13382
13383     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13384
13385     if (last_element_new != EL_UNDEFINED)
13386       MergeAndCloseNeighbourElements(x, y, &new_element,
13387                                      last_x, last_y, &last_element_new,
13388                                      getClosedSteel2, change_level);
13389   }
13390   else if (IS_SP_CHIP(new_element))
13391   {
13392     int last_element_new = EL_UNDEFINED;
13393     int direction = MV_NONE;
13394     int i;
13395
13396     // (do not keep existing directions, regardless of kind of old element)
13397
13398     for (i = 0; i < NUM_DIRECTIONS; i++)
13399     {
13400       int xx = x + xy[i].x;
13401       int yy = y + xy[i].y;
13402
13403       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13404           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13405       {
13406         int dir = MV_DIR_FROM_BIT(i);
13407         int dir_opposite = MV_DIR_OPPOSITE(dir);
13408         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13409         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13410         int last_direction_new = last_direction_old | dir_opposite;
13411
13412         if (last_direction_old == MV_NONE)
13413         {
13414           last_element_new = getChipFromOpenDirection(last_direction_new);
13415           direction |= dir;
13416         }
13417         else if (last_direction_old & (dir | dir_opposite))
13418         {
13419           direction |= MV_DIR_OPPOSITE(last_direction_old);
13420         }
13421         else
13422         {
13423           direction |= MV_DIR_OPPOSITE(dir);
13424         }
13425       }
13426     }
13427
13428     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13429
13430     if (last_element_new != EL_UNDEFINED)
13431       MergeAndCloseNeighbourElements(x, y, &new_element,
13432                                      last_x, last_y, &last_element_new,
13433                                      getClosedChip, change_level);
13434   }
13435   else if (IS_SP_HARDWARE_BASE(new_element))
13436   {
13437     int nr = GetSimpleRandom(6);
13438
13439     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13440                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13441                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13442                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13443                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13444   }
13445   else if (new_element == EL_SP_HARDWARE_GREEN ||
13446            new_element == EL_SP_HARDWARE_BLUE ||
13447            new_element == EL_SP_HARDWARE_RED)
13448   {
13449     int nr = GetSimpleRandom(3);
13450
13451     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13452                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13453   }
13454   else if (IS_GROUP_ELEMENT(new_element))
13455   {
13456     boolean connected_drawing = FALSE;
13457     int i;
13458
13459     for (i = 0; i < NUM_DIRECTIONS; i++)
13460     {
13461       int xx = x + xy[i].x;
13462       int yy = y + xy[i].y;
13463
13464       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13465           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13466         connected_drawing = TRUE;
13467     }
13468
13469     if (!connected_drawing)
13470       ResolveGroupElement(new_element);
13471
13472     new_element = GetElementFromGroupElement(new_element);
13473   }
13474   else if (IS_BELT_SWITCH(old_element))
13475   {
13476     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13477     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13478
13479     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13480                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13481
13482     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13483   }
13484   else
13485   {
13486     static int swappable_elements[][2] =
13487     {
13488       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13489       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13490       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13491       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13492       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13493       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13494       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13495       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13496       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13497       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13498       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13499       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13500       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13501       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13502       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13503       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13504       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13505       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13506       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13507       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13508       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13509       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13510       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13511       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13512       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13513       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13514       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13515       { EL_PEARL,                       EL_WALL_PEARL                   },
13516       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13517       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13518       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13519       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13520       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13521       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13522       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13523       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13524       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13525       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13526       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13527       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13528       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13529       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13530       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13531       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13532
13533       { -1,                             -1                              },
13534     };
13535     static int rotatable_elements_4[][4] =
13536     {
13537       {
13538         EL_BUG_UP,
13539         EL_BUG_RIGHT,
13540         EL_BUG_DOWN,
13541         EL_BUG_LEFT
13542       },
13543       {
13544         EL_SPACESHIP_UP,
13545         EL_SPACESHIP_RIGHT,
13546         EL_SPACESHIP_DOWN,
13547         EL_SPACESHIP_LEFT
13548       },
13549       {
13550         EL_BD_BUTTERFLY_UP,
13551         EL_BD_BUTTERFLY_RIGHT,
13552         EL_BD_BUTTERFLY_DOWN,
13553         EL_BD_BUTTERFLY_LEFT
13554       },
13555       {
13556         EL_BD_FIREFLY_UP,
13557         EL_BD_FIREFLY_RIGHT,
13558         EL_BD_FIREFLY_DOWN,
13559         EL_BD_FIREFLY_LEFT
13560       },
13561       {
13562         EL_PACMAN_UP,
13563         EL_PACMAN_RIGHT,
13564         EL_PACMAN_DOWN,
13565         EL_PACMAN_LEFT
13566       },
13567       {
13568         EL_YAMYAM_UP,
13569         EL_YAMYAM_RIGHT,
13570         EL_YAMYAM_DOWN,
13571         EL_YAMYAM_LEFT
13572       },
13573       {
13574         EL_ARROW_UP,
13575         EL_ARROW_RIGHT,
13576         EL_ARROW_DOWN,
13577         EL_ARROW_LEFT
13578       },
13579       {
13580         EL_SP_PORT_UP,
13581         EL_SP_PORT_RIGHT,
13582         EL_SP_PORT_DOWN,
13583         EL_SP_PORT_LEFT
13584       },
13585       {
13586         EL_SP_GRAVITY_PORT_UP,
13587         EL_SP_GRAVITY_PORT_RIGHT,
13588         EL_SP_GRAVITY_PORT_DOWN,
13589         EL_SP_GRAVITY_PORT_LEFT
13590       },
13591       {
13592         EL_SP_GRAVITY_ON_PORT_UP,
13593         EL_SP_GRAVITY_ON_PORT_RIGHT,
13594         EL_SP_GRAVITY_ON_PORT_DOWN,
13595         EL_SP_GRAVITY_ON_PORT_LEFT
13596       },
13597       {
13598         EL_SP_GRAVITY_OFF_PORT_UP,
13599         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13600         EL_SP_GRAVITY_OFF_PORT_DOWN,
13601         EL_SP_GRAVITY_OFF_PORT_LEFT
13602       },
13603       {
13604         EL_MOLE_UP,
13605         EL_MOLE_RIGHT,
13606         EL_MOLE_DOWN,
13607         EL_MOLE_LEFT
13608       },
13609       {
13610         EL_BALLOON_SWITCH_UP,
13611         EL_BALLOON_SWITCH_RIGHT,
13612         EL_BALLOON_SWITCH_DOWN,
13613         EL_BALLOON_SWITCH_LEFT
13614       },
13615       {
13616         EL_MM_MCDUFFIN_UP,
13617         EL_MM_MCDUFFIN_RIGHT,
13618         EL_MM_MCDUFFIN_DOWN,
13619         EL_MM_MCDUFFIN_LEFT
13620       },
13621       {
13622         EL_MM_MIRROR_FIXED_1,
13623         EL_MM_MIRROR_FIXED_4,
13624         EL_MM_MIRROR_FIXED_3,
13625         EL_MM_MIRROR_FIXED_2
13626       },
13627       {
13628         EL_MM_STEEL_GRID_FIXED_1,
13629         EL_MM_STEEL_GRID_FIXED_4,
13630         EL_MM_STEEL_GRID_FIXED_2,
13631         EL_MM_STEEL_GRID_FIXED_3
13632       },
13633       {
13634         EL_MM_WOODEN_GRID_FIXED_1,
13635         EL_MM_WOODEN_GRID_FIXED_4,
13636         EL_MM_WOODEN_GRID_FIXED_2,
13637         EL_MM_WOODEN_GRID_FIXED_3
13638       },
13639       {
13640         EL_MM_POLARIZER_CROSS_1,
13641         EL_MM_POLARIZER_CROSS_4,
13642         EL_MM_POLARIZER_CROSS_3,
13643         EL_MM_POLARIZER_CROSS_2
13644       },
13645       {
13646         EL_MM_PACMAN_UP,
13647         EL_MM_PACMAN_RIGHT,
13648         EL_MM_PACMAN_DOWN,
13649         EL_MM_PACMAN_LEFT
13650       },
13651       {
13652         EL_DF_LASER_UP,
13653         EL_DF_LASER_RIGHT,
13654         EL_DF_LASER_DOWN,
13655         EL_DF_LASER_LEFT
13656       },
13657       {
13658         EL_DF_RECEIVER_UP,
13659         EL_DF_RECEIVER_RIGHT,
13660         EL_DF_RECEIVER_DOWN,
13661         EL_DF_RECEIVER_LEFT
13662       },
13663       {
13664         EL_DF_SLOPE_1,
13665         EL_DF_SLOPE_4,
13666         EL_DF_SLOPE_3,
13667         EL_DF_SLOPE_2
13668       },
13669
13670       {
13671         -1,
13672       },
13673     };
13674     static int rotatable_elements_8[][8] =
13675     {
13676       {
13677         EL_DF_STEEL_GRID_FIXED_1,
13678         EL_DF_STEEL_GRID_FIXED_8,
13679         EL_DF_STEEL_GRID_FIXED_7,
13680         EL_DF_STEEL_GRID_FIXED_6,
13681         EL_DF_STEEL_GRID_FIXED_5,
13682         EL_DF_STEEL_GRID_FIXED_4,
13683         EL_DF_STEEL_GRID_FIXED_3,
13684         EL_DF_STEEL_GRID_FIXED_2
13685       },
13686       {
13687         EL_DF_WOODEN_GRID_FIXED_1,
13688         EL_DF_WOODEN_GRID_FIXED_8,
13689         EL_DF_WOODEN_GRID_FIXED_7,
13690         EL_DF_WOODEN_GRID_FIXED_6,
13691         EL_DF_WOODEN_GRID_FIXED_5,
13692         EL_DF_WOODEN_GRID_FIXED_4,
13693         EL_DF_WOODEN_GRID_FIXED_3,
13694         EL_DF_WOODEN_GRID_FIXED_2
13695       },
13696       {
13697         EL_DF_STEEL_GRID_ROTATING_1,
13698         EL_DF_STEEL_GRID_ROTATING_8,
13699         EL_DF_STEEL_GRID_ROTATING_7,
13700         EL_DF_STEEL_GRID_ROTATING_6,
13701         EL_DF_STEEL_GRID_ROTATING_5,
13702         EL_DF_STEEL_GRID_ROTATING_4,
13703         EL_DF_STEEL_GRID_ROTATING_3,
13704         EL_DF_STEEL_GRID_ROTATING_2
13705       },
13706       {
13707         EL_DF_WOODEN_GRID_ROTATING_1,
13708         EL_DF_WOODEN_GRID_ROTATING_8,
13709         EL_DF_WOODEN_GRID_ROTATING_7,
13710         EL_DF_WOODEN_GRID_ROTATING_6,
13711         EL_DF_WOODEN_GRID_ROTATING_5,
13712         EL_DF_WOODEN_GRID_ROTATING_4,
13713         EL_DF_WOODEN_GRID_ROTATING_3,
13714         EL_DF_WOODEN_GRID_ROTATING_2
13715       },
13716
13717       {
13718         -1,
13719       },
13720     };
13721     static int rotatable_elements_16[][16] =
13722     {
13723       {
13724         EL_MM_MIRROR_1,
13725         EL_MM_MIRROR_16,
13726         EL_MM_MIRROR_15,
13727         EL_MM_MIRROR_14,
13728         EL_MM_MIRROR_13,
13729         EL_MM_MIRROR_12,
13730         EL_MM_MIRROR_11,
13731         EL_MM_MIRROR_10,
13732         EL_MM_MIRROR_9,
13733         EL_MM_MIRROR_8,
13734         EL_MM_MIRROR_7,
13735         EL_MM_MIRROR_6,
13736         EL_MM_MIRROR_5,
13737         EL_MM_MIRROR_4,
13738         EL_MM_MIRROR_3,
13739         EL_MM_MIRROR_2
13740       },
13741       {
13742         EL_MM_TELEPORTER_5,
13743         EL_MM_TELEPORTER_4,
13744         EL_MM_TELEPORTER_3,
13745         EL_MM_TELEPORTER_2,
13746         EL_MM_TELEPORTER_1,
13747         EL_MM_TELEPORTER_16,
13748         EL_MM_TELEPORTER_15,
13749         EL_MM_TELEPORTER_14,
13750         EL_MM_TELEPORTER_13,
13751         EL_MM_TELEPORTER_12,
13752         EL_MM_TELEPORTER_11,
13753         EL_MM_TELEPORTER_10,
13754         EL_MM_TELEPORTER_9,
13755         EL_MM_TELEPORTER_8,
13756         EL_MM_TELEPORTER_7,
13757         EL_MM_TELEPORTER_6
13758       },
13759       {
13760         EL_MM_TELEPORTER_RED_5,
13761         EL_MM_TELEPORTER_RED_4,
13762         EL_MM_TELEPORTER_RED_3,
13763         EL_MM_TELEPORTER_RED_2,
13764         EL_MM_TELEPORTER_RED_1,
13765         EL_MM_TELEPORTER_RED_16,
13766         EL_MM_TELEPORTER_RED_15,
13767         EL_MM_TELEPORTER_RED_14,
13768         EL_MM_TELEPORTER_RED_13,
13769         EL_MM_TELEPORTER_RED_12,
13770         EL_MM_TELEPORTER_RED_11,
13771         EL_MM_TELEPORTER_RED_10,
13772         EL_MM_TELEPORTER_RED_9,
13773         EL_MM_TELEPORTER_RED_8,
13774         EL_MM_TELEPORTER_RED_7,
13775         EL_MM_TELEPORTER_RED_6
13776       },
13777       {
13778         EL_MM_TELEPORTER_YELLOW_5,
13779         EL_MM_TELEPORTER_YELLOW_4,
13780         EL_MM_TELEPORTER_YELLOW_3,
13781         EL_MM_TELEPORTER_YELLOW_2,
13782         EL_MM_TELEPORTER_YELLOW_1,
13783         EL_MM_TELEPORTER_YELLOW_16,
13784         EL_MM_TELEPORTER_YELLOW_15,
13785         EL_MM_TELEPORTER_YELLOW_14,
13786         EL_MM_TELEPORTER_YELLOW_13,
13787         EL_MM_TELEPORTER_YELLOW_12,
13788         EL_MM_TELEPORTER_YELLOW_11,
13789         EL_MM_TELEPORTER_YELLOW_10,
13790         EL_MM_TELEPORTER_YELLOW_9,
13791         EL_MM_TELEPORTER_YELLOW_8,
13792         EL_MM_TELEPORTER_YELLOW_7,
13793         EL_MM_TELEPORTER_YELLOW_6
13794       },
13795       {
13796         EL_MM_TELEPORTER_GREEN_5,
13797         EL_MM_TELEPORTER_GREEN_4,
13798         EL_MM_TELEPORTER_GREEN_3,
13799         EL_MM_TELEPORTER_GREEN_2,
13800         EL_MM_TELEPORTER_GREEN_1,
13801         EL_MM_TELEPORTER_GREEN_16,
13802         EL_MM_TELEPORTER_GREEN_15,
13803         EL_MM_TELEPORTER_GREEN_14,
13804         EL_MM_TELEPORTER_GREEN_13,
13805         EL_MM_TELEPORTER_GREEN_12,
13806         EL_MM_TELEPORTER_GREEN_11,
13807         EL_MM_TELEPORTER_GREEN_10,
13808         EL_MM_TELEPORTER_GREEN_9,
13809         EL_MM_TELEPORTER_GREEN_8,
13810         EL_MM_TELEPORTER_GREEN_7,
13811         EL_MM_TELEPORTER_GREEN_6
13812       },
13813       {
13814         EL_MM_TELEPORTER_BLUE_5,
13815         EL_MM_TELEPORTER_BLUE_4,
13816         EL_MM_TELEPORTER_BLUE_3,
13817         EL_MM_TELEPORTER_BLUE_2,
13818         EL_MM_TELEPORTER_BLUE_1,
13819         EL_MM_TELEPORTER_BLUE_16,
13820         EL_MM_TELEPORTER_BLUE_15,
13821         EL_MM_TELEPORTER_BLUE_14,
13822         EL_MM_TELEPORTER_BLUE_13,
13823         EL_MM_TELEPORTER_BLUE_12,
13824         EL_MM_TELEPORTER_BLUE_11,
13825         EL_MM_TELEPORTER_BLUE_10,
13826         EL_MM_TELEPORTER_BLUE_9,
13827         EL_MM_TELEPORTER_BLUE_8,
13828         EL_MM_TELEPORTER_BLUE_7,
13829         EL_MM_TELEPORTER_BLUE_6
13830       },
13831       {
13832         EL_MM_POLARIZER_1,
13833         EL_MM_POLARIZER_16,
13834         EL_MM_POLARIZER_15,
13835         EL_MM_POLARIZER_14,
13836         EL_MM_POLARIZER_13,
13837         EL_MM_POLARIZER_12,
13838         EL_MM_POLARIZER_11,
13839         EL_MM_POLARIZER_10,
13840         EL_MM_POLARIZER_9,
13841         EL_MM_POLARIZER_8,
13842         EL_MM_POLARIZER_7,
13843         EL_MM_POLARIZER_6,
13844         EL_MM_POLARIZER_5,
13845         EL_MM_POLARIZER_4,
13846         EL_MM_POLARIZER_3,
13847         EL_MM_POLARIZER_2
13848       },
13849       {
13850         EL_DF_MIRROR_1,
13851         EL_DF_MIRROR_16,
13852         EL_DF_MIRROR_15,
13853         EL_DF_MIRROR_14,
13854         EL_DF_MIRROR_13,
13855         EL_DF_MIRROR_12,
13856         EL_DF_MIRROR_11,
13857         EL_DF_MIRROR_10,
13858         EL_DF_MIRROR_9,
13859         EL_DF_MIRROR_8,
13860         EL_DF_MIRROR_7,
13861         EL_DF_MIRROR_6,
13862         EL_DF_MIRROR_5,
13863         EL_DF_MIRROR_4,
13864         EL_DF_MIRROR_3,
13865         EL_DF_MIRROR_2
13866       },
13867       {
13868         EL_DF_MIRROR_ROTATING_1,
13869         EL_DF_MIRROR_ROTATING_16,
13870         EL_DF_MIRROR_ROTATING_15,
13871         EL_DF_MIRROR_ROTATING_14,
13872         EL_DF_MIRROR_ROTATING_13,
13873         EL_DF_MIRROR_ROTATING_12,
13874         EL_DF_MIRROR_ROTATING_11,
13875         EL_DF_MIRROR_ROTATING_10,
13876         EL_DF_MIRROR_ROTATING_9,
13877         EL_DF_MIRROR_ROTATING_8,
13878         EL_DF_MIRROR_ROTATING_7,
13879         EL_DF_MIRROR_ROTATING_6,
13880         EL_DF_MIRROR_ROTATING_5,
13881         EL_DF_MIRROR_ROTATING_4,
13882         EL_DF_MIRROR_ROTATING_3,
13883         EL_DF_MIRROR_ROTATING_2
13884       },
13885       {
13886         EL_DF_MIRROR_FIXED_1,
13887         EL_DF_MIRROR_FIXED_16,
13888         EL_DF_MIRROR_FIXED_15,
13889         EL_DF_MIRROR_FIXED_14,
13890         EL_DF_MIRROR_FIXED_13,
13891         EL_DF_MIRROR_FIXED_12,
13892         EL_DF_MIRROR_FIXED_11,
13893         EL_DF_MIRROR_FIXED_10,
13894         EL_DF_MIRROR_FIXED_9,
13895         EL_DF_MIRROR_FIXED_8,
13896         EL_DF_MIRROR_FIXED_7,
13897         EL_DF_MIRROR_FIXED_6,
13898         EL_DF_MIRROR_FIXED_5,
13899         EL_DF_MIRROR_FIXED_4,
13900         EL_DF_MIRROR_FIXED_3,
13901         EL_DF_MIRROR_FIXED_2
13902       },
13903
13904       {
13905         -1,
13906       },
13907     };
13908     int i, j;
13909
13910     for (i = 0; swappable_elements[i][0] != -1; i++)
13911     {
13912       int element1 = swappable_elements[i][0];
13913       int element2 = swappable_elements[i][1];
13914
13915       if (old_element == element1 || old_element == element2)
13916         new_element = (old_element == element1 ? element2 : element1);
13917     }
13918
13919     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13920     {
13921       for (j = 0; j < 4; j++)
13922       {
13923         int element = rotatable_elements_4[i][j];
13924
13925         if (old_element == element)
13926           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13927                          button == 2 ? rotatable_elements_4[i][0]           :
13928                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13929                          old_element);
13930       }
13931     }
13932
13933     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13934     {
13935       for (j = 0; j < 8; j++)
13936       {
13937         int element = rotatable_elements_8[i][j];
13938
13939         if (old_element == element)
13940           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13941                          button == 2 ? rotatable_elements_8[i][0]           :
13942                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13943                          old_element);
13944       }
13945     }
13946
13947     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13948     {
13949       for (j = 0; j < 16; j++)
13950       {
13951         int element = rotatable_elements_16[i][j];
13952
13953         if (old_element == element)
13954           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13955                          button == 2 ? rotatable_elements_16[i][0]             :
13956                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13957                          old_element);
13958       }
13959     }
13960
13961     if (old_element != new_element)
13962     {
13963       int max_infotext_len = getMaxInfoTextLength();
13964       char infotext[MAX_OUTPUT_LINESIZE + 1];
13965
13966       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13967       infotext[max_infotext_len] = '\0';
13968
13969       ClearEditorGadgetInfoText();
13970
13971       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13972                 infotext);
13973     }
13974   }
13975
13976   if (IS_MM_WALL_EDITOR(new_element))
13977     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13978   else
13979     SetElementSimple(x, y, new_element, change_level);
13980
13981   last_x = x;
13982   last_y = y;
13983 }
13984
13985 static void ResetIntelliDraw(void)
13986 {
13987   int x, y;
13988
13989   for (x = 0; x < lev_fieldx; x++)
13990     for (y = 0; y < lev_fieldy; y++)
13991       IntelliDrawBuffer[x][y] = Tile[x][y];
13992
13993   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13994 }
13995
13996 static boolean draw_mode_hires = FALSE;
13997
13998 static boolean isHiresTileElement(int element)
13999 {
14000   return (IS_MM_WALL(element)        || element == EL_EMPTY);
14001 }
14002
14003 static boolean isHiresDrawElement(int element)
14004 {
14005   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
14006 }
14007
14008 static int numHiresTiles(int element)
14009 {
14010   if (IS_MM_WALL(element))
14011     return get_number_of_bits(MM_WALL_BITS(element));
14012
14013   return 1;
14014 }
14015
14016 static void SetDrawModeHiRes(int element)
14017 {
14018   draw_mode_hires =
14019     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
14020      isHiresDrawElement(element));
14021 }
14022
14023 static boolean getDrawModeHiRes(void)
14024 {
14025   return draw_mode_hires;
14026 }
14027
14028 static int getLoResScreenPos(int pos)
14029 {
14030   return (getDrawModeHiRes() ? pos / 2 : pos);
14031 }
14032
14033 static int getLoResScreenMod(int pos)
14034 {
14035   return (getDrawModeHiRes() ? pos % 2 : 0);
14036 }
14037
14038 static void SetElementExt(int x, int y, int dx, int dy, int element,
14039                           boolean change_level, int button)
14040 {
14041   if (element < 0)
14042     SetElementSimple(x, y, Tile[x][y], change_level);
14043   else if (GetKeyModState() & KMOD_Shift)
14044     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
14045   else
14046     SetElementSimpleExt(x, y, dx, dy, element, change_level);
14047 }
14048
14049 static void SetElement(int x, int y, int element)
14050 {
14051   SetElementExt(x, y, 0, 0, element, TRUE, -1);
14052 }
14053
14054 static void SetElementButton(int x, int y, int dx, int dy, int element,
14055                              int button)
14056 {
14057   SetElementExt(x, y, dx, dy, element, TRUE, button);
14058 }
14059
14060 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
14061 {
14062   int lx = getLoResScreenPos(sx2) + level_xpos;
14063   int ly = getLoResScreenPos(sy2) + level_ypos;
14064   int dx = getLoResScreenMod(sx2);
14065   int dy = getLoResScreenMod(sy2);
14066
14067   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
14068 }
14069
14070 static void SetLevelElementHiRes(int lx2, int ly2, int element)
14071 {
14072   int lx = lx2 / 2;
14073   int ly = ly2 / 2;
14074   int dx = lx2 % 2;
14075   int dy = ly2 % 2;
14076
14077   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
14078 }
14079
14080 static int getLevelElementHiRes(int lx2, int ly2)
14081 {
14082   int lx = lx2 / 2;
14083   int ly = ly2 / 2;
14084   int dx = lx2 % 2;
14085   int dy = ly2 % 2;
14086   int element = Tile[lx][ly];
14087   unsigned int bitmask = (dx + 1) << (dy * 2);
14088
14089   if (IS_MM_WALL(element))
14090   {
14091     if (element & bitmask)
14092       return map_mm_wall_element(element);
14093     else
14094       return EL_EMPTY;
14095   }
14096
14097   return element;
14098 }
14099
14100 static void DrawLineElement(int x, int y, int element, boolean change_level)
14101 {
14102   SetElementHiRes(x, y, element, change_level);
14103 }
14104
14105 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
14106                      int element, boolean change_level)
14107 {
14108   int xsize = ABS(to_x - from_x);
14109   int ysize = ABS(to_y - from_y);
14110   int dx = (to_x < from_x ? -1 : +1);
14111   int dy = (to_y < from_y ? -1 : +1);
14112   int i;
14113
14114   if (from_y == to_y)                   // horizontal line
14115   {
14116     for (i = 0; i <= xsize; i++)
14117       DrawLineElement(from_x + i * dx, from_y, element, change_level);
14118   }
14119   else if (from_x == to_x)              // vertical line
14120   {
14121     for (i = 0; i <= ysize; i++)
14122       DrawLineElement(from_x, from_y + i * dy, element, change_level);
14123   }
14124   else                                  // diagonal line
14125   {
14126     if (ysize < xsize)                  // a < 1
14127     {
14128       float a = (float)ysize / (float)xsize;
14129
14130       for (i = 0; i <= xsize; i++)
14131       {
14132         int x = dx * i;
14133         int y = dy * (int)(a * i + 0.5);
14134
14135         DrawLineElement(from_x + x, from_y + y, element, change_level);
14136       }
14137     }
14138     else                                // a >= 1
14139     {
14140       float a = (float)xsize / (float)ysize;
14141
14142       for (i = 0; i <= ysize; i++)
14143       {
14144         int x = dx * (int)(a * i + 0.5);
14145         int y = dy * i;
14146
14147         DrawLineElement(from_x + x, from_y + y, element, change_level);
14148       }
14149     }
14150   }
14151 }
14152
14153 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
14154                     int element, boolean change_level)
14155 {
14156   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
14157   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
14158   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
14159   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
14160 }
14161
14162 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
14163                           int element, boolean change_level)
14164 {
14165   int y;
14166
14167   if (from_y > to_y)
14168     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
14169
14170   for (y = from_y; y <= to_y; y++)
14171     DrawLine(from_x, y, to_x, y, element, change_level);
14172 }
14173
14174 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
14175                        int element, boolean change_level)
14176 {
14177   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
14178   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
14179   int len_x = ABS(to_x - from_x);
14180   int len_y = ABS(to_y - from_y);
14181   int radius, x, y;
14182
14183   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
14184
14185   // not optimal (some points get drawn twice) but simple,
14186   // and fast enough for the few points we are drawing
14187
14188   for (x = 0; x <= radius; x++)
14189   {
14190     int sx, sy, sx2, sy2, lx, ly;
14191
14192     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
14193
14194     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14195     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14196     sx = getLoResScreenPos(sx2);
14197     sy = getLoResScreenPos(sy2);
14198     lx = sx + level_xpos;
14199     ly = sy + level_ypos;
14200
14201     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14202       DrawLineElement(sx2, sy2, element, change_level);
14203   }
14204
14205   for (y = 0; y <= radius; y++)
14206   {
14207     int sx, sy, sx2, sy2, lx, ly;
14208
14209     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14210
14211     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14212     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14213     sx = getLoResScreenPos(sx2);
14214     sy = getLoResScreenPos(sy2);
14215     lx = sx + level_xpos;
14216     ly = sy + level_ypos;
14217
14218     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14219       DrawLineElement(sx2, sy2, element, change_level);
14220   }
14221 }
14222
14223 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14224                     int element, boolean change_level)
14225 {
14226   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14227   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14228
14229   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14230 }
14231
14232 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14233
14234 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14235 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14236                        int element, boolean change_level)
14237 {
14238   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14239   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14240   int mirror_to_x2 = from_x - (to_x2 - from_x);
14241   int mirror_to_y2 = from_y - (to_y2 - from_y);
14242
14243   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14244   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14245   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14246   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14247 }
14248 #endif
14249
14250 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14251 {
14252   int from_sx, from_sy;
14253   int to_sx, to_sy;
14254
14255   if (from_x > to_x)
14256     swap_numbers(&from_x, &to_x);
14257
14258   if (from_y > to_y)
14259     swap_numbers(&from_y, &to_y);
14260
14261   from_sx = SX + from_x * ed_tilesize;
14262   from_sy = SY + from_y * ed_tilesize;
14263   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14264   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14265
14266   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14267   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14268   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14269   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14270
14271   if (from_x == to_x && from_y == to_y)
14272     MarkTileDirty(from_x/2, from_y/2);
14273   else
14274     redraw_mask |= REDRAW_FIELD;
14275 }
14276
14277 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14278                         int element, boolean change_level)
14279 {
14280   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14281 }
14282
14283 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14284                        int element, boolean change_level)
14285 {
14286   if (element == -1 || change_level)
14287     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14288   else
14289     DrawAreaBorder(from_x, from_y, to_x, to_y);
14290 }
14291
14292 // values for CopyBrushExt()
14293 #define CB_AREA_TO_BRUSH                0
14294 #define CB_BRUSH_TO_CURSOR              1
14295 #define CB_BRUSH_TO_LEVEL               2
14296 #define CB_DELETE_OLD_CURSOR            3
14297 #define CB_DUMP_BRUSH                   4
14298 #define CB_DUMP_BRUSH_SMALL             5
14299 #define CB_CLIPBOARD_TO_BRUSH           6
14300 #define CB_BRUSH_TO_CLIPBOARD           7
14301 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14302 #define CB_UPDATE_BRUSH_POSITION        9
14303 #define CB_FLIP_BRUSH_X                 10
14304 #define CB_FLIP_BRUSH_Y                 11
14305 #define CB_FLIP_BRUSH_XY                12
14306
14307 #define MAX_CB_PART_SIZE        10
14308 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14309 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14310 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14311                                  MAX_CB_NUM_LINES *     \
14312                                  MAX_CB_PART_SIZE)
14313
14314 static int getFlippedTileExt(int map[], int element)
14315 {
14316   int i;
14317
14318   for (i = 0; map[i] != -1; i++)
14319     if (map[i] == element)
14320       return map[i ^ 1];        // get flipped element by flipping LSB of index
14321
14322   return element;
14323 }
14324
14325 static int getFlippedTileX(int element)
14326 {
14327   int map[] =
14328   {
14329     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14330     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14331     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14332     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14333     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14334     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14335     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14336     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14337     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14338     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14339     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14340     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14341     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14342     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14343     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14344     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14345     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14346     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14347     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14348     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14349     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14350     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14351     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14352     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14353     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14354     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14355     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14356     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14357     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14358     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14359
14360     -1
14361   };
14362
14363   return getFlippedTileExt(map, element);
14364 }
14365
14366 static int getFlippedTileY(int element)
14367 {
14368   int map[] =
14369   {
14370     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14371     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14372     EL_BUG_UP,                          EL_BUG_DOWN,
14373     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14374     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14375     EL_ARROW_UP,                        EL_ARROW_DOWN,
14376     EL_MOLE_UP,                         EL_MOLE_DOWN,
14377     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14378     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14379     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14380     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14381     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14382     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14383     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14384     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14385     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14386     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14387     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14388     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14389     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14390     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14391     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14392     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14393     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14394
14395     -1
14396   };
14397
14398   return getFlippedTileExt(map, element);
14399 }
14400
14401 static int getFlippedTileXY(int element)
14402 {
14403   int map[] =
14404   {
14405     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14406     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14407     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14408     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14409     EL_BUG_LEFT,                        EL_BUG_UP,
14410     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14411     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14412     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14413     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14414     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14415     EL_ARROW_LEFT,                      EL_ARROW_UP,
14416     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14417     EL_MOLE_LEFT,                       EL_MOLE_UP,
14418     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14419     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14420     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14421     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14422     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14423     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14424     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14425     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14426     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14427     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14428     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14429     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14430     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14431     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14432     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14433     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14434     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14435     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14436     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14437     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14438     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14439     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14440     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14441     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14442     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14443     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14444     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14445     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14446     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14447
14448     -1
14449   };
14450
14451   return getFlippedTileExt(map, element);
14452 }
14453
14454 static int getFlippedTile(int element, int mode)
14455 {
14456   if (IS_MM_ELEMENT(element))
14457   {
14458     // get MM game element
14459     element = map_element_RND_to_MM(element);
14460
14461     // get flipped game element
14462     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14463                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14464                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14465                element);
14466
14467     // get RND game element again
14468     element = map_element_MM_to_RND(element);
14469   }
14470   else
14471   {
14472     // get flipped game element
14473     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14474                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14475                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14476                element);
14477   }
14478
14479   return element;
14480 }
14481
14482 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14483 {
14484   // flip tiles
14485   short tile1_flipped = getFlippedTile(*tile1, mode);
14486   short tile2_flipped = getFlippedTile(*tile2, mode);
14487
14488   // swap tiles
14489   *tile1 = tile2_flipped;
14490   *tile2 = tile1_flipped;
14491 }
14492
14493 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14494 {
14495   DrawLineElement(sx, sy, element, change_level);
14496 }
14497
14498 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14499                          int button, int mode)
14500 {
14501   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14502   static int brush_width, brush_height;
14503   static int last_cursor_x = -1, last_cursor_y = -1;
14504   static boolean delete_old_brush = FALSE;
14505   int new_element = BUTTON_ELEMENT(button);
14506   int x, y;
14507
14508   if (mode == CB_DUMP_BRUSH ||
14509       mode == CB_DUMP_BRUSH_SMALL ||
14510       mode == CB_BRUSH_TO_CLIPBOARD ||
14511       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14512   {
14513     if (edit_mode != ED_MODE_DRAWING)
14514       return;
14515
14516     char part[MAX_CB_PART_SIZE + 1] = "";
14517     char text[MAX_CB_TEXT_SIZE + 1] = "";
14518     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14519     int height = (draw_with_brush ? brush_height : lev_fieldy);
14520     char *format = "%s%03d";
14521
14522     for (y = 0; y < height; y++)
14523       for (x = 0; x < width; x++)
14524         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14525           format = "%s%04d";
14526
14527     for (y = 0; y < height; y++)
14528     {
14529       for (x = 0; x < width; x++)
14530       {
14531         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14532         char *prefix = (mode == CB_DUMP_BRUSH ||
14533                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14534
14535         if (element >= NUM_FILE_ELEMENTS)
14536           element = EL_UNKNOWN;
14537
14538         // copy brush to level sketch text buffer for the R'n'D forum:
14539         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14540         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14541         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14542         strcat(text, part);
14543       }
14544
14545       strcat(text, "\n");
14546     }
14547
14548     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14549         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14550       SDL_SetClipboardText(text);
14551     else
14552       Print("%s", text);        // print brush data to console and log file
14553
14554     return;
14555   }
14556
14557   if (mode == CB_CLIPBOARD_TO_BRUSH)
14558   {
14559     if (edit_mode != ED_MODE_DRAWING)
14560       return;
14561
14562     if (!SDL_HasClipboardText())
14563     {
14564       Request("Clipboard is empty!", REQ_CONFIRM);
14565
14566       return;
14567     }
14568
14569     boolean copy_to_brush = (draw_with_brush ||
14570                              drawing_function == GADGET_ID_GRAB_BRUSH);
14571
14572     // this will delete the old brush, if already drawing with a brush
14573     if (copy_to_brush)
14574       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14575
14576     // initialization is required for "odd" (incomplete) clipboard content
14577     for (x = 0; x < MAX_LEV_FIELDX; x++)
14578       for (y = 0; y < MAX_LEV_FIELDY; y++)
14579         brush_buffer[x][y] = EL_EMPTY;
14580
14581     brush_width  = 0;
14582     brush_height = 0;
14583     x = 0;
14584     y = 0;
14585
14586     char *clipboard_text = SDL_GetClipboardText();
14587     char *ptr = clipboard_text;
14588     boolean allow_new_row = FALSE;
14589     boolean stop = FALSE;
14590
14591     while (*ptr && !stop)
14592     {
14593       boolean prefix_found = FALSE;
14594       boolean start_new_row = FALSE;
14595
14596       // level sketch element number prefixes (may be multi-byte characters)
14597       char *prefix_list[] = { "`", "¸" };
14598       int i;
14599
14600       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14601       {
14602         char *prefix = prefix_list[i];
14603
14604         // check if string is large enough for prefix
14605         if (strlen(ptr) < strlen(prefix))
14606         {
14607           stop = TRUE;
14608
14609           break;
14610         }
14611
14612         // check if string starts with prefix
14613         if (strPrefix(ptr, prefix))
14614         {
14615           ptr += strlen(prefix);
14616
14617           prefix_found = TRUE;
14618
14619           break;
14620         }
14621       }
14622
14623       // check if prefix found and followed by (at least) three digits
14624       if (prefix_found &&
14625           strlen(ptr) >= 3 &&
14626           ptr[0] >= '0' && ptr[0] <= '9' &&
14627           ptr[1] >= '0' && ptr[1] <= '9' &&
14628           ptr[2] >= '0' && ptr[2] <= '9')
14629       {
14630         int element = ((ptr[0] - '0') * 100 +
14631                        (ptr[1] - '0') * 10 +
14632                        (ptr[2] - '0'));
14633
14634         ptr += 3;
14635
14636         // level sketch element number might consist of four digits
14637         if (ptr[0] >= '0' && ptr[0] <= '9')
14638         {
14639           element = element * 10 + (ptr[0] - '0');
14640           ptr++;
14641         }
14642
14643         // remap some (historic, now obsolete) elements
14644         element = getMappedElement(element);
14645
14646         if (element >= NUM_FILE_ELEMENTS)
14647           element = EL_UNKNOWN;
14648
14649         brush_buffer[x][y] = element;
14650
14651         brush_width  = MAX(x + 1, brush_width);
14652         brush_height = MAX(y + 1, brush_height);
14653
14654         x++;
14655
14656         if (x >= MAX_LEV_FIELDX)
14657           start_new_row = TRUE;
14658
14659         allow_new_row = TRUE;
14660       }
14661       else
14662       {
14663         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14664           start_new_row = TRUE;
14665
14666         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14667       }
14668
14669       if (start_new_row)
14670       {
14671         x = 0;
14672         y++;
14673
14674         if (y >= MAX_LEV_FIELDY)
14675           stop = TRUE;
14676
14677         allow_new_row = FALSE;
14678       }
14679     }
14680
14681     SDL_free(clipboard_text);
14682
14683     if (brush_width == 0 || brush_height == 0)
14684     {
14685       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14686
14687       return;
14688     }
14689
14690     if (copy_to_brush)
14691     {
14692       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14693       int mx, my;
14694
14695       SDL_GetMouseState(&mx, &my);
14696
14697       // if inside drawing area, activate and draw brush at last mouse position
14698       if (mx >= gi->x && mx < gi->x + gi->width &&
14699           my >= gi->y && my < gi->y + gi->height)
14700         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14701
14702       draw_with_brush = TRUE;
14703     }
14704     else
14705     {
14706       char request[100];
14707
14708       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14709               brush_width, brush_height);
14710
14711       if (!Request(request, REQ_ASK))
14712         return;
14713
14714       for (x = 0; x < MAX_LEV_FIELDX; x++)
14715         for (y = 0; y < MAX_LEV_FIELDY; y++)
14716           Tile[x][y] = brush_buffer[x][y];
14717
14718       lev_fieldx = level.fieldx = brush_width;
14719       lev_fieldy = level.fieldy = brush_height;
14720
14721       boolean use_bd_engine = TRUE;
14722       boolean use_em_engine = TRUE;
14723       boolean use_sp_engine = TRUE;
14724       boolean use_mm_engine = TRUE;
14725
14726       for (x = 0; x < MAX_LEV_FIELDX; x++)
14727       {
14728         for (y = 0; y < MAX_LEV_FIELDY; y++)
14729         {
14730           int element = Tile[x][y];
14731
14732           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14733             use_bd_engine = FALSE;
14734
14735           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14736             use_em_engine = FALSE;
14737
14738           if (!IS_SP_ELEMENT(element))
14739             use_sp_engine = FALSE;
14740
14741           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14742             use_mm_engine = FALSE;
14743         }
14744       }
14745
14746       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14747                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14748                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14749                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14750                                 GAME_ENGINE_TYPE_RND);
14751
14752       // update element selection list
14753       ReinitializeElementList();
14754       ModifyEditorElementList();
14755
14756       SetBorderElement();
14757
14758       DrawEditModeWindow();
14759       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14760     }
14761
14762     return;
14763   }
14764
14765   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14766     return;
14767
14768   if (mode == CB_AREA_TO_BRUSH)
14769   {
14770     int from_lx, from_ly;
14771
14772     if (from_x > to_x)
14773       swap_numbers(&from_x, &to_x);
14774
14775     if (from_y > to_y)
14776       swap_numbers(&from_y, &to_y);
14777
14778     brush_width = to_x - from_x + 1;
14779     brush_height = to_y - from_y + 1;
14780
14781     from_lx = from_x + level_xpos;
14782     from_ly = from_y + level_ypos;
14783
14784     for (y = 0; y < brush_height; y++)
14785     {
14786       for (x = 0; x < brush_width; x++)
14787       {
14788         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14789
14790         if (button != 1)
14791           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14792       }
14793     }
14794
14795     if (button != 1)
14796       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14797
14798     delete_old_brush = FALSE;
14799   }
14800   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14801            mode == CB_BRUSH_TO_LEVEL)
14802   {
14803     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14804     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14805     int cursor_from_x = cursor_x - brush_width / 2;
14806     int cursor_from_y = cursor_y - brush_height / 2;
14807     int border_from_x = cursor_x, border_from_y = cursor_y;
14808     int border_to_x = cursor_x, border_to_y = cursor_y;
14809
14810     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14811       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14812
14813     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14814         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14815     {
14816       delete_old_brush = FALSE;
14817
14818       return;
14819     }
14820
14821     for (y = 0; y < brush_height; y++)
14822     {
14823       for (x = 0; x < brush_width; x++)
14824       {
14825         int sx = cursor_from_x + x;
14826         int sy = cursor_from_y + y;
14827         int lx = sx + level_xpos;
14828         int ly = sy + level_ypos;
14829         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14830         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14831                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14832                        brush_buffer[x][y] : new_element);
14833
14834         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14835         {
14836           if (sx < border_from_x)
14837             border_from_x = sx;
14838           else if (sx > border_to_x)
14839             border_to_x = sx;
14840           if (sy < border_from_y)
14841             border_from_y = sy;
14842           else if (sy > border_to_y)
14843             border_to_y = sy;
14844
14845           DrawBrushElement(sx, sy, element, change_level);
14846         }
14847       }
14848     }
14849
14850     if (mode != CB_DELETE_OLD_CURSOR)
14851       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14852
14853     last_cursor_x = cursor_x;
14854     last_cursor_y = cursor_y;
14855
14856     delete_old_brush = TRUE;
14857   }
14858   else if (mode == CB_FLIP_BRUSH_X)
14859   {
14860     for (y = 0; y < brush_height; y++)
14861       for (x = 0; x < (brush_width + 1) / 2; x++)
14862         SwapFlippedTiles(&brush_buffer[x][y],
14863                          &brush_buffer[brush_width - x - 1][y], mode);
14864
14865     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14866   }
14867   else if (mode == CB_FLIP_BRUSH_Y)
14868   {
14869     for (y = 0; y < (brush_height + 1) / 2; y++)
14870       for (x = 0; x < brush_width; x++)
14871         SwapFlippedTiles(&brush_buffer[x][y],
14872                          &brush_buffer[x][brush_height - y - 1], mode);
14873
14874     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14875   }
14876   else if (mode == CB_FLIP_BRUSH_XY)
14877   {
14878     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14879
14880     for (y = 0; y < MAX(brush_width, brush_height); y++)
14881       for (x = 0; x <= y; x++)
14882         SwapFlippedTiles(&brush_buffer[x][y],
14883                          &brush_buffer[y][x], mode);
14884
14885     swap_numbers(&brush_width, &brush_height);
14886
14887     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14888   }
14889
14890   if (mode == CB_UPDATE_BRUSH_POSITION)
14891   {
14892     last_cursor_x = from_x;
14893     last_cursor_y = from_y;
14894   }
14895 }
14896
14897 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14898                             int button)
14899 {
14900   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14901 }
14902
14903 static void CopyBrushToLevel(int x, int y, int button)
14904 {
14905   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14906 }
14907
14908 static void CopyBrushToCursor(int x, int y)
14909 {
14910   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14911 }
14912
14913 static void UpdateBrushPosition(int x, int y)
14914 {
14915   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14916 }
14917
14918 static void DeleteBrushFromCursor(void)
14919 {
14920   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14921 }
14922
14923 static void FlipBrushX(void)
14924 {
14925   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14926 }
14927
14928 static void FlipBrushY(void)
14929 {
14930   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14931 }
14932
14933 static void RotateBrush(void)
14934 {
14935   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14936   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14937 }
14938
14939 void DumpBrush(void)
14940 {
14941   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14942 }
14943
14944 void DumpBrush_Small(void)
14945 {
14946   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14947 }
14948
14949 void CopyClipboardToBrush(void)
14950 {
14951   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14952 }
14953
14954 void CopyBrushToClipboard(void)
14955 {
14956   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14957 }
14958
14959 void CopyBrushToClipboard_Small(void)
14960 {
14961   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14962 }
14963
14964 void UndoLevelEditorOperation(void)
14965 {
14966   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14967 }
14968
14969 void RedoLevelEditorOperation(void)
14970 {
14971   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14972 }
14973
14974 static void FloodFill(int from_x, int from_y, int fill_element)
14975 {
14976   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14977 }
14978
14979 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14980 {
14981   int from_x = from_sx2 + 2 * level_xpos;
14982   int from_y = from_sy2 + 2 * level_ypos;
14983   int max_fillx = lev_fieldx * 2;
14984   int max_filly = lev_fieldy * 2;
14985   short Fill[max_fillx][max_filly];
14986   int x, y;
14987
14988   for (x = 0; x < max_fillx; x++)
14989     for (y = 0; y < max_filly; y++)
14990       Fill[x][y] = getLevelElementHiRes(x, y);
14991
14992   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14993                     Fill, max_fillx, max_filly);
14994
14995   for (x = 0; x < max_fillx; x++)
14996     for (y = 0; y < max_filly; y++)
14997       if (Fill[x][y] == fill_element)
14998         SetLevelElementHiRes(x, y, Fill[x][y]);
14999 }
15000
15001 // values for DrawLevelText() modes
15002 #define TEXT_INIT               0
15003 #define TEXT_SETCURSOR          1
15004 #define TEXT_WRITECHAR          2
15005 #define TEXT_BACKSPACE          3
15006 #define TEXT_NEWLINE            4
15007 #define TEXT_END                5
15008 #define TEXT_QUERY_TYPING       6
15009
15010 static int DrawLevelText(int sx, int sy, char letter, int mode)
15011 {
15012   static short delete_buffer[MAX_LEV_FIELDX];
15013   static int start_sx;
15014   static int last_sx, last_sy;
15015   static boolean typing = FALSE;
15016   int letter_element;
15017   int lx = 0, ly = 0;
15018
15019   // map lower case letters to upper case and convert special characters
15020   if (letter >= 'a' && letter <= 'z')
15021     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
15022   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
15023     letter_element = EL_CHAR_AUMLAUT;
15024   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
15025     letter_element = EL_CHAR_OUMLAUT;
15026   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
15027     letter_element = EL_CHAR_UUMLAUT;
15028   else if (letter == '^')
15029     letter_element = EL_CHAR_COPYRIGHT;
15030   else
15031     letter_element = EL_CHAR_ASCII0 + letter;
15032
15033   if (mode != TEXT_INIT)
15034   {
15035     if (!typing)
15036       return FALSE;
15037
15038     if (mode != TEXT_SETCURSOR)
15039     {
15040       sx = last_sx;
15041       sy = last_sy;
15042     }
15043
15044     lx = last_sx + level_xpos;
15045     ly = last_sy + level_ypos;
15046   }
15047
15048   switch (mode)
15049   {
15050     case TEXT_INIT:
15051       if (typing)
15052         DrawLevelText(0, 0, 0, TEXT_END);
15053
15054       typing = TRUE;
15055       start_sx = sx;
15056       last_sx = sx;
15057       last_sy = sy;
15058       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
15059       break;
15060
15061     case TEXT_SETCURSOR:
15062       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
15063       DrawAreaBorder(sx, sy, sx, sy);
15064       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
15065                      ed_tilesize, ed_tilesize);
15066       last_sx = sx;
15067       last_sy = sy;
15068       break;
15069
15070     case TEXT_WRITECHAR:
15071       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
15072       {
15073         if (new_element1 >= EL_STEEL_CHAR_START &&
15074             new_element1 <= EL_STEEL_CHAR_END)
15075           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
15076
15077         delete_buffer[sx - start_sx] = Tile[lx][ly];
15078         Tile[lx][ly] = letter_element;
15079
15080         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
15081           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
15082         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15083           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15084         else
15085           DrawLevelText(0, 0, 0, TEXT_END);
15086
15087         level.changed = TRUE;
15088       }
15089       break;
15090
15091     case TEXT_BACKSPACE:
15092       if (sx > start_sx)
15093       {
15094         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
15095         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
15096         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
15097       }
15098       break;
15099
15100     case TEXT_NEWLINE:
15101       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
15102         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
15103       else
15104         DrawLevelText(0, 0, 0, TEXT_END);
15105       break;
15106
15107     case TEXT_END:
15108       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15109       DrawEditorElement(sx, sy, Tile[lx][ly]);
15110       StopTextInput();
15111       typing = FALSE;
15112       break;
15113
15114     case TEXT_QUERY_TYPING:
15115       break;
15116
15117     default:
15118       break;
15119   }
15120
15121   return typing;
15122 }
15123
15124 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
15125                           int element, boolean change_level)
15126 {
15127   int lx = sx + level_xpos;
15128   int ly = sy + level_ypos;
15129
15130   if (element == -1)
15131     DrawEditorElement(sx, sy, Tile[lx][ly]);
15132   else
15133     DrawAreaBorder(sx, sy, sx, sy);
15134 }
15135
15136 static void CheckLevelBorderElement(boolean redraw_playfield)
15137 {
15138   int last_border_element = BorderElement;
15139
15140   SetBorderElement();
15141
15142   if (redraw_playfield && BorderElement != last_border_element)
15143     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15144 }
15145
15146 static void CopyLevelToUndoBuffer(int mode)
15147 {
15148   static boolean accumulated_undo = FALSE;
15149   boolean new_undo_buffer_position = TRUE;
15150   int x, y;
15151
15152   if (undo_buffer_steps == 0)
15153     accumulated_undo = FALSE;
15154
15155   switch (mode)
15156   {
15157     case UNDO_IMMEDIATE:
15158       accumulated_undo = FALSE;
15159       break;
15160
15161     case UNDO_ACCUMULATE:
15162       if (accumulated_undo)
15163         new_undo_buffer_position = FALSE;
15164       accumulated_undo = TRUE;
15165       break;
15166
15167     default:
15168       break;
15169   }
15170
15171   if (new_undo_buffer_position)
15172   {
15173     // advance position in undo buffer ring
15174     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
15175
15176     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
15177       undo_buffer_steps++;
15178   }
15179
15180   // always reset redo buffer when storing level change into undo buffer
15181   redo_buffer_steps = 0;
15182
15183   for (x = 0; x < lev_fieldx; x++)
15184     for (y = 0; y < lev_fieldy; y++)
15185       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
15186
15187   // check if drawing operation forces change of border style
15188   CheckLevelBorderElement(TRUE);
15189
15190   level.changed = TRUE;
15191 }
15192
15193 static void RandomPlacement(int new_element)
15194 {
15195   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
15196   int num_free_positions = 0;
15197   int num_percentage, num_elements;
15198   int x, y;
15199
15200   ResetIntelliDraw();
15201
15202   // determine number of free positions for randomly placing the new element
15203   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
15204   {
15205     free_position[x][y] =
15206       (random_placement_background_restricted ?
15207        Tile[x][y] == random_placement_background_element :
15208        Tile[x][y] != new_element);
15209
15210     if (free_position[x][y])
15211       num_free_positions++;
15212   }
15213
15214   // determine number of new elements to place there
15215   num_percentage = num_free_positions * random_placement_value / 100;
15216   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15217                   num_percentage : random_placement_value);
15218
15219   // if less free positions than elements to place, fill all these positions
15220   if (num_free_positions < num_elements)
15221   {
15222     for (x = 0; x < lev_fieldx; x++)
15223       for (y = 0; y < lev_fieldy; y++)
15224         if (free_position[x][y])
15225           SetElement(x, y, new_element);
15226   }
15227   else
15228   {
15229     while (num_elements > 0)
15230     {
15231       x = GetSimpleRandom(lev_fieldx);
15232       y = GetSimpleRandom(lev_fieldy);
15233
15234       // don't place element at the same position twice
15235       if (free_position[x][y])
15236       {
15237         free_position[x][y] = FALSE;
15238         SetElement(x, y, new_element);
15239         num_elements--;
15240       }
15241     }
15242   }
15243
15244   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15245   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15246 }
15247
15248 static void WrapLevel(int dx, int dy)
15249 {
15250   int wrap_dx = lev_fieldx - dx;
15251   int wrap_dy = lev_fieldy - dy;
15252   int x, y;
15253
15254   for (x = 0; x < lev_fieldx; x++)
15255     for (y = 0; y < lev_fieldy; y++)
15256       TileBackup[x][y] = Tile[x][y];
15257
15258   for (x = 0; x < lev_fieldx; x++)
15259     for (y = 0; y < lev_fieldy; y++)
15260       Tile[x][y] =
15261         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15262
15263   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15264   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15265 }
15266
15267 static void DrawAreaElementHighlight(boolean highlighted,
15268                                      boolean highlighted_similar)
15269 {
15270   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15271
15272   if (!highlighted)
15273     return;
15274
15275   int x, y;
15276
15277   for (x = 0; x < ed_fieldx; x++)
15278   {
15279     for (y = 0; y < ed_fieldy; y++)
15280     {
15281       boolean highlight = FALSE;
15282       int lx = x + level_xpos;
15283       int ly = y + level_ypos;
15284
15285       if (!IN_LEV_FIELD(lx, ly))
15286         continue;
15287
15288       // check if element is the same
15289       if (Tile[lx][ly] == new_element1)
15290         highlight = TRUE;
15291
15292       // check if element is similar
15293       if (highlighted_similar &&
15294           strEqual(element_info[Tile[lx][ly]].class_name,
15295                    element_info[new_element1].class_name))
15296         highlight = TRUE;
15297
15298       // check if element is matching MM style wall
15299       if (IS_MM_WALL(Tile[lx][ly]) &&
15300           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15301         highlight = TRUE;
15302
15303       if (!highlight)
15304         continue;
15305
15306       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15307       {
15308         int i;
15309
15310         for (i = 0; i < 4; i++)
15311         {
15312           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15313             continue;
15314
15315           int xx = x * 2 + (i % 2);
15316           int yy = y * 2 + (i / 2);
15317           int sx = SX + xx * ed_tilesize / 2;
15318           int sy = SY + yy * ed_tilesize / 2;
15319           int from_sx = sx;
15320           int from_sy = sy;
15321           int to_sx = sx + ed_tilesize / 2 - 1;
15322           int to_sy = sy + ed_tilesize / 2 - 1;
15323
15324           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15325           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15326           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15327           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15328         }
15329       }
15330       else
15331       {
15332         int sx = SX + x * ed_tilesize;
15333         int sy = SY + y * ed_tilesize;
15334         int from_sx = sx;
15335         int from_sy = sy;
15336         int to_sx = sx + ed_tilesize - 1;
15337         int to_sy = sy + ed_tilesize - 1;
15338
15339         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15340         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15341         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15342         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15343       }
15344     }
15345   }
15346 }
15347
15348 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15349 {
15350   char *template_filename_old = getLocalLevelTemplateFilename();
15351   char *template_filename_new =
15352     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15353
15354   if (copyFile(template_filename_old, template_filename_new) != 0)
15355     Request("Cannot copy level template!", REQ_CONFIRM);
15356
15357   free(template_filename_new);
15358 }
15359
15360 static void HandleDrawingAreas(struct GadgetInfo *gi)
15361 {
15362   static boolean started_inside_drawing_area = FALSE;
15363   static int last_sx = -1;
15364   static int last_sy = -1;
15365   static int last_sx2 = -1;
15366   static int last_sy2 = -1;
15367   int id = gi->custom_id;
15368   int type_id = gi->custom_type_id;
15369   boolean button_press_event;
15370   boolean button_release_event;
15371   boolean inside_drawing_area = !gi->event.off_borders;
15372   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15373   int actual_drawing_function;
15374   int button = gi->event.button;
15375   int new_element = BUTTON_ELEMENT(button);
15376   int sx = gi->event.x, sy = gi->event.y;
15377   int min_sx = 0, min_sy = 0;
15378   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15379   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15380   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15381   int sx2 = gi->event.mx / mini_item_xsize;
15382   int sy2 = gi->event.my / mini_item_ysize;
15383   int dx = sx2 % 2;
15384   int dy = sy2 % 2;
15385   int lx = 0, ly = 0;
15386   int x, y;
15387
15388   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15389   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15390
15391   // make sure to stay inside drawing area boundaries
15392   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15393   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15394
15395   if (draw_level)
15396   {
15397     int min_lx = 0, min_ly = 0;
15398     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15399
15400     // get positions inside level field
15401     lx = sx + level_xpos;
15402     ly = sy + level_ypos;
15403
15404     if (!IN_LEV_FIELD(lx, ly))
15405       inside_drawing_area = FALSE;
15406
15407     // make sure to stay inside level field boundaries
15408     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15409     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15410
15411     // correct drawing area positions accordingly
15412     sx = lx - level_xpos;
15413     sy = ly - level_ypos;
15414   }
15415
15416   // also correct MM wall-sized (double) drawing area positions accordingly
15417   if (sx2 / 2 < sx || sx2 / 2 > sx)
15418   {
15419     dx = (sx2 / 2 < sx ? 0 : 1);
15420     sx2 = sx * 2 + dx;
15421   }
15422   if (sy2 / 2 < sy || sy2 / 2 > sy)
15423   {
15424     dy = (sy2 / 2 < sy ? 0 : 1);
15425     sy2 = sy * 2 + dy;
15426   }
15427
15428   if (!button_press_event && !button_release_event)
15429   {
15430     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15431     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15432                              isHiresTileElement(old_element) &&
15433                              isHiresDrawElement(new_element));
15434
15435     // prevent handling events for every pixel position when moving mouse
15436     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15437         (sx2 == last_sx2 && sy2 == last_sy2))
15438       return;
15439   }
15440
15441   last_sx = sx;
15442   last_sy = sy;
15443   last_sx2 = sx2;
15444   last_sy2 = sy2;
15445
15446   if (button_press_event)
15447     started_inside_drawing_area = inside_drawing_area;
15448
15449   if (!started_inside_drawing_area)
15450     return;
15451
15452   if (!IS_VALID_BUTTON(button))
15453     return;
15454
15455   // handle info callback for each invocation of action callback
15456   gi->callback_info(gi);
15457
15458   // automatically switch to 'single item' drawing mode, if needed
15459   actual_drawing_function =
15460     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15461      drawing_function : GADGET_ID_SINGLE_ITEMS);
15462
15463   // clicking into drawing area with pressed Control key picks element
15464   if (GetKeyModState() & KMOD_Control)
15465   {
15466     last_drawing_function = drawing_function;
15467     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15468   }
15469
15470   if (GetKeyModState() & KMOD_Shift)
15471   {
15472     if (button_press_event || button_release_event)
15473       ResetIntelliDraw();
15474   }
15475
15476   SetDrawModeHiRes(-1);         // reset to normal draw mode
15477
15478   switch (actual_drawing_function)
15479   {
15480     case GADGET_ID_SINGLE_ITEMS:
15481       if (draw_level)
15482       {
15483         if (button_release_event)
15484         {
15485           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15486
15487           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15488               !inside_drawing_area)
15489             DeleteBrushFromCursor();
15490
15491           break;
15492         }
15493
15494         if (draw_with_brush)
15495         {
15496           CopyBrushToLevel(sx, sy, button);
15497         }
15498         else
15499         {
15500           SetDrawModeHiRes(new_element);
15501
15502           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15503           {
15504             // remove player at old position
15505             for (y = 0; y < lev_fieldy; y++)
15506             {
15507               for (x = 0; x < lev_fieldx; x++)
15508               {
15509                 int old_element = Tile[x][y];
15510
15511                 if (IS_PLAYER_ELEMENT(old_element) &&
15512                     IS_PLAYER_ELEMENT(new_element))
15513                 {
15514                   int replaced_with_element =
15515                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15516                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15517
15518                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15519                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15520
15521                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15522                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15523
15524                      new_element >= EL_PLAYER_1 &&
15525                      new_element <= EL_PLAYER_4 &&
15526                      new_element == old_element ? EL_EMPTY :
15527
15528                      old_element);
15529
15530                   SetElement(x, y, replaced_with_element);
15531                 }
15532                 else if (IS_MM_MCDUFFIN(old_element) &&
15533                          IS_MM_MCDUFFIN(new_element))
15534                 {
15535                   // remove McDuffin at old position
15536                   SetElement(x, y, EL_EMPTY);
15537                 }
15538               }
15539             }
15540           }
15541
15542           SetElementButton(lx, ly, dx, dy, new_element, button);
15543         }
15544       }
15545       else if (!button_release_event)
15546       {
15547         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15548
15549         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15550           DrawMiniGraphicExt(drawto,
15551                              gi->x + sx * MINI_TILEX,
15552                              gi->y + sy * MINI_TILEY,
15553                              el2edimg(new_element));
15554         else
15555           DrawFixedGraphicExt(drawto,
15556                               gi->x + sx * TILEX,
15557                               gi->y + sy * TILEY,
15558                               el2edimg(new_element), 0);
15559
15560         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15561           new_element = GFX_ELEMENT(new_element);
15562
15563         drawingarea_info[type_id].value[pos] = new_element;
15564
15565         CopyElementPropertiesToGame(properties_element);
15566
15567         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15568         {
15569           UpdateCustomElementGraphicGadgets();
15570
15571           FrameCounter = 0;     // restart animation frame counter
15572         }
15573       }
15574       break;
15575
15576     case GADGET_ID_CONNECTED_ITEMS:
15577       {
15578         static int last_sx = -1;
15579         static int last_sy = -1;
15580
15581         if (button_release_event)
15582           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15583
15584         SetDrawModeHiRes(new_element);
15585
15586         if (getDrawModeHiRes())
15587         {
15588           sx = sx2;
15589           sy = sy2;
15590         }
15591
15592         if (!button_press_event)
15593           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15594
15595         last_sx = sx;
15596         last_sy = sy;
15597       }
15598       break;
15599
15600     case GADGET_ID_LINE:
15601     case GADGET_ID_ARC:
15602     case GADGET_ID_RECTANGLE:
15603     case GADGET_ID_FILLED_BOX:
15604       SetDrawModeHiRes(new_element);
15605
15606       if (getDrawModeHiRes())
15607       {
15608         sx = sx2;
15609         sy = sy2;
15610       }
15611       // FALLTHROUGH
15612     case GADGET_ID_GRAB_BRUSH:
15613     case GADGET_ID_TEXT:
15614       {
15615         static int last_sx = -1;
15616         static int last_sy = -1;
15617         static int start_sx = -1;
15618         static int start_sy = -1;
15619         void (*draw_func)(int, int, int, int, int, boolean);
15620
15621         if (drawing_function == GADGET_ID_LINE)
15622           draw_func = DrawLine;
15623         else if (drawing_function == GADGET_ID_ARC)
15624           draw_func = DrawArc;
15625         else if (drawing_function == GADGET_ID_RECTANGLE)
15626           draw_func = DrawBox;
15627         else if (drawing_function == GADGET_ID_FILLED_BOX)
15628           draw_func = DrawFilledBox;
15629         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15630           draw_func = SelectArea;
15631         else // (drawing_function == GADGET_ID_TEXT)
15632           draw_func = SetTextCursor;
15633
15634         if (button_press_event)
15635         {
15636           draw_func(sx, sy, sx, sy, new_element, FALSE);
15637           start_sx = last_sx = sx;
15638           start_sy = last_sy = sy;
15639
15640           if (drawing_function == GADGET_ID_TEXT)
15641             DrawLevelText(0, 0, 0, TEXT_END);
15642         }
15643         else if (button_release_event)
15644         {
15645           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15646           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15647           {
15648             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15649             CopyBrushToCursor(sx, sy);
15650             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15651                           MB_LEFTBUTTON);
15652             draw_with_brush = TRUE;
15653           }
15654           else if (drawing_function == GADGET_ID_TEXT)
15655             DrawLevelText(sx, sy, 0, TEXT_INIT);
15656           else
15657             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15658         }
15659         else if (last_sx != sx || last_sy != sy)
15660         {
15661           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15662           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15663             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15664           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15665           last_sx = sx;
15666           last_sy = sy;
15667         }
15668       }
15669       break;
15670
15671     case GADGET_ID_FLOOD_FILL:
15672       if (button_press_event && Tile[lx][ly] != new_element)
15673       {
15674         if (IS_MM_WALL_EDITOR(new_element))
15675           FloodFillWall_MM(sx2, sy2, new_element);
15676         else
15677           FloodFill(lx, ly, new_element);
15678
15679         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15680         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15681       }
15682       break;
15683
15684     case GADGET_ID_PICK_ELEMENT:
15685       if (button_release_event)
15686         ClickOnGadget(level_editor_gadget[last_drawing_function],
15687                       MB_LEFTBUTTON);
15688       else if (draw_level)
15689         PickDrawingElement(button, Tile[lx][ly]);
15690       else
15691       {
15692         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15693
15694         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15695       }
15696
15697     default:
15698       break;
15699   }
15700
15701   // do not mark level as modified for certain non-level-changing gadgets
15702   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15703        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15704       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15705       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15706     return;
15707
15708   level.changed = TRUE;
15709 }
15710
15711 static void HandleCounterButtons(struct GadgetInfo *gi)
15712 {
15713   int gadget_id = gi->custom_id;
15714   int counter_id = gi->custom_type_id;
15715   int button = gi->event.button;
15716   int *counter_value = counterbutton_info[counter_id].value;
15717   int step = BUTTON_STEPSIZE(button) *
15718     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15719
15720   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15721   {
15722     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15723     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15724     boolean level_changed = LevelChanged();
15725
15726     if ((level_changed && pressed) || (!level_changed && released))
15727       return;
15728
15729     if (level_changed && !Request("Level has changed! Discard changes?",
15730                                   REQ_ASK))
15731     {
15732       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15733         ModifyEditorCounterValue(counter_id, *counter_value);
15734
15735       return;
15736     }
15737   }
15738
15739   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15740     *counter_value = gi->textinput.number_value;
15741   else
15742     ModifyEditorCounterValue(counter_id, *counter_value + step);
15743
15744   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15745   {
15746     int last_game_engine_type = level.game_engine_type;
15747
15748     LoadLevel(level_nr);
15749     LoadScore(level_nr);
15750
15751     SaveLevelSetup_SeriesInfo();
15752
15753     TapeErase();
15754
15755     ResetUndoBuffer();
15756     DrawEditModeWindow();
15757
15758     if (level.game_engine_type != last_game_engine_type)
15759     {
15760       // update element selection list
15761       ReinitializeElementList();
15762       ModifyEditorElementList();
15763     }
15764
15765     return;
15766   }
15767
15768   switch (counter_id)
15769   {
15770     case ED_COUNTER_ID_YAMYAM_CONTENT:
15771       DrawYamYamContentAreas();
15772       break;
15773
15774     case ED_COUNTER_ID_BALL_CONTENT:
15775       DrawMagicBallContentAreas();
15776       break;
15777
15778     case ED_COUNTER_ID_ANDROID_CONTENT:
15779       DrawAndroidElementArea();
15780       break;
15781
15782     case ED_COUNTER_ID_GROUP_CONTENT:
15783       DrawGroupElementArea();
15784       CopyGroupElementPropertiesToGame(properties_element);
15785       break;
15786
15787     case ED_COUNTER_ID_INVENTORY_SIZE:
15788       DrawPlayerInitialInventoryArea(properties_element);
15789       break;
15790
15791     case ED_COUNTER_ID_MM_BALL_CONTENT:
15792       DrawMMBallContentArea();
15793       break;
15794
15795     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15796     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15797       DrawEnvelopeTextArea(-1);
15798       break;
15799
15800     case ED_COUNTER_ID_LEVEL_XSIZE:
15801     case ED_COUNTER_ID_LEVEL_YSIZE:
15802       lev_fieldx = level.fieldx;
15803       lev_fieldy = level.fieldy;
15804
15805       // check if resizing of level results in change of border border
15806       SetBorderElement();
15807
15808       break;
15809
15810     default:
15811       break;
15812   }
15813
15814   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15815        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15816       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15817        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15818     CopyElementPropertiesToGame(properties_element);
15819
15820   // do not mark level as modified for certain non-level-changing gadgets
15821   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15822        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15823       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15824        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15825     return;
15826
15827   level.changed = TRUE;
15828 }
15829
15830 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15831 {
15832   int type_id = gi->custom_type_id;
15833
15834   strcpy(textinput_info[type_id].value, gi->textinput.value);
15835
15836   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15837   {
15838     CopyElementPropertiesToGame(properties_element);
15839
15840     ModifyEditorElementList();  // update changed button info text
15841   }
15842
15843   // do not mark level as modified for certain non-level-changing gadgets
15844   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15845       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15846     return;
15847
15848   level.changed = TRUE;
15849 }
15850
15851 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15852 {
15853   int type_id = gi->custom_type_id;
15854
15855   strncpy(textarea_info[type_id].value, gi->textarea.value,
15856           MAX_ENVELOPE_TEXT_LEN);
15857   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15858
15859   level.changed = TRUE;
15860 }
15861
15862 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15863 {
15864   int type_id = gi->custom_type_id;
15865   int value_old = *selectbox_info[type_id].value;
15866   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15867
15868   *selectbox_info[type_id].value = value_new;
15869
15870   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15871   {
15872     DrawLevelConfigWindow();
15873   }
15874   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15875   {
15876     element_info[properties_element].current_change_page = gi->selectbox.index;
15877
15878     DrawPropertiesWindow();
15879   }
15880   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15881             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15882            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15883             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15884            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15885   {
15886     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15887     {
15888       // when changing action type, also check action mode and action arg
15889       if (value_old != value_new)
15890         setSelectboxSpecialActionVariablesIfNeeded();
15891
15892       DrawPropertiesChange();
15893     }
15894
15895     CopyElementPropertiesToGame(properties_element);
15896   }
15897   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15898   {
15899     // show or hide "engine" tabulator depending on game engine type
15900     DrawLevelConfigWindow();
15901
15902     // update element selection list depending on game engine type
15903     ReinitializeElementList();
15904     ModifyEditorElementList();
15905   }
15906   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15907   {
15908     // update BD cycle delay counter gadgets depending on BD scheduling type
15909     DrawLevelConfigWindow();
15910   }
15911
15912   // do not mark level as modified for certain non-level-changing gadgets
15913   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15914       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15915     return;
15916
15917   level.changed = TRUE;
15918 }
15919
15920 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15921 {
15922   int type_id = gi->custom_type_id;
15923   int i;
15924
15925   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15926       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15927   {
15928     edit_mode_levelconfig = gi->custom_type_id;
15929
15930     DrawLevelConfigWindow();
15931   }
15932   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15933            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15934   {
15935     edit_mode_properties = gi->custom_type_id;
15936
15937     DrawPropertiesWindow();
15938   }
15939   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15940            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15941   {
15942     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15943
15944     // backup original "level.field" (needed to track playfield changes)
15945     CopyPlayfield(level.field, TileBackup);
15946
15947     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15948     CopyPlayfield(Tile, level.field);
15949
15950     if (new_template ||
15951         Request("Save this template and kill the old?", REQ_ASK))
15952       SaveLevelTemplate();
15953
15954     if (new_template)
15955       Request("Template saved!", REQ_CONFIRM);
15956
15957     // restore original "level.field" (needed to track playfield changes)
15958     CopyPlayfield(TileBackup, level.field);
15959   }
15960   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15961   {
15962     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15963
15964     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15965         leveldir_current->readonly)
15966     {
15967       Request("This level set is read-only!", REQ_CONFIRM);
15968
15969       return;
15970     }
15971
15972     if (strEqual(levelset_name, ""))
15973     {
15974       Request("Please enter level set title!", REQ_CONFIRM);
15975
15976       return;
15977     }
15978
15979     if (strEqual(levelset_author, ""))
15980     {
15981       Request("Please enter level set author!", REQ_CONFIRM);
15982
15983       return;
15984     }
15985
15986     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15987     {
15988       if (UpdateUserLevelSet(levelset_subdir,
15989                              levelset_name,
15990                              levelset_author,
15991                              levelset_num_levels))
15992       {
15993         Request("Level set updated!", REQ_CONFIRM);
15994       }
15995       else
15996       {
15997         Request("Updating level set failed!", REQ_CONFIRM);
15998       }
15999     }
16000     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
16001     {
16002       if (level.changed && !Request("Level has changed! Discard changes?",
16003                                      REQ_ASK))
16004         return;
16005
16006       if (CreateUserLevelSet(levelset_subdir,
16007                              levelset_name,
16008                              levelset_author,
16009                              levelset_num_levels,
16010                              levelset_use_levelset_artwork))
16011       {
16012         if (levelset_copy_level_template)
16013           CopyLevelTemplateToUserLevelSet(levelset_subdir);
16014
16015         Request("New level set created!", REQ_CONFIRM);
16016
16017         AddUserLevelSetToLevelInfo(levelset_subdir);
16018         ChangeEditorToLevelSet(levelset_subdir);
16019       }
16020       else
16021       {
16022         Request("Creating new level set failed!", REQ_CONFIRM);
16023       }
16024     }
16025   }
16026   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
16027            custom_element.num_change_pages < MAX_CHANGE_PAGES)
16028   {
16029     struct ElementInfo *ei = &element_info[properties_element];
16030
16031     // when modifying custom element, ask for copying level template
16032     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16033       return;
16034
16035     setElementChangePages(ei, ei->num_change_pages + 1);
16036
16037     // set new change page to be new current change page
16038     ei->current_change_page = ei->num_change_pages - 1;
16039     ei->change = &ei->change_page[ei->current_change_page];
16040
16041     setElementChangeInfoToDefaults(ei->change);
16042
16043     DrawPropertiesWindow();
16044
16045     level.changed = TRUE;
16046   }
16047   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
16048            custom_element.num_change_pages > MIN_CHANGE_PAGES)
16049   {
16050     struct ElementInfo *ei = &element_info[properties_element];
16051
16052     // when modifying custom element, ask for copying level template
16053     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16054       return;
16055
16056     // copy all change pages after change page to be deleted
16057     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
16058       ei->change_page[i] = ei->change_page[i + 1];
16059
16060     setElementChangePages(ei, ei->num_change_pages - 1);
16061
16062     DrawPropertiesWindow();
16063
16064     level.changed = TRUE;
16065   }
16066 }
16067
16068 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
16069 {
16070   int type_id = gi->custom_type_id;
16071
16072   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
16073       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
16074   {
16075     struct ElementInfo *ei = &element_info[properties_element];
16076     int step = BUTTON_STEPSIZE(gi->event.button);
16077
16078     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
16079     ei->current_change_page += step;
16080
16081     if (ei->current_change_page < 0)
16082       ei->current_change_page = 0;
16083     else if (ei->current_change_page >= ei->num_change_pages)
16084       ei->current_change_page = ei->num_change_pages - 1;
16085
16086     DrawPropertiesWindow();
16087   }
16088   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
16089            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16090   {
16091     struct ElementInfo *ei = &element_info[properties_element];
16092     int current_change_page = ei->current_change_page;
16093
16094     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
16095     {
16096       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
16097         ei->change_page[current_change_page];
16098     }
16099     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
16100     {
16101       // when modifying custom element, ask for copying level template
16102       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
16103         return;
16104
16105       ei->change_page[current_change_page] =
16106         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
16107
16108       level.changed = TRUE;
16109     }
16110
16111     DrawPropertiesWindow();
16112   }
16113 }
16114
16115 static void HandleRadiobuttons(struct GadgetInfo *gi)
16116 {
16117   int type_id = gi->custom_type_id;
16118
16119   *radiobutton_info[type_id].value =
16120     radiobutton_info[type_id].checked_value;
16121
16122   // do not mark level as modified for certain non-level-changing gadgets
16123   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
16124       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
16125     return;
16126
16127   level.changed = TRUE;
16128 }
16129
16130 static void HandleCheckbuttons(struct GadgetInfo *gi)
16131 {
16132   int type_id = gi->custom_type_id;
16133
16134   *checkbutton_info[type_id].value ^= TRUE;
16135
16136   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
16137       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
16138       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
16139       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
16140          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
16141         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
16142          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
16143        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
16144   {
16145     CopyElementPropertiesToGame(properties_element);
16146   }
16147
16148   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
16149   {
16150     UpdateCustomElementGraphicGadgets();
16151   }
16152   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
16153            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
16154   {
16155     boolean template_related_changes_found = FALSE;
16156     int i;
16157
16158     // check if any custom, group or empty elements have been changed
16159     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
16160       if ((IS_CUSTOM_ELEMENT(i) ||
16161            IS_GROUP_ELEMENT(i) ||
16162            IS_EMPTY_ELEMENT(i)) &&
16163           element_info[i].modified_settings)
16164         template_related_changes_found = TRUE;
16165
16166     if (level.use_custom_template &&
16167         !fileExists(getGlobalLevelTemplateFilename()))
16168     {
16169       Request("No level template found!", REQ_CONFIRM);
16170
16171       level.use_custom_template = FALSE;
16172
16173       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16174
16175       return;
16176     }
16177
16178     if (level.use_custom_template &&
16179         template_related_changes_found &&
16180         !Request("Discard changes and use level template?", REQ_ASK))
16181     {
16182       level.use_custom_template = FALSE;
16183
16184       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
16185
16186       return;
16187     }
16188
16189     if (!level.use_custom_template &&
16190         Request("Copy settings from level template?", REQ_ASK))
16191     {
16192       return;
16193     }
16194
16195     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
16196
16197     DrawEditModeWindow();
16198   }
16199   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
16200   {
16201     if (setup.editor.use_template_for_new_levels &&
16202         !fileExists(getGlobalLevelTemplateFilename()))
16203     {
16204       Request("No level template found!", REQ_CONFIRM);
16205
16206       return;
16207     }
16208
16209     if (setup.editor.use_template_for_new_levels &&
16210         level.changed &&
16211         !Request("Discard level and load template?", REQ_ASK))
16212     {
16213       return;
16214     }
16215
16216     if (!setup.editor.use_template_for_new_levels &&
16217         level.changed &&
16218         !Request("Discard level and use empty level?", REQ_ASK))
16219     {
16220       return;
16221     }
16222
16223     LoadLevel(level_nr);
16224     LoadScore(level_nr);
16225
16226     TapeErase();
16227
16228     ResetUndoBuffer();
16229     DrawEditModeWindow();
16230   }
16231   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16232   {
16233     SetAutomaticNumberOfGemsNeeded();
16234   }
16235
16236   // do not mark level as modified for certain non-level-changing gadgets
16237   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16238        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16239       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16240        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16241        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16242       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16243     return;
16244
16245   level.changed = TRUE;
16246 }
16247
16248 static void HandleControlButtons(struct GadgetInfo *gi)
16249 {
16250   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16251   static int last_edit_mode = ED_MODE_DRAWING;
16252   static int last_custom_copy_mode = -1;
16253   static int last_button = 0;
16254   int id = gi->custom_id;
16255   int button = gi->event.button;
16256   int step = BUTTON_STEPSIZE(button);
16257   int new_element = BUTTON_ELEMENT(button);
16258   int last_properties_element = properties_element;
16259   int x, y;
16260
16261   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16262     DrawLevelText(0, 0, 0, TEXT_END);
16263
16264   if (id < ED_NUM_CTRL1_BUTTONS &&
16265       id != GADGET_ID_SINGLE_ITEMS &&
16266       id != GADGET_ID_PICK_ELEMENT &&
16267       edit_mode != ED_MODE_DRAWING &&
16268       drawing_function != GADGET_ID_PICK_ELEMENT &&
16269       !(GetKeyModState() & KMOD_Control))
16270     ChangeEditModeWindow(ED_MODE_DRAWING);
16271
16272   // element copy mode active, but no element button pressed => deactivate
16273   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16274     last_custom_copy_mode = -1;
16275
16276   // when showing palette on element buttons, change element of button used
16277   if (editor.palette.show_on_element_buttons &&
16278       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16279   {
16280     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16281
16282     id = GADGET_ID_PALETTE;
16283   }
16284
16285   switch (id)
16286   {
16287     case GADGET_ID_SCROLL_LEFT:
16288       if (level_xpos >= 0)
16289       {
16290         if (lev_fieldx < ed_fieldx - 2)
16291           break;
16292
16293         level_xpos -= step;
16294         if (level_xpos < -1)
16295           level_xpos = -1;
16296         if (button == 1)
16297           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16298         else
16299           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16300
16301         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16302                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16303       }
16304       break;
16305
16306     case GADGET_ID_SCROLL_RIGHT:
16307       if (level_xpos <= lev_fieldx - ed_fieldx)
16308       {
16309         if (lev_fieldx < ed_fieldx - 2)
16310           break;
16311
16312         level_xpos += step;
16313         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16314           level_xpos = lev_fieldx - ed_fieldx + 1;
16315         if (button == 1)
16316           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16317         else
16318           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16319
16320         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16321                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16322       }
16323       break;
16324
16325     case GADGET_ID_SCROLL_UP:
16326       if (level_ypos >= 0)
16327       {
16328         if (lev_fieldy < ed_fieldy - 2)
16329           break;
16330
16331         level_ypos -= step;
16332         if (level_ypos < -1)
16333           level_ypos = -1;
16334         if (button == 1)
16335           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16336         else
16337           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16338
16339         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16340                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16341       }
16342       break;
16343
16344     case GADGET_ID_SCROLL_DOWN:
16345       if (level_ypos <= lev_fieldy - ed_fieldy)
16346       {
16347         if (lev_fieldy < ed_fieldy - 2)
16348           break;
16349
16350         level_ypos += step;
16351         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16352           level_ypos = lev_fieldy - ed_fieldy + 1;
16353         if (button == 1)
16354           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16355         else
16356           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16357
16358         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16359                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16360       }
16361       break;
16362
16363     case GADGET_ID_SCROLL_HORIZONTAL:
16364       level_xpos = gi->event.item_position - 1;
16365
16366       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16367       BackToFront();
16368
16369       break;
16370
16371     case GADGET_ID_SCROLL_VERTICAL:
16372       level_ypos = gi->event.item_position - 1;
16373
16374       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16375       BackToFront();
16376
16377       break;
16378
16379     case GADGET_ID_SCROLL_LIST_UP:
16380     case GADGET_ID_SCROLL_LIST_DOWN:
16381     case GADGET_ID_SCROLL_LIST_VERTICAL:
16382       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16383         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16384       else
16385       {
16386         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16387         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16388
16389         if (element_shift < 0)
16390           element_shift = 0;
16391         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16392           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16393
16394         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16395                      GDI_SCROLLBAR_ITEM_POSITION,
16396                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16397       }
16398
16399       ModifyEditorElementList();
16400
16401       break;
16402
16403     case GADGET_ID_PROPERTIES:
16404       // always switch off element properties when they are already displayed
16405       last_properties_element = new_element;
16406     case GADGET_ID_ELEMENT_LEFT:
16407     case GADGET_ID_ELEMENT_MIDDLE:
16408     case GADGET_ID_ELEMENT_RIGHT:
16409       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16410                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16411                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16412                             new_element);
16413
16414       if (edit_mode != ED_MODE_PROPERTIES)
16415       {
16416         last_edit_mode = edit_mode;
16417
16418         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16419
16420         last_level_drawing_function = drawing_function;
16421         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16422                       MB_LEFTBUTTON);
16423       }
16424       else if (properties_element != last_properties_element)
16425       {
16426         DrawEditModeWindow();
16427       }
16428       else
16429       {
16430         ChangeEditModeWindow(ED_MODE_DRAWING);
16431
16432         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16433                       MB_LEFTBUTTON);
16434       }
16435       break;
16436
16437     case GADGET_ID_PALETTE:
16438       if (edit_mode != ED_MODE_PALETTE)
16439       {
16440         last_edit_mode = edit_mode;
16441
16442         ChangeEditModeWindow(ED_MODE_PALETTE);
16443       }
16444       else
16445       {
16446         ChangeEditModeWindow(last_edit_mode);
16447       }
16448       break;
16449
16450     case GADGET_ID_WRAP_LEFT:
16451       WrapLevel(-step, 0);
16452       break;
16453
16454     case GADGET_ID_WRAP_RIGHT:
16455       WrapLevel(step, 0);
16456       break;
16457
16458     case GADGET_ID_WRAP_UP:
16459       WrapLevel(0, -step);
16460       break;
16461
16462     case GADGET_ID_WRAP_DOWN:
16463       WrapLevel(0, step);
16464       break;
16465
16466     case GADGET_ID_SINGLE_ITEMS:
16467     case GADGET_ID_CONNECTED_ITEMS:
16468     case GADGET_ID_LINE:
16469     case GADGET_ID_ARC:
16470     case GADGET_ID_TEXT:
16471     case GADGET_ID_RECTANGLE:
16472     case GADGET_ID_FILLED_BOX:
16473     case GADGET_ID_FLOOD_FILL:
16474     case GADGET_ID_GRAB_BRUSH:
16475     case GADGET_ID_PICK_ELEMENT:
16476       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16477         last_drawing_function = drawing_function;
16478       drawing_function = id;
16479       draw_with_brush = FALSE;
16480       break;
16481
16482     case GADGET_ID_RANDOM_PLACEMENT:
16483       RandomPlacement(new_element);
16484       break;
16485
16486     case GADGET_ID_ZOOM:
16487       // zoom level editor tile size in or out (or reset to default size)
16488       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16489                      button == 2 ? ed_tilesize_default :
16490                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16491
16492       // when using touch device, cycle through all zoom tilesizes
16493       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16494         ed_tilesize = MICRO_TILESIZE;
16495
16496       // limit zoom level by upper and lower bound
16497       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16498
16499       InitZoomLevelSettings(ed_tilesize);
16500
16501       if (edit_mode == ED_MODE_DRAWING)
16502       {
16503         DrawDrawingWindow();
16504
16505         // redraw zoom gadget info text
16506         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16507       }
16508
16509       // save current editor zoom tilesize
16510       SaveSetup_AutoSetup();
16511
16512       break;
16513
16514     case GADGET_ID_CUSTOM_COPY_FROM:
16515     case GADGET_ID_CUSTOM_COPY_TO:
16516     case GADGET_ID_CUSTOM_EXCHANGE:
16517       last_custom_copy_mode = id;
16518       last_drawing_function = drawing_function;
16519       break;
16520
16521     case GADGET_ID_CUSTOM_COPY:
16522       CopyCustomElement(properties_element, -1, id);
16523       break;
16524
16525     case GADGET_ID_CUSTOM_PASTE:
16526       CopyCustomElement(-1, properties_element, id);
16527       break;
16528
16529     case GADGET_ID_UNDO:
16530       if (button < 0)   // keep button value (even if modifier keys are pressed)
16531         button = -button;
16532       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16533         button = 3;
16534
16535       if (button == 1 && undo_buffer_steps == 0)
16536       {
16537         Request("Undo buffer empty!", REQ_CONFIRM);
16538
16539         break;
16540       }
16541       else if (button == 2)
16542       {
16543         break;
16544       }
16545       else if (button == 3 && redo_buffer_steps == 0)
16546       {
16547         Request("Redo buffer empty!", REQ_CONFIRM);
16548
16549         break;
16550       }
16551
16552       if (edit_mode != ED_MODE_DRAWING)
16553         ChangeEditModeWindow(ED_MODE_DRAWING);
16554
16555       if (button == 1)
16556       {
16557         // undo
16558
16559         undo_buffer_position =
16560           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16561
16562         undo_buffer_steps--;
16563         redo_buffer_steps++;
16564       }
16565       else
16566       {
16567         // redo
16568
16569         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16570
16571         undo_buffer_steps++;
16572         redo_buffer_steps--;
16573       }
16574
16575       for (x = 0; x < lev_fieldx; x++)
16576         for (y = 0; y < lev_fieldy; y++)
16577           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16578
16579       // check if undo operation forces change of border style
16580       CheckLevelBorderElement(FALSE);
16581
16582       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16583
16584       break;
16585
16586     case GADGET_ID_CONF:
16587       if (edit_mode != ED_MODE_LEVELCONFIG)
16588       {
16589         last_edit_mode = edit_mode;
16590
16591         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16592       }
16593       else
16594       {
16595         ChangeEditModeWindow(ED_MODE_DRAWING);
16596       }
16597       break;
16598
16599     case GADGET_ID_CLEAR:
16600       if (edit_mode != ED_MODE_DRAWING)
16601         ChangeEditModeWindow(ED_MODE_DRAWING);
16602
16603       for (x = 0; x < MAX_LEV_FIELDX; x++)
16604         for (y = 0; y < MAX_LEV_FIELDY; y++)
16605           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16606
16607       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16608
16609       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16610       break;
16611
16612     case GADGET_ID_SAVE:
16613     {
16614       // saving read-only levels into personal level set modifies global vars
16615       // "leveldir_current" and "level_nr"; restore them after saving level
16616       LevelDirTree *leveldir_former = leveldir_current;
16617       int level_nr_former = level_nr;
16618       char *level_filename;
16619       boolean new_level;
16620
16621       if (leveldir_current->readonly &&
16622           !PrepareSavingIntoPersonalLevelSet())
16623         break;
16624
16625       level_filename = getDefaultLevelFilename(level_nr);
16626       new_level = !fileExists(level_filename);
16627
16628       if (new_level ||
16629           Request("Save this level and kill the old?", REQ_ASK))
16630       {
16631         if (leveldir_former->readonly)
16632           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16633
16634         SetAutomaticNumberOfGemsNeeded();
16635
16636         CopyPlayfield(Tile, level.field);
16637         SaveLevel(level_nr);
16638
16639         level.changed = FALSE;
16640
16641         if (new_level)
16642         {
16643           char level_saved_msg[64];
16644
16645           if (leveldir_former->readonly)
16646             sprintf(level_saved_msg,
16647                     "Level saved as level %d into personal level set!",
16648                     level_nr);
16649           else
16650             strcpy(level_saved_msg, "Level saved!");
16651
16652           Request(level_saved_msg, REQ_CONFIRM);
16653         }
16654       }
16655
16656       // "cd" back to copied-from levelset (in case of saved read-only level)
16657       leveldir_current = leveldir_former;
16658       level_nr = level_nr_former;
16659
16660       break;
16661     }
16662
16663     case GADGET_ID_TEST:
16664       if (LevelChanged())
16665         level.game_version = GAME_VERSION_ACTUAL;
16666
16667       CopyPlayfield(level.field, TileBackup);
16668       CopyPlayfield(Tile, level.field);
16669
16670       CopyNativeLevel_RND_to_Native(&level);
16671
16672       UnmapLevelEditorGadgets();
16673       UndrawSpecialEditorDoor();
16674
16675       CloseDoor(DOOR_CLOSE_ALL);
16676
16677       // needed before playing if editor playfield area has different size
16678       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16679
16680       // redraw_mask = REDRAW_ALL;
16681
16682       level_editor_test_game = TRUE;
16683
16684       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16685
16686       break;
16687
16688     case GADGET_ID_EXIT:
16689       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16690       break;
16691
16692     default:
16693       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16694           id <= GADGET_ID_ELEMENTLIST_LAST)
16695       {
16696         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16697
16698         new_element = editor_elements[element_position + element_shift];
16699
16700         if (IS_EDITOR_CASCADE(new_element))
16701         {
16702           int i;
16703
16704           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16705           {
16706             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16707             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16708
16709             if (*cascade_element == new_element)
16710             {
16711               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16712               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16713
16714               // update element selection list
16715               ReinitializeElementList();
16716               ModifyEditorElementList();
16717
16718               // update cascading gadget info text
16719               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16720
16721               // save current editor cascading state
16722               SaveSetup_EditorCascade();
16723
16724               break;
16725             }
16726           }
16727
16728           break;
16729         }
16730
16731         if (last_custom_copy_mode != -1)
16732         {
16733           if (CopyCustomElement(properties_element, new_element,
16734                                 last_custom_copy_mode))
16735           {
16736             ClickOnGadget(level_editor_gadget[last_drawing_function],
16737                           MB_LEFTBUTTON);
16738
16739             last_custom_copy_mode = -1;
16740           }
16741
16742           break;
16743         }
16744
16745         // change element of button used to show palette
16746         if (editor.palette.show_on_element_buttons)
16747           button = last_button;
16748
16749         PickDrawingElement(button, new_element);
16750
16751         if (!stick_element_properties_window &&
16752             drawing_function != GADGET_ID_PICK_ELEMENT &&
16753             !(GetKeyModState() & KMOD_Control))
16754         {
16755           properties_element = new_element;
16756           if (edit_mode == ED_MODE_PROPERTIES)
16757             DrawPropertiesWindow();
16758         }
16759
16760         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16761           ClickOnGadget(level_editor_gadget[last_drawing_function],
16762                         MB_LEFTBUTTON);
16763
16764         if (!use_permanent_palette)
16765           ChangeEditModeWindow(last_edit_mode);
16766       }
16767 #ifdef DEBUG
16768       else if (gi->event.type == GD_EVENT_PRESSED)
16769         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16770       else if (gi->event.type == GD_EVENT_RELEASED)
16771         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16772       else if (gi->event.type == GD_EVENT_MOVING)
16773         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16774       else
16775         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16776 #endif
16777       break;
16778   }
16779 }
16780
16781 void HandleLevelEditorKeyInput(Key key)
16782 {
16783   char letter = getCharFromKey(key);
16784
16785   if (drawing_function == GADGET_ID_TEXT &&
16786       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16787   {
16788     if (letter)
16789       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16790     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16791       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16792     else if (key == KSYM_Return)
16793       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16794     else if (key == KSYM_Escape)
16795       DrawLevelText(0, 0, 0, TEXT_END);
16796
16797     return;
16798   }
16799
16800   int id = GADGET_ID_NONE;
16801   int new_element_shift = element_shift;
16802   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16803   int button = MB_LEFTBUTTON;
16804   int i;
16805
16806   switch (key)
16807   {
16808     case KSYM_Left:
16809       id = GADGET_ID_SCROLL_LEFT;
16810       break;
16811     case KSYM_Right:
16812       id = GADGET_ID_SCROLL_RIGHT;
16813       break;
16814     case KSYM_Up:
16815       id = GADGET_ID_SCROLL_UP;
16816       break;
16817     case KSYM_Down:
16818       id = GADGET_ID_SCROLL_DOWN;
16819       break;
16820
16821     case KSYM_Page_Up:
16822     case KSYM_Page_Down:
16823       step *= (key == KSYM_Page_Up ? -1 : +1);
16824       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16825
16826       if (element_shift < 0)
16827         element_shift = 0;
16828       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16829         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16830
16831       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16832                    GDI_SCROLLBAR_ITEM_POSITION,
16833                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16834
16835       ModifyEditorElementList();
16836
16837       break;
16838
16839     case KSYM_Home:
16840     case KSYM_End:
16841       element_shift = (key == KSYM_Home ? 0 :
16842                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16843
16844       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16845                    GDI_SCROLLBAR_ITEM_POSITION,
16846                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16847
16848       ModifyEditorElementList();
16849
16850       break;
16851
16852     case KSYM_Insert:
16853     case KSYM_Delete:
16854
16855       // this is needed to prevent interference with running "True X-Mouse"
16856       if (GetKeyModStateFromEvents() & KMOD_Control)
16857         break;
16858
16859       // check for last or next editor cascade block in element list
16860       for (i = 0; i < num_editor_elements; i++)
16861       {
16862         if ((key == KSYM_Insert && i == element_shift) ||
16863             (key == KSYM_Delete && new_element_shift > element_shift))
16864           break;
16865
16866         // jump to next cascade block (or to start of element list)
16867         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16868           new_element_shift = i;
16869       }
16870
16871       if (i < num_editor_elements)
16872         element_shift = new_element_shift;
16873
16874       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16875         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16876
16877       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16878                    GDI_SCROLLBAR_ITEM_POSITION,
16879                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16880
16881       ModifyEditorElementList();
16882
16883       break;
16884
16885     case KSYM_Escape:
16886       if (edit_mode == ED_MODE_DRAWING)
16887         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16888       else if (edit_mode == ED_MODE_LEVELCONFIG)
16889         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16890       else if (edit_mode == ED_MODE_PROPERTIES)
16891         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16892       else if (edit_mode == ED_MODE_PALETTE)
16893         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16894       else              // should never happen
16895         ChangeEditModeWindow(ED_MODE_DRAWING);
16896
16897       break;
16898
16899     default:
16900       break;
16901   }
16902
16903   if (id != GADGET_ID_NONE)
16904     ClickOnGadget(level_editor_gadget[id], button);
16905   else if (letter == '1' || letter == '?')
16906     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16907   else if (letter == '2')
16908     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16909   else if (letter == '3')
16910     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16911   else if (letter == '.')
16912     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16913   else if (letter == 'U')
16914     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16915   else if (letter == '-' || key == KSYM_KP_Subtract)
16916     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16917   else if (letter == '0' || key == KSYM_KP_0)
16918     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16919   else if (letter == '+' || key == KSYM_KP_Add ||
16920            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16921     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16922   else if (key == KSYM_Return ||
16923            key == KSYM_space ||
16924            key == setup.shortcut.toggle_pause)
16925     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16926   else
16927     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16928       if (letter && letter == controlbutton_info[i].shortcut)
16929         if (!anyTextGadgetActive())
16930           ClickOnGadget(level_editor_gadget[i], button);
16931
16932   if (draw_with_brush)
16933   {
16934     if (letter == 'x')
16935       FlipBrushX();
16936     else if (letter == 'y')
16937       FlipBrushY();
16938     else if (letter == 'z')
16939       RotateBrush();
16940   }
16941 }
16942
16943 static void HandleLevelEditorIdle_Properties(void)
16944 {
16945   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16946   int x = editor.settings.element_graphic.x + element_border;
16947   int y = editor.settings.element_graphic.y + element_border;
16948   static DelayCounter action_delay = { 0 };
16949   int i;
16950
16951   action_delay.value = GameFrameDelay;
16952
16953   if (!DelayReached(&action_delay))
16954     return;
16955
16956   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16957   {
16958     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16959
16960     if (gi->mapped && gi->active && gi->selectbox.open)
16961       return;
16962   }
16963
16964   DrawEditorElementAnimation(SX + x, SY + y);
16965
16966   redraw_mask |= REDRAW_FIELD;
16967
16968   FrameCounter++;       // increase animation frame counter
16969 }
16970
16971 static void HandleLevelEditorIdle_Drawing(void)
16972 {
16973   static boolean last_highlighted = FALSE;
16974   static boolean last_highlighted_similar = FALSE;
16975   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16976   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16977
16978   if (highlighted != last_highlighted ||
16979       (highlighted && highlighted_similar != last_highlighted_similar))
16980   {
16981     DrawAreaElementHighlight(highlighted, highlighted_similar);
16982
16983     redraw_mask |= REDRAW_FIELD;
16984   }
16985
16986   last_highlighted = highlighted;
16987   last_highlighted_similar = highlighted_similar;
16988 }
16989
16990 void HandleLevelEditorIdle(void)
16991 {
16992   if (edit_mode == ED_MODE_PROPERTIES)
16993     HandleLevelEditorIdle_Properties();
16994   else if (edit_mode == ED_MODE_DRAWING)
16995     HandleLevelEditorIdle_Drawing();
16996 }
16997
16998 static void ClearEditorGadgetInfoText(void)
16999 {
17000   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
17001 }
17002
17003 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
17004 {
17005   char infotext[MAX_OUTPUT_LINESIZE + 1];
17006   int max_infotext_len = getMaxInfoTextLength();
17007
17008   if (gi == NULL || strlen(gi->info_text) == 0)
17009     return;
17010
17011   strncpy(infotext, gi->info_text, max_infotext_len);
17012   infotext[max_infotext_len] = '\0';
17013
17014   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
17015   {
17016     int key = controlbutton_info[gi->custom_id].shortcut;
17017
17018     if (key)
17019     {
17020       char shortcut[MAX_OUTPUT_LINESIZE + 1];
17021
17022       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
17023         sprintf(shortcut, " ('.' or '%c')", key);
17024       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
17025         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
17026       else if (gi->custom_id == GADGET_ID_TEST)
17027         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
17028       else if (gi->custom_id == GADGET_ID_UNDO)
17029         sprintf(shortcut, " ('%c/Shift-U')", key);
17030       else if (gi->custom_id == GADGET_ID_ZOOM)
17031         sprintf(shortcut, " ('%c', '0', '-')", key);
17032       else
17033         sprintf(shortcut, " ('%s%c')",
17034                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
17035
17036       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
17037         strcat(infotext, shortcut);
17038     }
17039   }
17040
17041   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
17042 }
17043
17044 void HandleEditorGadgetInfoText(void *ptr)
17045 {
17046   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
17047
17048   if (game_status != GAME_MODE_EDITOR)
17049     return;
17050
17051   ClearEditorGadgetInfoText();
17052
17053   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
17054     return;
17055
17056   // misuse this function to delete brush cursor, if needed
17057   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
17058     DeleteBrushFromCursor();
17059
17060   PrintEditorGadgetInfoText(gi);
17061 }
17062
17063 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
17064 {
17065   int id = gi->custom_id;
17066   int type_id = gi->custom_type_id;
17067   int sx = gi->event.x;
17068   int sy = gi->event.y;
17069   int lx = sx + level_xpos;
17070   int ly = sy + level_ypos;
17071   int min_sx = 0, min_sy = 0;
17072   int max_sx = gi->drawing.area_xsize - 1;
17073   int max_sy = gi->drawing.area_ysize - 1;
17074   int actual_drawing_function = drawing_function;
17075   int max_infotext_len = getMaxInfoTextLength();
17076   char infotext[MAX_OUTPUT_LINESIZE + 1];
17077
17078   infotext[0] = '\0';           // start with empty info text
17079
17080   // pressed Control key: simulate picking element
17081   if (GetKeyModState() & KMOD_Control)
17082     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
17083
17084   ClearEditorGadgetInfoText();
17085
17086   if (gi->event.type == GD_EVENT_INFO_LEAVING)
17087     return;
17088
17089   // make sure to stay inside drawing area boundaries
17090   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
17091   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
17092
17093   if (id == GADGET_ID_DRAWING_LEVEL)
17094   {
17095     if (button_status)
17096     {
17097       int min_lx = 0, min_ly = 0;
17098       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
17099
17100       // get positions inside level field
17101       lx = sx + level_xpos;
17102       ly = sy + level_ypos;
17103
17104       // make sure to stay inside level field boundaries
17105       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
17106       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
17107
17108       // correct drawing area positions accordingly
17109       sx = lx - level_xpos;
17110       sy = ly - level_ypos;
17111     }
17112
17113     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17114     {
17115       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
17116       {
17117         static int start_lx = 0;
17118         static int start_ly = 0;
17119         char *text;
17120
17121         if (gi->event.type == GD_EVENT_PRESSED)
17122         {
17123           start_lx = lx;
17124           start_ly = ly;
17125         }
17126
17127         switch (actual_drawing_function)
17128         {
17129           case GADGET_ID_SINGLE_ITEMS:
17130             text = "Drawing single items";
17131             break;
17132           case GADGET_ID_CONNECTED_ITEMS:
17133             text = "Drawing connected items";
17134             break;
17135           case GADGET_ID_LINE:
17136             text = "Drawing line";
17137             break;
17138           case GADGET_ID_ARC:
17139             text = "Drawing arc";
17140             break;
17141           case GADGET_ID_TEXT:
17142             text = "Setting text cursor";
17143             break;
17144           case GADGET_ID_RECTANGLE:
17145             text = "Drawing rectangle";
17146             break;
17147           case GADGET_ID_FILLED_BOX:
17148             text = "Drawing filled box";
17149             break;
17150           case GADGET_ID_FLOOD_FILL:
17151             text = "Flood fill";
17152             break;
17153           case GADGET_ID_GRAB_BRUSH:
17154             text = "Grabbing brush";
17155             break;
17156           case GADGET_ID_PICK_ELEMENT:
17157             text = "Picking element";
17158             break;
17159
17160           default:
17161             text = "Drawing position";
17162             break;
17163         }
17164
17165         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17166           sprintf(infotext, "%s: %d, %d", text, lx, ly);
17167         else
17168           sprintf(infotext, "%s: %d, %d", text,
17169                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
17170       }
17171       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17172         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
17173       else
17174         sprintf(infotext, "Level position: %d, %d", lx, ly);
17175     }
17176
17177     // misuse this function to draw brush cursor, if needed
17178     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
17179     {
17180       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
17181         CopyBrushToCursor(sx, sy);
17182       else
17183         DeleteBrushFromCursor();
17184     }
17185
17186     if (!draw_with_brush)
17187       UpdateBrushPosition(sx, sy);
17188   }
17189   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
17190   {
17191     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
17192     int element = drawingarea_info[type_id].value[pos];
17193
17194     strncpy(infotext, getElementInfoText(element), max_infotext_len);
17195   }
17196   else
17197   {
17198     if (id == GADGET_ID_CUSTOM_CONTENT)
17199       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
17200     else if (id == GADGET_ID_GROUP_CONTENT)
17201       sprintf(infotext, "group element position: %d", sx + 1);
17202     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
17203              id <= GADGET_ID_YAMYAM_CONTENT_7)
17204       sprintf(infotext, "content area %d position: %d, %d",
17205               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
17206     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17207              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17208       sprintf(infotext, "content area %d position: %d, %d",
17209               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17210     else if (id == GADGET_ID_ANDROID_CONTENT)
17211       sprintf(infotext, "android element position: %d", sx + 1);
17212     else if (drawingarea_info[type_id].infotext != NULL)
17213       strcpy(infotext, drawingarea_info[type_id].infotext);
17214   }
17215
17216   infotext[max_infotext_len] = '\0';
17217
17218   if (strlen(infotext) > 0)
17219     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17220 }
17221
17222 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17223                             boolean quick_quit)
17224 {
17225   if (!ask_if_level_has_changed ||
17226       !LevelChanged() ||
17227       Request("Level has changed! Exit without saving?",
17228               REQ_ASK | REQ_STAY_OPEN))
17229   {
17230     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17231     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17232
17233     // draw normal door
17234     UndrawSpecialEditorDoor();
17235
17236     // use door animation if door 1 viewport is unchanged and contains toolbox
17237     if (useEditorDoorAnimation())
17238       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17239
17240     // close editor doors if viewport definition is the same as in main menu
17241     if (vp_door_1->x      == DX     &&
17242         vp_door_1->y      == DY     &&
17243         vp_door_1->width  == DXSIZE &&
17244         vp_door_1->height == DYSIZE &&
17245         vp_door_2->x      == VX     &&
17246         vp_door_2->y      == VY     &&
17247         vp_door_2->width  == VXSIZE &&
17248         vp_door_2->height == VYSIZE)
17249       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17250     else
17251       SetDoorState(DOOR_CLOSE_ALL);
17252
17253     BackToFront();
17254
17255     if (quick_quit)
17256       FadeSkipNextFadeIn();
17257
17258     SetGameStatus(GAME_MODE_MAIN);
17259
17260     DrawMainMenu();
17261   }
17262   else
17263   {
17264     if (!global.use_envelope_request)
17265     {
17266       CloseDoor(DOOR_CLOSE_1);
17267       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17268     }
17269   }
17270 }