extended support for rock/diamond settings in BD engine to level editor
[rocksndiamonds.git] / src / editor.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // editor.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "game.h"
21 #include "init.h"
22 #include "tape.h"
23
24
25 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
26
27
28 // ----------------------------------------------------------------------------
29 // screen and artwork graphic pixel position definitions
30 // ----------------------------------------------------------------------------
31
32 // values for the control window
33 #define ED_CTRL1_BUTTONS_HORIZ          4       // toolbox
34 #define ED_CTRL1_BUTTONS_VERT           4
35 #define ED_CTRL2_BUTTONS_HORIZ          3       // level
36 #define ED_CTRL2_BUTTONS_VERT           2
37 #define ED_CTRL3_BUTTONS_HORIZ          3       // CE and GE
38 #define ED_CTRL3_BUTTONS_VERT           1
39 #define ED_CTRL4_BUTTONS_HORIZ          2       // CE and GE
40 #define ED_CTRL4_BUTTONS_VERT           1
41 #define ED_CTRL5_BUTTONS_HORIZ          1       // properties
42 #define ED_CTRL5_BUTTONS_VERT           1
43 #define ED_CTRL6_BUTTONS_HORIZ          3       // properties
44 #define ED_CTRL6_BUTTONS_VERT           1
45 #define ED_CTRL7_BUTTONS_HORIZ          1       // palette
46 #define ED_CTRL7_BUTTONS_VERT           1
47
48 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
49 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
50 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
51 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
52 #define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
53 #define ED_NUM_CTRL6_BUTTONS   (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT)
54 #define ED_NUM_CTRL7_BUTTONS   (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT)
55 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
56 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
57 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
58 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
59 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
60 #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS)
61 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_7_BUTTONS
62
63 // values for the element list
64 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
65 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
66 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
67 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
68 #define ED_ELEMENTLIST_COLS             MAX(1, editor.palette.cols)
69 #define ED_ELEMENTLIST_ROWS             MAX(1, editor.palette.rows)
70 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (ED_ELEMENTLIST_COLS)
71 #define ED_ELEMENTLIST_BUTTONS_VERT     (ED_ELEMENTLIST_ROWS)
72 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
73                                          ED_ELEMENTLIST_BUTTONS_VERT)
74
75 // standard distances
76 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
77 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
78 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
79 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
80 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
81 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
82 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
83                                          ED_DRAWINGAREA_BORDER_SIZE)
84 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
85
86 // values for drawingarea gadgets
87 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
88 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
89 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
90 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
91 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
92
93 // values for checkbutton gadgets
94 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
95 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
96
97 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
98 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
99
100 #define ED_SETTINGS_LEVEL_TABS_X        (editor.settings.tabs.x)
101 #define ED_SETTINGS_LEVEL_TABS_Y        (editor.settings.tabs.y)
102 #define ED_SETTINGS_ELEMENT_TABS_X      (editor.settings.tabs.x)
103 #define ED_SETTINGS_ELEMENT_TABS_Y      (editor.settings.tabs.y +       \
104                                          editor.settings.tabs.yoffset2)
105
106 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
107 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
108
109 #define ED_LEVEL_TABS_XSTART            (ED_SETTINGS_LEVEL_TABS_X)
110 #define ED_LEVEL_TABS_YSTART            (ED_SETTINGS_LEVEL_TABS_Y)
111 #define ED_LEVEL_SETTINGS_XSTART        (ED_SETTINGS_LEVEL_TABS_X +     \
112                                          ED_SETTINGS_TABS_XOFFSET)
113 #define ED_LEVEL_SETTINGS_YSTART        (ED_SETTINGS_LEVEL_TABS_Y +     \
114                                          ED_TABBUTTON_YSIZE +           \
115                                          ED_GADGET_TINY_DISTANCE +      \
116                                          ED_TAB_BAR_HEIGHT +            \
117                                          ED_SETTINGS_TABS_YOFFSET +     \
118                                          getFontHeight(FONT_TEXT_1) +   \
119                                          ED_GADGET_TEXT_DISTANCE)
120 #define ED_ELEMENT_TABS_XSTART          (ED_SETTINGS_ELEMENT_TABS_X)
121 #define ED_ELEMENT_TABS_YSTART          (ED_SETTINGS_ELEMENT_TABS_Y)
122 #define ED_ELEMENT_SETTINGS_XSTART      (ED_SETTINGS_ELEMENT_TABS_X +   \
123                                          ED_SETTINGS_TABS_XOFFSET)
124 #define ED_ELEMENT_SETTINGS_YSTART      (ED_SETTINGS_ELEMENT_TABS_Y +   \
125                                          ED_TABBUTTON_YSIZE +           \
126                                          ED_GADGET_TINY_DISTANCE +      \
127                                          ED_TAB_BAR_HEIGHT +            \
128                                          ED_SETTINGS_TABS_YOFFSET)
129
130 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
131                                          ED_GADGET_TEXT_DISTANCE)
132 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
133                                          ED_GADGET_LINE_DISTANCE)
134
135 #define ED_POS_RANGE                    (10000)
136 #define ED_POS_LEVEL_TABS_FIRST         (1 * ED_POS_RANGE)
137 #define ED_POS_LEVEL_TABS_LAST          (2 * ED_POS_RANGE - 1)
138 #define ED_POS_LEVEL_SETTINGS_FIRST     (2 * ED_POS_RANGE)
139 #define ED_POS_LEVEL_SETTINGS_LAST      (3 * ED_POS_RANGE - 1)
140 #define ED_POS_ELEMENT_TABS_FIRST       (3 * ED_POS_RANGE)
141 #define ED_POS_ELEMENT_TABS_LAST        (4 * ED_POS_RANGE - 1)
142 #define ED_POS_ELEMENT_SETTINGS_FIRST   (4 * ED_POS_RANGE)
143 #define ED_POS_ELEMENT_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
144
145 #define ED_LEVEL_TABS_XPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
146 #define ED_LEVEL_TABS_YPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
147
148 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
149 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
150
151 #define ED_ELEMENT_TABS_XPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
152 #define ED_ELEMENT_TABS_YPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
153
154 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
155 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
156
157 #define IS_POS_LEVEL_TABS(n)          ((n) >= ED_POS_LEVEL_TABS_FIRST && \
158                                        (n) <= ED_POS_LEVEL_TABS_LAST)
159 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
160                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
161 #define IS_POS_ELEMENT_TABS(n)        ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
162                                        (n) <= ED_POS_ELEMENT_TABS_LAST)
163 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
164                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
165
166 #define ED_LEVEL_TABS_LINE(n)           ((n) - ED_POS_LEVEL_TABS_FIRST)
167 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
168 #define ED_ELEMENT_TABS_LINE(n)         ((n) - ED_POS_ELEMENT_TABS_FIRST)
169 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
170
171 #define ED_LEVEL_TABS_X(n)              (ED_LEVEL_TABS_XSTART + \
172                                          (n) * ED_SETTINGS_TABS_XOFFSET)
173 #define ED_LEVEL_TABS_Y(n)              (ED_LEVEL_TABS_YSTART + \
174                                          (n) * ED_SETTINGS_TABS_YOFFSET)
175
176 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
177                                          (n) * ED_SETTINGS_XOFFSET)
178 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
179                                          (n) * ED_SETTINGS_YOFFSET)
180
181 #define ED_ELEMENT_TABS_X(n)            (ED_ELEMENT_TABS_XSTART +       \
182                                          (n) * ED_SETTINGS_TABS_XOFFSET)
183 #define ED_ELEMENT_TABS_Y(n)            (ED_ELEMENT_TABS_YSTART +       \
184                                          (n) * ED_SETTINGS_TABS_YOFFSET)
185
186 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
187                                          (n) * ED_SETTINGS_XOFFSET)
188 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
189                                          (n) * ED_SETTINGS_YOFFSET)
190
191 #define ED_POS_TO_LEVEL_TABS_X(n)       \
192   (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n)))
193 #define ED_POS_TO_LEVEL_TABS_Y(n)       \
194   (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n)))
195
196 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
197   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
198 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
199   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
200
201 #define ED_POS_TO_ELEMENT_TABS_X(n)     \
202   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
203 #define ED_POS_TO_ELEMENT_TABS_Y(n)     \
204   (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n)))
205
206 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
207   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
208 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
209   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
210
211 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_TABS(n) ? \
212                                          ED_POS_TO_LEVEL_TABS_X(n) : \
213                                          IS_POS_LEVEL_SETTINGS(n) ?     \
214                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
215                                          IS_POS_ELEMENT_TABS(n) ?       \
216                                          ED_POS_TO_ELEMENT_TABS_X(n) : \
217                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
218                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
219 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_TABS(n) ? \
220                                          ED_POS_TO_LEVEL_TABS_Y(n) : \
221                                          IS_POS_LEVEL_SETTINGS(n) ?     \
222                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
223                                          IS_POS_ELEMENT_TABS(n) ?       \
224                                          ED_POS_TO_ELEMENT_TABS_Y(n) : \
225                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
226                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
227
228 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
229                                          ED_DRAWINGAREA_TILE_SIZE)
230 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
231                                          ED_DRAWINGAREA_TILE_SIZE)
232
233 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
234                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
235 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
236                                          (ED_CHECKBUTTON_YSIZE -        \
237                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
238
239 #define ED_AREA_XOFFSET_2(n)      (0)
240 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
241                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
242
243 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
244                                     ED_SETTINGS_XOFF((i).xoffset) +     \
245                                     ED_AREA_XOFFSET_1((i).x) -          \
246                                     ED_AREA_XOFFSET_2((i).area_xsize))
247 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
248                                     ED_SETTINGS_YOFF((i).yoffset) +     \
249                                     ED_AREA_YOFFSET_1((i).y) -          \
250                                     ED_AREA_YOFFSET_2((i).area_ysize))
251
252 // values for element content drawing areas
253 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
254 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
255 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
256 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
257
258 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
259 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
260 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
261 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
262
263 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
264 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
265 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
266 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
267
268 // element content
269 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
270 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
271
272 // yamyam content
273 #define ED_XPOS_YAM                     0
274 #define ED_YPOS_YAM                     5
275 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
276 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
277 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
278 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
279 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
280                                          ED_SETTINGS_XOFF(n))
281 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
282                                          ED_SETTINGS_YOFF(n) +          \
283                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
284                                          ED_AREA_YOFFSET_2(3))
285
286 // magic ball content
287 #define ED_XPOS_BALL                    0
288 #define ED_YPOS_BALL                    6
289 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
290 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
291 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
292 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
293 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
294                                          ED_SETTINGS_XOFF(n))
295 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
296                                          ED_SETTINGS_YOFF(n) +          \
297                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
298                                          ED_AREA_YOFFSET_2(3))
299
300 // values for scrolling gadgets for drawing area
301 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
302 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
303
304 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
305 #define ED_SCROLL_UP_YPOS               (0)
306 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
307 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
308 #define ED_SCROLL_LEFT_XPOS             (0)
309 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
310 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
311 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
312 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
313                                          ED_SCROLLBUTTON_XSIZE)
314 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
315 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
316 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
317 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
318 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
319                                          ED_SCROLLBUTTON_YSIZE)
320 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
321 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
322
323 // values for scrolling gadgets for element list
324 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
325 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
326
327 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
328                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
329                                          ED_ELEMENTLIST_XSIZE)
330 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
331 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
332 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
333                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
334                                          ED_ELEMENTLIST_YSIZE -         \
335                                          ED_SCROLLBUTTON2_YSIZE)
336 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
337 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
338                                          ED_SCROLLBUTTON2_YSIZE)
339 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
340 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
341                                          ED_ELEMENTLIST_YSIZE -         \
342                                          2 * ED_SCROLLBUTTON2_YSIZE)
343
344 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText()
345 #define INFOTEXT_FONT           FONT_TEXT_2
346 #define INFOTEXT_XSIZE          SXSIZE
347 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
348 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
349 #define INFOTEXT_X              (editor.settings.tooltip.x)
350 #define INFOTEXT_Y              (editor.settings.tooltip.y)
351 #define INFOTEXT_XY_REDEFINED   (INFOTEXT_X != -1 || INFOTEXT_Y != -1)
352 #define INFOTEXT_XPOS           SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0)
353 #define INFOTEXT_YPOS           SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \
354                                       SYSIZE - INFOTEXT_YSIZE)
355
356
357 // ----------------------------------------------------------------------------
358 // editor gadget definitions
359 // ----------------------------------------------------------------------------
360
361 enum
362 {
363   GADGET_ID_NONE = -1,
364
365   // drawing toolbox buttons
366
367   GADGET_ID_SINGLE_ITEMS,
368   GADGET_ID_CONNECTED_ITEMS,
369   GADGET_ID_LINE,
370   GADGET_ID_ARC,
371   GADGET_ID_RECTANGLE,
372   GADGET_ID_FILLED_BOX,
373   GADGET_ID_WRAP_UP,
374   GADGET_ID_TEXT,
375   GADGET_ID_FLOOD_FILL,
376   GADGET_ID_WRAP_LEFT,
377   GADGET_ID_ZOOM,
378   GADGET_ID_WRAP_RIGHT,
379   GADGET_ID_RANDOM_PLACEMENT,
380   GADGET_ID_GRAB_BRUSH,
381   GADGET_ID_WRAP_DOWN,
382   GADGET_ID_PICK_ELEMENT,
383
384   GADGET_ID_UNDO,
385   GADGET_ID_CONF,
386   GADGET_ID_SAVE,
387   GADGET_ID_CLEAR,
388   GADGET_ID_TEST,
389   GADGET_ID_EXIT,
390
391   GADGET_ID_CUSTOM_COPY_FROM,
392   GADGET_ID_CUSTOM_COPY_TO,
393   GADGET_ID_CUSTOM_EXCHANGE,
394   GADGET_ID_CUSTOM_COPY,
395   GADGET_ID_CUSTOM_PASTE,
396
397   GADGET_ID_PROPERTIES,
398   GADGET_ID_ELEMENT_LEFT,
399   GADGET_ID_ELEMENT_MIDDLE,
400   GADGET_ID_ELEMENT_RIGHT,
401   GADGET_ID_PALETTE,
402
403   // counter gadget identifiers
404
405   GADGET_ID_SELECT_LEVEL_DOWN,
406   GADGET_ID_SELECT_LEVEL_TEXT,
407   GADGET_ID_SELECT_LEVEL_UP,
408   GADGET_ID_LEVEL_XSIZE_DOWN,
409   GADGET_ID_LEVEL_XSIZE_TEXT,
410   GADGET_ID_LEVEL_XSIZE_UP,
411   GADGET_ID_LEVEL_YSIZE_DOWN,
412   GADGET_ID_LEVEL_YSIZE_TEXT,
413   GADGET_ID_LEVEL_YSIZE_UP,
414   GADGET_ID_LEVEL_RANDOM_DOWN,
415   GADGET_ID_LEVEL_RANDOM_TEXT,
416   GADGET_ID_LEVEL_RANDOM_UP,
417   GADGET_ID_LEVEL_GEMSLIMIT_DOWN,
418   GADGET_ID_LEVEL_GEMSLIMIT_TEXT,
419   GADGET_ID_LEVEL_GEMSLIMIT_UP,
420   GADGET_ID_LEVEL_TIMELIMIT_DOWN,
421   GADGET_ID_LEVEL_TIMELIMIT_TEXT,
422   GADGET_ID_LEVEL_TIMELIMIT_UP,
423   GADGET_ID_LEVEL_TIMESCORE_DOWN,
424   GADGET_ID_LEVEL_TIMESCORE_TEXT,
425   GADGET_ID_LEVEL_TIMESCORE_UP,
426   GADGET_ID_LEVEL_RANDOM_SEED_DOWN,
427   GADGET_ID_LEVEL_RANDOM_SEED_TEXT,
428   GADGET_ID_LEVEL_RANDOM_SEED_UP,
429   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
430   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
431   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
432   GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,
433   GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,
434   GADGET_ID_BD_CYCLE_DELAY_MS_UP,
435   GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,
436   GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,
437   GADGET_ID_BD_CYCLE_DELAY_C64_UP,
438   GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,
439   GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,
440   GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
441   GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,
442   GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,
443   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
444   GADGET_ID_BD_PUSHING_PROB_DOWN,
445   GADGET_ID_BD_PUSHING_PROB_TEXT,
446   GADGET_ID_BD_PUSHING_PROB_UP,
447   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,
448   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,
449   GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
450   GADGET_ID_ELEMENT_VALUE1_DOWN,
451   GADGET_ID_ELEMENT_VALUE1_TEXT,
452   GADGET_ID_ELEMENT_VALUE1_UP,
453   GADGET_ID_ELEMENT_VALUE2_DOWN,
454   GADGET_ID_ELEMENT_VALUE2_TEXT,
455   GADGET_ID_ELEMENT_VALUE2_UP,
456   GADGET_ID_ELEMENT_VALUE3_DOWN,
457   GADGET_ID_ELEMENT_VALUE3_TEXT,
458   GADGET_ID_ELEMENT_VALUE3_UP,
459   GADGET_ID_ELEMENT_VALUE4_DOWN,
460   GADGET_ID_ELEMENT_VALUE4_TEXT,
461   GADGET_ID_ELEMENT_VALUE4_UP,
462   GADGET_ID_YAMYAM_CONTENT_DOWN,
463   GADGET_ID_YAMYAM_CONTENT_TEXT,
464   GADGET_ID_YAMYAM_CONTENT_UP,
465   GADGET_ID_BALL_CONTENT_DOWN,
466   GADGET_ID_BALL_CONTENT_TEXT,
467   GADGET_ID_BALL_CONTENT_UP,
468   GADGET_ID_ANDROID_CONTENT_DOWN,
469   GADGET_ID_ANDROID_CONTENT_TEXT,
470   GADGET_ID_ANDROID_CONTENT_UP,
471   GADGET_ID_ENVELOPE_XSIZE_DOWN,
472   GADGET_ID_ENVELOPE_XSIZE_TEXT,
473   GADGET_ID_ENVELOPE_XSIZE_UP,
474   GADGET_ID_ENVELOPE_YSIZE_DOWN,
475   GADGET_ID_ENVELOPE_YSIZE_TEXT,
476   GADGET_ID_ENVELOPE_YSIZE_UP,
477   GADGET_ID_INVENTORY_SIZE_DOWN,
478   GADGET_ID_INVENTORY_SIZE_TEXT,
479   GADGET_ID_INVENTORY_SIZE_UP,
480   GADGET_ID_MM_BALL_CONTENT_DOWN,
481   GADGET_ID_MM_BALL_CONTENT_TEXT,
482   GADGET_ID_MM_BALL_CONTENT_UP,
483   GADGET_ID_CUSTOM_SCORE_DOWN,
484   GADGET_ID_CUSTOM_SCORE_TEXT,
485   GADGET_ID_CUSTOM_SCORE_UP,
486   GADGET_ID_CUSTOM_GEMCOUNT_DOWN,
487   GADGET_ID_CUSTOM_GEMCOUNT_TEXT,
488   GADGET_ID_CUSTOM_GEMCOUNT_UP,
489   GADGET_ID_CUSTOM_VALUE_FIX_DOWN,
490   GADGET_ID_CUSTOM_VALUE_FIX_TEXT,
491   GADGET_ID_CUSTOM_VALUE_FIX_UP,
492   GADGET_ID_CUSTOM_VALUE_RND_DOWN,
493   GADGET_ID_CUSTOM_VALUE_RND_TEXT,
494   GADGET_ID_CUSTOM_VALUE_RND_UP,
495   GADGET_ID_PUSH_DELAY_FIX_DOWN,
496   GADGET_ID_PUSH_DELAY_FIX_TEXT,
497   GADGET_ID_PUSH_DELAY_FIX_UP,
498   GADGET_ID_PUSH_DELAY_RND_DOWN,
499   GADGET_ID_PUSH_DELAY_RND_TEXT,
500   GADGET_ID_PUSH_DELAY_RND_UP,
501   GADGET_ID_DROP_DELAY_FIX_DOWN,
502   GADGET_ID_DROP_DELAY_FIX_TEXT,
503   GADGET_ID_DROP_DELAY_FIX_UP,
504   GADGET_ID_DROP_DELAY_RND_DOWN,
505   GADGET_ID_DROP_DELAY_RND_TEXT,
506   GADGET_ID_DROP_DELAY_RND_UP,
507   GADGET_ID_MOVE_DELAY_FIX_DOWN,
508   GADGET_ID_MOVE_DELAY_FIX_TEXT,
509   GADGET_ID_MOVE_DELAY_FIX_UP,
510   GADGET_ID_MOVE_DELAY_RND_DOWN,
511   GADGET_ID_MOVE_DELAY_RND_TEXT,
512   GADGET_ID_MOVE_DELAY_RND_UP,
513   GADGET_ID_STEP_DELAY_FIX_DOWN,
514   GADGET_ID_STEP_DELAY_FIX_TEXT,
515   GADGET_ID_STEP_DELAY_FIX_UP,
516   GADGET_ID_STEP_DELAY_RND_DOWN,
517   GADGET_ID_STEP_DELAY_RND_TEXT,
518   GADGET_ID_STEP_DELAY_RND_UP,
519   GADGET_ID_EXPLOSION_DELAY_DOWN,
520   GADGET_ID_EXPLOSION_DELAY_TEXT,
521   GADGET_ID_EXPLOSION_DELAY_UP,
522   GADGET_ID_IGNITION_DELAY_DOWN,
523   GADGET_ID_IGNITION_DELAY_TEXT,
524   GADGET_ID_IGNITION_DELAY_UP,
525   GADGET_ID_CHANGE_DELAY_FIX_DOWN,
526   GADGET_ID_CHANGE_DELAY_FIX_TEXT,
527   GADGET_ID_CHANGE_DELAY_FIX_UP,
528   GADGET_ID_CHANGE_DELAY_RND_DOWN,
529   GADGET_ID_CHANGE_DELAY_RND_TEXT,
530   GADGET_ID_CHANGE_DELAY_RND_UP,
531   GADGET_ID_CHANGE_CONT_RND_DOWN,
532   GADGET_ID_CHANGE_CONT_RND_TEXT,
533   GADGET_ID_CHANGE_CONT_RND_UP,
534   GADGET_ID_GROUP_CONTENT_DOWN,
535   GADGET_ID_GROUP_CONTENT_TEXT,
536   GADGET_ID_GROUP_CONTENT_UP,
537
538   // drawing area identifiers
539
540   GADGET_ID_DRAWING_LEVEL,
541   GADGET_ID_YAMYAM_CONTENT_0,
542   GADGET_ID_YAMYAM_CONTENT_1,
543   GADGET_ID_YAMYAM_CONTENT_2,
544   GADGET_ID_YAMYAM_CONTENT_3,
545   GADGET_ID_YAMYAM_CONTENT_4,
546   GADGET_ID_YAMYAM_CONTENT_5,
547   GADGET_ID_YAMYAM_CONTENT_6,
548   GADGET_ID_YAMYAM_CONTENT_7,
549   GADGET_ID_MAGIC_BALL_CONTENT_0,
550   GADGET_ID_MAGIC_BALL_CONTENT_1,
551   GADGET_ID_MAGIC_BALL_CONTENT_2,
552   GADGET_ID_MAGIC_BALL_CONTENT_3,
553   GADGET_ID_MAGIC_BALL_CONTENT_4,
554   GADGET_ID_MAGIC_BALL_CONTENT_5,
555   GADGET_ID_MAGIC_BALL_CONTENT_6,
556   GADGET_ID_MAGIC_BALL_CONTENT_7,
557   GADGET_ID_ANDROID_CONTENT,
558   GADGET_ID_AMOEBA_CONTENT,
559   GADGET_ID_BD_SNAP_ELEMENT,
560   GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,
561   GADGET_ID_BD_MAGIC_WALL_ROCK_TO,
562   GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
563   GADGET_ID_BD_MAGIC_WALL_NUT_TO,
564   GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
565   GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
566   GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
567   GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,
568   GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,
569   GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
570   GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
571   GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
572   GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
573   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
574   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
575   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
576   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
577   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
578   GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
579   GADGET_ID_BD_ACID_EATS_ELEMENT,
580   GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,
581   GADGET_ID_BD_BITER_EATS_ELEMENT,
582   GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
583   GADGET_ID_BD_NUT_CONTENT,
584   GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
585   GADGET_ID_BD_SAND_LOOKS_LIKE,
586   GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,
587   GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
588   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
589   GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
590   GADGET_ID_START_ELEMENT,
591   GADGET_ID_ARTWORK_ELEMENT,
592   GADGET_ID_EXPLOSION_ELEMENT,
593   GADGET_ID_INVENTORY_CONTENT,
594   GADGET_ID_MM_BALL_CONTENT,
595   GADGET_ID_CUSTOM_GRAPHIC,
596   GADGET_ID_CUSTOM_CONTENT,
597   GADGET_ID_CUSTOM_MOVE_ENTER,
598   GADGET_ID_CUSTOM_MOVE_LEAVE,
599   GADGET_ID_CUSTOM_CHANGE_TARGET,
600   GADGET_ID_CUSTOM_CHANGE_CONTENT,
601   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
602   GADGET_ID_CUSTOM_CHANGE_ACTION,
603   GADGET_ID_GROUP_CONTENT,
604   GADGET_ID_RANDOM_BACKGROUND,
605
606   // text input identifiers
607
608   GADGET_ID_LEVEL_NAME,
609   GADGET_ID_LEVEL_AUTHOR,
610   GADGET_ID_LEVELSET_NAME,
611   GADGET_ID_LEVELSET_AUTHOR,
612   GADGET_ID_ELEMENT_NAME,
613
614   // text area identifiers
615
616   GADGET_ID_ENVELOPE_INFO,
617
618   // selectbox identifiers
619
620   GADGET_ID_TIME_OR_STEPS,
621   GADGET_ID_TIME_SCORE_BASE,
622   GADGET_ID_GAME_ENGINE_TYPE,
623   GADGET_ID_BD_SCHEDULING_TYPE,
624   GADGET_ID_LEVELSET_SAVE_MODE,
625   GADGET_ID_WIND_DIRECTION,
626   GADGET_ID_PLAYER_SPEED,
627   GADGET_ID_BD_GRAVITY_DIRECTION,
628   GADGET_ID_MM_BALL_CHOICE_MODE,
629   GADGET_ID_CUSTOM_WALK_TO_ACTION,
630   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
631   GADGET_ID_CUSTOM_DEADLINESS,
632   GADGET_ID_CUSTOM_MOVE_PATTERN,
633   GADGET_ID_CUSTOM_MOVE_DIRECTION,
634   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
635   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
636   GADGET_ID_CUSTOM_SMASH_TARGETS,
637   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
638   GADGET_ID_CUSTOM_ACCESS_TYPE,
639   GADGET_ID_CUSTOM_ACCESS_LAYER,
640   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
641   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
642   GADGET_ID_CHANGE_TIME_UNITS,
643   GADGET_ID_CHANGE_DIRECT_ACTION,
644   GADGET_ID_CHANGE_OTHER_ACTION,
645   GADGET_ID_CHANGE_SIDE,
646   GADGET_ID_CHANGE_PLAYER,
647   GADGET_ID_CHANGE_PAGE,
648   GADGET_ID_CHANGE_REPLACE_WHEN,
649   GADGET_ID_ACTION_TYPE,
650   GADGET_ID_ACTION_MODE,
651   GADGET_ID_ACTION_ARG,
652   GADGET_ID_SELECT_CHANGE_PAGE,
653   GADGET_ID_GROUP_CHOICE_MODE,
654
655   // textbutton identifiers
656
657   GADGET_ID_LEVELCONFIG_LEVEL,
658   GADGET_ID_LEVELCONFIG_LEVELSET,
659   GADGET_ID_LEVELCONFIG_EDITOR,
660   GADGET_ID_LEVELCONFIG_ENGINE,
661   GADGET_ID_PROPERTIES_INFO,
662   GADGET_ID_PROPERTIES_CONFIG,
663   GADGET_ID_PROPERTIES_CONFIG_1,
664   GADGET_ID_PROPERTIES_CONFIG_2,
665   GADGET_ID_PROPERTIES_CHANGE,
666   GADGET_ID_SAVE_AS_TEMPLATE_1,
667   GADGET_ID_SAVE_AS_TEMPLATE_2,
668   GADGET_ID_SAVE_LEVELSET,
669   GADGET_ID_ADD_CHANGE_PAGE,
670   GADGET_ID_DEL_CHANGE_PAGE,
671
672   // graphicbutton identifiers
673
674   GADGET_ID_PREV_CHANGE_PAGE,
675   GADGET_ID_NEXT_CHANGE_PAGE,
676   GADGET_ID_COPY_CHANGE_PAGE,
677   GADGET_ID_PASTE_CHANGE_PAGE,
678
679   // gadgets for scrolling of drawing area
680
681   GADGET_ID_SCROLL_UP,
682   GADGET_ID_SCROLL_DOWN,
683   GADGET_ID_SCROLL_LEFT,
684   GADGET_ID_SCROLL_RIGHT,
685   GADGET_ID_SCROLL_HORIZONTAL,
686   GADGET_ID_SCROLL_VERTICAL,
687
688   // gadgets for scrolling element list
689
690   GADGET_ID_SCROLL_LIST_UP,
691   GADGET_ID_SCROLL_LIST_DOWN,
692   GADGET_ID_SCROLL_LIST_VERTICAL,
693
694   // checkbuttons/radiobuttons for level/element properties
695
696   GADGET_ID_AUTO_COUNT_GEMS,
697   GADGET_ID_RATE_TIME_OVER_SCORE,
698   GADGET_ID_USE_LEVELSET_ARTWORK,
699   GADGET_ID_COPY_LEVEL_TEMPLATE,
700   GADGET_ID_RANDOM_PERCENTAGE,
701   GADGET_ID_RANDOM_QUANTITY,
702   GADGET_ID_RANDOM_RESTRICTED,
703   GADGET_ID_BD_INTERMISSION,
704   GADGET_ID_BD_PAL_TIMING,
705   GADGET_ID_BD_LINE_SHIFTING_BORDERS,
706   GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
707   GADGET_ID_BD_SHORT_EXPLOSIONS,
708   GADGET_ID_STICK_ELEMENT,
709   GADGET_ID_EM_SLIPPERY_GEMS,
710   GADGET_ID_EM_EXPLODES_BY_FIRE,
711   GADGET_ID_USE_SPRING_BUG,
712   GADGET_ID_USE_TIME_ORB_BUG,
713   GADGET_ID_USE_LIFE_BUGS,
714   GADGET_ID_RANDOM_BALL_CONTENT,
715   GADGET_ID_INITIAL_BALL_ACTIVE,
716   GADGET_ID_GROW_INTO_DIGGABLE,
717   GADGET_ID_SB_FIELDS_NEEDED,
718   GADGET_ID_SB_OBJECTS_NEEDED,
719   GADGET_ID_AUTO_EXIT_SOKOBAN,
720   GADGET_ID_SOLVED_BY_ONE_PLAYER,
721   GADGET_ID_FINISH_DIG_COLLECT,
722   GADGET_ID_KEEP_WALKABLE_CE,
723   GADGET_ID_CONTINUOUS_SNAPPING,
724   GADGET_ID_BLOCK_SNAP_FIELD,
725   GADGET_ID_BLOCK_LAST_FIELD,
726   GADGET_ID_SP_BLOCK_LAST_FIELD,
727   GADGET_ID_INSTANT_RELOCATION,
728   GADGET_ID_SHIFTED_RELOCATION,
729   GADGET_ID_LAZY_RELOCATION,
730   GADGET_ID_USE_START_ELEMENT,
731   GADGET_ID_USE_ARTWORK_ELEMENT,
732   GADGET_ID_USE_EXPLOSION_ELEMENT,
733   GADGET_ID_INITIAL_GRAVITY,
734   GADGET_ID_USE_INITIAL_INVENTORY,
735   GADGET_ID_CAN_PASS_TO_WALKABLE,
736   GADGET_ID_CAN_FALL_INTO_ACID,
737   GADGET_ID_CAN_MOVE_INTO_ACID,
738   GADGET_ID_DONT_COLLIDE_WITH,
739   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
740   GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
741   GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
742   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
743   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
744   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
745   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
746   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
747   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
748   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
749   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
750   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
751   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
752   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
753   GADGET_ID_BD_REPLICATORS_ACTIVE,
754   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
755   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
756   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
757   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
758   GADGET_ID_BD_CREATURES_START_BACKWARDS,
759   GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
760   GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
761   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
762   GADGET_ID_ENVELOPE_AUTOWRAP,
763   GADGET_ID_ENVELOPE_CENTERED,
764   GADGET_ID_MM_LASER_RED,
765   GADGET_ID_MM_LASER_GREEN,
766   GADGET_ID_MM_LASER_BLUE,
767   GADGET_ID_DF_LASER_RED,
768   GADGET_ID_DF_LASER_GREEN,
769   GADGET_ID_DF_LASER_BLUE,
770   GADGET_ID_ROTATE_MM_BALL_CONTENT,
771   GADGET_ID_EXPLODE_MM_BALL,
772   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
773   GADGET_ID_CUSTOM_CAN_EXPLODE,
774   GADGET_ID_CUSTOM_EXPLODE_FIRE,
775   GADGET_ID_CUSTOM_EXPLODE_SMASH,
776   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
777   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
778   GADGET_ID_CUSTOM_DEADLY,
779   GADGET_ID_CUSTOM_CAN_MOVE,
780   GADGET_ID_CUSTOM_CAN_FALL,
781   GADGET_ID_CUSTOM_CAN_SMASH,
782   GADGET_ID_CUSTOM_SLIPPERY,
783   GADGET_ID_CUSTOM_ACCESSIBLE,
784   GADGET_ID_CUSTOM_GRAV_REACHABLE,
785   GADGET_ID_CUSTOM_USE_LAST_VALUE,
786   GADGET_ID_CUSTOM_USE_GRAPHIC,
787   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
788   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
789   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
790   GADGET_ID_CUSTOM_CAN_CHANGE,
791   GADGET_ID_CHANGE_USE_CONTENT,
792   GADGET_ID_CHANGE_USE_EXPLOSION,
793   GADGET_ID_CHANGE_ONLY_COMPLETE,
794   GADGET_ID_CHANGE_USE_RANDOM,
795   GADGET_ID_CHANGE_HAS_ACTION,
796   GADGET_ID_CHANGE_DELAY,
797   GADGET_ID_CHANGE_BY_DIRECT_ACT,
798   GADGET_ID_CHANGE_BY_OTHER_ACT,
799
800   NUM_STATIC_GADGET_IDS
801 };
802
803 // gadgets for buttons in element list (dynamic)
804 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
805 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
806                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
807
808 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
809
810 // radio button numbers
811 enum
812 {
813   RADIO_NR_NONE,
814   RADIO_NR_DRAWING_TOOLBOX,
815   RADIO_NR_RANDOM_ELEMENTS
816 };
817
818 // values for counter gadgets
819 enum
820 {
821   ED_COUNTER_ID_SELECT_LEVEL,
822   ED_COUNTER_ID_LEVEL_XSIZE,
823   ED_COUNTER_ID_LEVEL_YSIZE,
824   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
825   ED_COUNTER_ID_LEVEL_TIMELIMIT,
826   ED_COUNTER_ID_LEVEL_TIMESCORE,
827   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
828   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
829   ED_COUNTER_ID_LEVEL_RANDOM,
830   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
831   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
832   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
833   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
834   ED_COUNTER_ID_BD_PUSHING_PROB,
835   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
836   ED_COUNTER_ID_ELEMENT_VALUE1,
837   ED_COUNTER_ID_ELEMENT_VALUE2,
838   ED_COUNTER_ID_ELEMENT_VALUE3,
839   ED_COUNTER_ID_ELEMENT_VALUE4,
840   ED_COUNTER_ID_YAMYAM_CONTENT,
841   ED_COUNTER_ID_BALL_CONTENT,
842   ED_COUNTER_ID_ANDROID_CONTENT,
843   ED_COUNTER_ID_ENVELOPE_XSIZE,
844   ED_COUNTER_ID_ENVELOPE_YSIZE,
845   ED_COUNTER_ID_INVENTORY_SIZE,
846   ED_COUNTER_ID_MM_BALL_CONTENT,
847   ED_COUNTER_ID_CUSTOM_SCORE,
848   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
849   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
850   ED_COUNTER_ID_CUSTOM_VALUE_RND,
851   ED_COUNTER_ID_PUSH_DELAY_FIX,
852   ED_COUNTER_ID_PUSH_DELAY_RND,
853   ED_COUNTER_ID_DROP_DELAY_FIX,
854   ED_COUNTER_ID_DROP_DELAY_RND,
855   ED_COUNTER_ID_MOVE_DELAY_FIX,
856   ED_COUNTER_ID_MOVE_DELAY_RND,
857   ED_COUNTER_ID_STEP_DELAY_FIX,
858   ED_COUNTER_ID_STEP_DELAY_RND,
859   ED_COUNTER_ID_EXPLOSION_DELAY,
860   ED_COUNTER_ID_IGNITION_DELAY,
861   ED_COUNTER_ID_GROUP_CONTENT,
862   ED_COUNTER_ID_CHANGE_DELAY_FIX,
863   ED_COUNTER_ID_CHANGE_DELAY_RND,
864   ED_COUNTER_ID_CHANGE_CONT_RND,
865
866   ED_NUM_COUNTERBUTTONS
867 };
868
869 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
870 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
871 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
872 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
873 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
874 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
875
876 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
877 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
878 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
879 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
880 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
881 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
882
883 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
884 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
885
886 // values for scrollbutton gadgets
887 enum
888 {
889   ED_SCROLLBUTTON_ID_AREA_UP,
890   ED_SCROLLBUTTON_ID_AREA_DOWN,
891   ED_SCROLLBUTTON_ID_AREA_LEFT,
892   ED_SCROLLBUTTON_ID_AREA_RIGHT,
893   ED_SCROLLBUTTON_ID_LIST_UP,
894   ED_SCROLLBUTTON_ID_LIST_DOWN,
895
896   ED_NUM_SCROLLBUTTONS
897 };
898
899 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
900 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
901
902 // values for scrollbar gadgets
903 enum
904 {
905   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
906   ED_SCROLLBAR_ID_AREA_VERTICAL,
907   ED_SCROLLBAR_ID_LIST_VERTICAL,
908
909   ED_NUM_SCROLLBARS
910 };
911
912 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
913 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
914
915 // values for text input gadgets
916 enum
917 {
918   ED_TEXTINPUT_ID_LEVEL_NAME,
919   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
920   ED_TEXTINPUT_ID_LEVELSET_NAME,
921   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
922   ED_TEXTINPUT_ID_ELEMENT_NAME,
923
924   ED_NUM_TEXTINPUT
925 };
926
927 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
928 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
929
930 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
931 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
932
933 // values for text area gadgets
934 enum
935 {
936   ED_TEXTAREA_ID_ENVELOPE_INFO,
937
938   ED_NUM_TEXTAREAS
939 };
940
941 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
942 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
943
944 // values for selectbox gadgets
945 enum
946 {
947   ED_SELECTBOX_ID_TIME_OR_STEPS,
948   ED_SELECTBOX_ID_TIME_SCORE_BASE,
949   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
950   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
951   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
952   ED_SELECTBOX_ID_WIND_DIRECTION,
953   ED_SELECTBOX_ID_PLAYER_SPEED,
954   ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
955   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
956   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
957   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
958   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
959   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
960   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
961   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
962   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
963   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
964   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
965   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
966   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
967   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
968   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
969   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
970   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
971   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
972   ED_SELECTBOX_ID_CHANGE_SIDE,
973   ED_SELECTBOX_ID_CHANGE_PLAYER,
974   ED_SELECTBOX_ID_CHANGE_PAGE,
975   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
976   ED_SELECTBOX_ID_ACTION_TYPE,
977   ED_SELECTBOX_ID_ACTION_MODE,
978   ED_SELECTBOX_ID_ACTION_ARG,
979   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
980   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
981
982   ED_NUM_SELECTBOX
983 };
984
985 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
986 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
987
988 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
989 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
990
991 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
992 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
993
994 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
995 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
996 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
997 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
998 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
999 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
1000
1001 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
1002 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
1003
1004 // values for textbutton gadgets
1005 enum
1006 {
1007   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
1008   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1009   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1010   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1011   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1012   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1013   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1014   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1015   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1016   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1017   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1018   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1019   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1020   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1021
1022   ED_NUM_TEXTBUTTONS
1023 };
1024
1025 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1026 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1027
1028 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1029 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1030
1031 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1032 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1033
1034 // values for graphicbutton gadgets
1035 enum
1036 {
1037   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1038   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1039   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1040   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1041
1042   ED_NUM_GRAPHICBUTTONS
1043 };
1044
1045 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1046 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1047
1048 // values for checkbutton gadgets
1049 enum
1050 {
1051   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1052   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1053   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1054   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1055   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1056   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1057   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1058   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1059   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1060   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1061   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1062   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1063   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1064   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1065   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1066   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1067   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1068   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1069   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1070   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1071   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1072   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1073   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1074   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1075   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1076   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1077   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1078   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1079   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1080   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1081   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1082   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1083   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1084   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1085   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1086   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1087   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1088   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1089   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1090   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1091   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1092   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1093   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1094   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1095   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1096   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1097   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1098   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1099   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1100   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1101   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1102   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1103   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1104   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1105   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1106   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1107   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1108   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1109   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1110   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1111   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1112   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1113   ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
1114   ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
1115   ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
1116   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1117   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1118   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1119   ED_CHECKBUTTON_ID_MM_LASER_RED,
1120   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1121   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1122   ED_CHECKBUTTON_ID_DF_LASER_RED,
1123   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1124   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1125   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1126   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1127   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1128   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1129   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1130   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1131   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1132   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1133   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1134   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1135   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1136   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1137   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1138   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1139   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1140   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1141   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1142   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1143   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1144   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1145   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1146   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1147   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1148   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1149   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1150   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1151   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1152
1153   ED_NUM_CHECKBUTTONS
1154 };
1155
1156 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1157 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1158
1159 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1160 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1161
1162 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1163 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1164
1165 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1166 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
1167
1168 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1169 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1170 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1171 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1172 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1173 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1174
1175 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1176 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1177
1178 // values for radiobutton gadgets
1179 enum
1180 {
1181   ED_RADIOBUTTON_ID_PERCENTAGE,
1182   ED_RADIOBUTTON_ID_QUANTITY,
1183
1184   ED_NUM_RADIOBUTTONS
1185 };
1186
1187 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1188 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1189
1190 // values for drawing area gadgets
1191 enum
1192 {
1193   ED_DRAWING_ID_DRAWING_LEVEL,
1194   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1195   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1196   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1197   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1198   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1199   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1200   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1201   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1202   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1203   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1204   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1205   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1206   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1207   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1208   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1209   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1210   ED_DRAWING_ID_ANDROID_CONTENT,
1211   ED_DRAWING_ID_AMOEBA_CONTENT,
1212   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1213   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1214   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1215   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1216   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1217   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1218   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1219   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1220   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1221   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1222   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1223   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1224   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1225   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1226   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1227   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1228   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1229   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1230   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1231   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1232   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1233   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1234   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1235   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1236   ED_DRAWING_ID_BD_NUT_CONTENT,
1237   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1238   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1239   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
1240   ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
1241   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
1242   ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
1243   ED_DRAWING_ID_START_ELEMENT,
1244   ED_DRAWING_ID_ARTWORK_ELEMENT,
1245   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1246   ED_DRAWING_ID_INVENTORY_CONTENT,
1247   ED_DRAWING_ID_MM_BALL_CONTENT,
1248   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1249   ED_DRAWING_ID_CUSTOM_CONTENT,
1250   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1251   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1252   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1253   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1254   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1255   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1256   ED_DRAWING_ID_GROUP_CONTENT,
1257   ED_DRAWING_ID_RANDOM_BACKGROUND,
1258
1259   ED_NUM_DRAWING_AREAS
1260 };
1261
1262 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1263 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1264
1265
1266 // ----------------------------------------------------------------------------
1267 // some internally used definitions
1268 // ----------------------------------------------------------------------------
1269
1270 // values for CopyLevelToUndoBuffer()
1271 #define UNDO_IMMEDIATE                  0
1272 #define UNDO_ACCUMULATE                 1
1273
1274 // values for scrollbars
1275 #define ED_SCROLL_NO                    0
1276 #define ED_SCROLL_LEFT                  1
1277 #define ED_SCROLL_RIGHT                 2
1278 #define ED_SCROLL_UP                    4
1279 #define ED_SCROLL_DOWN                  8
1280
1281 // screens in the level editor
1282 #define ED_MODE_DRAWING                 0
1283 #define ED_MODE_LEVELCONFIG             1
1284 #define ED_MODE_PROPERTIES              2
1285 #define ED_MODE_PALETTE                 3
1286
1287 // sub-screens in the global settings section
1288 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1289 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1290 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1291 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1292
1293 // sub-screens in the element properties section
1294 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1295 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1296 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1297 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1298 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1299
1300 // how many steps can be cancelled
1301 #define NUM_UNDO_STEPS                  (64 + 1)
1302
1303 // values for elements with score for certain actions
1304 #define MIN_SCORE                       0
1305 #define MAX_SCORE                       999
1306
1307 // values for elements with count for collecting
1308 #define MIN_COLLECT_COUNT               0
1309 #define MAX_COLLECT_COUNT               999
1310
1311 // values for random placement
1312 #define RANDOM_USE_PERCENTAGE           0
1313 #define RANDOM_USE_QUANTITY             1
1314
1315 // values for level set save mode
1316 #define LEVELSET_SAVE_MODE_UPDATE       0
1317 #define LEVELSET_SAVE_MODE_CREATE       1
1318
1319 // default value for element tile size in drawing area
1320 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1321 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1322
1323
1324 // ----------------------------------------------------------------------------
1325 // some internally used data structure definitions
1326 // ----------------------------------------------------------------------------
1327
1328 static struct
1329 {
1330   int graphic;
1331   int gadget_id;
1332   struct XYTileSize *pos;
1333   int gadget_type;
1334   char *infotext;
1335   char shortcut;
1336 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1337 {
1338   // note: some additional characters are already reserved for "cheat mode"
1339   // shortcuts (":XYZ" style) -- for details, see "events.c"
1340
1341   // ---------- toolbox control buttons ---------------------------------------
1342
1343   {
1344     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1345     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1346     "Draw single items",                        's'
1347   },
1348   {
1349     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1350     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1351     "Draw connected items",                     'd'
1352   },
1353   {
1354     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1355     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1356     "Draw lines",                               'l'
1357   },
1358   {
1359     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1360     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1361     "Draw arcs",                                'a'
1362   },
1363   {
1364     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1365     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1366     "Draw outline rectangles",                  'r'
1367   },
1368   {
1369     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1370     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1371     "Draw filled rectangles",                   'R'
1372   },
1373   {
1374     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1375     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1376     "Wrap (rotate) level up",                   0
1377   },
1378   {
1379     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1380     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1381     "Enter text elements",                      't'
1382   },
1383   {
1384     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1385     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1386     "Flood fill",                               'f'
1387   },
1388   {
1389     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1390     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1391     "Wrap (rotate) level left",                 0
1392   },
1393   {
1394     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1395     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1396     "Zoom level tile size",                     '+'
1397   },
1398   {
1399     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1400     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1401     "Wrap (rotate) level right",                0
1402   },
1403   {
1404     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1405     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1406     "Random element placement",                 0
1407   },
1408   {
1409     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1410     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1411     "Grab brush",                               'b'
1412   },
1413   {
1414     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1415     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1416     "Wrap (rotate) level down",                 0
1417   },
1418   {
1419     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1420     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1421     "Pick drawing element",                     ','
1422   },
1423
1424   // ---------- level control buttons -----------------------------------------
1425
1426   {
1427     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1428     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1429     "Undo/redo last operation",                 'u'
1430   },
1431   {
1432     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1433     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1434     "Level and editor settings",                'I'
1435   },
1436   {
1437     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1438     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1439     "Save level",                               'S'
1440   },
1441   {
1442     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1443     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1444     "Clear level",                              'C'
1445   },
1446   {
1447     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1448     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1449     "Test level",                               'T'
1450   },
1451   {
1452     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1453     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1454     "Exit level editor",                        'E'
1455   },
1456
1457   // ---------- CE and GE control buttons -------------------------------------
1458
1459   {
1460     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1461     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1462     "Copy settings from other element",         0
1463   },
1464   {
1465     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1466     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1467     "Copy settings to other element",           0
1468   },
1469   {
1470     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1471     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1472     "Exchange element with other element",      0
1473   },
1474   {
1475     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1476     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1477     "Copy settings from this element",          0
1478   },
1479   {
1480     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1481     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1482     "Paste settings to this element",           0
1483   },
1484
1485   // ---------- palette control buttons ---------------------------------------
1486
1487   {
1488     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1489     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1490     "Properties of drawing element",            'p'
1491   },
1492   {
1493     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1494     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1495     "Properties of drawing element 1",          '1'
1496   },
1497   {
1498     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1499     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1500     "Properties of drawing element 2",          '2'
1501   },
1502   {
1503     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1504     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1505     "Properties of drawing element 3",          '3'
1506   },
1507   {
1508     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1509     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1510     "Show list of elements",                    'e'
1511   }
1512 };
1513
1514 static int random_placement_value = 10;
1515 static int random_placement_method = RANDOM_USE_QUANTITY;
1516 static int random_placement_background_element = EL_SAND;
1517 static boolean random_placement_background_restricted = FALSE;
1518 static boolean stick_element_properties_window = FALSE;
1519 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1520 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1521 static struct ElementChangeInfo custom_element_change;
1522 static struct ElementGroupInfo group_element_info;
1523 static struct ElementInfo custom_element;
1524
1525 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1526 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1527 static int levelset_num_levels = 100;
1528 static boolean levelset_use_levelset_artwork = FALSE;
1529 static boolean levelset_copy_level_template = FALSE;
1530 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1531
1532 static struct
1533 {
1534   int gadget_type_id;
1535   int x, y;
1536   int min_value, max_value;
1537   int gadget_id_down, gadget_id_up;
1538   int gadget_id_text;
1539   int gadget_id_align;
1540   int *value;
1541   char *text_above, *text_left, *text_right;
1542 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1543 {
1544   // ---------- current level number ------------------------------------------
1545
1546   {
1547     ED_COUNTER_ID_SELECT_LEVEL,
1548     -1, -1,     // these values are not constant, but can change at runtime
1549     1,                                          100,
1550     GADGET_ID_SELECT_LEVEL_DOWN,                GADGET_ID_SELECT_LEVEL_UP,
1551     GADGET_ID_SELECT_LEVEL_TEXT,                GADGET_ID_NONE,
1552     &level_nr,
1553     NULL,                                       NULL, NULL
1554   },
1555
1556   // ---------- level and editor settings -------------------------------------
1557
1558   {
1559     ED_COUNTER_ID_LEVEL_XSIZE,
1560     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1561     MIN_LEV_FIELDX,                             MAX_LEV_FIELDX,
1562     GADGET_ID_LEVEL_XSIZE_DOWN,                 GADGET_ID_LEVEL_XSIZE_UP,
1563     GADGET_ID_LEVEL_XSIZE_TEXT,                 GADGET_ID_NONE,
1564     &level.fieldx,
1565     "Playfield size:",                          NULL, "Width",
1566   },
1567   {
1568     ED_COUNTER_ID_LEVEL_YSIZE,
1569     -1,                                         ED_LEVEL_SETTINGS_YPOS(4),
1570     MIN_LEV_FIELDY,                             MAX_LEV_FIELDY,
1571     GADGET_ID_LEVEL_YSIZE_DOWN,                 GADGET_ID_LEVEL_YSIZE_UP,
1572     GADGET_ID_LEVEL_YSIZE_TEXT,                 GADGET_ID_LEVEL_XSIZE_UP,
1573     &level.fieldy,
1574     NULL,                                       " ", "Height",
1575   },
1576   {
1577     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1578     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
1579     0,                                          999,
1580     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,             GADGET_ID_LEVEL_GEMSLIMIT_UP,
1581     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,             GADGET_ID_NONE,
1582     &level.gems_needed,
1583     NULL,                                       "Number of gems to collect:", NULL
1584   },
1585   {
1586     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1587     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
1588     0,                                          9999,
1589     GADGET_ID_LEVEL_TIMELIMIT_DOWN,             GADGET_ID_LEVEL_TIMELIMIT_UP,
1590     GADGET_ID_LEVEL_TIMELIMIT_TEXT,             GADGET_ID_NONE,
1591     &level.time,
1592     "Time or step limit to solve level:",       NULL, NULL
1593   },
1594   {
1595     ED_COUNTER_ID_LEVEL_TIMESCORE,
1596     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
1597     0,                                          999,
1598     GADGET_ID_LEVEL_TIMESCORE_DOWN,             GADGET_ID_LEVEL_TIMESCORE_UP,
1599     GADGET_ID_LEVEL_TIMESCORE_TEXT,             GADGET_ID_NONE,
1600     &level.score[SC_TIME_BONUS],
1601     "Score for time or steps left:",            NULL, NULL
1602   },
1603   {
1604     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1605     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(13),
1606     0,                                          9999,
1607     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,           GADGET_ID_LEVEL_RANDOM_SEED_UP,
1608     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,           GADGET_ID_NONE,
1609     &level.random_seed,
1610     NULL,                                       "Random seed:", "(0 => random)"
1611   },
1612   {
1613     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1614     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1615     1,                                          MAX_LEVELS,
1616     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,         GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1617     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,         GADGET_ID_NONE,
1618     &levelset_num_levels,
1619     "Number of levels:",                        NULL, NULL,
1620   },
1621   {
1622     ED_COUNTER_ID_LEVEL_RANDOM,
1623     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1624     1,                                          100,
1625     GADGET_ID_LEVEL_RANDOM_DOWN,                GADGET_ID_LEVEL_RANDOM_UP,
1626     GADGET_ID_LEVEL_RANDOM_TEXT,                GADGET_ID_NONE,
1627     &random_placement_value,
1628     "Random element placement:",                NULL, "in"
1629   },
1630   {
1631     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1632     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1633     50,                                         500,
1634     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,           GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1635     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,           GADGET_ID_NONE,
1636     &level.bd_cycle_delay_ms,
1637     NULL,                                       NULL, "Game cycle delay (ms)"
1638   },
1639   {
1640     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1641     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(3),
1642     0,                                          32,
1643     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,          GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1644     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,          GADGET_ID_NONE,
1645     &level.bd_cycle_delay_c64,
1646     NULL,                                       NULL, "Game cycle delay (C64-style)"
1647   },
1648   {
1649     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1650     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1651     1,                                          40,
1652     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1653     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1654     &level.bd_hatching_delay_cycles,
1655     NULL,                                       NULL, "Hatching delay (cycles)"
1656   },
1657   {
1658     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1659     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
1660     1,                                          40,
1661     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1662     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1663     &level.bd_hatching_delay_seconds,
1664     NULL,                                       NULL, "Hatching delay (seconds)"
1665   },
1666
1667   // ---------- element settings: configure (various elements) ----------------
1668
1669   {
1670     ED_COUNTER_ID_BD_PUSHING_PROB,
1671     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1672     0,                                          100,
1673     GADGET_ID_BD_PUSHING_PROB_DOWN,             GADGET_ID_BD_PUSHING_PROB_UP,
1674     GADGET_ID_BD_PUSHING_PROB_TEXT,             GADGET_ID_NONE,
1675     &level.bd_pushing_prob,
1676     NULL,                                       NULL, "Push probability"
1677   },
1678   {
1679     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1680     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1681     0,                                          100,
1682     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1683     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1684     &level.bd_pushing_prob_with_sweet,
1685     NULL,                                       NULL, "Push probability with sweet"
1686   },
1687   {
1688     ED_COUNTER_ID_ELEMENT_VALUE1,
1689     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1690     MIN_SCORE,                                  MAX_SCORE,
1691     GADGET_ID_ELEMENT_VALUE1_DOWN,              GADGET_ID_ELEMENT_VALUE1_UP,
1692     GADGET_ID_ELEMENT_VALUE1_TEXT,              GADGET_ID_NONE,
1693     NULL,                                       // will be set when used
1694     NULL,                                       NULL, NULL
1695   },
1696   {
1697     ED_COUNTER_ID_ELEMENT_VALUE2,
1698     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
1699     MIN_SCORE,                                  MAX_SCORE,
1700     GADGET_ID_ELEMENT_VALUE2_DOWN,              GADGET_ID_ELEMENT_VALUE2_UP,
1701     GADGET_ID_ELEMENT_VALUE2_TEXT,              GADGET_ID_NONE,
1702     NULL,                                       // will be set when used
1703     NULL,                                       NULL, NULL
1704   },
1705   {
1706     ED_COUNTER_ID_ELEMENT_VALUE3,
1707     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1708     MIN_SCORE,                                  MAX_SCORE,
1709     GADGET_ID_ELEMENT_VALUE3_DOWN,              GADGET_ID_ELEMENT_VALUE3_UP,
1710     GADGET_ID_ELEMENT_VALUE3_TEXT,              GADGET_ID_NONE,
1711     NULL,                                       // will be set when used
1712     NULL,                                       NULL, NULL
1713   },
1714   {
1715     ED_COUNTER_ID_ELEMENT_VALUE4,
1716     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1717     MIN_SCORE,                                  MAX_SCORE,
1718     GADGET_ID_ELEMENT_VALUE4_DOWN,              GADGET_ID_ELEMENT_VALUE4_UP,
1719     GADGET_ID_ELEMENT_VALUE4_TEXT,              GADGET_ID_NONE,
1720     NULL,                                       // will be set when used
1721     NULL,                                       NULL, NULL
1722   },
1723   {
1724     ED_COUNTER_ID_YAMYAM_CONTENT,
1725     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1726     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1727     GADGET_ID_YAMYAM_CONTENT_DOWN,              GADGET_ID_YAMYAM_CONTENT_UP,
1728     GADGET_ID_YAMYAM_CONTENT_TEXT,              GADGET_ID_NONE,
1729     &level.num_yamyam_contents,
1730     NULL,                                       NULL, "Number of content areas"
1731   },
1732   {
1733     ED_COUNTER_ID_BALL_CONTENT,
1734     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1735     MIN_ELEMENT_CONTENTS,                       MAX_ELEMENT_CONTENTS,
1736     GADGET_ID_BALL_CONTENT_DOWN,                GADGET_ID_BALL_CONTENT_UP,
1737     GADGET_ID_BALL_CONTENT_TEXT,                GADGET_ID_NONE,
1738     &level.num_ball_contents,
1739     NULL,                                       NULL, "Number of content areas"
1740   },
1741   {
1742     ED_COUNTER_ID_ANDROID_CONTENT,
1743     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
1744     MIN_ANDROID_ELEMENTS,                       MAX_ANDROID_ELEMENTS,
1745     GADGET_ID_ANDROID_CONTENT_DOWN,             GADGET_ID_ANDROID_CONTENT_UP,
1746     GADGET_ID_ANDROID_CONTENT_TEXT,             GADGET_ID_NONE,
1747     &level.num_android_clone_elements,
1748     NULL,                                       NULL, "Number of clonable elements"
1749   },
1750   {
1751     ED_COUNTER_ID_ENVELOPE_XSIZE,
1752     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
1753     MIN_ENVELOPE_XSIZE,                         MAX_ENVELOPE_XSIZE,
1754     GADGET_ID_ENVELOPE_XSIZE_DOWN,              GADGET_ID_ENVELOPE_XSIZE_UP,
1755     GADGET_ID_ENVELOPE_XSIZE_TEXT,              GADGET_ID_NONE,
1756     NULL,                                       // will be set when used
1757     NULL,                                       NULL, "Width",
1758   },
1759   {
1760     ED_COUNTER_ID_ENVELOPE_YSIZE,
1761     -1,                                         ED_ELEMENT_SETTINGS_YPOS(0),
1762     MIN_ENVELOPE_YSIZE,                         MAX_ENVELOPE_YSIZE,
1763     GADGET_ID_ENVELOPE_YSIZE_DOWN,              GADGET_ID_ENVELOPE_YSIZE_UP,
1764     GADGET_ID_ENVELOPE_YSIZE_TEXT,              GADGET_ID_ENVELOPE_XSIZE_UP,
1765     NULL,                                       // will be set when used
1766     NULL,                                       " ", "Height",
1767   },
1768   {
1769     ED_COUNTER_ID_INVENTORY_SIZE,
1770     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
1771     MIN_INITIAL_INVENTORY_SIZE,                 MAX_INITIAL_INVENTORY_SIZE,
1772     GADGET_ID_INVENTORY_SIZE_DOWN,              GADGET_ID_INVENTORY_SIZE_UP,
1773     GADGET_ID_INVENTORY_SIZE_TEXT,              GADGET_ID_NONE,
1774     &level.initial_inventory_size[0],
1775     NULL,                                       NULL, "Number of inventory elements"
1776   },
1777   {
1778     ED_COUNTER_ID_MM_BALL_CONTENT,
1779     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1780     MIN_ELEMENTS_IN_GROUP,                      MAX_MM_BALL_CONTENTS,
1781     GADGET_ID_MM_BALL_CONTENT_DOWN,             GADGET_ID_MM_BALL_CONTENT_UP,
1782     GADGET_ID_MM_BALL_CONTENT_TEXT,             GADGET_ID_NONE,
1783     &level.num_mm_ball_contents,
1784     NULL,                                       NULL, "Number of content elements"
1785   },
1786
1787   // ---------- element settings: configure 1 (custom elements) ---------------
1788
1789   {
1790     ED_COUNTER_ID_CUSTOM_SCORE,
1791     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1792     MIN_SCORE,                                  MAX_SCORE,
1793     GADGET_ID_CUSTOM_SCORE_DOWN,                GADGET_ID_CUSTOM_SCORE_UP,
1794     GADGET_ID_CUSTOM_SCORE_TEXT,                GADGET_ID_NONE,
1795     &custom_element.collect_score_initial,
1796     NULL,                                       "CE score", " "
1797   },
1798   {
1799     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1800     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1801     MIN_COLLECT_COUNT,                          MAX_COLLECT_COUNT,
1802     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,             GADGET_ID_CUSTOM_GEMCOUNT_UP,
1803     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,             GADGET_ID_CUSTOM_SCORE_UP,
1804     &custom_element.collect_count_initial,
1805     NULL,                                       "CE count", NULL
1806   },
1807   {
1808     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1809     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1810     0,                                          9999,
1811     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1812     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,            GADGET_ID_NONE,
1813     &custom_element.ce_value_fixed_initial,
1814     NULL,                                       "CE value", NULL
1815   },
1816   {
1817     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1818     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
1819     0,                                          9999,
1820     GADGET_ID_CUSTOM_VALUE_RND_DOWN,            GADGET_ID_CUSTOM_VALUE_RND_UP,
1821     GADGET_ID_CUSTOM_VALUE_RND_TEXT,            GADGET_ID_CUSTOM_VALUE_FIX_UP,
1822     &custom_element.ce_value_random_initial,
1823     NULL,                                       "+random", NULL
1824   },
1825   {
1826     ED_COUNTER_ID_PUSH_DELAY_FIX,
1827     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1828     0,                                          999,
1829     GADGET_ID_PUSH_DELAY_FIX_DOWN,              GADGET_ID_PUSH_DELAY_FIX_UP,
1830     GADGET_ID_PUSH_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1831     &custom_element.push_delay_fixed,
1832     NULL,                                       "Push delay", NULL
1833   },
1834   {
1835     ED_COUNTER_ID_PUSH_DELAY_RND,
1836     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1837     0,                                          999,
1838     GADGET_ID_PUSH_DELAY_RND_DOWN,              GADGET_ID_PUSH_DELAY_RND_UP,
1839     GADGET_ID_PUSH_DELAY_RND_TEXT,              GADGET_ID_PUSH_DELAY_FIX_UP,
1840     &custom_element.push_delay_random,
1841     NULL,                                       "+random", NULL
1842   },
1843   {
1844     ED_COUNTER_ID_DROP_DELAY_FIX,
1845     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(7),
1846     0,                                          999,
1847     GADGET_ID_DROP_DELAY_FIX_DOWN,              GADGET_ID_DROP_DELAY_FIX_UP,
1848     GADGET_ID_DROP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1849     &custom_element.drop_delay_fixed,
1850     NULL,                                       "Drop delay", NULL
1851   },
1852   {
1853     ED_COUNTER_ID_DROP_DELAY_RND,
1854     -1,                                         ED_ELEMENT_SETTINGS_YPOS(7),
1855     0,                                          999,
1856     GADGET_ID_DROP_DELAY_RND_DOWN,              GADGET_ID_DROP_DELAY_RND_UP,
1857     GADGET_ID_DROP_DELAY_RND_TEXT,              GADGET_ID_DROP_DELAY_FIX_UP,
1858     &custom_element.drop_delay_random,
1859     NULL,                                       "+random", NULL
1860   },
1861
1862   // ---------- element settings: configure 2 (custom elements) ---------------
1863
1864   {
1865     ED_COUNTER_ID_MOVE_DELAY_FIX,
1866     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
1867     0,                                          999,
1868     GADGET_ID_MOVE_DELAY_FIX_DOWN,              GADGET_ID_MOVE_DELAY_FIX_UP,
1869     GADGET_ID_MOVE_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1870     &custom_element.move_delay_fixed,
1871     NULL,                                       "Move delay", NULL
1872   },
1873   {
1874     ED_COUNTER_ID_MOVE_DELAY_RND,
1875     -1,                                         ED_ELEMENT_SETTINGS_YPOS(5),
1876     0,                                          999,
1877     GADGET_ID_MOVE_DELAY_RND_DOWN,              GADGET_ID_MOVE_DELAY_RND_UP,
1878     GADGET_ID_MOVE_DELAY_RND_TEXT,              GADGET_ID_MOVE_DELAY_FIX_UP,
1879     &custom_element.move_delay_random,
1880     NULL,                                       "+random", NULL
1881   },
1882   {
1883     ED_COUNTER_ID_STEP_DELAY_FIX,
1884     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(6),
1885     0,                                          999,
1886     GADGET_ID_STEP_DELAY_FIX_DOWN,              GADGET_ID_STEP_DELAY_FIX_UP,
1887     GADGET_ID_STEP_DELAY_FIX_TEXT,              GADGET_ID_NONE,
1888     &custom_element.step_delay_fixed,
1889     NULL,                                       "Step delay", NULL
1890   },
1891   {
1892     ED_COUNTER_ID_STEP_DELAY_RND,
1893     -1,                                         ED_ELEMENT_SETTINGS_YPOS(6),
1894     0,                                          999,
1895     GADGET_ID_STEP_DELAY_RND_DOWN,              GADGET_ID_STEP_DELAY_RND_UP,
1896     GADGET_ID_STEP_DELAY_RND_TEXT,              GADGET_ID_STEP_DELAY_FIX_UP,
1897     &custom_element.step_delay_random,
1898     NULL,                                       "+random", NULL
1899   },
1900   {
1901     ED_COUNTER_ID_EXPLOSION_DELAY,
1902     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
1903     0,                                          999,
1904     GADGET_ID_EXPLOSION_DELAY_DOWN,             GADGET_ID_EXPLOSION_DELAY_UP,
1905     GADGET_ID_EXPLOSION_DELAY_TEXT,             GADGET_ID_NONE,
1906     &custom_element.explosion_delay,
1907     NULL,                                       "Explosion delay", NULL
1908   },
1909   {
1910     ED_COUNTER_ID_IGNITION_DELAY,
1911     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
1912     0,                                          999,
1913     GADGET_ID_IGNITION_DELAY_DOWN,              GADGET_ID_IGNITION_DELAY_UP,
1914     GADGET_ID_IGNITION_DELAY_TEXT,              GADGET_ID_NONE,
1915     &custom_element.ignition_delay,
1916     NULL,                                       "Ignition delay", "(by fire)"
1917   },
1918
1919   // ---------- element settings: configure (group elements) ------------------
1920
1921   {
1922     ED_COUNTER_ID_GROUP_CONTENT,
1923     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
1924     MIN_ELEMENTS_IN_GROUP,                      MAX_ELEMENTS_IN_GROUP,
1925     GADGET_ID_GROUP_CONTENT_DOWN,               GADGET_ID_GROUP_CONTENT_UP,
1926     GADGET_ID_GROUP_CONTENT_TEXT,               GADGET_ID_NONE,
1927     &group_element_info.num_elements,
1928     NULL,                                       NULL, "Number of elements in group"
1929   },
1930
1931   // ---------- element settings: advanced (custom elements) ------------------
1932
1933   {
1934     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1935     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(2),
1936     0,                                          999,
1937     GADGET_ID_CHANGE_DELAY_FIX_DOWN,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1938     GADGET_ID_CHANGE_DELAY_FIX_TEXT,            GADGET_ID_NONE,
1939     &custom_element_change.delay_fixed,
1940     NULL,                                       "CE delay", NULL,
1941   },
1942   {
1943     ED_COUNTER_ID_CHANGE_DELAY_RND,
1944     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
1945     0,                                          999,
1946     GADGET_ID_CHANGE_DELAY_RND_DOWN,            GADGET_ID_CHANGE_DELAY_RND_UP,
1947     GADGET_ID_CHANGE_DELAY_RND_TEXT,            GADGET_ID_CHANGE_DELAY_FIX_UP,
1948     &custom_element_change.delay_random,
1949     NULL,                                       "+random", NULL
1950   },
1951   {
1952     ED_COUNTER_ID_CHANGE_CONT_RND,
1953     ED_ELEMENT_SETTINGS_XPOS(3),                ED_ELEMENT_SETTINGS_YPOS(12),
1954     0,                                          100,
1955     GADGET_ID_CHANGE_CONT_RND_DOWN,             GADGET_ID_CHANGE_CONT_RND_UP,
1956     GADGET_ID_CHANGE_CONT_RND_TEXT,             GADGET_ID_NONE,
1957     &custom_element_change.random_percentage,
1958     NULL,                                       "Use random replace:", "%"
1959   },
1960 };
1961
1962 static struct
1963 {
1964   int gadget_type_id;
1965   int x, y;
1966   int gadget_id;
1967   int size;
1968   char *value;
1969   char *text_above, *infotext;
1970 } textinput_info[ED_NUM_TEXTINPUT] =
1971 {
1972   {
1973     ED_TEXTINPUT_ID_LEVEL_NAME,
1974     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1975     GADGET_ID_LEVEL_NAME,
1976     MAX_LEVEL_NAME_LEN,
1977     level.name,
1978     "Title:", "Title for this level"
1979   },
1980   {
1981     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
1982     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
1983     GADGET_ID_LEVEL_AUTHOR,
1984     MAX_LEVEL_AUTHOR_LEN,
1985     level.author,
1986     "Author:", "Author for this level"
1987   },
1988   {
1989     ED_TEXTINPUT_ID_LEVELSET_NAME,
1990     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
1991     GADGET_ID_LEVELSET_NAME,
1992     MAX_LEVEL_NAME_LEN,
1993     levelset_name,
1994     "Title:", "Title for this or new level set"
1995   },
1996   {
1997     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
1998     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
1999     GADGET_ID_LEVELSET_AUTHOR,
2000     MAX_LEVEL_AUTHOR_LEN,
2001     levelset_author,
2002     "Author:", "Author for this or new level set"
2003   },
2004   {
2005     ED_TEXTINPUT_ID_ELEMENT_NAME,
2006     -1, -1,     // these values are not constant, but can change at runtime
2007     GADGET_ID_ELEMENT_NAME,
2008     MAX_ELEMENT_NAME_LEN - 2,                   // currently 2 chars less editable
2009     custom_element.description,
2010     NULL, "Element name"
2011   }
2012 };
2013
2014 static struct
2015 {
2016   int gadget_type_id;
2017   int x, y;
2018   int gadget_id;
2019   int xsize, ysize;
2020   char *value;
2021   char *text_above, *text_above_cropped, *infotext;
2022 } textarea_info[ED_NUM_TEXTAREAS] =
2023 {
2024   {
2025     ED_TEXTAREA_ID_ENVELOPE_INFO,
2026     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
2027     GADGET_ID_ENVELOPE_INFO,
2028     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2029     NULL,
2030     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2031   }
2032 };
2033
2034 static struct ValueTextInfo options_time_or_steps[] =
2035 {
2036   { 0,                                  "seconds"                       },
2037   { 1,                                  "steps"                         },
2038
2039   { -1,                                 NULL                            }
2040 };
2041
2042 static struct ValueTextInfo options_time_score_base[] =
2043 {
2044   { 1,                                  "per second/step"               },
2045   { 10,                                 "per 10 seconds/steps"          },
2046
2047   { -1,                                 NULL                            }
2048 };
2049
2050 static struct ValueTextInfo options_game_engine_type[] =
2051 {
2052   { GAME_ENGINE_TYPE_RND,               "Rocks'n'Diamonds"              },
2053   { GAME_ENGINE_TYPE_BD,                "Boulder Dash"                  },
2054   { GAME_ENGINE_TYPE_EM,                "Emerald Mine"                  },
2055   { GAME_ENGINE_TYPE_SP,                "Supaplex"                      },
2056   { GAME_ENGINE_TYPE_MM,                "Mirror Magic"                  },
2057
2058   { -1,                                 NULL                            }
2059 };
2060
2061 static struct ValueTextInfo options_levelset_save_mode[] =
2062 {
2063   { LEVELSET_SAVE_MODE_UPDATE,          "Update this level set"         },
2064   { LEVELSET_SAVE_MODE_CREATE,          "Create new level set"          },
2065
2066   { -1,                                 NULL                            }
2067 };
2068
2069 static struct ValueTextInfo options_bd_gravity_direction[] =
2070 {
2071   { GD_MV_DOWN,                         "down"                          },
2072   { GD_MV_UP,                           "up"                            },
2073   { GD_MV_LEFT,                         "left"                          },
2074   { GD_MV_RIGHT,                        "right"                         },
2075
2076   { -1,                                 NULL                            }
2077 };
2078
2079 static struct ValueTextInfo options_wind_direction[] =
2080 {
2081   { MV_START_NONE,                      "none"                          },
2082   { MV_START_LEFT,                      "left"                          },
2083   { MV_START_RIGHT,                     "right"                         },
2084   { MV_START_UP,                        "up"                            },
2085   { MV_START_DOWN,                      "down"                          },
2086
2087   { -1,                                 NULL                            }
2088 };
2089
2090 static struct ValueTextInfo options_player_speed[] =
2091 {
2092   { 0,                                  "frozen"                        },
2093   { 1,                                  "very slow"                     },
2094   { 2,                                  "slow"                          },
2095   { 4,                                  "normal"                        },
2096   { 8,                                  "fast"                          },
2097   { 16,                                 "very fast"                     },
2098   { 32,                                 "ultrafast"                     },
2099
2100   { -1,                                 NULL                            }
2101 };
2102
2103 static struct ValueTextInfo options_access_type[] =
2104 {
2105   { EP_WALKABLE,                        "walkable"                      },
2106   { EP_PASSABLE,                        "passable"                      },
2107
2108   { -1,                                 NULL                            }
2109 };
2110
2111 static struct ValueTextInfo options_access_layer[] =
2112 {
2113   { EP_ACCESSIBLE_OVER,                 "over"                          },
2114   { EP_ACCESSIBLE_INSIDE,               "inside"                        },
2115   { EP_ACCESSIBLE_UNDER,                "under"                         },
2116
2117   { -1,                                 NULL                            }
2118 };
2119
2120 static struct ValueTextInfo options_access_protected[] =
2121 {
2122   { 0,                                  "unprotected"                   },
2123   { 1,                                  "protected"                     },
2124
2125   { -1,                                 NULL                            }
2126 };
2127
2128 static struct ValueTextInfo options_access_direction[] =
2129 {
2130   { MV_NO_DIRECTION,                    "no direction"                  },
2131   { MV_LEFT,                            "left"                          },
2132   { MV_RIGHT,                           "right"                         },
2133   { MV_UP,                              "up"                            },
2134   { MV_DOWN,                            "down"                          },
2135   { MV_LEFT  | MV_UP,                   "left + up"                     },
2136   { MV_LEFT  | MV_DOWN,                 "left + down"                   },
2137   { MV_RIGHT | MV_UP,                   "right + up"                    },
2138   { MV_RIGHT | MV_DOWN,                 "right + down"                  },
2139   { MV_HORIZONTAL,                      "horizontal"                    },
2140   { MV_VERTICAL,                        "vertical"                      },
2141   { MV_HORIZONTAL | MV_UP,              "horizontal + up"               },
2142   { MV_HORIZONTAL | MV_DOWN,            "horizontal + down"             },
2143   { MV_VERTICAL   | MV_LEFT,            "vertical + left"               },
2144   { MV_VERTICAL   | MV_RIGHT,           "vertical + right"              },
2145   { MV_ALL_DIRECTIONS,                  "all directions"                },
2146
2147   { -1,                                 NULL                            }
2148 };
2149
2150 static struct ValueTextInfo options_walk_to_action[] =
2151 {
2152   { EP_DIGGABLE,                        "diggable"                      },
2153   { EP_COLLECTIBLE_ONLY,                "collectible"                   },
2154   { EP_DROPPABLE,                       "collectible & droppable"       },
2155   { EP_THROWABLE,                       "collectible & throwable"       },
2156   { EP_PUSHABLE,                        "pushable"                      },
2157
2158   { -1,                                 NULL                            }
2159 };
2160
2161 static struct ValueTextInfo options_move_pattern[] =
2162 {
2163   { MV_LEFT,                            "left"                          },
2164   { MV_RIGHT,                           "right"                         },
2165   { MV_UP,                              "up"                            },
2166   { MV_DOWN,                            "down"                          },
2167   { MV_HORIZONTAL,                      "horizontal"                    },
2168   { MV_VERTICAL,                        "vertical"                      },
2169   { MV_ALL_DIRECTIONS,                  "all directions"                },
2170   { MV_WIND_DIRECTION,                  "wind direction"                },
2171   { MV_TOWARDS_PLAYER,                  "towards player"                },
2172   { MV_AWAY_FROM_PLAYER,                "away from player"              },
2173   { MV_ALONG_LEFT_SIDE,                 "along left side"               },
2174   { MV_ALONG_RIGHT_SIDE,                "along right side"              },
2175   { MV_TURNING_LEFT,                    "turning left"                  },
2176   { MV_TURNING_RIGHT,                   "turning right"                 },
2177   { MV_TURNING_LEFT_RIGHT,              "turning left, right"           },
2178   { MV_TURNING_RIGHT_LEFT,              "turning right, left"           },
2179   { MV_TURNING_RANDOM,                  "turning random"                },
2180   { MV_MAZE_RUNNER,                     "maze runner style"             },
2181   { MV_MAZE_HUNTER,                     "maze hunter style"             },
2182   { MV_WHEN_PUSHED,                     "when pushed"                   },
2183   { MV_WHEN_DROPPED,                    "when dropped/thrown"           },
2184
2185   { -1,                                 NULL                            }
2186 };
2187
2188 static struct ValueTextInfo options_move_direction[] =
2189 {
2190   { MV_START_AUTOMATIC,                 "automatic"                     },
2191   { MV_START_LEFT,                      "left"                          },
2192   { MV_START_RIGHT,                     "right"                         },
2193   { MV_START_UP,                        "up"                            },
2194   { MV_START_DOWN,                      "down"                          },
2195   { MV_START_RANDOM,                    "random"                        },
2196   { MV_START_PREVIOUS,                  "previous"                      },
2197
2198   { -1,                                 NULL                            }
2199 };
2200
2201 static struct ValueTextInfo options_move_stepsize[] =
2202 {
2203   { 0,                                  "not moving"                    },
2204   { 1,                                  "very slow"                     },
2205   { 2,                                  "slow"                          },
2206   { 4,                                  "normal"                        },
2207   { 8,                                  "fast"                          },
2208   { 16,                                 "very fast"                     },
2209   { 32,                                 "even faster"                   },
2210
2211   { -1,                                 NULL                            }
2212 };
2213
2214 static struct ValueTextInfo options_move_leave_type[] =
2215 {
2216   { LEAVE_TYPE_UNLIMITED,               "leave behind"                  },
2217   { LEAVE_TYPE_LIMITED,                 "change it to"                  },
2218
2219   { -1,                                 NULL                            }
2220 };
2221
2222 static struct ValueTextInfo options_smash_targets[] =
2223 {
2224   { EP_CAN_SMASH_PLAYER,                "player"                        },
2225 #if 0
2226   { EP_CAN_SMASH_ENEMIES,               "enemies"                       },
2227 #endif
2228   { EP_CAN_SMASH_EVERYTHING,            "everything"                    },
2229
2230   { -1,                                 NULL                            }
2231 };
2232
2233 static struct ValueTextInfo options_slippery_type[] =
2234 {
2235   { SLIPPERY_ANY_RANDOM,                "random"                        },
2236   { SLIPPERY_ANY_LEFT_RIGHT,            "left, right"                   },
2237   { SLIPPERY_ANY_RIGHT_LEFT,            "right, left"                   },
2238   { SLIPPERY_ONLY_LEFT,                 "only left"                     },
2239   { SLIPPERY_ONLY_RIGHT,                "only right"                    },
2240
2241   { -1,                                 NULL                            }
2242 };
2243
2244 static struct ValueTextInfo options_deadliness[] =
2245 {
2246   { EP_DONT_RUN_INTO,                   "running into"                  },
2247   { EP_DONT_COLLIDE_WITH,               "colliding with"                },
2248   { EP_DONT_GET_HIT_BY,                 "getting hit by"                },
2249   { EP_DONT_TOUCH,                      "touching"                      },
2250
2251   { -1,                                 NULL                            }
2252 };
2253
2254 static struct ValueTextInfo options_explosion_type[] =
2255 {
2256   { EXPLODES_3X3,                       "3x3"                           },
2257   { EXPLODES_CROSS,                     "3+3"                           },
2258   { EXPLODES_1X1,                       "1x1"                           },
2259
2260   { -1,                                 NULL                            }
2261 };
2262
2263 static struct ValueTextInfo options_time_units[] =
2264 {
2265   { 1,                                  "frames"                        },
2266   { FRAMES_PER_SECOND,                  "seconds"                       },
2267
2268   { -1,                                 NULL                            }
2269 };
2270
2271 static struct ValueTextInfo options_change_direct_action[] =
2272 {
2273   { CE_TOUCHED_BY_PLAYER,               "touched by player"             },
2274   { CE_PRESSED_BY_PLAYER,               "pressed by player"             },
2275   { CE_SWITCHED_BY_PLAYER,              "switched by player"            },
2276   { CE_SNAPPED_BY_PLAYER,               "snapped by player"             },
2277   { CE_PUSHED_BY_PLAYER,                "pushed by player"              },
2278   { CE_ENTERED_BY_PLAYER,               "entered by player"             },
2279   { CE_LEFT_BY_PLAYER,                  "left by player"                },
2280   { CE_DROPPED_BY_PLAYER,               "dropped/thrown by player"      },
2281   { CE_SWITCHED,                        "switched"                      },
2282   { CE_HITTING_SOMETHING,               "hitting something"             },
2283   { CE_HIT_BY_SOMETHING,                "hit by something"              },
2284 #if 0
2285   { CE_BLOCKED,                         "blocked"                       },
2286 #endif
2287   { CE_IMPACT,                          "impact (on something)"         },
2288   { CE_SMASHED,                         "smashed (from above)"          },
2289 #if 0
2290   { CE_VALUE_CHANGES,                   "CE value changes"              },
2291   { CE_SCORE_CHANGES,                   "CE score changes"              },
2292 #endif
2293   { CE_VALUE_GETS_ZERO,                 "CE value gets 0"               },
2294   { CE_SCORE_GETS_ZERO,                 "CE score gets 0"               },
2295   { CE_UNDEFINED,                       " "                             },
2296   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2297   { CE_CLICKED_BY_MOUSE,                "clicked by mouse"              },
2298   { CE_PRESSED_BY_MOUSE,                "pressed by mouse"              },
2299   { CE_UNDEFINED,                       " "                             },
2300   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2301   { CE_NEXT_TO_PLAYER,                  "next to player"                },
2302
2303   { -1,                                 NULL                            }
2304 };
2305
2306 static struct ValueTextInfo options_change_other_action[] =
2307 {
2308   { CE_PLAYER_TOUCHES_X,                "player touches"                },
2309   { CE_PLAYER_PRESSES_X,                "player presses"                },
2310   { CE_PLAYER_SWITCHES_X,               "player switches"               },
2311   { CE_PLAYER_SNAPS_X,                  "player snaps"                  },
2312   { CE_PLAYER_PUSHES_X,                 "player pushes"                 },
2313   { CE_PLAYER_ENTERS_X,                 "player enters"                 },
2314   { CE_PLAYER_LEAVES_X,                 "player leaves"                 },
2315   { CE_PLAYER_DIGS_X,                   "player digs"                   },
2316   { CE_PLAYER_COLLECTS_X,               "player collects"               },
2317   { CE_PLAYER_DROPS_X,                  "player drops/throws"           },
2318   { CE_TOUCHING_X,                      "touching"                      },
2319   { CE_HITTING_X,                       "hitting"                       },
2320   { CE_DIGGING_X,                       "digging"                       },
2321   { CE_HIT_BY_X,                        "hit by"                        },
2322   { CE_SWITCH_OF_X,                     "switch of"                     },
2323   { CE_CHANGE_OF_X,                     "change by page of"             },
2324   { CE_EXPLOSION_OF_X,                  "explosion of"                  },
2325   { CE_MOVE_OF_X,                       "move of"                       },
2326   { CE_CREATION_OF_X,                   "creation of"                   },
2327   { CE_VALUE_CHANGES_OF_X,              "CE value changes of"           },
2328   { CE_SCORE_CHANGES_OF_X,              "CE score changes of"           },
2329   { CE_VALUE_GETS_ZERO_OF_X,            "CE value gets 0 of"            },
2330   { CE_SCORE_GETS_ZERO_OF_X,            "CE score gets 0 of"            },
2331   { CE_UNDEFINED,                       " "                             },
2332   { CE_HEADLINE_SPECIAL_EVENTS,         "[mouse events]"                },
2333   { CE_MOUSE_CLICKED_ON_X,              "mouse clicked on"              },
2334   { CE_MOUSE_PRESSED_ON_X,              "mouse pressed on"              },
2335   { CE_UNDEFINED,                       " "                             },
2336   { CE_HEADLINE_SPECIAL_EVENTS,         "[static states]"               },
2337   { CE_PLAYER_NEXT_TO_X,                "player next to"                },
2338   { CE_NEXT_TO_X,                       "next to"                       },
2339
2340   { -1,                                 NULL                            }
2341 };
2342
2343 static struct ValueTextInfo options_change_trigger_side[] =
2344 {
2345   { CH_SIDE_LEFT,                       "left"                          },
2346   { CH_SIDE_RIGHT,                      "right"                         },
2347   { CH_SIDE_TOP,                        "top"                           },
2348   { CH_SIDE_BOTTOM,                     "bottom"                        },
2349   { CH_SIDE_LEFT_RIGHT,                 "left/right"                    },
2350   { CH_SIDE_TOP_BOTTOM,                 "top/bottom"                    },
2351   { CH_SIDE_ANY,                        "any"                           },
2352
2353   { -1,                                 NULL                            }
2354 };
2355
2356 static struct ValueTextInfo options_change_trigger_player[] =
2357 {
2358   { CH_PLAYER_1,                        "1"                             },
2359   { CH_PLAYER_2,                        "2"                             },
2360   { CH_PLAYER_3,                        "3"                             },
2361   { CH_PLAYER_4,                        "4"                             },
2362   { CH_PLAYER_ANY,                      "any"                           },
2363
2364   { -1,                                 NULL                            }
2365 };
2366
2367 static struct ValueTextInfo options_change_trigger_page[] =
2368 {
2369   { (1u << 0),                          "1"                             },
2370   { (1u << 1),                          "2"                             },
2371   { (1u << 2),                          "3"                             },
2372   { (1u << 3),                          "4"                             },
2373   { (1u << 4),                          "5"                             },
2374   { (1u << 5),                          "6"                             },
2375   { (1u << 6),                          "7"                             },
2376   { (1u << 7),                          "8"                             },
2377   { (1u << 8),                          "9"                             },
2378   { (1u << 9),                          "10"                            },
2379   { (1u << 10),                         "11"                            },
2380   { (1u << 11),                         "12"                            },
2381   { (1u << 12),                         "13"                            },
2382   { (1u << 13),                         "14"                            },
2383   { (1u << 14),                         "15"                            },
2384   { (1u << 15),                         "16"                            },
2385   { (1u << 16),                         "17"                            },
2386   { (1u << 17),                         "18"                            },
2387   { (1u << 18),                         "19"                            },
2388   { (1u << 19),                         "20"                            },
2389   { (1u << 20),                         "21"                            },
2390   { (1u << 21),                         "22"                            },
2391   { (1u << 22),                         "23"                            },
2392   { (1u << 23),                         "24"                            },
2393   { (1u << 24),                         "25"                            },
2394   { (1u << 25),                         "26"                            },
2395   { (1u << 26),                         "27"                            },
2396   { (1u << 27),                         "28"                            },
2397   { (1u << 28),                         "29"                            },
2398   { (1u << 29),                         "30"                            },
2399   { (1u << 30),                         "31"                            },
2400   { (1u << 31),                         "32"                            },
2401   { CH_PAGE_ANY,                        "any"                           },
2402
2403   { -1,                                 NULL                            }
2404 };
2405
2406 static struct ValueTextInfo options_change_replace_when[] =
2407 {
2408   { CP_WHEN_EMPTY,                      "empty"                         },
2409   { CP_WHEN_WALKABLE,                   "walkable"                      },
2410   { CP_WHEN_DIGGABLE,                   "diggable"                      },
2411   { CP_WHEN_COLLECTIBLE,                "collectible"                   },
2412   { CP_WHEN_REMOVABLE,                  "removable"                     },
2413   { CP_WHEN_DESTRUCTIBLE,               "destructible"                  },
2414
2415   { -1,                                 NULL                            }
2416 };
2417
2418 static struct ValueTextInfo options_action_type[] =
2419 {
2420   { CA_NO_ACTION,                       "no action"                     },
2421   { CA_UNDEFINED,                       " "                             },
2422   { CA_HEADLINE_LEVEL_ACTIONS,          "[level]"                       },
2423   { CA_RESTART_LEVEL,                   "restart level"                 },
2424   { CA_SHOW_ENVELOPE,                   "show envelope"                 },
2425   { CA_SET_LEVEL_TIME,                  "set time"                      },
2426   { CA_SET_LEVEL_SCORE,                 "set score"                     },
2427   { CA_SET_LEVEL_GEMS,                  "set gems"                      },
2428   { CA_SET_LEVEL_WIND,                  "set wind dir."                 },
2429   { CA_SET_LEVEL_RANDOM_SEED,           "set random seed"               },
2430   { CA_UNDEFINED,                       " "                             },
2431   { CA_HEADLINE_PLAYER_ACTIONS,         "[player]"                      },
2432   { CA_MOVE_PLAYER,                     "move player"                   },
2433   { CA_MOVE_PLAYER_NEW,                 "move player new"               },
2434   { CA_EXIT_PLAYER,                     "exit player"                   },
2435   { CA_KILL_PLAYER,                     "kill player"                   },
2436   { CA_SET_PLAYER_KEYS,                 "set keys"                      },
2437   { CA_SET_PLAYER_SPEED,                "set speed"                     },
2438   { CA_SET_PLAYER_SHIELD,               "set shield"                    },
2439   { CA_SET_PLAYER_GRAVITY,              "set gravity"                   },
2440   { CA_SET_PLAYER_ARTWORK,              "set artwork"                   },
2441   { CA_SET_PLAYER_INVENTORY,            "set inventory"                 },
2442   { CA_UNDEFINED,                       " "                             },
2443   { CA_HEADLINE_CE_ACTIONS,             "[CE]"                          },
2444   { CA_SET_CE_VALUE,                    "set CE value"                  },
2445   { CA_SET_CE_SCORE,                    "set CE score"                  },
2446   { CA_SET_CE_ARTWORK,                  "set CE artwork"                },
2447   { CA_UNDEFINED,                       " "                             },
2448   { CA_HEADLINE_ENGINE_ACTIONS,         "[engine]"                      },
2449   { CA_SET_ENGINE_SCAN_MODE,            "set scan mode"                 },
2450
2451   { -1,                                 NULL                            }
2452 };
2453
2454 static struct ValueTextInfo options_action_mode_none[] =
2455 {
2456   { CA_MODE_UNDEFINED,                  " "                             },
2457
2458   { -1,                                 NULL                            }
2459 };
2460
2461 static struct ValueTextInfo options_action_mode_assign[] =
2462 {
2463   { CA_MODE_SET,                        "="                             },
2464
2465   { -1,                                 NULL                            }
2466 };
2467
2468 static struct ValueTextInfo options_action_mode_add_remove[] =
2469 {
2470   { CA_MODE_ADD,                        "+"                             },
2471   { CA_MODE_SUBTRACT,                   "-"                             },
2472
2473   { -1,                                 NULL                            }
2474 };
2475
2476 static struct ValueTextInfo options_action_mode_calculate[] =
2477 {
2478   { CA_MODE_SET,                        "="                             },
2479   { CA_MODE_ADD,                        "+"                             },
2480   { CA_MODE_SUBTRACT,                   "-"                             },
2481   { CA_MODE_MULTIPLY,                   "*"                             },
2482   { CA_MODE_DIVIDE,                     "/"                             },
2483   { CA_MODE_MODULO,                     "%"                             },
2484
2485   { -1,                                 NULL                            }
2486 };
2487
2488 static struct ValueTextInfo options_action_arg_none[] =
2489 {
2490   { CA_ARG_UNDEFINED,                   "         "                     },
2491
2492   { -1,                                 NULL                            }
2493 };
2494
2495 static struct ValueTextInfo options_action_arg_player[] =
2496 {
2497   { CA_ARG_PLAYER_HEADLINE,             "[player]"                      },
2498   { CA_ARG_PLAYER_1,                    "1"                             },
2499   { CA_ARG_PLAYER_2,                    "2"                             },
2500   { CA_ARG_PLAYER_3,                    "3"                             },
2501   { CA_ARG_PLAYER_4,                    "4"                             },
2502   { CA_ARG_PLAYER_ANY,                  "any"                           },
2503   { CA_ARG_PLAYER_TRIGGER,              "trigger"                       },
2504   { CA_ARG_PLAYER_ACTION,               "action ->"                     },
2505
2506   { -1,                                 NULL                            }
2507 };
2508
2509 static struct ValueTextInfo options_action_arg_number[] =
2510 {
2511   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2512   { CA_ARG_0,                           "0"                             },
2513   { CA_ARG_1,                           "1"                             },
2514   { CA_ARG_2,                           "2"                             },
2515   { CA_ARG_3,                           "3"                             },
2516   { CA_ARG_4,                           "4"                             },
2517   { CA_ARG_5,                           "5"                             },
2518   { CA_ARG_10,                          "10"                            },
2519   { CA_ARG_100,                         "100"                           },
2520   { CA_ARG_1000,                        "1000"                          },
2521   { CA_ARG_UNDEFINED,                   " "                             },
2522   { CA_ARG_NUMBER_MIN,                  "min"                           },
2523   { CA_ARG_NUMBER_MAX,                  "max"                           },
2524   { CA_ARG_UNDEFINED,                   " "                             },
2525   { CA_ARG_NUMBER_RESET,                "reset"                         },
2526   { CA_ARG_UNDEFINED,                   " "                             },
2527   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2528   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2529   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2530   { CA_ARG_UNDEFINED,                   " "                             },
2531   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2532   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2533   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2534   { CA_ARG_UNDEFINED,                   " "                             },
2535   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2536   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2537   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2538   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2539   { CA_ARG_UNDEFINED,                   " "                             },
2540   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2541   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2542   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2543   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2544
2545   { -1,                                 NULL                            }
2546 };
2547
2548 static struct ValueTextInfo options_action_arg_value[] =
2549 {
2550   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2551   { CA_ARG_0,                           "0"                             },
2552   { CA_ARG_1,                           "1"                             },
2553   { CA_ARG_2,                           "2"                             },
2554   { CA_ARG_3,                           "3"                             },
2555   { CA_ARG_4,                           "4"                             },
2556   { CA_ARG_5,                           "5"                             },
2557   { CA_ARG_10,                          "10"                            },
2558   { CA_ARG_100,                         "100"                           },
2559   { CA_ARG_1000,                        "1000"                          },
2560   { CA_ARG_UNDEFINED,                   " "                             },
2561   { CA_ARG_NUMBER_MIN,                  "min"                           },
2562   { CA_ARG_NUMBER_MAX,                  "max"                           },
2563   { CA_ARG_UNDEFINED,                   " "                             },
2564   { CA_ARG_NUMBER_RESET,                "reset"                         },
2565   { CA_ARG_UNDEFINED,                   " "                             },
2566   { CA_ARG_NUMBER_CE_VALUE,             "CE value"                      },
2567   { CA_ARG_NUMBER_CE_SCORE,             "CE score"                      },
2568   { CA_ARG_NUMBER_CE_DELAY,             "CE delay"                      },
2569   { CA_ARG_UNDEFINED,                   " "                             },
2570   { CA_ARG_NUMBER_LEVEL_TIME,           "time"                          },
2571   { CA_ARG_NUMBER_LEVEL_GEMS,           "gems"                          },
2572   { CA_ARG_NUMBER_LEVEL_SCORE,          "score"                         },
2573   { CA_ARG_UNDEFINED,                   " "                             },
2574   { CA_ARG_ELEMENT_CV_HEADLINE,         "[CE value]"                    },
2575   { CA_ARG_ELEMENT_CV_TARGET,           "target"                        },
2576   { CA_ARG_ELEMENT_CV_TRIGGER,          "trigger"                       },
2577   { CA_ARG_ELEMENT_CV_ACTION,           "action ->"                     },
2578   { CA_ARG_UNDEFINED,                   " "                             },
2579   { CA_ARG_ELEMENT_CS_HEADLINE,         "[CE score]"                    },
2580   { CA_ARG_ELEMENT_CS_TARGET,           "target"                        },
2581   { CA_ARG_ELEMENT_CS_TRIGGER,          "trigger"                       },
2582   { CA_ARG_ELEMENT_CS_ACTION,           "action ->"                     },
2583   { CA_ARG_UNDEFINED,                   " "                             },
2584   { CA_ARG_ELEMENT_NR_HEADLINE,         "[element]"                     },
2585   { CA_ARG_ELEMENT_NR_TARGET,           "target"                        },
2586   { CA_ARG_ELEMENT_NR_TRIGGER,          "trigger"                       },
2587   { CA_ARG_ELEMENT_NR_ACTION,           "action ->"                     },
2588
2589   { -1,                                 NULL                            }
2590 };
2591
2592 static struct ValueTextInfo options_action_arg_envelope[] =
2593 {
2594   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2595   { CA_ARG_1,                           "1"                             },
2596   { CA_ARG_2,                           "2"                             },
2597   { CA_ARG_3,                           "3"                             },
2598   { CA_ARG_4,                           "4"                             },
2599   { CA_ARG_UNDEFINED,                   " "                             },
2600   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2601   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2602   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2603   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2604
2605   { -1,                                 NULL                            }
2606 };
2607
2608 static struct ValueTextInfo options_action_arg_key[] =
2609 {
2610   { CA_ARG_NUMBER_HEADLINE,             "[number]"                      },
2611   { CA_ARG_1,                           "1"                             },
2612   { CA_ARG_2,                           "2"                             },
2613   { CA_ARG_3,                           "3"                             },
2614   { CA_ARG_4,                           "4"                             },
2615   { CA_ARG_5,                           "5"                             },
2616   { CA_ARG_6,                           "6"                             },
2617   { CA_ARG_7,                           "7"                             },
2618   { CA_ARG_8,                           "8"                             },
2619   { CA_ARG_UNDEFINED,                   " "                             },
2620   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2621   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2622   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2623   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2624
2625   { -1,                                 NULL                            }
2626 };
2627
2628 static struct ValueTextInfo options_action_arg_speed[] =
2629 {
2630   { CA_ARG_SPEED_HEADLINE,              "[speed]"                       },
2631   { CA_ARG_SPEED_NOT_MOVING,            "frozen"                        },
2632   { CA_ARG_SPEED_VERY_SLOW,             "very slow"                     },
2633   { CA_ARG_SPEED_SLOW,                  "slow"                          },
2634   { CA_ARG_SPEED_NORMAL,                "normal"                        },
2635   { CA_ARG_SPEED_FAST,                  "fast"                          },
2636   { CA_ARG_SPEED_VERY_FAST,             "very fast"                     },
2637   { CA_ARG_SPEED_EVEN_FASTER,           "ultrafast"                     },
2638   { CA_ARG_UNDEFINED,                   " "                             },
2639   { CA_ARG_SPEED_SLOWER,                "slower"                        },
2640   { CA_ARG_SPEED_FASTER,                "faster"                        },
2641   { CA_ARG_UNDEFINED,                   " "                             },
2642   { CA_ARG_SPEED_RESET,                 "reset"                         },
2643
2644   { -1,                                 NULL                            }
2645 };
2646
2647 static struct ValueTextInfo options_action_arg_shield[] =
2648 {
2649   { CA_ARG_SHIELD_HEADLINE,             "[shield]"                      },
2650   { CA_ARG_SHIELD_OFF,                  "off"                           },
2651   { CA_ARG_SHIELD_NORMAL,               "normal"                        },
2652   { CA_ARG_SHIELD_DEADLY,               "deadly"                        },
2653
2654   { -1,                                 NULL                            }
2655 };
2656
2657 static struct ValueTextInfo options_action_arg_artwork[] =
2658 {
2659   { CA_ARG_ELEMENT_HEADLINE,            "[element]"                     },
2660   { CA_ARG_ELEMENT_TARGET,              "target"                        },
2661   { CA_ARG_ELEMENT_TRIGGER,             "trigger"                       },
2662   { CA_ARG_ELEMENT_ACTION,              "action ->"                     },
2663   { CA_ARG_UNDEFINED,                   " "                             },
2664   { CA_ARG_ELEMENT_RESET,               "reset"                         },
2665
2666   { -1,                                 NULL                            }
2667 };
2668
2669 static struct ValueTextInfo options_action_arg_gravity[] =
2670 {
2671   { CA_ARG_GRAVITY_HEADLINE,            "[gravity]"                     },
2672   { CA_ARG_GRAVITY_ON,                  "on"                            },
2673   { CA_ARG_GRAVITY_OFF,                 "off"                           },
2674   { CA_ARG_GRAVITY_TOGGLE,              "toggle"                        },
2675
2676   { -1,                                 NULL                            }
2677 };
2678
2679 static struct ValueTextInfo options_action_arg_direction[] =
2680 {
2681   { CA_ARG_DIRECTION_HEADLINE,          "[dir.]"                        },
2682   { CA_ARG_DIRECTION_NONE,              "none"                          },
2683   { CA_ARG_DIRECTION_LEFT,              "left"                          },
2684   { CA_ARG_DIRECTION_RIGHT,             "right"                         },
2685   { CA_ARG_DIRECTION_UP,                "up"                            },
2686   { CA_ARG_DIRECTION_DOWN,              "down"                          },
2687   { CA_ARG_DIRECTION_TRIGGER,           "trigger"                       },
2688   { CA_ARG_DIRECTION_TRIGGER_BACK,      "-trigger"                      },
2689
2690   { -1,                                 NULL                            }
2691 };
2692
2693 static struct ValueTextInfo options_action_arg_scan_mode[] =
2694 {
2695   { CA_ARG_SCAN_MODE_HEADLINE,          "[mode]"                        },
2696   { CA_ARG_SCAN_MODE_NORMAL,            "normal"                        },
2697   { CA_ARG_SCAN_MODE_REVERSE,           "reverse"                       },
2698
2699   { -1,                                 NULL                            }
2700 };
2701
2702 static struct ValueTextInfo options_action_arg_inventory[] =
2703 {
2704   { CA_ARG_INVENTORY_HEADLINE,          "[add]"                         },
2705   { CA_ARG_ELEMENT_TARGET,              "+ target"                      },
2706   { CA_ARG_ELEMENT_TRIGGER,             "+ trigger"                     },
2707   { CA_ARG_ELEMENT_ACTION,              "+ action"                      },
2708   { CA_ARG_UNDEFINED,                   " "                             },
2709   { CA_ARG_INVENTORY_RM_HEADLINE,       "[remove]"                      },
2710   { CA_ARG_INVENTORY_RM_TARGET,         "- target"                      },
2711   { CA_ARG_INVENTORY_RM_TRIGGER,        "- trigger"                     },
2712   { CA_ARG_INVENTORY_RM_ACTION,         "- action"                      },
2713   { CA_ARG_INVENTORY_RM_FIRST,          "- first"                       },
2714   { CA_ARG_INVENTORY_RM_LAST,           "- last"                        },
2715   { CA_ARG_INVENTORY_RM_ALL,            "- all"                         },
2716   { CA_ARG_UNDEFINED,                   " "                             },
2717   { CA_ARG_INVENTORY_RESET,             "reset"                         },
2718
2719   { -1,                                 NULL                            }
2720 };
2721
2722 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2723 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2724 {
2725   { -1,                                 NULL                            }
2726 };
2727
2728 static struct ValueTextInfo options_group_choice_mode[] =
2729 {
2730   { ANIM_RANDOM,                        "random"                        },
2731   { ANIM_LOOP,                          "loop"                          },
2732   { ANIM_LINEAR,                        "linear"                        },
2733   { ANIM_PINGPONG,                      "pingpong"                      },
2734   { ANIM_PINGPONG2,                     "pingpong 2"                    },
2735   { ANIM_LEVEL_NR,                      "level number"                  },
2736
2737   { -1,                                 NULL                            }
2738 };
2739
2740 static struct ValueTextInfo options_bd_scheduling_type[] =
2741 {
2742   { GD_SCHEDULING_MILLISECONDS,         "Milliseconds"                  },
2743   { GD_SCHEDULING_BD1,                  "BD1"                           },
2744   { GD_SCHEDULING_BD2,                  "BD2"                           },
2745   { GD_SCHEDULING_PLCK,                 "Construction Kit"              },
2746   { GD_SCHEDULING_CRDR,                 "Crazy Dream 7"                 },
2747   { GD_SCHEDULING_BD1_ATARI,            "Atari BD1"                     },
2748   { GD_SCHEDULING_BD2_PLCK_ATARI,       "Atari BD2 / PLCK"              },
2749
2750   { -1,                                   NULL                          }
2751 };
2752
2753 static struct ValueTextInfo *action_arg_modes[] =
2754 {
2755   options_action_mode_none,
2756   options_action_mode_assign,
2757   options_action_mode_add_remove,
2758   options_action_mode_calculate,
2759 };
2760
2761 static struct
2762 {
2763   int value;
2764   int mode;
2765   struct ValueTextInfo *options;
2766 }
2767 action_arg_options[] =
2768 {
2769   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2770   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2771   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2772   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2773   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2774   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2775   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2776   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2777   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2778   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2779   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2780   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2781   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2782   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2783   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2784   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2785   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2786   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2787   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2788   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2789   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2790   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2791
2792   { -1,                         FALSE,  NULL                            }
2793 };
2794
2795 static struct
2796 {
2797   int gadget_type_id;
2798   int x, y;
2799   int gadget_id;
2800   int gadget_id_align;
2801   int size;     // char size of selectbox or '-1' (dynamically determined)
2802   struct ValueTextInfo *options;
2803   int *value;
2804   char *text_above, *text_left, *text_right, *infotext;
2805 } selectbox_info[ED_NUM_SELECTBOX] =
2806 {
2807   // ---------- level and editor settings -------------------------------------
2808
2809   {
2810     ED_SELECTBOX_ID_TIME_OR_STEPS,
2811     -1,                                         ED_LEVEL_SETTINGS_YPOS(8),
2812     GADGET_ID_TIME_OR_STEPS,                    GADGET_ID_LEVEL_TIMELIMIT_UP,
2813     -1,
2814     options_time_or_steps,
2815     &level.use_step_counter,
2816     NULL, NULL, "(0 => no limit)",              "Select time or step limit"
2817   },
2818   {
2819     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2820     -1,                                         ED_LEVEL_SETTINGS_YPOS(10),
2821     GADGET_ID_TIME_SCORE_BASE,                  GADGET_ID_LEVEL_TIMESCORE_UP,
2822     -1,
2823     options_time_score_base,
2824     &level.time_score_base,
2825     NULL, NULL, NULL,                           "Select time score for 1 or 10 seconds/steps"
2826   },
2827   {
2828     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2829     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(12),
2830     GADGET_ID_GAME_ENGINE_TYPE,                 GADGET_ID_NONE,
2831     -1,
2832     options_game_engine_type,
2833     &level.game_engine_type,
2834     NULL, "Game engine:", NULL,                 "Select game engine"
2835   },
2836   {
2837     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2838     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
2839     GADGET_ID_BD_SCHEDULING_TYPE,               GADGET_ID_NONE,
2840     -1,
2841     options_bd_scheduling_type,
2842     &level.bd_scheduling_type,
2843     NULL, "Scheduling type:", NULL,             "Select level timing"
2844   },
2845   {
2846     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2847     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
2848     GADGET_ID_LEVELSET_SAVE_MODE,               GADGET_ID_NONE,
2849     -1,
2850     options_levelset_save_mode,
2851     &levelset_save_mode,
2852     "Action:", NULL, NULL,                      "Select action when saving level set"
2853   },
2854
2855   // ---------- element settings: configure (several elements) ----------------
2856
2857   {
2858     ED_SELECTBOX_ID_WIND_DIRECTION,
2859     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2860     GADGET_ID_WIND_DIRECTION,                   GADGET_ID_NONE,
2861     -1,
2862     options_wind_direction,
2863     &level.wind_direction_initial,
2864     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2865   },
2866   {
2867     ED_SELECTBOX_ID_PLAYER_SPEED,
2868     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(7),
2869     GADGET_ID_PLAYER_SPEED,                     GADGET_ID_NONE,
2870     -1,
2871     options_player_speed,
2872     &level.initial_player_stepsize[0],
2873     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2874   },
2875   {
2876     ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
2877     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
2878     GADGET_ID_BD_GRAVITY_DIRECTION,             GADGET_ID_NONE,
2879     -1,
2880     options_bd_gravity_direction,
2881     &level.bd_gravity_direction,
2882     NULL, "Gravity direction:", NULL,           "Select initial gravity direction"
2883   },
2884   {
2885     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2886     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
2887     GADGET_ID_MM_BALL_CHOICE_MODE,              GADGET_ID_NONE,
2888     -1,
2889     options_group_choice_mode,
2890     &level.mm_ball_choice_mode,
2891     NULL, "Choice type:", NULL,                 "Select type of content choice"
2892   },
2893
2894   // ---------- element settings: configure 1 (custom elements) ---------------
2895
2896   {
2897     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2898     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2899     GADGET_ID_CUSTOM_ACCESS_TYPE,               GADGET_ID_NONE,
2900     -1,
2901     options_access_type,
2902     &custom_element.access_type,
2903     NULL, NULL, NULL,                           "Select type of access to this field"
2904   },
2905   {
2906     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2907     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2908     GADGET_ID_CUSTOM_ACCESS_LAYER,              GADGET_ID_CUSTOM_ACCESS_TYPE,
2909     -1,
2910     options_access_layer,
2911     &custom_element.access_layer,
2912     NULL, NULL, NULL,                           "Select layer of access for this field"
2913   },
2914   {
2915     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2916     -1,                                         ED_ELEMENT_SETTINGS_YPOS(2),
2917     GADGET_ID_CUSTOM_ACCESS_PROTECTED,          GADGET_ID_CUSTOM_ACCESS_LAYER,
2918     -1,
2919     options_access_protected,
2920     &custom_element.access_protected,
2921     NULL, NULL, NULL,                           "Select protected access for this field"
2922   },
2923   {
2924     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2925     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2926     GADGET_ID_CUSTOM_ACCESS_DIRECTION,          GADGET_ID_NONE,
2927     -1,
2928     options_access_direction,
2929     &custom_element.access_direction,
2930     NULL, "from", NULL,                         "Select access direction for this field"
2931   },
2932   {
2933     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2934     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2935     GADGET_ID_CUSTOM_WALK_TO_ACTION,            GADGET_ID_NONE,
2936     -1,
2937     options_walk_to_action,
2938     &custom_element.walk_to_action,
2939     NULL, NULL, NULL,                           "Select diggable/collectible/pushable"
2940   },
2941
2942   // ---------- element settings: configure 2 (custom elements) ---------------
2943
2944   {
2945     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2946     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(1),
2947     GADGET_ID_CUSTOM_MOVE_PATTERN,              GADGET_ID_NONE,
2948     -1,
2949     options_move_pattern,
2950     &custom_element.move_pattern,
2951     NULL, "Can move", NULL,                     "Select element move pattern"
2952   },
2953   {
2954     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2955     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
2956     GADGET_ID_CUSTOM_MOVE_DIRECTION,            GADGET_ID_NONE,
2957     -1,
2958     options_move_direction,
2959     &custom_element.move_direction_initial,
2960     NULL, "Starts moving", NULL,                "Select initial element move direction"
2961   },
2962   {
2963     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2964     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
2965     GADGET_ID_CUSTOM_MOVE_STEPSIZE,             GADGET_ID_NONE,
2966     -1,
2967     options_move_stepsize,
2968     &custom_element.move_stepsize,
2969     NULL, "Move/fall speed", NULL,              "Select speed of element movement"
2970   },
2971   {
2972     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2973     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(3),
2974     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,           GADGET_ID_NONE,
2975     -1,
2976     options_move_leave_type,
2977     &custom_element.move_leave_type,
2978     // left text with leading spaces to place gadget next to "can dig" gadget
2979     // (needed because drawing area gadgets created after selectbox gadgets)
2980     // NULL, "can dig:    can", ":",            "leave behind or change element"
2981     NULL, "            Can", ":",               "Select leave behind or change element"
2982   },
2983   {
2984     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
2985     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
2986     GADGET_ID_CUSTOM_SMASH_TARGETS,             GADGET_ID_CUSTOM_CAN_SMASH,
2987     -1,
2988     options_smash_targets,
2989     &custom_element.smash_targets,
2990     NULL, "Can smash", NULL,                    "Select elements that can be smashed"
2991   },
2992   {
2993     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
2994     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
2995     GADGET_ID_CUSTOM_SLIPPERY_TYPE,             GADGET_ID_NONE,
2996     -1,
2997     options_slippery_type,
2998     &custom_element.slippery_type,
2999     NULL, "Slippery", NULL,                     "Select where other elements fall down"
3000   },
3001   {
3002     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
3003     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(10),
3004     GADGET_ID_CUSTOM_DEADLINESS,                GADGET_ID_NONE,
3005     -1,
3006     options_deadliness,
3007     &custom_element.deadliness,
3008     NULL, "Deadly when", NULL,                  "Select deadliness of element"
3009   },
3010   {
3011     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
3012     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(11),
3013     GADGET_ID_CUSTOM_EXPLOSION_TYPE,            GADGET_ID_NONE,
3014     -1,
3015     options_explosion_type,
3016     &custom_element.explosion_type,
3017     NULL, "Can explode", NULL,                  "Select explosion type"
3018   },
3019
3020   // ---------- element settings: advanced (custom elements) ------------------
3021
3022   {
3023     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
3024     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(3),
3025     GADGET_ID_CHANGE_TIME_UNITS,                GADGET_ID_NONE,
3026     -1,
3027     options_time_units,
3028     &custom_element_change.delay_frames,
3029     NULL, "Delay time given in", NULL,          "Select delay time units for change"
3030   },
3031   {
3032     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
3033     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(4),
3034     GADGET_ID_CHANGE_DIRECT_ACTION,             GADGET_ID_NONE,
3035     -1,
3036     options_change_direct_action,
3037     &custom_element_change.direct_action,
3038     NULL, NULL, NULL,                           "Select type of direct action"
3039   },
3040   {
3041     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3042     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(5),
3043     GADGET_ID_CHANGE_OTHER_ACTION,              GADGET_ID_NONE,
3044     -1,
3045     options_change_other_action,
3046     &custom_element_change.other_action,
3047     NULL, NULL, "element:",                     "Select type of other element action"
3048   },
3049   {
3050     ED_SELECTBOX_ID_CHANGE_SIDE,
3051     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(6),
3052     GADGET_ID_CHANGE_SIDE,                      GADGET_ID_NONE,
3053     -1,
3054     options_change_trigger_side,
3055     &custom_element_change.trigger_side,
3056     NULL, "at", "side",                         "Select element side triggering change"
3057   },
3058   {
3059     ED_SELECTBOX_ID_CHANGE_PLAYER,
3060     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3061     GADGET_ID_CHANGE_PLAYER,                    GADGET_ID_NONE,
3062     -1,
3063     options_change_trigger_player,
3064     &custom_element_change.trigger_player,
3065     NULL, "Player:", " ",                       "Select player that causes change"
3066   },
3067   {
3068     ED_SELECTBOX_ID_CHANGE_PAGE,
3069     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(7),
3070     GADGET_ID_CHANGE_PAGE,                      GADGET_ID_CHANGE_PLAYER,
3071     -1,
3072     options_change_trigger_page,
3073     &custom_element_change.trigger_page,
3074     NULL, "Page:", NULL,                        "Select change page that causes change"
3075   },
3076   {
3077     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3078     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(10),
3079     GADGET_ID_CHANGE_REPLACE_WHEN,              GADGET_ID_NONE,
3080     -1,
3081     options_change_replace_when,
3082     &custom_element_change.replace_when,
3083     NULL, "Replace when", NULL,                 "Select which elements can be replaced"
3084   },
3085   {
3086     ED_SELECTBOX_ID_ACTION_TYPE,
3087     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(13),
3088     GADGET_ID_ACTION_TYPE,                      GADGET_ID_NONE,
3089     15,
3090     options_action_type,
3091     &custom_element_change.action_type,
3092     NULL, NULL, NULL,                           "Select action on specified condition"
3093   },
3094   {
3095     ED_SELECTBOX_ID_ACTION_MODE,
3096     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3097     GADGET_ID_ACTION_MODE,                      GADGET_ID_ACTION_TYPE,
3098     -1,
3099     options_action_mode_none,
3100     &custom_element_change.action_mode,
3101     NULL, NULL, NULL,                           "Select action operator"
3102   },
3103   {
3104     ED_SELECTBOX_ID_ACTION_ARG,
3105     -1,                                         ED_ELEMENT_SETTINGS_YPOS(13),
3106     GADGET_ID_ACTION_ARG,                       GADGET_ID_ACTION_MODE,
3107     -1,
3108     options_action_arg_none,
3109     &custom_element_change.action_arg,
3110     NULL, NULL, NULL,                           "Select action parameter"
3111   },
3112   {
3113     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3114     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(14),
3115     GADGET_ID_SELECT_CHANGE_PAGE,               GADGET_ID_NONE,
3116     3,
3117     options_change_page,
3118     &custom_element.current_change_page,
3119     NULL, NULL, NULL,                           "Select element change page"
3120   },
3121
3122   // ---------- element settings: configure (group elements) ------------------
3123
3124   {
3125     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3126     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3127     GADGET_ID_GROUP_CHOICE_MODE,                GADGET_ID_NONE,
3128     -1,
3129     options_group_choice_mode,
3130     &group_element_info.choice_mode,
3131     NULL, "Choice type:", NULL,                 "Select type of group element choice"
3132   },
3133 };
3134
3135 static struct
3136 {
3137   int gadget_type_id;
3138   int x, y;
3139   int gadget_id;
3140   int gadget_id_align;
3141   int size;
3142   char *text;
3143   char *text_above, *text_left, *text_right, *infotext;
3144 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3145 {
3146   // ---------- level and editor settings (tabs) ------------------------------
3147
3148   {
3149     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3150     ED_LEVEL_TABS_XPOS(0),                      ED_LEVEL_TABS_YPOS(0),
3151     GADGET_ID_LEVELCONFIG_LEVEL,                GADGET_ID_NONE,
3152     8,                                          "Level",
3153     NULL, NULL, NULL,                           "Configure level settings"
3154   },
3155   {
3156     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3157     -1,                                         -1,
3158     GADGET_ID_LEVELCONFIG_LEVELSET,             GADGET_ID_LEVELCONFIG_LEVEL,
3159     8,                                          "Levelset",
3160     NULL, NULL, NULL,                           "Update this or create new level set"
3161   },
3162   {
3163     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3164     -1,                                         -1,
3165     GADGET_ID_LEVELCONFIG_EDITOR,               GADGET_ID_LEVELCONFIG_LEVELSET,
3166     8,                                          "Editor",
3167     NULL, NULL, NULL,                           "Configure editor settings"
3168   },
3169   {
3170     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3171     -1,                                         -1,
3172     GADGET_ID_LEVELCONFIG_ENGINE,               GADGET_ID_LEVELCONFIG_EDITOR,
3173     8,                                          "Engine",
3174     NULL, NULL, NULL,                           "Configure engine settings"
3175   },
3176
3177   // ---------- element settings (tabs) ---------------------------------------
3178
3179   {
3180     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3181     ED_ELEMENT_TABS_XPOS(0),                    ED_ELEMENT_TABS_YPOS(0),
3182     GADGET_ID_PROPERTIES_INFO,                  GADGET_ID_NONE,
3183     8,                                          "Info",
3184     NULL, NULL, NULL,                           "Show information about element"
3185   },
3186   {
3187     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3188     -1,                                         -1,
3189     GADGET_ID_PROPERTIES_CONFIG,                GADGET_ID_PROPERTIES_INFO,
3190     8,                                          "Config",
3191     NULL, NULL, NULL,                           "Configure element properties"
3192   },
3193   {
3194     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3195     -1,                                         -1,
3196     GADGET_ID_PROPERTIES_CONFIG_1,              GADGET_ID_PROPERTIES_INFO,
3197     8,                                          "Config 1",
3198     NULL, NULL, NULL,                           "Configure element properties, part 1"
3199   },
3200   {
3201     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3202     -1,                                         -1,
3203     GADGET_ID_PROPERTIES_CONFIG_2,              GADGET_ID_PROPERTIES_CONFIG_1,
3204     8,                                          "Config 2",
3205     NULL, NULL, NULL,                           "Configure element properties, part 2"
3206   },
3207   {
3208     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3209     -1,                                         -1,
3210     GADGET_ID_PROPERTIES_CHANGE,                GADGET_ID_PROPERTIES_CONFIG_2,
3211     8,                                          "Change",
3212     NULL, NULL, NULL,                           "Configure custom element change pages"
3213   },
3214
3215   // ---------- level and editor settings (buttons) ---------------------------
3216
3217   {
3218     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3219     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(10),
3220     GADGET_ID_SAVE_LEVELSET,                    GADGET_ID_LEVELSET_SAVE_MODE,
3221     -1,                                         "Save",
3222     NULL, NULL, NULL,                           "Update or create level set"
3223   },
3224   {
3225     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3226     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3227     GADGET_ID_SAVE_AS_TEMPLATE_2,               GADGET_ID_NONE,
3228     -1,                                         "Save",
3229     NULL, NULL,                                 "this level as level template",
3230     "Save current settings as new template"
3231   },
3232
3233   // ---------- element settings (buttons) ------------------------------------
3234
3235   {
3236     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3237     -1,                                         -1,
3238     GADGET_ID_SAVE_AS_TEMPLATE_1,               GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3239     -1,                                         "Save",
3240     NULL, " ",                                  "As Template",
3241     "Save current settings as new template"
3242   },
3243   {
3244     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3245     -1,                                         -1,
3246     GADGET_ID_ADD_CHANGE_PAGE,                  GADGET_ID_PASTE_CHANGE_PAGE,
3247     -1,                                         "New",
3248     NULL, NULL, NULL,                           "Add new change page"
3249   },
3250   {
3251     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3252     -1,                                         -1,
3253     GADGET_ID_DEL_CHANGE_PAGE,                  GADGET_ID_ADD_CHANGE_PAGE,
3254     -1,                                         "Delete",
3255     NULL, NULL, NULL,                           "Delete current change page"
3256   },
3257 };
3258
3259 static struct
3260 {
3261   int gadget_type_id;
3262   int graphic;
3263   int x, y;
3264   int gadget_id;
3265   int gadget_id_align;
3266   char *text_left, *text_right, *infotext;
3267 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3268 {
3269   {
3270     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3271     IMG_EDITOR_COUNTER_DOWN,
3272     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3273     GADGET_ID_PREV_CHANGE_PAGE,                 GADGET_ID_NONE,
3274     NULL, NULL,                                 "Select previous change page"
3275   },
3276   {
3277     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3278     IMG_EDITOR_COUNTER_UP,
3279     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3280     GADGET_ID_NEXT_CHANGE_PAGE,                 GADGET_ID_SELECT_CHANGE_PAGE,
3281     NULL, "Change page",                        "Select next change page"
3282   },
3283   {
3284     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3285     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3286     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3287     GADGET_ID_COPY_CHANGE_PAGE,                 GADGET_ID_NEXT_CHANGE_PAGE,
3288     " ", NULL,                                  "Copy settings from this change page"
3289   },
3290   {
3291     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3292     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3293     -1,                                         ED_ELEMENT_SETTINGS_YPOS(14),
3294     GADGET_ID_PASTE_CHANGE_PAGE,                GADGET_ID_COPY_CHANGE_PAGE,
3295     NULL, NULL,                                 "Paste settings to this change page"
3296   },
3297 };
3298
3299 static struct
3300 {
3301   int x, y;
3302 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3303
3304 static struct
3305 {
3306   int gadget_type_id;
3307   int graphic;
3308   int gadget_id;
3309   char *infotext;
3310 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3311 {
3312   {
3313     ED_SCROLLBUTTON_ID_AREA_UP,
3314     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3315     GADGET_ID_SCROLL_UP,
3316     "Scroll level editing area up"
3317   },
3318   {
3319     ED_SCROLLBUTTON_ID_AREA_DOWN,
3320     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3321     GADGET_ID_SCROLL_DOWN,
3322     "Scroll level editing area down"
3323   },
3324   {
3325     ED_SCROLLBUTTON_ID_AREA_LEFT,
3326     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3327     GADGET_ID_SCROLL_LEFT,
3328     "Scroll level editing area left"
3329   },
3330   {
3331     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3332     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3333     GADGET_ID_SCROLL_RIGHT,
3334     "Scroll level editing area right"
3335   },
3336   {
3337     ED_SCROLLBUTTON_ID_LIST_UP,
3338     IMG_EDITOR_PALETTE_SCROLL_UP,
3339     GADGET_ID_SCROLL_LIST_UP,
3340     "Scroll element list up ('Page Up')"
3341   },
3342   {
3343     ED_SCROLLBUTTON_ID_LIST_DOWN,
3344     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3345     GADGET_ID_SCROLL_LIST_DOWN,
3346     "Scroll element list down ('Page Down')"
3347   },
3348 };
3349
3350 static struct
3351 {
3352   int x, y;
3353   int width, height;
3354   int wheel_x, wheel_y;
3355   int wheel_width, wheel_height;
3356 } scrollbar_pos[ED_NUM_SCROLLBARS];
3357
3358 static struct
3359 {
3360   int gadget_type_id;
3361   int graphic;
3362   int type;
3363   int gadget_id;
3364   char *infotext;
3365 } scrollbar_info[ED_NUM_SCROLLBARS] =
3366 {
3367   {
3368     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3369     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3370     GD_TYPE_SCROLLBAR_HORIZONTAL,
3371     GADGET_ID_SCROLL_HORIZONTAL,
3372     "Scroll level editing area horizontally"
3373   },
3374   {
3375     ED_SCROLLBAR_ID_AREA_VERTICAL,
3376     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3377     GD_TYPE_SCROLLBAR_VERTICAL,
3378     GADGET_ID_SCROLL_VERTICAL,
3379     "Scroll level editing area vertically"
3380   },
3381   {
3382     ED_SCROLLBAR_ID_LIST_VERTICAL,
3383     IMG_EDITOR_PALETTE_SCROLLBAR,
3384     GD_TYPE_SCROLLBAR_VERTICAL,
3385     GADGET_ID_SCROLL_LIST_VERTICAL,
3386     "Scroll element list vertically"
3387   }
3388 };
3389
3390
3391 static struct
3392 {
3393   int gadget_type_id;
3394   int x, y;
3395   int gadget_id;
3396   int gadget_id_align;
3397   int radio_button_nr;
3398   int *value;
3399   int checked_value;
3400   char *text_left, *text_right, *infotext;
3401 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3402 {
3403   {
3404     ED_RADIOBUTTON_ID_PERCENTAGE,
3405     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3406     GADGET_ID_RANDOM_PERCENTAGE,                GADGET_ID_LEVEL_RANDOM_UP,
3407     RADIO_NR_RANDOM_ELEMENTS,
3408     &random_placement_method,                   RANDOM_USE_PERCENTAGE,
3409     " ", "percentage",                          "Use percentage for random elements"
3410   },
3411   {
3412     ED_RADIOBUTTON_ID_QUANTITY,
3413     -1,                                         ED_LEVEL_SETTINGS_YPOS(0),
3414     GADGET_ID_RANDOM_QUANTITY,                  GADGET_ID_RANDOM_PERCENTAGE,
3415     RADIO_NR_RANDOM_ELEMENTS,
3416     &random_placement_method,                   RANDOM_USE_QUANTITY,
3417     " ", "quantity",                            "Use quantity for random elements"
3418   }
3419 };
3420
3421 static struct
3422 {
3423   int gadget_type_id;
3424   int x, y;
3425   int gadget_id;
3426   int gadget_id_align;
3427   boolean *value;
3428   char *text_above, *text_left, *text_right, *infotext;
3429 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3430 {
3431   // ---------- level and editor settings -------------------------------------
3432
3433   {
3434     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3435     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3436     GADGET_ID_AUTO_COUNT_GEMS,                  GADGET_ID_NONE,
3437     &level.auto_count_gems,
3438     NULL, NULL,
3439     "Automatically count gems needed",          "Set counter to number of gems"
3440   },
3441   {
3442     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3443     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(11),
3444     GADGET_ID_RATE_TIME_OVER_SCORE,             GADGET_ID_NONE,
3445     &level.rate_time_over_score,
3446     NULL, NULL,
3447     "Rate time/steps used over score",          "Sort high scores by playing time/steps"
3448   },
3449   {
3450     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3451     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3452     GADGET_ID_USE_LEVELSET_ARTWORK,             GADGET_ID_NONE,
3453     &levelset_use_levelset_artwork,
3454     NULL, NULL,
3455     "Use current custom artwork",               "Use custom artwork of this level set"
3456   },
3457   {
3458     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3459     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3460     GADGET_ID_COPY_LEVEL_TEMPLATE,              GADGET_ID_NONE,
3461     &levelset_copy_level_template,
3462     NULL, NULL,
3463     "Copy current level template",              "Copy level template of this level set"
3464   },
3465   {
3466     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3467     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(1),
3468     GADGET_ID_RANDOM_RESTRICTED,                GADGET_ID_NONE,
3469     &random_placement_background_restricted,
3470     NULL, NULL,
3471     "Restrict random placement to:",            "Set random placement restriction"
3472   },
3473   {
3474     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3475     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(4),
3476     GADGET_ID_CUSTOM_USE_TEMPLATE_3,            GADGET_ID_NONE,
3477     &setup.editor.use_template_for_new_levels,
3478     "Template for new levels and CE/GE:", NULL,
3479     "Use template for new levels",              "Use template for level properties"
3480   },
3481   {
3482     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3483     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(5),
3484     GADGET_ID_CUSTOM_USE_TEMPLATE_2,            GADGET_ID_NONE,
3485     &level.use_custom_template,
3486     NULL, NULL,
3487     "Use template for custom elements",         "Use template for custom properties"
3488   },
3489   {
3490     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3491     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(0),
3492     GADGET_ID_BD_INTERMISSION,                  GADGET_ID_NONE,
3493     &level.bd_intermission,
3494     "Boulder Dash game engine settings:", NULL,
3495     "Intermission",                             "Level is an intermission level"
3496   },
3497   {
3498     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3499     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(2),
3500     GADGET_ID_BD_PAL_TIMING,                    GADGET_ID_NONE,
3501     &level.bd_pal_timing,
3502     NULL, NULL,
3503     "PAL timing",                               "Use slower timer (like PAL C64)"
3504   },
3505   {
3506     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3507     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(6),
3508     GADGET_ID_BD_LINE_SHIFTING_BORDERS,         GADGET_ID_NONE,
3509     &level.bd_line_shifting_borders,
3510     "Compatibility settings:", NULL,
3511     "Line-shifting borders",                    "Use line-shifting wrap-around"
3512   },
3513   {
3514     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3515     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(7),
3516     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,       GADGET_ID_NONE,
3517     &level.bd_scan_first_and_last_row,
3518     NULL, NULL,
3519     "Scan first and last row",                  "Also process top/bottom border rows"
3520   },
3521   {
3522     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3523     ED_LEVEL_SETTINGS_XPOS(0),                  ED_LEVEL_SETTINGS_YPOS(8),
3524     GADGET_ID_BD_SHORT_EXPLOSIONS,              GADGET_ID_NONE,
3525     &level.bd_short_explosions,
3526     NULL, NULL,
3527     "Short explosions",                         "Use four game cycles for explosions"
3528   },
3529
3530   // ---------- element settings: configure (various elements) ----------------
3531
3532   {
3533     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3534     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3535     GADGET_ID_STICK_ELEMENT,                    GADGET_ID_NONE,
3536     &stick_element_properties_window,
3537     NULL, NULL,
3538     "Stick this screen to edit content",        "Stick this screen to edit content"
3539   },
3540   {
3541     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3542     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3543     GADGET_ID_EM_SLIPPERY_GEMS,                 GADGET_ID_NONE,
3544     &level.em_slippery_gems,
3545     NULL, NULL,
3546     "Slip down from certain flat walls",        "Use EM/DC style slipping behaviour"
3547   },
3548   {
3549     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3550     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3551     GADGET_ID_EM_EXPLODES_BY_FIRE,              GADGET_ID_NONE,
3552     &level.em_explodes_by_fire,
3553     NULL, NULL,
3554     "Explodes with chain reaction",             "Use R'n'D style explosion behaviour"
3555   },
3556   {
3557     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3558     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3559     GADGET_ID_USE_SPRING_BUG,                   GADGET_ID_NONE,
3560     &level.use_spring_bug,
3561     NULL, NULL,
3562     "Use spring pushing bug",                   "Use odd spring pushing behaviour"
3563   },
3564   {
3565     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3566     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3567     GADGET_ID_USE_TIME_ORB_BUG,                 GADGET_ID_NONE,
3568     &level.use_time_orb_bug,
3569     NULL, NULL,
3570     "Use time orb bug",                         "Use odd time orb behaviour"
3571   },
3572   {
3573     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3574     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3575     GADGET_ID_USE_LIFE_BUGS,                    GADGET_ID_NONE,
3576     &level.use_life_bugs,
3577     NULL, NULL,
3578     "Use buggy element behaviour",              "Use odd (historic) element behaviour"
3579   },
3580   {
3581     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3582     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3583     GADGET_ID_RANDOM_BALL_CONTENT,              GADGET_ID_NONE,
3584     &level.ball_random,
3585     NULL, NULL,
3586     "Create single random element",             "Only create one element from content"
3587   },
3588   {
3589     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3590     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3591     GADGET_ID_INITIAL_BALL_ACTIVE,              GADGET_ID_NONE,
3592     &level.ball_active_initial,
3593     NULL, NULL,
3594     "Magic ball initially activated",           "Activate magic ball after level start"
3595   },
3596   {
3597     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3598     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3599     GADGET_ID_GROW_INTO_DIGGABLE,               GADGET_ID_NONE,
3600     &level.grow_into_diggable,
3601     NULL, NULL,
3602     "Can grow into anything diggable",          "Grow into more than just sand"
3603   },
3604   {
3605     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3606     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3607     GADGET_ID_SB_FIELDS_NEEDED,                 GADGET_ID_NONE,
3608     &level.sb_fields_needed,
3609     NULL, NULL,
3610     "All fields need to be filled",             "Require all SB fields to be solved"
3611   },
3612   {
3613     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3614     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3615     GADGET_ID_SB_OBJECTS_NEEDED,                GADGET_ID_NONE,
3616     &level.sb_objects_needed,
3617     NULL, NULL,
3618     "All objects need to be placed",            "Require all SB objects to be solved"
3619   },
3620   {
3621     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3622     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3623     GADGET_ID_AUTO_EXIT_SOKOBAN,                GADGET_ID_NONE,
3624     &level.auto_exit_sokoban,
3625     NULL, NULL,
3626     "Exit level if all tasks solved",           "Automatically finish Sokoban levels"
3627   },
3628   {
3629     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3630     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
3631     GADGET_ID_SOLVED_BY_ONE_PLAYER,             GADGET_ID_NONE,
3632     &level.solved_by_one_player,
3633     NULL, NULL,
3634     "Only one player must enter exit",          "Level solved by first player in exit"
3635   },
3636   {
3637     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3638     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3639     GADGET_ID_FINISH_DIG_COLLECT,               GADGET_ID_NONE,
3640     &level.finish_dig_collect,
3641     NULL, NULL,
3642     "CE action on finished dig/collect",        "Only finished dig/collect triggers CE"
3643   },
3644   {
3645     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3646     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3647     GADGET_ID_KEEP_WALKABLE_CE,                 GADGET_ID_NONE,
3648     &level.keep_walkable_ce,
3649     NULL, NULL,
3650     "Keep walkable CE changed to player",       "Keep CE changing to player if walkable"
3651   },
3652   {
3653     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3654     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3655     GADGET_ID_CONTINUOUS_SNAPPING,              GADGET_ID_NONE,
3656     &level.continuous_snapping,
3657     NULL, NULL,
3658     "Continuous snapping",                      "Use snapping without releasing key"
3659   },
3660   {
3661     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3662     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
3663     GADGET_ID_BLOCK_SNAP_FIELD,                 GADGET_ID_NONE,
3664     &level.block_snap_field,
3665     NULL, NULL,
3666     "Block snapped field when snapping",        "Use snapping delay to show animation"
3667   },
3668   {
3669     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3670     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3671     GADGET_ID_BLOCK_LAST_FIELD,                 GADGET_ID_NONE,
3672     &level.block_last_field,
3673     NULL, NULL,
3674     "Block last field when moving",             "Player blocks last field when moving"
3675   },
3676   {
3677     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3678     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3679     GADGET_ID_SP_BLOCK_LAST_FIELD,              GADGET_ID_NONE,
3680     &level.sp_block_last_field,
3681     NULL, NULL,
3682     "Block last field when moving",             "Player blocks last field when moving"
3683   },
3684   {
3685     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3686     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3687     GADGET_ID_INSTANT_RELOCATION,               GADGET_ID_NONE,
3688     &level.instant_relocation,
3689     NULL, NULL,
3690     "No scrolling when relocating",             "Player gets relocated without delay"
3691   },
3692   {
3693     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3694     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3695     GADGET_ID_SHIFTED_RELOCATION,               GADGET_ID_NONE,
3696     &level.shifted_relocation,
3697     NULL, NULL,
3698     "No centering when relocating",             "Level not centered after relocation"
3699   },
3700   {
3701     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3702     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
3703     GADGET_ID_LAZY_RELOCATION,                  GADGET_ID_NONE,
3704     &level.lazy_relocation,
3705     NULL, NULL,
3706     "Only redraw off-screen relocation",        "No redraw if relocation target visible"
3707   },
3708   {
3709     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3710     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
3711     GADGET_ID_USE_START_ELEMENT,                GADGET_ID_NONE,
3712     &level.use_start_element[0],
3713     NULL, NULL,
3714     "Use level start element:",                "Start level at this element's position"
3715   },
3716   {
3717     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3718     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
3719     GADGET_ID_USE_ARTWORK_ELEMENT,              GADGET_ID_NONE,
3720     &level.use_artwork_element[0],
3721     NULL, NULL,
3722     "Use artwork from element:",                "Use player artwork from other element"
3723   },
3724   {
3725     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3726     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(12),
3727     GADGET_ID_USE_EXPLOSION_ELEMENT,            GADGET_ID_NONE,
3728     &level.use_explosion_element[0],
3729     NULL, NULL,
3730     "Use explosion from element:",              "Use explosion properties from element"
3731   },
3732   {
3733     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3734     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
3735     GADGET_ID_INITIAL_GRAVITY,                  GADGET_ID_NONE,
3736     &level.initial_player_gravity[0],
3737     NULL, NULL,
3738     "Use initial gravity",                      "Set initial player gravity"
3739   },
3740   {
3741     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3742     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3743     GADGET_ID_USE_INITIAL_INVENTORY,            GADGET_ID_NONE,
3744     &level.use_initial_inventory[0],
3745     NULL, NULL,
3746     "Use initial inventory:",                   "Use collected elements on level start"
3747   },
3748   {
3749     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3750     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
3751     GADGET_ID_CAN_PASS_TO_WALKABLE,             GADGET_ID_NONE,
3752     &level.can_pass_to_walkable,
3753     NULL, NULL,
3754     "Can pass to walkable element",             "Player can pass to empty or walkable"
3755   },
3756   {
3757     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3758     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3759     GADGET_ID_CAN_FALL_INTO_ACID,               GADGET_ID_NONE,
3760     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3761     NULL, NULL,
3762     "Can fall into acid (with gravity)",        "Player can fall into acid pool"
3763   },
3764   {
3765     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3766     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3767     GADGET_ID_CAN_MOVE_INTO_ACID,               GADGET_ID_NONE,
3768     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3769     NULL, NULL,
3770     "Can move into acid",                       "Element can move into acid pool"
3771   },
3772   {
3773     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3774     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3775     GADGET_ID_DONT_COLLIDE_WITH,                GADGET_ID_NONE,
3776     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3777     NULL, NULL,
3778     "Deadly when colliding with",               "Element is deadly when hitting player"
3779   },
3780   {
3781     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3782     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3783     GADGET_ID_BD_DIAGONAL_MOVEMENTS,            GADGET_ID_NONE,
3784     &level.bd_diagonal_movements,
3785     NULL, NULL,
3786     "Can move diagonally",                      "Player can move diagonally"
3787   },
3788   {
3789     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3790     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3791     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,         GADGET_ID_NONE,
3792     &level.bd_topmost_player_active,
3793     NULL, NULL,
3794     "Topmost player is active",                 "Use first player found on playfield"
3795   },
3796   {
3797     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3798     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
3799     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,     GADGET_ID_NONE,
3800     &level.bd_push_mega_rock_with_sweet,
3801     NULL, NULL,
3802     "Mega rocks pushable with sweet",           "Push mega rocks after eating sweet"
3803   },
3804   {
3805     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3806     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3807     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,      GADGET_ID_NONE,
3808     &level.bd_magic_wall_wait_hatching,
3809     NULL, NULL,
3810     "Wait for player's birth",                  "Timer start waits for player's birth"
3811   },
3812   {
3813     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3814     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3815     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,       GADGET_ID_NONE,
3816     &level.bd_magic_wall_stops_amoeba,
3817     NULL, NULL,
3818     "Turn amoeba to diamonds",                  "Activation changes amoeba to diamonds"
3819   },
3820   {
3821     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3822     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3823     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,      GADGET_ID_NONE,
3824     &level.bd_amoeba_wait_for_hatching,
3825     NULL, NULL,
3826     "Wait for player's birth",                  "Timer start waits for player's birth"
3827   },
3828   {
3829     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3830     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3831     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,      GADGET_ID_NONE,
3832     &level.bd_amoeba_start_immediately,
3833     NULL, NULL,
3834     "Start growing immediately",                "Start slow growth time immediately"
3835   },
3836   {
3837     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3838     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
3839     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,    GADGET_ID_NONE,
3840     &level.bd_amoeba_2_explode_by_amoeba,
3841     NULL, NULL,
3842     "Explodes if touched by amoeba",            "Amoeba 2 explodes if touched by amoeba"
3843   },
3844   {
3845     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3846     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3847     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,      GADGET_ID_NONE,
3848     &level.bd_voodoo_collects_diamonds,
3849     NULL, NULL,
3850     "Can collect diamonds",                     "Can collect diamonds for the player"
3851   },
3852   {
3853     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3854     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3855     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,      GADGET_ID_NONE,
3856     &level.bd_voodoo_hurt_kills_player,
3857     NULL, NULL,
3858     "Player is killed if hurt",                 "If hurt in any way, player is killed"
3859   },
3860   {
3861     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3862     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3863     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,           GADGET_ID_NONE,
3864     &level.bd_voodoo_dies_by_rock,
3865     NULL, NULL,
3866     "Killed by falling rock",                   "Can be killed by a falling rock"
3867   },
3868   {
3869     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3870     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3871     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,    GADGET_ID_NONE,
3872     &level.bd_voodoo_vanish_by_explosion,
3873     NULL, NULL,
3874     "Disappears in explosions",                 "Can be destroyed by explosions"
3875   },
3876   {
3877     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3878     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3879     GADGET_ID_BD_SLIME_IS_PREDICTABLE,          GADGET_ID_NONE,
3880     &level.bd_slime_is_predictable,
3881     NULL, NULL,
3882     "Slime is predictable",                     "Use predictable random numbers"
3883   },
3884   {
3885     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3886     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3887     GADGET_ID_BD_CHANGE_EXPANDING_WALL,         GADGET_ID_NONE,
3888     &level.bd_change_expanding_wall,
3889     NULL, NULL,
3890     "Change direction",                         "Switch horizontal/vertical direction"
3891   },
3892   {
3893     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3894     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3895     GADGET_ID_BD_REPLICATORS_ACTIVE,            GADGET_ID_NONE,
3896     &level.bd_replicators_active,
3897     NULL, NULL,
3898     "Active at start",                          "Replicators start in active state"
3899   },
3900   {
3901     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3902     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3903     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,         GADGET_ID_NONE,
3904     &level.bd_conveyor_belts_active,
3905     NULL, NULL,
3906     "Active at start",                          "Conveyor belts start in active state"
3907   },
3908   {
3909     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3910     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3911     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,        GADGET_ID_NONE,
3912     &level.bd_conveyor_belts_changed,
3913     NULL, NULL,
3914     "Change direction",                         "Switch conveyor belt direction"
3915   },
3916   {
3917     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3918     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3919     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,        GADGET_ID_NONE,
3920     &level.bd_water_cannot_flow_down,
3921     NULL, NULL,
3922     "Does not flow downwards",                  "Water can only flow up, left and right"
3923   },
3924   {
3925     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3926     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3927     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,         GADGET_ID_NONE,
3928     &level.bd_hammer_walls_reappear,
3929     NULL, NULL,
3930     "Hammered walls reappear",                  "Hammered walls reappear after delay"
3931   },
3932   {
3933     ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
3934     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(0),
3935     GADGET_ID_BD_CREATURES_START_BACKWARDS,     GADGET_ID_NONE,
3936     &level.bd_creatures_start_backwards,
3937     NULL, NULL,
3938     "Creatures start moving backwards",         "Creatures start in opposite direction"
3939   },
3940   {
3941     ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
3942     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3943     GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,    GADGET_ID_NONE,
3944     &level.bd_creatures_turn_on_hatching,
3945     NULL, NULL,
3946     "Creatures turn on hatching",               "Creatures change direction on hatching"
3947   },
3948   {
3949     ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
3950     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3951     GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,         GADGET_ID_NONE,
3952     &level.bd_gravity_switch_active,
3953     NULL, NULL,
3954     "Gravity switch active at start",           "Gravity switch starts in active state"
3955   },
3956   {
3957     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
3958     ED_LEVEL_SETTINGS_XPOS(0),                  ED_ELEMENT_SETTINGS_YPOS(3),
3959     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,           GADGET_ID_NONE,
3960     &level.bd_gravity_affects_all,
3961     NULL, NULL,
3962     "Gravity change affects everything",        "Gravity affects all falling objects"
3963   },
3964   {
3965     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
3966     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3967     GADGET_ID_ENVELOPE_AUTOWRAP,                GADGET_ID_NONE,
3968     &level.envelope[0].autowrap,
3969     NULL, NULL,
3970     "Auto-wrap",                                "Automatically wrap envelope text"
3971   },
3972   {
3973     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
3974     -1,                                         ED_ELEMENT_SETTINGS_YPOS(1),
3975     GADGET_ID_ENVELOPE_CENTERED,                GADGET_ID_ENVELOPE_AUTOWRAP,
3976     &level.envelope[0].centered,
3977     NULL, " ",
3978     "Centered",                                 "Automatically center envelope text"
3979   },
3980   {
3981     ED_CHECKBUTTON_ID_MM_LASER_RED,
3982     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
3983     GADGET_ID_MM_LASER_RED,                     GADGET_ID_NONE,
3984     &level.mm_laser_red,
3985     "Choose color components for laser:", NULL,
3986     "Red",                                      "Use red color components in laser"
3987   },
3988   {
3989     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
3990     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
3991     GADGET_ID_MM_LASER_GREEN,                   GADGET_ID_NONE,
3992     &level.mm_laser_green,
3993     NULL, NULL,
3994     "Green",                                    "Use green color components in laser"
3995   },
3996   {
3997     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
3998     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
3999     GADGET_ID_MM_LASER_BLUE,                    GADGET_ID_NONE,
4000     &level.mm_laser_blue,
4001     NULL, NULL,
4002     "Blue",                                     "Use blue color components in laser"
4003   },
4004   {
4005     ED_CHECKBUTTON_ID_DF_LASER_RED,
4006     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4007     GADGET_ID_DF_LASER_RED,                     GADGET_ID_NONE,
4008     &level.df_laser_red,
4009     "Choose color components for laser:", NULL,
4010     "Red",                                      "Use red color components in laser"
4011   },
4012   {
4013     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
4014     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4015     GADGET_ID_DF_LASER_GREEN,                   GADGET_ID_NONE,
4016     &level.df_laser_green,
4017     NULL, NULL,
4018     "Green",                                    "Use green color components in laser"
4019   },
4020   {
4021     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
4022     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(3),
4023     GADGET_ID_DF_LASER_BLUE,                    GADGET_ID_NONE,
4024     &level.df_laser_blue,
4025     NULL, NULL,
4026     "Blue",                                     "Use blue color components in laser"
4027   },
4028   {
4029     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
4030     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(5),
4031     GADGET_ID_ROTATE_MM_BALL_CONTENT,           GADGET_ID_NONE,
4032     &level.rotate_mm_ball_content,
4033     NULL, NULL,
4034     "Randomly rotate created content",          "Randomly rotate newly created content"
4035   },
4036   {
4037     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
4038     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(6),
4039     GADGET_ID_EXPLODE_MM_BALL,                  GADGET_ID_NONE,
4040     &level.explode_mm_ball,
4041     NULL, NULL,
4042     "Explode ball instead of melting",          "Use explosion to release ball content"
4043   },
4044
4045   // ---------- element settings: configure 1 (custom elements) ---------------
4046
4047   {
4048     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
4049     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4050     GADGET_ID_CUSTOM_USE_GRAPHIC,               GADGET_ID_NONE,
4051     &custom_element.use_gfx_element,
4052     NULL, NULL,
4053     "Use graphic of element:",                  "Use existing element graphic"
4054   },
4055   {
4056     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
4057     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(14),
4058     GADGET_ID_CUSTOM_USE_TEMPLATE_1,            GADGET_ID_NONE,
4059     &level.use_custom_template,
4060     NULL, NULL,
4061     "Use template",                             "Use template for custom properties"
4062   },
4063   {
4064     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4065     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(2),
4066     GADGET_ID_CUSTOM_ACCESSIBLE,                GADGET_ID_NONE,
4067     &custom_element_properties[EP_ACCESSIBLE],
4068     NULL, NULL,
4069     NULL,                                       "Player can walk to or pass this field"
4070   },
4071   {
4072     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4073     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4074     GADGET_ID_CUSTOM_GRAV_REACHABLE,            GADGET_ID_NONE,
4075     &custom_element_properties[EP_GRAVITY_REACHABLE],
4076     NULL, NULL,
4077     "Reachable despite gravity",                "Player can walk/dig despite gravity"
4078   },
4079   {
4080     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4081     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4082     GADGET_ID_CUSTOM_USE_LAST_VALUE,            GADGET_ID_NONE,
4083     &custom_element.use_last_ce_value,
4084     NULL, NULL,
4085     "Use last CE value after change",           "Use last CE value after change"
4086   },
4087   {
4088     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4089     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(4),
4090     GADGET_ID_CUSTOM_WALK_TO_OBJECT,            GADGET_ID_NONE,
4091     &custom_element_properties[EP_WALK_TO_OBJECT],
4092     NULL, NULL,
4093     NULL,                                       "Player can dig/collect/push element"
4094   },
4095   {
4096     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4097     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4098     GADGET_ID_CUSTOM_INDESTRUCTIBLE,            GADGET_ID_NONE,
4099     &custom_element_properties[EP_INDESTRUCTIBLE],
4100     NULL, NULL,
4101     "Indestructible",                           "Element is indestructible"
4102   },
4103
4104   // ---------- element settings: configure 2 (custom elements) ---------------
4105
4106   {
4107     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4108     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4109     GADGET_ID_CUSTOM_CAN_MOVE,                  GADGET_ID_NONE,
4110     &custom_element_properties[EP_CAN_MOVE],
4111     NULL, NULL,
4112     NULL,                                       "Element can move with some pattern"
4113   },
4114   {
4115     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4116     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(8),
4117     GADGET_ID_CUSTOM_CAN_FALL,                  GADGET_ID_NONE,
4118     &custom_element_properties[EP_CAN_FALL],
4119     NULL, NULL,
4120     "Can fall",                                 "Element can fall down"
4121   },
4122   {
4123     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4124     -1,                                         ED_ELEMENT_SETTINGS_YPOS(8),
4125     GADGET_ID_CUSTOM_CAN_SMASH,                 GADGET_ID_CUSTOM_CAN_FALL,
4126     &custom_element_properties[EP_CAN_SMASH],
4127     NULL, " ",
4128     NULL,                                       "Element can smash other elements"
4129   },
4130   {
4131     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4132     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(9),
4133     GADGET_ID_CUSTOM_SLIPPERY,                  GADGET_ID_NONE,
4134     &custom_element_properties[EP_SLIPPERY],
4135     NULL, NULL,
4136     NULL,                                       "Other elements can fall down from it"
4137   },
4138   {
4139     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4140     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(10),
4141     GADGET_ID_CUSTOM_DEADLY,                    GADGET_ID_NONE,
4142     &custom_element_properties[EP_DEADLY],
4143     NULL, NULL,
4144     NULL,                                       "Element can kill the player"
4145   },
4146   {
4147     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4148     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(11),
4149     GADGET_ID_CUSTOM_CAN_EXPLODE,               GADGET_ID_NONE,
4150     &custom_element_properties[EP_CAN_EXPLODE],
4151     NULL, NULL,
4152     NULL,                                       "Element can explode"
4153   },
4154   {
4155     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4156     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(12),
4157     GADGET_ID_CUSTOM_EXPLODE_FIRE,              GADGET_ID_NONE,
4158     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4159     NULL, NULL,
4160     "By fire",                                  "Element can explode by fire/explosion"
4161   },
4162   {
4163     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4164     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4165     GADGET_ID_CUSTOM_EXPLODE_SMASH,             GADGET_ID_CUSTOM_EXPLODE_FIRE,
4166     &custom_element_properties[EP_EXPLODES_SMASHED],
4167     NULL, " ",
4168     "Smashed",                                  "Element can explode when smashed"
4169   },
4170   {
4171     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4172     -1,                                         ED_ELEMENT_SETTINGS_YPOS(12),
4173     GADGET_ID_CUSTOM_EXPLODE_IMPACT,            GADGET_ID_CUSTOM_EXPLODE_SMASH,
4174     &custom_element_properties[EP_EXPLODES_IMPACT],
4175     NULL, " ",
4176     "Impact",                                   "Element can explode on impact"
4177   },
4178
4179   // ---------- element settings: advanced (custom elements) ------------------
4180
4181   {
4182     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4183     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(1),
4184     GADGET_ID_CUSTOM_CAN_CHANGE,                GADGET_ID_NONE,
4185     &custom_element_change.can_change,
4186     NULL, NULL,
4187     "Element changes to:",                      "Change element on specified condition"
4188   },
4189   {
4190     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4191     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(2),
4192     GADGET_ID_CHANGE_DELAY,                     GADGET_ID_NONE,
4193     &custom_element_change_events[CE_DELAY],
4194     NULL, NULL,
4195     NULL,                                       "Element changes after delay"
4196   },
4197   {
4198     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4199     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(4),
4200     GADGET_ID_CHANGE_BY_DIRECT_ACT,             GADGET_ID_NONE,
4201     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4202     NULL, NULL,
4203     NULL,                                       "Element changes by direct action"
4204   },
4205   {
4206     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4207     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(5),
4208     GADGET_ID_CHANGE_BY_OTHER_ACT,              GADGET_ID_NONE,
4209     &custom_element_change_events[CE_BY_OTHER_ACTION],
4210     NULL, NULL,
4211     NULL,                                       "Element changes by other element"
4212   },
4213   {
4214     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4215     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(8),
4216     GADGET_ID_CHANGE_USE_EXPLOSION,             GADGET_ID_NONE,
4217     &custom_element_change.explode,
4218     NULL, NULL,
4219     "Explode instead of change",                "Element explodes instead of change"
4220   },
4221   {
4222     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4223     ED_ELEMENT_SETTINGS_XPOS(1),                ED_ELEMENT_SETTINGS_YPOS(9),
4224     GADGET_ID_CHANGE_USE_CONTENT,               GADGET_ID_NONE,
4225     &custom_element_change.use_target_content,
4226     NULL, NULL,
4227     "Use extended change target:",              "Element changes to more elements"
4228   },
4229   {
4230     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4231     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(11),
4232     GADGET_ID_CHANGE_ONLY_COMPLETE,             GADGET_ID_NONE,
4233     &custom_element_change.only_if_complete,
4234     NULL, NULL,
4235     "Replace all or nothing",                   "Only replace when all can be changed"
4236   },
4237   {
4238     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4239     ED_ELEMENT_SETTINGS_XPOS(2),                ED_ELEMENT_SETTINGS_YPOS(12),
4240     GADGET_ID_CHANGE_USE_RANDOM,                GADGET_ID_NONE,
4241     &custom_element_change.use_random_replace,
4242     NULL, NULL,
4243     NULL,                                       "Use percentage for random replace"
4244   },
4245   {
4246     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4247     ED_ELEMENT_SETTINGS_XPOS(0),                ED_ELEMENT_SETTINGS_YPOS(13),
4248     GADGET_ID_CHANGE_HAS_ACTION,                GADGET_ID_NONE,
4249     &custom_element_change.has_action,
4250     NULL, NULL,
4251     NULL,                                       "Execute action on specified condition"
4252   },
4253 };
4254
4255 static struct
4256 {
4257   int gadget_type_id;
4258   int x, y;
4259   int xoffset, yoffset;
4260   int gadget_id;
4261   int gadget_id_align;
4262   int *value;
4263   int area_xsize, area_ysize;
4264   char *text_left, *text_right, *text_above, *text_below, *infotext;
4265 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4266 {
4267   // ---------- level playfield content ---------------------------------------
4268
4269   {
4270     ED_DRAWING_ID_DRAWING_LEVEL,
4271     0,                                          0,
4272     0,                                          0,
4273     GADGET_ID_DRAWING_LEVEL,                    GADGET_ID_NONE,
4274     NULL,
4275     -1, -1,     // these values are not constant, but can change at runtime
4276     NULL, NULL, NULL, NULL,                     NULL
4277   },
4278
4279   // ---------- yam yam content -----------------------------------------------
4280
4281   {
4282     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4283     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4284     ED_AREA_YAMYAM_CONTENT_XOFF(0),             ED_AREA_YAMYAM_CONTENT_YOFF(0),
4285     GADGET_ID_YAMYAM_CONTENT_0,                 GADGET_ID_NONE,
4286     &level.yamyam_content[0].e[0][0],           3, 3,
4287     NULL, NULL, NULL, "1",                      NULL
4288   },
4289   {
4290     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4291     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4292     ED_AREA_YAMYAM_CONTENT_XOFF(1),             ED_AREA_YAMYAM_CONTENT_YOFF(1),
4293     GADGET_ID_YAMYAM_CONTENT_1,                 GADGET_ID_NONE,
4294     &level.yamyam_content[1].e[0][0],           3, 3,
4295     NULL, NULL, NULL, "2",                      NULL
4296   },
4297   {
4298     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4299     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4300     ED_AREA_YAMYAM_CONTENT_XOFF(2),             ED_AREA_YAMYAM_CONTENT_YOFF(2),
4301     GADGET_ID_YAMYAM_CONTENT_2,                 GADGET_ID_NONE,
4302     &level.yamyam_content[2].e[0][0],           3, 3,
4303     NULL, NULL, NULL, "3",                      NULL
4304   },
4305   {
4306     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4307     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4308     ED_AREA_YAMYAM_CONTENT_XOFF(3),             ED_AREA_YAMYAM_CONTENT_YOFF(3),
4309     GADGET_ID_YAMYAM_CONTENT_3,                 GADGET_ID_NONE,
4310     &level.yamyam_content[3].e[0][0],           3, 3,
4311     NULL, NULL, NULL, "4",                      NULL
4312   },
4313   {
4314     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4315     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4316     ED_AREA_YAMYAM_CONTENT_XOFF(4),             ED_AREA_YAMYAM_CONTENT_YOFF(4),
4317     GADGET_ID_YAMYAM_CONTENT_4,                 GADGET_ID_NONE,
4318     &level.yamyam_content[4].e[0][0],           3, 3,
4319     NULL, NULL, NULL, "5",                      NULL
4320   },
4321   {
4322     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4323     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4324     ED_AREA_YAMYAM_CONTENT_XOFF(5),             ED_AREA_YAMYAM_CONTENT_YOFF(5),
4325     GADGET_ID_YAMYAM_CONTENT_5,                 GADGET_ID_NONE,
4326     &level.yamyam_content[5].e[0][0],           3, 3,
4327     NULL, NULL, NULL, "6",                      NULL
4328   },
4329   {
4330     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4331     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4332     ED_AREA_YAMYAM_CONTENT_XOFF(6),             ED_AREA_YAMYAM_CONTENT_YOFF(6),
4333     GADGET_ID_YAMYAM_CONTENT_6,                 GADGET_ID_NONE,
4334     &level.yamyam_content[6].e[0][0],           3, 3,
4335     NULL, NULL, NULL, "7",                      NULL
4336   },
4337   {
4338     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4339     ED_AREA_YAMYAM_CONTENT_XPOS,                ED_AREA_YAMYAM_CONTENT_YPOS,
4340     ED_AREA_YAMYAM_CONTENT_XOFF(7),             ED_AREA_YAMYAM_CONTENT_YOFF(7),
4341     GADGET_ID_YAMYAM_CONTENT_7,                 GADGET_ID_NONE,
4342     &level.yamyam_content[7].e[0][0],           3, 3,
4343     NULL, NULL, NULL, "8",                      NULL
4344   },
4345
4346   // ---------- magic ball content --------------------------------------------
4347
4348   {
4349     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4350     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4351     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4352     GADGET_ID_MAGIC_BALL_CONTENT_0,             GADGET_ID_NONE,
4353     &level.ball_content[0].e[0][0],             3, 3,
4354     NULL, NULL, NULL, "1",                      NULL
4355   },
4356   {
4357     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4358     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4359     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4360     GADGET_ID_MAGIC_BALL_CONTENT_1,             GADGET_ID_NONE,
4361     &level.ball_content[1].e[0][0],             3, 3,
4362     NULL, NULL, NULL, "2",                      NULL
4363   },
4364   {
4365     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4366     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4367     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4368     GADGET_ID_MAGIC_BALL_CONTENT_2,             GADGET_ID_NONE,
4369     &level.ball_content[2].e[0][0],             3, 3,
4370     NULL, NULL, NULL, "3",                      NULL
4371   },
4372   {
4373     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4374     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4375     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4376     GADGET_ID_MAGIC_BALL_CONTENT_3,             GADGET_ID_NONE,
4377     &level.ball_content[3].e[0][0],             3, 3,
4378     NULL, NULL, NULL, "4",                      NULL
4379   },
4380   {
4381     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4382     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4383     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4384     GADGET_ID_MAGIC_BALL_CONTENT_4,             GADGET_ID_NONE,
4385     &level.ball_content[4].e[0][0],             3, 3,
4386     NULL, NULL, NULL, "5",                      NULL
4387   },
4388   {
4389     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4390     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4391     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4392     GADGET_ID_MAGIC_BALL_CONTENT_5,             GADGET_ID_NONE,
4393     &level.ball_content[5].e[0][0],             3, 3,
4394     NULL, NULL, NULL, "6",                      NULL
4395   },
4396   {
4397     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4398     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4399     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4400     GADGET_ID_MAGIC_BALL_CONTENT_6,             GADGET_ID_NONE,
4401     &level.ball_content[6].e[0][0],             3, 3,
4402     NULL, NULL, NULL, "7",                      NULL
4403   },
4404   {
4405     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4406     ED_AREA_MAGIC_BALL_CONTENT_XPOS,            ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4407     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),         ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4408     GADGET_ID_MAGIC_BALL_CONTENT_7,             GADGET_ID_NONE,
4409     &level.ball_content[7].e[0][0],             3, 3,
4410     NULL, NULL, NULL, "8",                      NULL
4411   },
4412
4413   // ---------- android content -----------------------------------------------
4414
4415   {
4416     ED_DRAWING_ID_ANDROID_CONTENT,
4417     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4418     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4419     GADGET_ID_ANDROID_CONTENT,                  GADGET_ID_NONE,
4420     &level.android_clone_element[0],            MAX_ANDROID_ELEMENTS, 1,
4421     NULL, NULL, "Elements:", NULL,              "Elements android can clone"
4422   },
4423
4424   // ---------- amoeba content ------------------------------------------------
4425
4426   {
4427     ED_DRAWING_ID_AMOEBA_CONTENT,
4428     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4429     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4430     GADGET_ID_AMOEBA_CONTENT,                   GADGET_ID_NONE,
4431     &level.amoeba_content,                      1, 1,
4432     "Content:", NULL, NULL, NULL,               "Amoeba content"
4433   },
4434
4435   // ---------- BD snap element -----------------------------------------------
4436
4437   {
4438     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4439     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4440     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4441     GADGET_ID_BD_SNAP_ELEMENT,                  GADGET_ID_NONE,
4442     &level.bd_snap_element,                     1, 1,
4443     "Snap element:", NULL, NULL, NULL,          "Element created when snapping"
4444   },
4445
4446   // ---------- BD magic wall elements ----------------------------------------
4447
4448   {
4449     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4450     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(4),
4451     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4452     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,         GADGET_ID_NONE,
4453     &level.bd_magic_wall_diamond_to,            1, 1,
4454     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4455   },
4456   {
4457     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4458     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4459     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4460     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,            GADGET_ID_NONE,
4461     &level.bd_magic_wall_rock_to,               1, 1,
4462     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4463   },
4464   {
4465     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4466     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4467     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4468     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,       GADGET_ID_NONE,
4469     &level.bd_magic_wall_mega_rock_to,          1, 1,
4470     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4471   },
4472   {
4473     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4474     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4475     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4476     GADGET_ID_BD_MAGIC_WALL_NUT_TO,             GADGET_ID_NONE,
4477     &level.bd_magic_wall_nut_to,                1, 1,
4478     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4479   },
4480   {
4481     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4482     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4483     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4484     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,      GADGET_ID_NONE,
4485     &level.bd_magic_wall_nitro_pack_to,         1, 1,
4486     "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
4487   },
4488   {
4489     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4490     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(9),
4491     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4492     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,  GADGET_ID_NONE,
4493     &level.bd_magic_wall_flying_diamond_to,     1, 1,
4494     "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
4495   },
4496   {
4497     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4498     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4499     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4500     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,     GADGET_ID_NONE,
4501     &level.bd_magic_wall_flying_rock_to,        1, 1,
4502     "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
4503   },
4504
4505   // ---------- BD amoeba content ---------------------------------------------
4506
4507   {
4508     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4509     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4510     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4511     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,        GADGET_ID_NONE,
4512     &level.bd_amoeba_content_too_big,           1, 1,
4513     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba content if too big"
4514   },
4515   {
4516     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4517     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4518     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4519     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,       GADGET_ID_NONE,
4520     &level.bd_amoeba_content_enclosed,          1, 1,
4521     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba content if enclosed"
4522   },
4523
4524   // ---------- BD amoeba 2 content -------------------------------------------
4525
4526   {
4527     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4528     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4529     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4530     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,      GADGET_ID_NONE,
4531     &level.bd_amoeba_2_content_too_big,         1, 1,
4532     "If too big, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if too big"
4533   },
4534   {
4535     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4536     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(8),
4537     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4538     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,     GADGET_ID_NONE,
4539     &level.bd_amoeba_2_content_enclosed,        1, 1,
4540     "If enclosed, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if enclosed"
4541   },
4542   {
4543     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4544     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(10),
4545     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4546     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,    GADGET_ID_NONE,
4547     &level.bd_amoeba_2_content_exploding,       1, 1,
4548     "If exploding, changes to:", NULL, NULL, NULL, "BD amoeba 2 content if exploding"
4549   },
4550   {
4551     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4552     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(11),
4553     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4554     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4555     &level.bd_amoeba_2_content_looks_like,      1, 1,
4556     "Use graphic of element:", NULL, NULL, NULL, "BD amoeba 2 looks like this element"
4557   },
4558   {
4559     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4560     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4561     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4562     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,          GADGET_ID_NONE,
4563     &level.bd_slime_eats_element_1,             1, 1,
4564     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4565   },
4566   {
4567     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4568     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(5),
4569     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4570     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,   GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4571     &level.bd_slime_converts_to_element_1,      1, 1,
4572     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4573   },
4574   {
4575     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4576     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4577     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4578     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,          GADGET_ID_NONE,
4579     &level.bd_slime_eats_element_2,             1, 1,
4580     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4581   },
4582   {
4583     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4584     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(6),
4585     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4586     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,   GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4587     &level.bd_slime_converts_to_element_2,      1, 1,
4588     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4589   },
4590   {
4591     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4592     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4593     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4594     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,          GADGET_ID_NONE,
4595     &level.bd_slime_eats_element_3,             1, 1,
4596     "Can eat:", NULL, NULL, NULL,               "Element that can be eaten"
4597   },
4598   {
4599     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4600     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(7),
4601     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4602     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,   GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4603     &level.bd_slime_converts_to_element_3,      1, 1,
4604     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4605   },
4606   {
4607     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4608     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4609     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4610     GADGET_ID_BD_ACID_EATS_ELEMENT,             GADGET_ID_NONE,
4611     &level.bd_acid_eats_element,                1, 1,
4612     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4613   },
4614   {
4615     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4616     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4617     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4618     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,         GADGET_ID_NONE,
4619     &level.bd_acid_turns_to_element,            1, 1,
4620     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4621   },
4622   {
4623     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4624     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4625     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4626     GADGET_ID_BD_BITER_EATS_ELEMENT,            GADGET_ID_NONE,
4627     &level.bd_biter_eats_element,               1, 1,
4628     "Can eat:", NULL, NULL, NULL,               "Eats this element when moving"
4629   },
4630   {
4631     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4632     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4633     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4634     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,   GADGET_ID_NONE,
4635     &level.bd_bladder_converts_by_element,      1, 1,
4636     "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
4637   },
4638   {
4639     ED_DRAWING_ID_BD_NUT_CONTENT,
4640     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4641     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4642     GADGET_ID_BD_NUT_CONTENT,                   GADGET_ID_NONE,
4643     &level.bd_nut_content,                      1, 1,
4644     "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
4645   },
4646   {
4647     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4648     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(1),
4649     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4650     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,     GADGET_ID_NONE,
4651     &level.bd_expanding_wall_looks_like,        1, 1,
4652     "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
4653   },
4654   {
4655     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4656     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(0),
4657     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4658     GADGET_ID_BD_SAND_LOOKS_LIKE,               GADGET_ID_NONE,
4659     &level.bd_sand_looks_like,                  1, 1,
4660     "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
4661   },
4662   {
4663     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
4664     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4665     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4666     GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,      GADGET_ID_NONE,
4667     &level.bd_rock_turns_to_on_falling,         1, 1,
4668     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4669   },
4670   {
4671     ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
4672     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4673     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4674     GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,       GADGET_ID_NONE,
4675     &level.bd_rock_turns_to_on_impact,          1, 1,
4676     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4677   },
4678   {
4679     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
4680     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4681     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4682     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,   GADGET_ID_NONE,
4683     &level.bd_diamond_turns_to_on_falling,      1, 1,
4684     "Turns to when falling:", NULL, NULL, NULL, "Changes to this when falling starts"
4685   },
4686   {
4687     ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
4688     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(3),
4689     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4690     GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,    GADGET_ID_NONE,
4691     &level.bd_diamond_turns_to_on_impact,       1, 1,
4692     "Turns to on impact:", NULL, NULL, NULL,    "Changes to this when falling stops"
4693   },
4694
4695   // ---------- level start element -------------------------------------------
4696
4697   {
4698     ED_DRAWING_ID_START_ELEMENT,
4699     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(10),
4700     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4701     GADGET_ID_START_ELEMENT,                    GADGET_ID_USE_START_ELEMENT,
4702     &level.start_element[0],                    1, 1,
4703     NULL, NULL, NULL, NULL,                     "Level start element"
4704   },
4705
4706   // ---------- player artwork element ----------------------------------------
4707
4708   {
4709     ED_DRAWING_ID_ARTWORK_ELEMENT,
4710     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(11),
4711     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4712     GADGET_ID_ARTWORK_ELEMENT,                  GADGET_ID_USE_ARTWORK_ELEMENT,
4713     &level.artwork_element[0],                  1, 1,
4714     NULL, NULL, NULL, NULL,                     "Element for player artwork"
4715   },
4716
4717   // ---------- player explosion element --------------------------------------
4718
4719   {
4720     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4721     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(12),
4722     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4723     GADGET_ID_EXPLOSION_ELEMENT,                GADGET_ID_USE_EXPLOSION_ELEMENT,
4724     &level.explosion_element[0],                1, 1,
4725     NULL, NULL, NULL, NULL,                     "Element for player explosion"
4726   },
4727
4728   // ---------- player initial inventory --------------------------------------
4729
4730   {
4731     ED_DRAWING_ID_INVENTORY_CONTENT,
4732     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4733     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4734     GADGET_ID_INVENTORY_CONTENT,                GADGET_ID_USE_INITIAL_INVENTORY,
4735     &level.initial_inventory_content[0][0],     MAX_INITIAL_INVENTORY_SIZE, 1,
4736     NULL, NULL, NULL, NULL,                     "Content for initial inventory"
4737   },
4738
4739   // ---------- gray ball content -----------------------------------------
4740
4741   {
4742     ED_DRAWING_ID_MM_BALL_CONTENT,
4743     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4744     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4745     GADGET_ID_MM_BALL_CONTENT,                  GADGET_ID_NONE,
4746     &level.mm_ball_content[0],                  MAX_MM_BALL_CONTENTS, 1,
4747     "Content:", NULL, NULL, NULL,               "Content for gray ball"
4748   },
4749
4750   // ---------- element settings: configure 1 (custom elements) ---------------
4751
4752   // ---------- custom graphic ------------------------------------------------
4753
4754   {
4755     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4756     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4757     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4758     GADGET_ID_CUSTOM_GRAPHIC,                   GADGET_ID_CUSTOM_USE_GRAPHIC,
4759     &custom_element.gfx_element_initial,        1, 1,
4760     NULL, NULL, NULL, NULL,                     "Custom graphic element"
4761   },
4762
4763   // ---------- element settings: configure 2 (custom elements) ---------------
4764
4765   // ---------- custom content (when exploding) -------------------------------
4766
4767   {
4768     ED_DRAWING_ID_CUSTOM_CONTENT,
4769     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(11),
4770     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4771     GADGET_ID_CUSTOM_CONTENT,                   GADGET_ID_NONE,         // align three rows
4772     &custom_element.content.e[0][0],            3, 3,
4773     "Content:", NULL, NULL, NULL,               NULL
4774   },
4775
4776   // ---------- custom enter and leave element (when moving) ------------------
4777
4778   {
4779     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4780     ED_AREA_1X1_SETTINGS_XPOS(1),               ED_AREA_1X1_SETTINGS_YPOS(3),
4781     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4782     GADGET_ID_CUSTOM_MOVE_ENTER,                GADGET_ID_NONE,
4783     &custom_element.move_enter_element,         1, 1,
4784     "Can dig:", " ", NULL, NULL,                "Element that can be digged/collected"
4785   },
4786   {
4787     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4788     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(3),
4789     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4790     GADGET_ID_CUSTOM_MOVE_LEAVE,                GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4791     &custom_element.move_leave_element,         1, 1,
4792     NULL, NULL, NULL, NULL,                     "Element that will be left behind"
4793   },
4794
4795   // ---------- element settings: advanced (custom elements) ------------------
4796
4797   // ---------- custom change target ------------------------------------------
4798
4799   {
4800     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4801     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(1),
4802     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4803     GADGET_ID_CUSTOM_CHANGE_TARGET,             GADGET_ID_CUSTOM_CAN_CHANGE,
4804     &custom_element_change.target_element,      1, 1,
4805     NULL, "after/when:", NULL, NULL,            "New target element after change"
4806   },
4807
4808   // ---------- custom change content (extended change target) ----------------
4809
4810   {
4811     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4812     -1,                                         ED_AREA_3X3_SETTINGS_YPOS(9),
4813     0,                                          ED_AREA_3X3_SETTINGS_YOFF,
4814     GADGET_ID_CUSTOM_CHANGE_CONTENT,            GADGET_ID_NONE,         // align three rows
4815     &custom_element_change.target_content.e[0][0], 3, 3,
4816     NULL, NULL, NULL, NULL,                     "New extended elements after change"
4817   },
4818
4819   // ---------- custom change trigger (element causing change) ----------------
4820
4821   {
4822     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4823     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(5),
4824     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4825     GADGET_ID_CUSTOM_CHANGE_TRIGGER,            GADGET_ID_CHANGE_OTHER_ACTION,
4826     &custom_element_change.initial_trigger_element, 1, 1,
4827     NULL, NULL, NULL, NULL,                     "Other element triggering change"
4828   },
4829
4830   // ---------- custom change action (element used for action) ----------------
4831
4832   {
4833     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4834     -1,                                         ED_AREA_1X1_SETTINGS_YPOS(13),
4835     0,                                          ED_AREA_1X1_SETTINGS_YOFF,
4836     GADGET_ID_CUSTOM_CHANGE_ACTION,             GADGET_ID_ACTION_ARG,
4837     &custom_element_change.action_element,      1, 1,
4838     NULL, NULL, NULL, NULL,                     "Element used as action parameter"
4839   },
4840
4841   // ---------- group element content -----------------------------------------
4842
4843   {
4844     ED_DRAWING_ID_GROUP_CONTENT,
4845     ED_AREA_1X1_SETTINGS_XPOS(0),               ED_AREA_1X1_SETTINGS_YPOS(2),
4846     ED_AREA_1X1_SETTINGS_XOFF,                  ED_AREA_1X1_SETTINGS_YOFF,
4847     GADGET_ID_GROUP_CONTENT,                    GADGET_ID_NONE,
4848     &group_element_info.element[0],             MAX_ELEMENTS_IN_GROUP, 1,
4849     "Content:", NULL, NULL, NULL,               NULL
4850   },
4851
4852   // ---------- random background (for random painting) -----------------------
4853
4854   {
4855     ED_DRAWING_ID_RANDOM_BACKGROUND,
4856     -1,                                         ED_AREA_1X1_LSETTINGS_YPOS(1),
4857     0,                                          ED_AREA_1X1_LSETTINGS_YOFF,
4858     GADGET_ID_RANDOM_BACKGROUND,                GADGET_ID_RANDOM_RESTRICTED,
4859     &random_placement_background_element,       1, 1,
4860     NULL, NULL, NULL, NULL,                     "Random placement background"
4861   },
4862 };
4863
4864
4865 // ----------------------------------------------------------------------------
4866 // some internally used variables
4867 // ----------------------------------------------------------------------------
4868
4869 // maximal size of level editor drawing area
4870 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
4871
4872 // actual size of level editor drawing area
4873 static int ed_fieldx, ed_fieldy;
4874
4875 // actual position of level editor drawing area in level playfield
4876 static int level_xpos = -1, level_ypos = -1;
4877
4878 // actual tile size used to display playfield drawing area
4879 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
4880 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
4881
4882 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
4883
4884 // drawing elements on the three mouse buttons
4885 static int new_element1 = EL_WALL;
4886 static int new_element2 = EL_EMPTY;
4887 static int new_element3 = EL_SAND;
4888
4889 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
4890 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
4891                                 (button) == 2 ? new_element2 : \
4892                                 (button) == 3 ? new_element3 : EL_EMPTY)
4893
4894 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
4895
4896 static int use_permanent_palette = TRUE;
4897
4898 #define PX              (use_permanent_palette ? DX : SX)
4899 #define PY              (use_permanent_palette ? DY : SY)
4900 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
4901 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
4902
4903 // forward declaration for internal use
4904 static void CopyBrushToCursor(int, int);
4905 static void DeleteBrushFromCursor(void);
4906 static void ModifyEditorCounterValue(int, int);
4907 static void ModifyEditorCounterLimits(int, int, int);
4908 static void ModifyEditorSelectboxValue(int, int);
4909 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
4910 static void ModifyEditorDrawingArea(int, int, int);
4911 static void ModifyEditorElementList(void);
4912 static void AdjustElementListScrollbar(void);
4913 static void RedrawDrawingElements(void);
4914 static void DrawDrawingWindowExt(boolean);
4915 static void DrawDrawingWindow(void);
4916 static void DrawLevelConfigWindow(void);
4917 static void DrawPropertiesWindow(void);
4918 static void DrawPaletteWindow(void);
4919 static void UpdateCustomElementGraphicGadgets(void);
4920 static boolean checkPropertiesConfig(int);
4921 static void SetAutomaticNumberOfGemsNeeded(void);
4922 static void ClearEditorGadgetInfoText(void);
4923 static void CopyLevelToUndoBuffer(int);
4924 static void HandleDrawingAreas(struct GadgetInfo *);
4925 static void HandleCounterButtons(struct GadgetInfo *);
4926 static void HandleTextInputGadgets(struct GadgetInfo *);
4927 static void HandleTextAreaGadgets(struct GadgetInfo *);
4928 static void HandleSelectboxGadgets(struct GadgetInfo *);
4929 static void HandleTextbuttonGadgets(struct GadgetInfo *);
4930 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
4931 static void HandleRadiobuttons(struct GadgetInfo *);
4932 static void HandleCheckbuttons(struct GadgetInfo *);
4933 static void HandleControlButtons(struct GadgetInfo *);
4934 static void HandleDrawingAreaInfo(struct GadgetInfo *);
4935 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
4936 static boolean AskToCopyAndModifyLevelTemplate(void);
4937 static boolean getDrawModeHiRes(void);
4938 static int getTabulatorBarWidth(void);
4939 static int getTabulatorBarHeight(void);
4940 static Pixel getTabulatorBarColor(void);
4941 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
4942 static int numHiresTiles(int);
4943
4944 static int num_editor_gadgets = 0;      // dynamically determined
4945
4946 static struct GadgetInfo **level_editor_gadget = NULL;
4947 static int *right_gadget_border = NULL;
4948
4949 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
4950 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
4951 static boolean draw_with_brush = FALSE;
4952 static int properties_element = 0;
4953
4954 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4955 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4956 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4957 static int undo_buffer_position = 0;
4958 static int undo_buffer_steps = 0;
4959 static int redo_buffer_steps = 0;
4960
4961 static int edit_mode;
4962 static int edit_mode_levelconfig;
4963 static int edit_mode_properties;
4964
4965 static int element_shift = 0;
4966
4967 static int editor_el_players[] =
4968 {
4969   EL_PLAYER_1,
4970   EL_PLAYER_2,
4971   EL_PLAYER_3,
4972   EL_PLAYER_4
4973 };
4974 static int *editor_el_players_ptr = editor_el_players;
4975 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
4976
4977 static int editor_hl_boulderdash[] =
4978 {
4979   EL_INTERNAL_CASCADE_BD_ACTIVE,
4980   EL_CHAR('B'),
4981   EL_CHAR('D'),
4982   EL_EMPTY,
4983 };
4984
4985 static int editor_el_boulderdash[] =
4986 {
4987   EL_EMPTY,
4988   EL_SAND,
4989   EL_BD_ROCK,
4990   EL_BD_DIAMOND,
4991
4992   EL_STEELWALL,
4993   EL_BD_WALL,
4994   EL_BD_EXPANDABLE_WALL,
4995   EL_BD_MAGIC_WALL,
4996
4997   EL_BD_AMOEBA,
4998   EL_BD_BUTTERFLY_UP,
4999   EL_BD_FIREFLY_UP,
5000   EL_EXIT_CLOSED,
5001
5002   EL_BD_BUTTERFLY_LEFT,
5003   EL_BD_FIREFLY_LEFT,
5004   EL_BD_BUTTERFLY_RIGHT,
5005   EL_BD_FIREFLY_RIGHT,
5006
5007   EL_EMPTY,
5008   EL_BD_BUTTERFLY_DOWN,
5009   EL_BD_FIREFLY_DOWN,
5010   EL_EXIT_OPEN,
5011 };
5012 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
5013 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
5014 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
5015 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
5016
5017 static int editor_hl_boulderdash_native[] =
5018 {
5019   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
5020   EL_CHAR('B'),
5021   EL_CHAR('D'),
5022   EL_EMPTY,
5023 };
5024
5025 static int editor_el_boulderdash_native[] =
5026 {
5027   EL_EMPTY,
5028   EL_BD_SAND,
5029   EL_BD_ROCK,
5030   EL_BD_DIAMOND,
5031
5032   EL_BD_STEELWALL,
5033   EL_BD_WALL,
5034   EL_BD_SAND_2,
5035   EL_BD_MAGIC_WALL,
5036
5037   EL_BD_AMOEBA,
5038   EL_BD_BUTTERFLY_UP,
5039   EL_BD_FIREFLY_UP,
5040   EL_BD_EXIT_CLOSED,
5041
5042   EL_BD_BUTTERFLY_LEFT,
5043   EL_BD_FIREFLY_LEFT,
5044   EL_BD_BUTTERFLY_RIGHT,
5045   EL_BD_FIREFLY_RIGHT,
5046
5047   EL_BD_INBOX,
5048   EL_BD_BUTTERFLY_DOWN,
5049   EL_BD_FIREFLY_DOWN,
5050   EL_BD_EXIT_OPEN,
5051
5052   EL_BD_AMOEBA_2,
5053   EL_BD_BUTTERFLY_2_UP,
5054   EL_BD_FIREFLY_2_UP,
5055   EL_BD_SLIME,
5056
5057   EL_BD_BUTTERFLY_2_LEFT,
5058   EL_BD_FIREFLY_2_LEFT,
5059   EL_BD_BUTTERFLY_2_RIGHT,
5060   EL_BD_FIREFLY_2_RIGHT,
5061
5062   EL_BD_BOMB,
5063   EL_BD_BUTTERFLY_2_DOWN,
5064   EL_BD_FIREFLY_2_DOWN,
5065   EL_BD_FLYING_DIAMOND,
5066
5067   EL_BD_NITRO_PACK,
5068   EL_BD_DRAGONFLY_UP,
5069   EL_BD_STONEFLY_UP,
5070   EL_BD_DIAMOND_GLUED,
5071
5072   EL_BD_DRAGONFLY_LEFT,
5073   EL_BD_STONEFLY_LEFT,
5074   EL_BD_DRAGONFLY_RIGHT,
5075   EL_BD_STONEFLY_RIGHT,
5076
5077   EL_BD_NUT,
5078   EL_BD_DRAGONFLY_DOWN,
5079   EL_BD_STONEFLY_DOWN,
5080   EL_EMPTY,
5081
5082   EL_BD_BITER_SWITCH_1,
5083   EL_BD_BITER_UP,
5084   EL_BD_COW_UP,
5085   EL_EMPTY,
5086
5087   EL_BD_BITER_LEFT,
5088   EL_BD_COW_LEFT,
5089   EL_BD_BITER_RIGHT,
5090   EL_BD_COW_RIGHT,
5091
5092   EL_BD_VOODOO_DOLL,
5093   EL_BD_BITER_DOWN,
5094   EL_BD_COW_DOWN,
5095   EL_BD_GHOST,
5096
5097   EL_BD_SAND_GLUED,
5098   EL_BD_SAND_BALL,
5099   EL_BD_SAND_LOOSE,
5100   EL_BD_WALL_NON_SLOPED,
5101
5102   EL_BD_SAND_SLOPED_UP_LEFT,
5103   EL_BD_SAND_SLOPED_UP_RIGHT,
5104   EL_BD_WALL_SLOPED_UP_LEFT,
5105   EL_BD_WALL_SLOPED_UP_RIGHT,
5106
5107   EL_BD_SAND_SLOPED_DOWN_LEFT,
5108   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5109   EL_BD_WALL_SLOPED_DOWN_LEFT,
5110   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5111
5112   EL_BD_FLYING_ROCK,
5113   EL_BD_ROCK_GLUED,
5114   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5115   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5116
5117   EL_BD_WAITING_ROCK,
5118   EL_BD_CHASING_ROCK,
5119   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5120   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5121
5122   EL_BD_MEGA_ROCK,
5123   EL_BD_SWEET,
5124   EL_BD_INVISIBLE_EXIT_CLOSED,
5125   EL_BD_INVISIBLE_EXIT_OPEN,
5126
5127   EL_BD_STEELWALL_EXPLODABLE,
5128   EL_BD_STEELWALL_DIGGABLE,
5129   EL_BD_WALL_DIGGABLE,
5130   EL_BD_FALLING_WALL,
5131
5132   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5133   EL_BD_EXPANDABLE_WALL_VERTICAL,
5134   EL_BD_EXPANDABLE_WALL_ANY,
5135   EL_BD_EXPANDABLE_WALL_SWITCH,
5136
5137   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5138   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5139   EL_BD_EXPANDABLE_STEELWALL_ANY,
5140   EL_BD_CREATURE_SWITCH,
5141
5142   EL_BD_BLADDER,
5143   EL_BD_BLADDER_SPENDER,
5144   EL_BD_REPLICATOR,
5145   EL_BD_REPLICATOR_SWITCH,
5146
5147   EL_BD_CONVEYOR_LEFT,
5148   EL_BD_CONVEYOR_RIGHT,
5149   EL_BD_CONVEYOR_SWITCH,
5150   EL_BD_CONVEYOR_DIR_SWITCH,
5151
5152   EL_BD_CLOCK,
5153   EL_BD_TIME_PENALTY,
5154   EL_BD_GRAVESTONE,
5155   EL_BD_SKELETON,
5156
5157   EL_BD_WATER,
5158   EL_BD_ACID,
5159   EL_BD_LAVA,
5160   EL_BD_BOX,
5161
5162   EL_BD_GATE_1,
5163   EL_BD_GATE_2,
5164   EL_BD_GATE_3,
5165   EL_BD_TRAPPED_DIAMOND,
5166
5167   EL_BD_KEY_1,
5168   EL_BD_KEY_2,
5169   EL_BD_KEY_3,
5170   EL_BD_DIAMOND_KEY,
5171
5172   EL_BD_WALL_KEY_1,
5173   EL_BD_WALL_KEY_2,
5174   EL_BD_WALL_KEY_3,
5175   EL_BD_WALL_DIAMOND,
5176
5177   EL_BD_POT,
5178   EL_BD_GRAVITY_SWITCH,
5179   EL_BD_PNEUMATIC_HAMMER,
5180   EL_BD_TELEPORTER,
5181
5182   EL_BD_PLAYER,
5183   EL_BD_PLAYER_WITH_BOMB,
5184   EL_BD_PLAYER_GLUED,
5185   EL_BD_PLAYER_STIRRING,
5186 };
5187 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5188 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5189 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5190 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5191
5192 static int editor_hl_boulderdash_effects[] =
5193 {
5194   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5195   EL_CHAR('B'),
5196   EL_CHAR('D'),
5197   EL_CHAR('E'),
5198 };
5199
5200 static int editor_el_boulderdash_effects[] =
5201 {
5202   EL_BD_DIAMOND_FALLING,
5203   EL_BD_ROCK_FALLING,
5204   EL_BD_MEGA_ROCK_FALLING,
5205   EL_BD_FLYING_DIAMOND_FLYING,
5206
5207   EL_BD_FALLING_WALL_FALLING,
5208   EL_BD_NITRO_PACK_FALLING,
5209   EL_BD_NUT_FALLING,
5210   EL_BD_FLYING_ROCK_FLYING,
5211
5212   EL_BD_PLAYER_GROWING_1,
5213   EL_BD_PLAYER_GROWING_2,
5214   EL_BD_PLAYER_GROWING_3,
5215   EL_BD_PLAYER,
5216
5217   EL_BD_PLAYER_WITH_BOMB,
5218   EL_BD_PLAYER_STIRRING,
5219   EL_BD_EXIT_OPEN,
5220   EL_BD_INVISIBLE_EXIT_OPEN,
5221
5222   EL_BD_BLADDER_1,
5223   EL_BD_BLADDER_2,
5224   EL_BD_BLADDER_3,
5225   EL_BD_BLADDER_4,
5226
5227   EL_BD_BLADDER_5,
5228   EL_BD_BLADDER_6,
5229   EL_BD_BLADDER_7,
5230   EL_BD_BLADDER_8,
5231
5232   EL_BD_SAND_2,
5233   EL_BD_COW_ENCLOSED_1,
5234   EL_BD_COW_ENCLOSED_2,
5235   EL_BD_COW_ENCLOSED_3,
5236
5237   EL_BD_COW_ENCLOSED_4,
5238   EL_BD_COW_ENCLOSED_5,
5239   EL_BD_COW_ENCLOSED_6,
5240   EL_BD_COW_ENCLOSED_7,
5241
5242   EL_BD_WATER_1,
5243   EL_BD_WATER_2,
5244   EL_BD_WATER_3,
5245   EL_BD_WATER_4,
5246
5247   EL_BD_WATER_5,
5248   EL_BD_WATER_6,
5249   EL_BD_WATER_7,
5250   EL_BD_WATER_8,
5251
5252   EL_BD_WATER_9,
5253   EL_BD_WATER_10,
5254   EL_BD_WATER_11,
5255   EL_BD_WATER_12,
5256
5257   EL_BD_WATER_13,
5258   EL_BD_WATER_14,
5259   EL_BD_WATER_15,
5260   EL_BD_WATER_16,
5261
5262   EL_BD_BOMB_TICKING_1,
5263   EL_BD_BOMB_TICKING_2,
5264   EL_BD_BOMB_TICKING_3,
5265   EL_BD_BOMB_TICKING_4,
5266
5267   EL_BD_BOMB_TICKING_5,
5268   EL_BD_BOMB_TICKING_6,
5269   EL_BD_BOMB_TICKING_7,
5270   EL_EMPTY,
5271
5272   EL_BD_BOMB_EXPLODING_1,
5273   EL_BD_BOMB_EXPLODING_2,
5274   EL_BD_BOMB_EXPLODING_3,
5275   EL_BD_BOMB_EXPLODING_4,
5276
5277   EL_BD_NUT_BREAKING_1,
5278   EL_BD_NUT_BREAKING_2,
5279   EL_BD_NUT_BREAKING_3,
5280   EL_BD_NUT_BREAKING_4,
5281
5282   EL_BD_EXPLODING_1,
5283   EL_BD_EXPLODING_2,
5284   EL_BD_EXPLODING_3,
5285   EL_BD_EXPLODING_4,
5286
5287   EL_BD_EXPLODING_5,
5288   EL_BD_TIME_PENALTY,
5289   EL_BD_DIAMOND_GROWING_1,
5290   EL_BD_DIAMOND_GROWING_2,
5291
5292   EL_BD_DIAMOND_GROWING_3,
5293   EL_BD_DIAMOND_GROWING_4,
5294   EL_BD_DIAMOND_GROWING_5,
5295   EL_BD_NITRO_PACK_EXPLODING,
5296
5297   EL_BD_NITRO_PACK_EXPLODING_1,
5298   EL_BD_NITRO_PACK_EXPLODING_2,
5299   EL_BD_NITRO_PACK_EXPLODING_3,
5300   EL_BD_NITRO_PACK_EXPLODING_4,
5301
5302   EL_BD_ROCK_GROWING_1,
5303   EL_BD_ROCK_GROWING_2,
5304   EL_BD_ROCK_GROWING_3,
5305   EL_BD_ROCK_GROWING_4,
5306
5307   EL_BD_STEELWALL_GROWING_1,
5308   EL_BD_STEELWALL_GROWING_2,
5309   EL_BD_STEELWALL_GROWING_3,
5310   EL_BD_STEELWALL_GROWING_4,
5311
5312   EL_BD_CLOCK_GROWING_1,
5313   EL_BD_CLOCK_GROWING_2,
5314   EL_BD_CLOCK_GROWING_3,
5315   EL_BD_CLOCK_GROWING_4,
5316
5317   EL_BD_GHOST_EXPLODING_1,
5318   EL_BD_GHOST_EXPLODING_2,
5319   EL_BD_GHOST_EXPLODING_3,
5320   EL_BD_GHOST_EXPLODING_4,
5321 };
5322 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5323 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5324 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5325 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5326
5327 static int editor_hl_emerald_mine[] =
5328 {
5329   EL_INTERNAL_CASCADE_EM_ACTIVE,
5330   EL_CHAR('E'),
5331   EL_CHAR('M'),
5332   EL_EMPTY,
5333 };
5334
5335 static int editor_el_emerald_mine[] =
5336 {
5337   EL_SAND,
5338   EL_ROCK,
5339   EL_QUICKSAND_EMPTY,
5340   EL_QUICKSAND_FULL,
5341
5342   EL_STEELWALL,
5343   EL_WALL,
5344   EL_WALL_SLIPPERY,
5345   EL_MAGIC_WALL,
5346
5347   EL_EMERALD,
5348   EL_DIAMOND,
5349   EL_NUT,
5350   EL_BOMB,
5351
5352   EL_EM_DYNAMITE,
5353   EL_EM_DYNAMITE_ACTIVE,
5354   EL_EM_EXIT_CLOSED,
5355   EL_EM_EXIT_OPEN,
5356
5357   EL_YAMYAM_UP,
5358   EL_BUG_UP,
5359   EL_SPACESHIP_UP,
5360   EL_ROBOT,
5361
5362   EL_BUG_LEFT,
5363   EL_SPACESHIP_LEFT,
5364   EL_BUG_RIGHT,
5365   EL_SPACESHIP_RIGHT,
5366
5367   EL_ROBOT_WHEEL,
5368   EL_BUG_DOWN,
5369   EL_SPACESHIP_DOWN,
5370   EL_INVISIBLE_WALL,
5371
5372   EL_ACID_POOL_TOPLEFT,
5373   EL_ACID,
5374   EL_ACID_POOL_TOPRIGHT,
5375   EL_AMOEBA_DROP,
5376
5377   EL_ACID_POOL_BOTTOMLEFT,
5378   EL_ACID_POOL_BOTTOM,
5379   EL_ACID_POOL_BOTTOMRIGHT,
5380   EL_AMOEBA_WET,
5381
5382   EL_EM_KEY_1,
5383   EL_EM_KEY_2,
5384   EL_EM_KEY_3,
5385   EL_EM_KEY_4,
5386
5387   EL_EM_GATE_1,
5388   EL_EM_GATE_2,
5389   EL_EM_GATE_3,
5390   EL_EM_GATE_4,
5391
5392   EL_EM_GATE_1_GRAY,
5393   EL_EM_GATE_2_GRAY,
5394   EL_EM_GATE_3_GRAY,
5395   EL_EM_GATE_4_GRAY,
5396 };
5397 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5398 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5399 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5400 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5401
5402 static int editor_hl_emerald_mine_club[] =
5403 {
5404   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5405   EL_CHAR('E'),
5406   EL_CHAR('M'),
5407   EL_CHAR('C'),
5408 };
5409
5410 static int editor_el_emerald_mine_club[] =
5411 {
5412   EL_EMC_KEY_5,
5413   EL_EMC_KEY_6,
5414   EL_EMC_KEY_7,
5415   EL_EMC_KEY_8,
5416
5417   EL_EMC_GATE_5,
5418   EL_EMC_GATE_6,
5419   EL_EMC_GATE_7,
5420   EL_EMC_GATE_8,
5421
5422   EL_EMC_GATE_5_GRAY,
5423   EL_EMC_GATE_6_GRAY,
5424   EL_EMC_GATE_7_GRAY,
5425   EL_EMC_GATE_8_GRAY,
5426
5427   EL_EMC_STEELWALL_1,
5428   EL_EMC_STEELWALL_2,
5429   EL_EMC_STEELWALL_3,
5430   EL_EMC_STEELWALL_4,
5431
5432   EL_EMC_WALL_13,
5433   EL_EMC_WALL_14,
5434   EL_EMC_WALL_15,
5435   EL_EMC_WALL_16,
5436
5437   EL_EMC_WALL_SLIPPERY_1,
5438   EL_EMC_WALL_SLIPPERY_2,
5439   EL_EMC_WALL_SLIPPERY_3,
5440   EL_EMC_WALL_SLIPPERY_4,
5441
5442   EL_EMC_WALL_1,
5443   EL_EMC_WALL_2,
5444   EL_EMC_WALL_3,
5445   EL_EMC_WALL_4,
5446
5447   EL_EMC_WALL_5,
5448   EL_EMC_WALL_6,
5449   EL_EMC_WALL_7,
5450   EL_EMC_WALL_8,
5451
5452   EL_EMC_WALL_9,
5453   EL_EMC_WALL_10,
5454   EL_EMC_WALL_11,
5455   EL_EMC_WALL_12,
5456
5457   EL_EMC_GRASS,
5458   EL_EMC_FAKE_GRASS,
5459   EL_EMC_PLANT,
5460   EL_EMC_DRIPPER,
5461
5462   EL_EMC_MAGIC_BALL,
5463   EL_EMC_MAGIC_BALL_SWITCH,
5464   EL_EMC_LENSES,
5465   EL_EMC_MAGNIFIER,
5466
5467   EL_SPRING_LEFT,
5468   EL_SPRING,
5469   EL_SPRING_RIGHT,
5470   EL_EMC_SPRING_BUMPER,
5471
5472   EL_BALLOON,
5473   EL_YAMYAM_UP,
5474   EL_BALLOON_SWITCH_UP,
5475   EL_BALLOON_SWITCH_ANY,
5476
5477   EL_YAMYAM_LEFT,
5478   EL_BALLOON_SWITCH_LEFT,
5479   EL_YAMYAM_RIGHT,
5480   EL_BALLOON_SWITCH_RIGHT,
5481
5482   EL_EMC_ANDROID,
5483   EL_YAMYAM_DOWN,
5484   EL_BALLOON_SWITCH_DOWN,
5485   EL_BALLOON_SWITCH_NONE,
5486 };
5487 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5488 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5489 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5490 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5491
5492 static int editor_hl_rnd[] =
5493 {
5494   EL_INTERNAL_CASCADE_RND_ACTIVE,
5495   EL_CHAR('R'),
5496   EL_CHAR('N'),
5497   EL_CHAR('D'),
5498 };
5499
5500 static int editor_el_rnd[] =
5501 {
5502   EL_DYNAMITE,                  // RND
5503   EL_DYNAMITE_ACTIVE,           // RND
5504   EL_EMPTY,
5505   EL_EMPTY,
5506
5507   EL_KEY_1,
5508   EL_KEY_2,
5509   EL_KEY_3,
5510   EL_KEY_4,
5511
5512   EL_GATE_1,
5513   EL_GATE_2,
5514   EL_GATE_3,
5515   EL_GATE_4,
5516
5517   EL_GATE_1_GRAY,
5518   EL_GATE_2_GRAY,
5519   EL_GATE_3_GRAY,
5520   EL_GATE_4_GRAY,
5521
5522   EL_ARROW_LEFT,
5523   EL_ARROW_RIGHT,
5524   EL_ARROW_UP,
5525   EL_ARROW_DOWN,
5526
5527   EL_AMOEBA_DEAD,
5528   EL_AMOEBA_DRY,
5529   EL_AMOEBA_FULL,
5530   EL_GAME_OF_LIFE,
5531
5532   EL_EMERALD_YELLOW,
5533   EL_EMERALD_RED,
5534   EL_EMERALD_PURPLE,
5535   EL_BIOMAZE,
5536
5537   EL_WALL_EMERALD_YELLOW,
5538   EL_WALL_EMERALD_RED,
5539   EL_WALL_EMERALD_PURPLE,
5540   EL_WALL_BD_DIAMOND,
5541
5542   EL_SPEED_PILL,
5543   EL_PACMAN_UP,
5544   EL_TIME_ORB_FULL,
5545   EL_TIME_ORB_EMPTY,
5546
5547   EL_PACMAN_LEFT,
5548   EL_DARK_YAMYAM,
5549   EL_PACMAN_RIGHT,
5550   EL_YAMYAM,                    // RND
5551
5552   EL_BLACK_ORB,
5553   EL_PACMAN_DOWN,
5554   EL_LAMP,
5555   EL_LAMP_ACTIVE,
5556
5557   EL_DYNABOMB_INCREASE_NUMBER,
5558   EL_DYNABOMB_INCREASE_SIZE,
5559   EL_DYNABOMB_INCREASE_POWER,
5560   EL_STONEBLOCK,
5561
5562   EL_MOLE,
5563   EL_PENGUIN,
5564   EL_PIG,
5565   EL_DRAGON,
5566
5567   EL_BUG,
5568   EL_MOLE_UP,
5569   EL_BD_BUTTERFLY,
5570   EL_BD_FIREFLY,
5571
5572   EL_MOLE_LEFT,
5573   EL_SATELLITE,
5574   EL_MOLE_RIGHT,
5575   EL_PACMAN,
5576
5577   EL_SPACESHIP,
5578   EL_MOLE_DOWN,
5579   EL_INVISIBLE_STEELWALL,
5580   EL_INVISIBLE_WALL,
5581
5582   EL_EXPANDABLE_WALL,
5583   EL_EXPANDABLE_WALL_HORIZONTAL,
5584   EL_EXPANDABLE_WALL_VERTICAL,
5585   EL_EXPANDABLE_WALL_ANY,
5586 };
5587 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5588 static int *editor_el_rnd_ptr = editor_el_rnd;
5589 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5590 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5591
5592 static int editor_hl_sokoban[] =
5593 {
5594   EL_INTERNAL_CASCADE_SB_ACTIVE,
5595   EL_CHAR('S'),
5596   EL_CHAR('B'),
5597   EL_EMPTY,
5598 };
5599
5600 static int editor_el_sokoban[] =
5601 {
5602   EL_SOKOBAN_OBJECT,
5603   EL_SOKOBAN_FIELD_EMPTY,
5604   EL_SOKOBAN_FIELD_FULL,
5605   EL_SOKOBAN_FIELD_PLAYER,
5606 };
5607 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5608 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5609 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5610 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5611
5612 static int editor_hl_supaplex[] =
5613 {
5614   EL_INTERNAL_CASCADE_SP_ACTIVE,
5615   EL_CHAR('S'),
5616   EL_CHAR('P'),
5617   EL_EMPTY,
5618 };
5619
5620 static int editor_el_supaplex[] =
5621 {
5622   EL_SP_MURPHY,
5623   EL_EMPTY,
5624   EL_SP_BASE,
5625   EL_SP_BUGGY_BASE,
5626
5627   EL_SP_INFOTRON,
5628   EL_SP_ZONK,
5629   EL_SP_SNIKSNAK,
5630   EL_SP_ELECTRON,
5631
5632   EL_SP_DISK_RED,
5633   EL_SP_DISK_ORANGE,
5634   EL_SP_DISK_YELLOW,
5635   EL_SP_TERMINAL,
5636
5637   EL_SP_EXIT_CLOSED,
5638   EL_SP_PORT_HORIZONTAL,
5639   EL_SP_PORT_VERTICAL,
5640   EL_SP_PORT_ANY,
5641
5642   EL_SP_PORT_LEFT,
5643   EL_SP_PORT_RIGHT,
5644   EL_SP_PORT_UP,
5645   EL_SP_PORT_DOWN,
5646
5647   EL_SP_GRAVITY_PORT_LEFT,
5648   EL_SP_GRAVITY_PORT_RIGHT,
5649   EL_SP_GRAVITY_PORT_UP,
5650   EL_SP_GRAVITY_PORT_DOWN,
5651
5652   EL_SP_GRAVITY_ON_PORT_LEFT,
5653   EL_SP_GRAVITY_ON_PORT_RIGHT,
5654   EL_SP_GRAVITY_ON_PORT_UP,
5655   EL_SP_GRAVITY_ON_PORT_DOWN,
5656
5657   EL_SP_GRAVITY_OFF_PORT_LEFT,
5658   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5659   EL_SP_GRAVITY_OFF_PORT_UP,
5660   EL_SP_GRAVITY_OFF_PORT_DOWN,
5661
5662   EL_SP_HARDWARE_GRAY,
5663   EL_SP_HARDWARE_GREEN,
5664   EL_SP_HARDWARE_BLUE,
5665   EL_SP_HARDWARE_RED,
5666
5667   EL_SP_HARDWARE_BASE_1,
5668   EL_SP_HARDWARE_BASE_2,
5669   EL_SP_HARDWARE_BASE_3,
5670   EL_SP_HARDWARE_BASE_4,
5671
5672   EL_SP_HARDWARE_BASE_5,
5673   EL_SP_HARDWARE_BASE_6,
5674   EL_SP_HARDWARE_YELLOW,
5675   EL_SP_CHIP_TOP,
5676
5677   EL_SP_CHIP_SINGLE,
5678   EL_SP_CHIP_LEFT,
5679   EL_SP_CHIP_RIGHT,
5680   EL_SP_CHIP_BOTTOM,
5681 };
5682 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5683 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5684 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5685 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5686
5687 static int editor_hl_diamond_caves[] =
5688 {
5689   EL_INTERNAL_CASCADE_DC_ACTIVE,
5690   EL_CHAR('D'),
5691   EL_CHAR('C'),
5692   EL_CHAR('2'),
5693 };
5694
5695 static int editor_el_diamond_caves[] =
5696 {
5697   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5698   EL_EM_STEEL_EXIT_OPEN,        // DC2
5699   EL_WALL_EMERALD,              // DC2
5700   EL_WALL_DIAMOND,              // DC2
5701
5702   EL_PEARL,
5703   EL_CRYSTAL,
5704   EL_WALL_PEARL,
5705   EL_WALL_CRYSTAL,
5706
5707   EL_CONVEYOR_BELT_1_LEFT,
5708   EL_CONVEYOR_BELT_1_MIDDLE,
5709   EL_CONVEYOR_BELT_1_RIGHT,
5710   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5711
5712   EL_CONVEYOR_BELT_2_LEFT,
5713   EL_CONVEYOR_BELT_2_MIDDLE,
5714   EL_CONVEYOR_BELT_2_RIGHT,
5715   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5716
5717   EL_CONVEYOR_BELT_3_LEFT,
5718   EL_CONVEYOR_BELT_3_MIDDLE,
5719   EL_CONVEYOR_BELT_3_RIGHT,
5720   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5721
5722   EL_CONVEYOR_BELT_4_LEFT,
5723   EL_CONVEYOR_BELT_4_MIDDLE,
5724   EL_CONVEYOR_BELT_4_RIGHT,
5725   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5726
5727   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5728   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5729   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5730   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5731
5732   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5733   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5734   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5735   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5736
5737   EL_TIMEGATE_CLOSED,
5738   EL_TIMEGATE_OPEN,
5739   EL_TIMEGATE_SWITCH,
5740   EL_DC_TIMEGATE_SWITCH,
5741
5742   EL_SWITCHGATE_CLOSED,
5743   EL_SWITCHGATE_OPEN,
5744   EL_SWITCHGATE_SWITCH_UP,
5745   EL_SWITCHGATE_SWITCH_DOWN,
5746
5747   EL_LIGHT_SWITCH,
5748   EL_LIGHT_SWITCH_ACTIVE,
5749   EL_DC_SWITCHGATE_SWITCH_UP,
5750   EL_DC_SWITCHGATE_SWITCH_DOWN,
5751
5752   EL_STEEL_EXIT_CLOSED,
5753   EL_STEEL_EXIT_OPEN,
5754   EL_STEELWALL_SLIPPERY,
5755   EL_INVISIBLE_SAND,
5756
5757   EL_QUICKSAND_FAST_EMPTY,
5758   EL_QUICKSAND_FAST_FULL,
5759   EL_LANDMINE,
5760   EL_DC_LANDMINE,
5761
5762   EL_SHIELD_NORMAL,
5763   EL_SHIELD_DEADLY,
5764   EL_EXTRA_TIME,
5765   EL_DC_MAGIC_WALL,
5766
5767   EL_ENVELOPE_1,
5768   EL_ENVELOPE_2,
5769   EL_ENVELOPE_3,
5770   EL_ENVELOPE_4,
5771
5772   EL_SIGN_RADIOACTIVITY,
5773   EL_SIGN_WHEELCHAIR,
5774   EL_SIGN_PARKING,
5775   EL_SIGN_NO_ENTRY,
5776
5777   EL_SIGN_GIVE_WAY,
5778   EL_SIGN_ENTRY_FORBIDDEN,
5779   EL_SIGN_EMERGENCY_EXIT,
5780   EL_SIGN_YIN_YANG,
5781
5782 #if 0
5783   EL_SIGN_SPERMS,
5784   EL_SIGN_BULLET,
5785   EL_SIGN_HEART,
5786   EL_SIGN_CROSS,
5787
5788   EL_SIGN_FRANKIE,
5789   EL_EMPTY,
5790   EL_EMPTY,
5791   EL_EMPTY,
5792
5793   EL_SPERMS,
5794   EL_BULLET,
5795   EL_HEART,
5796   EL_CROSS,
5797
5798   EL_FRANKIE,
5799   EL_EMPTY,
5800   EL_EMPTY,
5801   EL_EMPTY,
5802 #endif
5803
5804   EL_DC_STEELWALL_2_SINGLE,
5805   EL_DC_STEELWALL_2_TOP,
5806   EL_SIGN_EXCLAMATION,
5807   EL_SIGN_STOP,
5808
5809   EL_DC_STEELWALL_2_LEFT,
5810   EL_DC_STEELWALL_2_MIDDLE,
5811   EL_DC_STEELWALL_2_HORIZONTAL,
5812   EL_DC_STEELWALL_2_RIGHT,
5813
5814   EL_DC_STEELWALL_1_TOPLEFT,
5815   EL_DC_STEELWALL_2_VERTICAL,
5816   EL_DC_STEELWALL_1_TOPRIGHT,
5817   EL_DC_GATE_WHITE,
5818
5819   EL_DC_STEELWALL_1_VERTICAL,
5820   EL_DC_STEELWALL_2_BOTTOM,
5821   EL_DC_KEY_WHITE,
5822   EL_DC_GATE_WHITE_GRAY,
5823
5824   EL_DC_STEELWALL_1_BOTTOMLEFT,
5825   EL_DC_STEELWALL_1_HORIZONTAL,
5826   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5827   EL_DC_GATE_FAKE_GRAY,
5828
5829   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5830   EL_DC_STEELWALL_1_BOTTOM,
5831   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5832   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5833
5834   EL_DC_STEELWALL_1_RIGHT,
5835   EL_EMPTY,
5836   EL_DC_STEELWALL_1_LEFT,
5837   EL_EXPANDABLE_STEELWALL_VERTICAL,
5838
5839   EL_DC_STEELWALL_1_TOPRIGHT_2,
5840   EL_DC_STEELWALL_1_TOP,
5841   EL_DC_STEELWALL_1_TOPLEFT_2,
5842   EL_EXPANDABLE_STEELWALL_ANY,
5843 };
5844 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5845 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5846 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5847 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5848
5849 static int editor_hl_dx_boulderdash[] =
5850 {
5851   EL_INTERNAL_CASCADE_DX_ACTIVE,
5852   EL_CHAR('D'),
5853   EL_CHAR('X'),
5854   EL_EMPTY,
5855 };
5856
5857 static int editor_el_dx_boulderdash[] =
5858 {
5859   EL_EMPTY,
5860   EL_TUBE_RIGHT_DOWN,
5861   EL_TUBE_HORIZONTAL_DOWN,
5862   EL_TUBE_LEFT_DOWN,
5863
5864   EL_TUBE_HORIZONTAL,
5865   EL_TUBE_VERTICAL_RIGHT,
5866   EL_TUBE_ANY,
5867   EL_TUBE_VERTICAL_LEFT,
5868
5869   EL_TUBE_VERTICAL,
5870   EL_TUBE_RIGHT_UP,
5871   EL_TUBE_HORIZONTAL_UP,
5872   EL_TUBE_LEFT_UP,
5873
5874   EL_TRAP,
5875   EL_DX_SUPABOMB,
5876   EL_EMPTY,
5877   EL_EMPTY
5878 };
5879 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
5880 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
5881 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
5882 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
5883
5884 static int editor_hl_mirror_magic[] =
5885 {
5886   EL_INTERNAL_CASCADE_MM_ACTIVE,
5887   EL_CHAR('M'),
5888   EL_CHAR('M'),
5889   EL_EMPTY,
5890 };
5891
5892 static int editor_el_mirror_magic[] =
5893 {
5894   EL_MM_MCDUFFIN_RIGHT,
5895   EL_MM_MCDUFFIN_UP,
5896   EL_MM_MCDUFFIN_LEFT,
5897   EL_MM_MCDUFFIN_DOWN,
5898
5899   EL_MM_MIRROR_START,
5900   EL_MM_MIRROR_FIXED_START,
5901   EL_MM_POLARIZER_START,
5902   EL_MM_POLARIZER_CROSS_START,
5903
5904   EL_MM_TELEPORTER_RED_START,
5905   EL_MM_TELEPORTER_YELLOW_START,
5906   EL_MM_TELEPORTER_GREEN_START,
5907   EL_MM_TELEPORTER_BLUE_START,
5908
5909   EL_MM_PRISM,
5910   EL_MM_FUSE_ACTIVE,
5911   EL_MM_PACMAN_RIGHT,
5912   EL_MM_EXIT_CLOSED,
5913
5914   EL_MM_KETTLE,
5915   EL_MM_BOMB,
5916   EL_MM_KEY,
5917   EL_MM_FUEL_FULL,
5918
5919   EL_MM_LIGHTBULB,
5920   EL_MM_LIGHTBULB_ACTIVE,
5921   EL_MM_GRAY_BALL,
5922   EL_MM_LIGHTBALL,
5923
5924   EL_MM_STEEL_WALL,
5925   EL_MM_WOODEN_WALL,
5926   EL_MM_ICE_WALL,
5927   EL_MM_AMOEBA_WALL,
5928
5929   EL_MM_STEEL_LOCK,
5930   EL_MM_WOODEN_LOCK,
5931   EL_MM_STEEL_BLOCK,
5932   EL_MM_WOODEN_BLOCK,
5933
5934   EL_MM_STEEL_GRID_FIXED_1,
5935   EL_MM_STEEL_GRID_FIXED_2,
5936   EL_MM_STEEL_GRID_FIXED_3,
5937   EL_MM_STEEL_GRID_FIXED_4,
5938
5939   EL_MM_WOODEN_GRID_FIXED_1,
5940   EL_MM_WOODEN_GRID_FIXED_2,
5941   EL_MM_WOODEN_GRID_FIXED_3,
5942   EL_MM_WOODEN_GRID_FIXED_4,
5943
5944   EL_MM_ENVELOPE_1,
5945   EL_MM_ENVELOPE_2,
5946   EL_MM_ENVELOPE_3,
5947   EL_MM_ENVELOPE_4
5948 };
5949 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
5950 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
5951 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
5952 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
5953
5954 static int editor_hl_deflektor[] =
5955 {
5956   EL_INTERNAL_CASCADE_DF_ACTIVE,
5957   EL_CHAR('D'),
5958   EL_CHAR('F'),
5959   EL_EMPTY,
5960 };
5961
5962 static int editor_el_deflektor[] =
5963 {
5964   EL_DF_LASER_RIGHT,
5965   EL_DF_LASER_UP,
5966   EL_DF_LASER_LEFT,
5967   EL_DF_LASER_DOWN,
5968
5969   EL_DF_RECEIVER_RIGHT,
5970   EL_DF_RECEIVER_UP,
5971   EL_DF_RECEIVER_LEFT,
5972   EL_DF_RECEIVER_DOWN,
5973
5974   EL_DF_MIRROR_START,
5975   EL_DF_MIRROR_ROTATING_START,
5976   EL_DF_MIRROR_FIXED_START,
5977   EL_DF_CELL,
5978
5979   EL_DF_FIBRE_OPTIC_RED_1,
5980   EL_DF_FIBRE_OPTIC_YELLOW_1,
5981   EL_DF_FIBRE_OPTIC_GREEN_1,
5982   EL_DF_FIBRE_OPTIC_BLUE_1,
5983
5984   EL_DF_STEEL_GRID_FIXED_START,
5985   EL_DF_STEEL_GRID_ROTATING_START,
5986   EL_DF_WOODEN_GRID_FIXED_START,
5987   EL_DF_WOODEN_GRID_ROTATING_START,
5988
5989   EL_DF_STEEL_WALL,
5990   EL_DF_WOODEN_WALL,
5991   EL_DF_REFRACTOR,
5992   EL_DF_MINE,
5993
5994   EL_DF_SLOPE_1,
5995   EL_DF_SLOPE_2,
5996   EL_DF_SLOPE_3,
5997   EL_DF_SLOPE_4
5998 };
5999 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
6000 static int *editor_el_deflektor_ptr = editor_el_deflektor;
6001 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
6002 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
6003
6004 static int editor_hl_chars[] =
6005 {
6006   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
6007   EL_CHAR('T'),
6008   EL_CHAR('X'),
6009   EL_CHAR('T'),
6010 };
6011
6012 static int editor_el_chars[] =
6013 {
6014   EL_CHAR(' '),
6015   EL_CHAR('!'),
6016   EL_CHAR('"'),
6017   EL_CHAR('#'),
6018
6019   EL_CHAR('$'),
6020   EL_CHAR('%'),
6021   EL_CHAR('&'),
6022   EL_CHAR('\''),
6023
6024   EL_CHAR('('),
6025   EL_CHAR(')'),
6026   EL_CHAR('*'),
6027   EL_CHAR('+'),
6028
6029   EL_CHAR(','),
6030   EL_CHAR('-'),
6031   EL_CHAR('.'),
6032   EL_CHAR('/'),
6033
6034   EL_CHAR('0'),
6035   EL_CHAR('1'),
6036   EL_CHAR('2'),
6037   EL_CHAR('3'),
6038
6039   EL_CHAR('4'),
6040   EL_CHAR('5'),
6041   EL_CHAR('6'),
6042   EL_CHAR('7'),
6043
6044   EL_CHAR('8'),
6045   EL_CHAR('9'),
6046   EL_CHAR(':'),
6047   EL_CHAR(';'),
6048
6049   EL_CHAR('<'),
6050   EL_CHAR('='),
6051   EL_CHAR('>'),
6052   EL_CHAR('?'),
6053
6054   EL_CHAR('@'),
6055   EL_CHAR('A'),
6056   EL_CHAR('B'),
6057   EL_CHAR('C'),
6058
6059   EL_CHAR('D'),
6060   EL_CHAR('E'),
6061   EL_CHAR('F'),
6062   EL_CHAR('G'),
6063
6064   EL_CHAR('H'),
6065   EL_CHAR('I'),
6066   EL_CHAR('J'),
6067   EL_CHAR('K'),
6068
6069   EL_CHAR('L'),
6070   EL_CHAR('M'),
6071   EL_CHAR('N'),
6072   EL_CHAR('O'),
6073
6074   EL_CHAR('P'),
6075   EL_CHAR('Q'),
6076   EL_CHAR('R'),
6077   EL_CHAR('S'),
6078
6079   EL_CHAR('T'),
6080   EL_CHAR('U'),
6081   EL_CHAR('V'),
6082   EL_CHAR('W'),
6083
6084   EL_CHAR('X'),
6085   EL_CHAR('Y'),
6086   EL_CHAR('Z'),
6087   EL_CHAR('['),
6088
6089   EL_CHAR('\\'),
6090   EL_CHAR(']'),
6091   EL_CHAR('^'),
6092   EL_CHAR('_'),
6093
6094   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6095   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6096   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6097   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6098
6099   EL_CHAR(CHAR_BYTE_DEGREE),
6100   EL_CHAR(CHAR_BYTE_REGISTERED),
6101   EL_CHAR(FONT_ASCII_CURSOR),
6102   EL_CHAR(FONT_ASCII_BUTTON),
6103
6104   EL_CHAR(FONT_ASCII_UP),
6105   EL_CHAR(FONT_ASCII_DOWN),
6106   EL_CHAR(' '),
6107   EL_CHAR(' ')
6108 };
6109 static int *editor_hl_chars_ptr = editor_hl_chars;
6110 static int *editor_el_chars_ptr = editor_el_chars;
6111 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6112 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6113
6114 static int editor_hl_steel_chars[] =
6115 {
6116   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6117   EL_STEEL_CHAR('T'),
6118   EL_STEEL_CHAR('X'),
6119   EL_STEEL_CHAR('T'),
6120 };
6121
6122 static int editor_el_steel_chars[] =
6123 {
6124   EL_STEEL_CHAR(' '),
6125   EL_STEEL_CHAR('!'),
6126   EL_STEEL_CHAR('"'),
6127   EL_STEEL_CHAR('#'),
6128
6129   EL_STEEL_CHAR('$'),
6130   EL_STEEL_CHAR('%'),
6131   EL_STEEL_CHAR('&'),
6132   EL_STEEL_CHAR('\''),
6133
6134   EL_STEEL_CHAR('('),
6135   EL_STEEL_CHAR(')'),
6136   EL_STEEL_CHAR('*'),
6137   EL_STEEL_CHAR('+'),
6138
6139   EL_STEEL_CHAR(','),
6140   EL_STEEL_CHAR('-'),
6141   EL_STEEL_CHAR('.'),
6142   EL_STEEL_CHAR('/'),
6143
6144   EL_STEEL_CHAR('0'),
6145   EL_STEEL_CHAR('1'),
6146   EL_STEEL_CHAR('2'),
6147   EL_STEEL_CHAR('3'),
6148
6149   EL_STEEL_CHAR('4'),
6150   EL_STEEL_CHAR('5'),
6151   EL_STEEL_CHAR('6'),
6152   EL_STEEL_CHAR('7'),
6153
6154   EL_STEEL_CHAR('8'),
6155   EL_STEEL_CHAR('9'),
6156   EL_STEEL_CHAR(':'),
6157   EL_STEEL_CHAR(';'),
6158
6159   EL_STEEL_CHAR('<'),
6160   EL_STEEL_CHAR('='),
6161   EL_STEEL_CHAR('>'),
6162   EL_STEEL_CHAR('?'),
6163
6164   EL_STEEL_CHAR('@'),
6165   EL_STEEL_CHAR('A'),
6166   EL_STEEL_CHAR('B'),
6167   EL_STEEL_CHAR('C'),
6168
6169   EL_STEEL_CHAR('D'),
6170   EL_STEEL_CHAR('E'),
6171   EL_STEEL_CHAR('F'),
6172   EL_STEEL_CHAR('G'),
6173
6174   EL_STEEL_CHAR('H'),
6175   EL_STEEL_CHAR('I'),
6176   EL_STEEL_CHAR('J'),
6177   EL_STEEL_CHAR('K'),
6178
6179   EL_STEEL_CHAR('L'),
6180   EL_STEEL_CHAR('M'),
6181   EL_STEEL_CHAR('N'),
6182   EL_STEEL_CHAR('O'),
6183
6184   EL_STEEL_CHAR('P'),
6185   EL_STEEL_CHAR('Q'),
6186   EL_STEEL_CHAR('R'),
6187   EL_STEEL_CHAR('S'),
6188
6189   EL_STEEL_CHAR('T'),
6190   EL_STEEL_CHAR('U'),
6191   EL_STEEL_CHAR('V'),
6192   EL_STEEL_CHAR('W'),
6193
6194   EL_STEEL_CHAR('X'),
6195   EL_STEEL_CHAR('Y'),
6196   EL_STEEL_CHAR('Z'),
6197   EL_STEEL_CHAR('['),
6198
6199   EL_STEEL_CHAR('\\'),
6200   EL_STEEL_CHAR(']'),
6201   EL_STEEL_CHAR('^'),
6202   EL_STEEL_CHAR('_'),
6203
6204   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6205   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6206   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6207   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6208
6209   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6210   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6211   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6212   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6213
6214   EL_STEEL_CHAR(FONT_ASCII_UP),
6215   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6216   EL_STEEL_CHAR(' '),
6217   EL_STEEL_CHAR(' ')
6218 };
6219 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6220 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6221 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6222 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6223
6224 static int editor_hl_custom[] =
6225 {
6226   EL_INTERNAL_CASCADE_CE_ACTIVE,
6227   EL_CHAR('C'),
6228   EL_CHAR('E'),
6229   EL_EMPTY,
6230 };
6231
6232 static int editor_el_custom[] =
6233 {
6234   EL_CUSTOM_START + 0,
6235   EL_CUSTOM_START + 1,
6236   EL_CUSTOM_START + 2,
6237   EL_CUSTOM_START + 3,
6238
6239   EL_CUSTOM_START + 4,
6240   EL_CUSTOM_START + 5,
6241   EL_CUSTOM_START + 6,
6242   EL_CUSTOM_START + 7,
6243
6244   EL_CUSTOM_START + 8,
6245   EL_CUSTOM_START + 9,
6246   EL_CUSTOM_START + 10,
6247   EL_CUSTOM_START + 11,
6248
6249   EL_CUSTOM_START + 12,
6250   EL_CUSTOM_START + 13,
6251   EL_CUSTOM_START + 14,
6252   EL_CUSTOM_START + 15,
6253
6254   EL_CUSTOM_START + 16,
6255   EL_CUSTOM_START + 17,
6256   EL_CUSTOM_START + 18,
6257   EL_CUSTOM_START + 19,
6258
6259   EL_CUSTOM_START + 20,
6260   EL_CUSTOM_START + 21,
6261   EL_CUSTOM_START + 22,
6262   EL_CUSTOM_START + 23,
6263
6264   EL_CUSTOM_START + 24,
6265   EL_CUSTOM_START + 25,
6266   EL_CUSTOM_START + 26,
6267   EL_CUSTOM_START + 27,
6268
6269   EL_CUSTOM_START + 28,
6270   EL_CUSTOM_START + 29,
6271   EL_CUSTOM_START + 30,
6272   EL_CUSTOM_START + 31,
6273
6274   EL_CUSTOM_START + 32,
6275   EL_CUSTOM_START + 33,
6276   EL_CUSTOM_START + 34,
6277   EL_CUSTOM_START + 35,
6278
6279   EL_CUSTOM_START + 36,
6280   EL_CUSTOM_START + 37,
6281   EL_CUSTOM_START + 38,
6282   EL_CUSTOM_START + 39,
6283
6284   EL_CUSTOM_START + 40,
6285   EL_CUSTOM_START + 41,
6286   EL_CUSTOM_START + 42,
6287   EL_CUSTOM_START + 43,
6288
6289   EL_CUSTOM_START + 44,
6290   EL_CUSTOM_START + 45,
6291   EL_CUSTOM_START + 46,
6292   EL_CUSTOM_START + 47,
6293
6294   EL_CUSTOM_START + 48,
6295   EL_CUSTOM_START + 49,
6296   EL_CUSTOM_START + 50,
6297   EL_CUSTOM_START + 51,
6298
6299   EL_CUSTOM_START + 52,
6300   EL_CUSTOM_START + 53,
6301   EL_CUSTOM_START + 54,
6302   EL_CUSTOM_START + 55,
6303
6304   EL_CUSTOM_START + 56,
6305   EL_CUSTOM_START + 57,
6306   EL_CUSTOM_START + 58,
6307   EL_CUSTOM_START + 59,
6308
6309   EL_CUSTOM_START + 60,
6310   EL_CUSTOM_START + 61,
6311   EL_CUSTOM_START + 62,
6312   EL_CUSTOM_START + 63,
6313
6314   EL_CUSTOM_START + 64,
6315   EL_CUSTOM_START + 65,
6316   EL_CUSTOM_START + 66,
6317   EL_CUSTOM_START + 67,
6318
6319   EL_CUSTOM_START + 68,
6320   EL_CUSTOM_START + 69,
6321   EL_CUSTOM_START + 70,
6322   EL_CUSTOM_START + 71,
6323
6324   EL_CUSTOM_START + 72,
6325   EL_CUSTOM_START + 73,
6326   EL_CUSTOM_START + 74,
6327   EL_CUSTOM_START + 75,
6328
6329   EL_CUSTOM_START + 76,
6330   EL_CUSTOM_START + 77,
6331   EL_CUSTOM_START + 78,
6332   EL_CUSTOM_START + 79,
6333
6334   EL_CUSTOM_START + 80,
6335   EL_CUSTOM_START + 81,
6336   EL_CUSTOM_START + 82,
6337   EL_CUSTOM_START + 83,
6338
6339   EL_CUSTOM_START + 84,
6340   EL_CUSTOM_START + 85,
6341   EL_CUSTOM_START + 86,
6342   EL_CUSTOM_START + 87,
6343
6344   EL_CUSTOM_START + 88,
6345   EL_CUSTOM_START + 89,
6346   EL_CUSTOM_START + 90,
6347   EL_CUSTOM_START + 91,
6348
6349   EL_CUSTOM_START + 92,
6350   EL_CUSTOM_START + 93,
6351   EL_CUSTOM_START + 94,
6352   EL_CUSTOM_START + 95,
6353
6354   EL_CUSTOM_START + 96,
6355   EL_CUSTOM_START + 97,
6356   EL_CUSTOM_START + 98,
6357   EL_CUSTOM_START + 99,
6358
6359   EL_CUSTOM_START + 100,
6360   EL_CUSTOM_START + 101,
6361   EL_CUSTOM_START + 102,
6362   EL_CUSTOM_START + 103,
6363
6364   EL_CUSTOM_START + 104,
6365   EL_CUSTOM_START + 105,
6366   EL_CUSTOM_START + 106,
6367   EL_CUSTOM_START + 107,
6368
6369   EL_CUSTOM_START + 108,
6370   EL_CUSTOM_START + 109,
6371   EL_CUSTOM_START + 110,
6372   EL_CUSTOM_START + 111,
6373
6374   EL_CUSTOM_START + 112,
6375   EL_CUSTOM_START + 113,
6376   EL_CUSTOM_START + 114,
6377   EL_CUSTOM_START + 115,
6378
6379   EL_CUSTOM_START + 116,
6380   EL_CUSTOM_START + 117,
6381   EL_CUSTOM_START + 118,
6382   EL_CUSTOM_START + 119,
6383
6384   EL_CUSTOM_START + 120,
6385   EL_CUSTOM_START + 121,
6386   EL_CUSTOM_START + 122,
6387   EL_CUSTOM_START + 123,
6388
6389   EL_CUSTOM_START + 124,
6390   EL_CUSTOM_START + 125,
6391   EL_CUSTOM_START + 126,
6392   EL_CUSTOM_START + 127,
6393
6394   EL_CUSTOM_START + 128,
6395   EL_CUSTOM_START + 129,
6396   EL_CUSTOM_START + 130,
6397   EL_CUSTOM_START + 131,
6398
6399   EL_CUSTOM_START + 132,
6400   EL_CUSTOM_START + 133,
6401   EL_CUSTOM_START + 134,
6402   EL_CUSTOM_START + 135,
6403
6404   EL_CUSTOM_START + 136,
6405   EL_CUSTOM_START + 137,
6406   EL_CUSTOM_START + 138,
6407   EL_CUSTOM_START + 139,
6408
6409   EL_CUSTOM_START + 140,
6410   EL_CUSTOM_START + 141,
6411   EL_CUSTOM_START + 142,
6412   EL_CUSTOM_START + 143,
6413
6414   EL_CUSTOM_START + 144,
6415   EL_CUSTOM_START + 145,
6416   EL_CUSTOM_START + 146,
6417   EL_CUSTOM_START + 147,
6418
6419   EL_CUSTOM_START + 148,
6420   EL_CUSTOM_START + 149,
6421   EL_CUSTOM_START + 150,
6422   EL_CUSTOM_START + 151,
6423
6424   EL_CUSTOM_START + 152,
6425   EL_CUSTOM_START + 153,
6426   EL_CUSTOM_START + 154,
6427   EL_CUSTOM_START + 155,
6428
6429   EL_CUSTOM_START + 156,
6430   EL_CUSTOM_START + 157,
6431   EL_CUSTOM_START + 158,
6432   EL_CUSTOM_START + 159,
6433
6434   EL_CUSTOM_START + 160,
6435   EL_CUSTOM_START + 161,
6436   EL_CUSTOM_START + 162,
6437   EL_CUSTOM_START + 163,
6438
6439   EL_CUSTOM_START + 164,
6440   EL_CUSTOM_START + 165,
6441   EL_CUSTOM_START + 166,
6442   EL_CUSTOM_START + 167,
6443
6444   EL_CUSTOM_START + 168,
6445   EL_CUSTOM_START + 169,
6446   EL_CUSTOM_START + 170,
6447   EL_CUSTOM_START + 171,
6448
6449   EL_CUSTOM_START + 172,
6450   EL_CUSTOM_START + 173,
6451   EL_CUSTOM_START + 174,
6452   EL_CUSTOM_START + 175,
6453
6454   EL_CUSTOM_START + 176,
6455   EL_CUSTOM_START + 177,
6456   EL_CUSTOM_START + 178,
6457   EL_CUSTOM_START + 179,
6458
6459   EL_CUSTOM_START + 180,
6460   EL_CUSTOM_START + 181,
6461   EL_CUSTOM_START + 182,
6462   EL_CUSTOM_START + 183,
6463
6464   EL_CUSTOM_START + 184,
6465   EL_CUSTOM_START + 185,
6466   EL_CUSTOM_START + 186,
6467   EL_CUSTOM_START + 187,
6468
6469   EL_CUSTOM_START + 188,
6470   EL_CUSTOM_START + 189,
6471   EL_CUSTOM_START + 190,
6472   EL_CUSTOM_START + 191,
6473
6474   EL_CUSTOM_START + 192,
6475   EL_CUSTOM_START + 193,
6476   EL_CUSTOM_START + 194,
6477   EL_CUSTOM_START + 195,
6478
6479   EL_CUSTOM_START + 196,
6480   EL_CUSTOM_START + 197,
6481   EL_CUSTOM_START + 198,
6482   EL_CUSTOM_START + 199,
6483
6484   EL_CUSTOM_START + 200,
6485   EL_CUSTOM_START + 201,
6486   EL_CUSTOM_START + 202,
6487   EL_CUSTOM_START + 203,
6488
6489   EL_CUSTOM_START + 204,
6490   EL_CUSTOM_START + 205,
6491   EL_CUSTOM_START + 206,
6492   EL_CUSTOM_START + 207,
6493
6494   EL_CUSTOM_START + 208,
6495   EL_CUSTOM_START + 209,
6496   EL_CUSTOM_START + 210,
6497   EL_CUSTOM_START + 211,
6498
6499   EL_CUSTOM_START + 212,
6500   EL_CUSTOM_START + 213,
6501   EL_CUSTOM_START + 214,
6502   EL_CUSTOM_START + 215,
6503
6504   EL_CUSTOM_START + 216,
6505   EL_CUSTOM_START + 217,
6506   EL_CUSTOM_START + 218,
6507   EL_CUSTOM_START + 219,
6508
6509   EL_CUSTOM_START + 220,
6510   EL_CUSTOM_START + 221,
6511   EL_CUSTOM_START + 222,
6512   EL_CUSTOM_START + 223,
6513
6514   EL_CUSTOM_START + 224,
6515   EL_CUSTOM_START + 225,
6516   EL_CUSTOM_START + 226,
6517   EL_CUSTOM_START + 227,
6518
6519   EL_CUSTOM_START + 228,
6520   EL_CUSTOM_START + 229,
6521   EL_CUSTOM_START + 230,
6522   EL_CUSTOM_START + 231,
6523
6524   EL_CUSTOM_START + 232,
6525   EL_CUSTOM_START + 233,
6526   EL_CUSTOM_START + 234,
6527   EL_CUSTOM_START + 235,
6528
6529   EL_CUSTOM_START + 236,
6530   EL_CUSTOM_START + 237,
6531   EL_CUSTOM_START + 238,
6532   EL_CUSTOM_START + 239,
6533
6534   EL_CUSTOM_START + 240,
6535   EL_CUSTOM_START + 241,
6536   EL_CUSTOM_START + 242,
6537   EL_CUSTOM_START + 243,
6538
6539   EL_CUSTOM_START + 244,
6540   EL_CUSTOM_START + 245,
6541   EL_CUSTOM_START + 246,
6542   EL_CUSTOM_START + 247,
6543
6544   EL_CUSTOM_START + 248,
6545   EL_CUSTOM_START + 249,
6546   EL_CUSTOM_START + 250,
6547   EL_CUSTOM_START + 251,
6548
6549   EL_CUSTOM_START + 252,
6550   EL_CUSTOM_START + 253,
6551   EL_CUSTOM_START + 254,
6552   EL_CUSTOM_START + 255
6553 };
6554 static int *editor_hl_custom_ptr = editor_hl_custom;
6555 static int *editor_el_custom_ptr = editor_el_custom;
6556 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6557 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6558
6559 static int editor_hl_group[] =
6560 {
6561   EL_INTERNAL_CASCADE_GE_ACTIVE,
6562   EL_CHAR('G'),
6563   EL_CHAR('E'),
6564   EL_EMPTY,
6565 };
6566
6567 static int editor_el_group[] =
6568 {
6569   EL_GROUP_START + 0,
6570   EL_GROUP_START + 1,
6571   EL_GROUP_START + 2,
6572   EL_GROUP_START + 3,
6573
6574   EL_GROUP_START + 4,
6575   EL_GROUP_START + 5,
6576   EL_GROUP_START + 6,
6577   EL_GROUP_START + 7,
6578
6579   EL_GROUP_START + 8,
6580   EL_GROUP_START + 9,
6581   EL_GROUP_START + 10,
6582   EL_GROUP_START + 11,
6583
6584   EL_GROUP_START + 12,
6585   EL_GROUP_START + 13,
6586   EL_GROUP_START + 14,
6587   EL_GROUP_START + 15,
6588
6589   EL_GROUP_START + 16,
6590   EL_GROUP_START + 17,
6591   EL_GROUP_START + 18,
6592   EL_GROUP_START + 19,
6593
6594   EL_GROUP_START + 20,
6595   EL_GROUP_START + 21,
6596   EL_GROUP_START + 22,
6597   EL_GROUP_START + 23,
6598
6599   EL_GROUP_START + 24,
6600   EL_GROUP_START + 25,
6601   EL_GROUP_START + 26,
6602   EL_GROUP_START + 27,
6603
6604   EL_GROUP_START + 28,
6605   EL_GROUP_START + 29,
6606   EL_GROUP_START + 30,
6607   EL_GROUP_START + 31
6608 };
6609 static int *editor_hl_group_ptr = editor_hl_group;
6610 static int *editor_el_group_ptr = editor_el_group;
6611 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6612 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6613
6614 static int editor_hl_empty_space[] =
6615 {
6616   EL_INTERNAL_CASCADE_ES_ACTIVE,
6617   EL_CHAR('E'),
6618   EL_CHAR('S'),
6619   EL_EMPTY,
6620 };
6621
6622 static int editor_el_empty_space[] =
6623 {
6624   EL_EMPTY_SPACE_1,
6625   EL_EMPTY_SPACE_2,
6626   EL_EMPTY_SPACE_3,
6627   EL_EMPTY_SPACE_4,
6628
6629   EL_EMPTY_SPACE_5,
6630   EL_EMPTY_SPACE_6,
6631   EL_EMPTY_SPACE_7,
6632   EL_EMPTY_SPACE_8,
6633
6634   EL_EMPTY_SPACE_9,
6635   EL_EMPTY_SPACE_10,
6636   EL_EMPTY_SPACE_11,
6637   EL_EMPTY_SPACE_12,
6638
6639   EL_EMPTY_SPACE_13,
6640   EL_EMPTY_SPACE_14,
6641   EL_EMPTY_SPACE_15,
6642   EL_EMPTY_SPACE_16
6643 };
6644 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6645 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6646 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6647 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6648
6649 static int editor_hl_reference[] =
6650 {
6651   EL_INTERNAL_CASCADE_REF_ACTIVE,
6652   EL_CHAR('R'),
6653   EL_CHAR('E'),
6654   EL_CHAR('F')
6655 };
6656
6657 static int editor_el_reference[] =
6658 {
6659   EL_TRIGGER_PLAYER,
6660   EL_TRIGGER_ELEMENT,
6661   EL_TRIGGER_CE_VALUE,
6662   EL_TRIGGER_CE_SCORE,
6663
6664   EL_SELF,
6665   EL_ANY_ELEMENT,
6666   EL_CURRENT_CE_VALUE,
6667   EL_CURRENT_CE_SCORE,
6668
6669   EL_PREV_CE_8,
6670   EL_PREV_CE_7,
6671   EL_PREV_CE_6,
6672   EL_PREV_CE_5,
6673
6674   EL_PREV_CE_4,
6675   EL_PREV_CE_3,
6676   EL_PREV_CE_2,
6677   EL_PREV_CE_1,
6678
6679   EL_NEXT_CE_1,
6680   EL_NEXT_CE_2,
6681   EL_NEXT_CE_3,
6682   EL_NEXT_CE_4,
6683
6684   EL_NEXT_CE_5,
6685   EL_NEXT_CE_6,
6686   EL_NEXT_CE_7,
6687   EL_NEXT_CE_8,
6688 };
6689 static int *editor_hl_reference_ptr = editor_hl_reference;
6690 static int *editor_el_reference_ptr = editor_el_reference;
6691 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6692 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6693
6694 static int editor_hl_user_defined[] =
6695 {
6696   EL_INTERNAL_CASCADE_USER_ACTIVE,
6697   EL_CHAR('M'),
6698   EL_CHAR('Y'),
6699   EL_EMPTY,
6700 };
6701
6702 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6703 static int *editor_el_user_defined_ptr = NULL;
6704 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6705 static int num_editor_el_user_defined = 0;
6706
6707 static int editor_hl_dynamic[] =
6708 {
6709   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6710   EL_CHAR('U'),
6711   EL_CHAR('S'),
6712   EL_CHAR('E'),
6713 };
6714
6715 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6716 static int *editor_el_dynamic_ptr = NULL;
6717 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6718 static int num_editor_el_dynamic = 0;
6719
6720 static int editor_hl_empty[] = { EL_EMPTY };
6721 static int *editor_el_empty = NULL;     // dynamically allocated
6722
6723 static int *editor_hl_empty_ptr = editor_hl_empty;
6724 static int *editor_el_empty_ptr = NULL;
6725 static int num_editor_hl_empty = 0;
6726 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6727
6728 static boolean use_el_empty = FALSE;
6729
6730 static int *editor_elements = NULL;     // dynamically allocated
6731 static int num_editor_elements = 0;     // dynamically determined
6732
6733 static boolean setup_editor_cascade_never = FALSE;
6734
6735 static boolean setup_editor_el_players                  = TRUE;
6736 static boolean setup_editor_el_boulderdash              = TRUE;
6737 static boolean setup_editor_el_boulderdash_native       = TRUE;
6738 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6739 static boolean setup_editor_el_emerald_mine             = TRUE;
6740 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6741 static boolean setup_editor_el_more                     = TRUE;
6742 static boolean setup_editor_el_sokoban                  = TRUE;
6743 static boolean setup_editor_el_supaplex                 = TRUE;
6744 static boolean setup_editor_el_diamond_caves            = TRUE;
6745 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6746 static boolean setup_editor_el_mirror_magic             = TRUE;
6747 static boolean setup_editor_el_deflektor                = TRUE;
6748 static boolean setup_editor_el_chars                    = TRUE;
6749 static boolean setup_editor_el_steel_chars              = TRUE;
6750 static boolean setup_editor_el_custom                   = TRUE;
6751 static boolean setup_editor_el_user_defined             = TRUE;
6752 static boolean setup_editor_el_dynamic                  = TRUE;
6753
6754 static int editor_hl_unused[] = { EL_EMPTY };
6755 static int *editor_hl_unused_ptr = editor_hl_unused;
6756 static int num_editor_hl_unused = 0;
6757
6758 static struct
6759 {
6760   boolean *setup_value;
6761   boolean *setup_cascade_value;
6762
6763   int **headline_list;
6764   int *headline_list_size;
6765
6766   int **element_list;
6767   int *element_list_size;
6768
6769   boolean last_setup_value;
6770 }
6771 editor_elements_info[] =
6772 {
6773   {
6774     &setup_editor_el_players,
6775     &setup_editor_cascade_never,
6776     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6777     &editor_el_players_ptr,             &num_editor_el_players
6778   },
6779   {
6780     &setup_editor_el_boulderdash,
6781     &setup.editor_cascade.el_bd,
6782     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6783     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6784   },
6785   {
6786     &setup_editor_el_boulderdash_native,
6787     &setup.editor_cascade.el_bd_native,
6788     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6789     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6790   },
6791   {
6792     &setup_editor_el_boulderdash_effects,
6793     &setup.editor_cascade.el_bd_effects,
6794     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6795     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6796   },
6797   {
6798     &setup_editor_el_emerald_mine,
6799     &setup.editor_cascade.el_em,
6800     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6801     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6802   },
6803   {
6804     &setup_editor_el_emerald_mine_club,
6805     &setup.editor_cascade.el_emc,
6806     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6807     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6808   },
6809   {
6810     &setup_editor_el_more,
6811     &setup.editor_cascade.el_rnd,
6812     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6813     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6814   },
6815   {
6816     &setup_editor_el_sokoban,
6817     &setup.editor_cascade.el_sb,
6818     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6819     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6820   },
6821   {
6822     &setup_editor_el_supaplex,
6823     &setup.editor_cascade.el_sp,
6824     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6825     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6826   },
6827   {
6828     &setup_editor_el_diamond_caves,
6829     &setup.editor_cascade.el_dc,
6830     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6831     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6832   },
6833   {
6834     &setup_editor_el_dx_boulderdash,
6835     &setup.editor_cascade.el_dx,
6836     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6837     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6838   },
6839   {
6840     &setup_editor_el_mirror_magic,
6841     &setup.editor_cascade.el_mm,
6842     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6843     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6844   },
6845   {
6846     &setup_editor_el_deflektor,
6847     &setup.editor_cascade.el_df,
6848     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6849     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6850   },
6851   {
6852     &setup_editor_el_chars,
6853     &setup.editor_cascade.el_chars,
6854     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6855     &editor_el_chars_ptr,               &num_editor_el_chars
6856   },
6857   {
6858     &setup_editor_el_steel_chars,
6859     &setup.editor_cascade.el_steel_chars,
6860     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6861     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6862   },
6863   {
6864     &setup_editor_el_custom,
6865     &setup.editor_cascade.el_ce,
6866     &editor_hl_custom_ptr,              &num_editor_hl_custom,
6867     &editor_el_custom_ptr,              &num_editor_el_custom
6868   },
6869   {
6870     &setup_editor_el_custom,
6871     &setup.editor_cascade.el_ge,
6872     &editor_hl_group_ptr,               &num_editor_hl_group,
6873     &editor_el_group_ptr,               &num_editor_el_group
6874   },
6875   {
6876     &setup_editor_el_custom,
6877     &setup.editor_cascade.el_es,
6878     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
6879     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
6880   },
6881   {
6882     &setup_editor_el_custom,
6883     &setup.editor_cascade.el_ref,
6884     &editor_hl_reference_ptr,           &num_editor_hl_reference,
6885     &editor_el_reference_ptr,           &num_editor_el_reference
6886   },
6887   {
6888     &setup_editor_el_user_defined,
6889     &setup.editor_cascade.el_user,
6890     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
6891     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
6892   },
6893   {
6894     &setup_editor_el_dynamic,
6895     &setup.editor_cascade.el_dynamic,
6896     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
6897     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
6898   },
6899   {
6900     &use_el_empty,
6901     &use_el_empty,
6902     &editor_hl_empty_ptr,               &num_editor_hl_empty,
6903     &editor_el_empty_ptr,               &num_editor_el_empty,
6904   },
6905   {
6906     NULL,
6907     NULL,
6908     NULL,                               NULL,
6909     NULL,                               NULL
6910   }
6911 };
6912
6913 static struct XY xy_directions[] =
6914 {
6915   { -1,  0 },
6916   { +1,  0 },
6917   {  0, -1 },
6918   {  0, +1 }
6919 };
6920
6921
6922 // ----------------------------------------------------------------------------
6923 // functions
6924 // ----------------------------------------------------------------------------
6925
6926 static int getMaxInfoTextLength(void)
6927 {
6928   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
6929 }
6930
6931 static int getTextWidthForGadget(char *text)
6932 {
6933   if (text == NULL)
6934     return 0;
6935
6936   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
6937 }
6938
6939 static int getTextWidthForDrawingArea(char *text)
6940 {
6941   if (text == NULL)
6942     return 0;
6943
6944   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
6945 }
6946
6947 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
6948 {
6949   return (gi->x + gi->width + getTextWidthForGadget(text));
6950 }
6951
6952 static char *getElementInfoText(int element)
6953 {
6954   char *info_text = NULL;
6955
6956   if (element < MAX_NUM_ELEMENTS)
6957   {
6958     if (strlen(element_info[element].description) > 0)
6959       info_text = element_info[element].description;
6960     else if (element_info[element].custom_description != NULL)
6961       info_text = element_info[element].custom_description;
6962     else if (element_info[element].editor_description != NULL)
6963       info_text = element_info[element].editor_description;
6964   }
6965
6966   if (info_text == NULL)
6967     info_text = INFOTEXT_UNKNOWN_ELEMENT;
6968
6969   return info_text;
6970 }
6971
6972 static char *getElementDescriptionFilenameExt(char *basename)
6973 {
6974   char *elements_subdir = ELEMENTS_DIRECTORY;
6975   static char *elements_subdir2 = NULL;
6976   static char *filename = NULL;
6977
6978   if (elements_subdir2 == NULL)
6979     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
6980
6981   checked_free(filename);
6982
6983   // 1st try: look for element description in current level set directory
6984   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
6985   if (fileExists(filename))
6986     return filename;
6987
6988   free(filename);
6989
6990   // 2nd try: look for element description in the game's base directory
6991   filename = getPath3(options.docs_directory, elements_subdir, basename);
6992   if (fileExists(filename))
6993     return filename;
6994
6995   return NULL;
6996 }
6997
6998 static char *getElementDescriptionFilename(int element)
6999 {
7000   char basename[MAX_FILENAME_LEN];
7001   char *filename;
7002
7003   // 1st try: look for element description file for exactly this element
7004   sprintf(basename, "%s.txt", element_info[element].token_name);
7005   filename = getElementDescriptionFilenameExt(basename);
7006   if (filename != NULL)
7007     return filename;
7008
7009   // 2nd try: look for element description file for this element's class
7010   sprintf(basename, "%s.txt", element_info[element].class_name);
7011   filename = getElementDescriptionFilenameExt(basename);
7012   if (filename != NULL)
7013     return filename;
7014
7015   // 3rd try: look for generic fallback text file for any element
7016   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
7017   if (filename != NULL)
7018     return filename;
7019
7020   return NULL;
7021 }
7022
7023 static boolean suppressBorderElement(void)
7024 {
7025   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
7026           lev_fieldx <= MAX_ED_FIELDX &&
7027           lev_fieldy <= MAX_ED_FIELDY);
7028 }
7029
7030 static void InitDynamicEditorElementList(int **elements, int *num_elements)
7031 {
7032   boolean element_found[NUM_FILE_ELEMENTS];
7033   int i, x, y;
7034
7035   // initialize list of used elements to "not used"
7036   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7037     element_found[i] = FALSE;
7038
7039   // find all elements used in current level
7040   for (y = 0; y < lev_fieldy; y++)
7041   {
7042     for (x = 0; x < lev_fieldx; x++)
7043     {
7044       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
7045         continue;
7046
7047       if (IS_MM_WALL(Tile[x][y]))
7048         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
7049       else
7050         element_found[Tile[x][y]] = TRUE;
7051     }
7052   }
7053
7054   *num_elements = 0;
7055
7056   // count number of elements used in current level
7057   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7058     if (element_found[i])
7059       (*num_elements)++;
7060
7061   // add space for up to 3 more elements for padding that may be needed
7062   *num_elements += 3;
7063
7064   // free memory for old list of elements, if needed
7065   checked_free(*elements);
7066
7067   // allocate memory for new list of elements
7068   *elements = checked_malloc(*num_elements * sizeof(int));
7069
7070   *num_elements = 0;
7071
7072   // add all elements used in current level (non-custom/group/empty elements)
7073   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7074     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
7075                               IS_GROUP_ELEMENT(i) ||
7076                               IS_EMPTY_ELEMENT(i)))
7077       (*elements)[(*num_elements)++] = i;
7078
7079   // add all elements used in current level (custom/group/empty elements)
7080   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7081     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
7082                              IS_GROUP_ELEMENT(i) ||
7083                              IS_EMPTY_ELEMENT(i)))
7084       (*elements)[(*num_elements)++] = i;
7085
7086   while (*num_elements % 4)     // pad with empty elements, if needed
7087     (*elements)[(*num_elements)++] = EL_EMPTY;
7088 }
7089
7090 static void ReinitializeElementList_EnableSections(void)
7091 {
7092   // default: enable all element sections
7093
7094   setup_editor_el_players               = TRUE;
7095   setup_editor_el_boulderdash           = TRUE;
7096   setup_editor_el_boulderdash_native    = TRUE;
7097   setup_editor_el_boulderdash_effects   = TRUE;
7098   setup_editor_el_emerald_mine          = TRUE;
7099   setup_editor_el_emerald_mine_club     = TRUE;
7100   setup_editor_el_more                  = TRUE;
7101   setup_editor_el_sokoban               = TRUE;
7102   setup_editor_el_supaplex              = TRUE;
7103   setup_editor_el_diamond_caves         = TRUE;
7104   setup_editor_el_dx_boulderdash        = TRUE;
7105   setup_editor_el_mirror_magic          = TRUE;
7106   setup_editor_el_deflektor             = TRUE;
7107   setup_editor_el_chars                 = TRUE;
7108   setup_editor_el_steel_chars           = TRUE;
7109
7110   setup_editor_el_custom                = TRUE;
7111   setup_editor_el_user_defined          = TRUE;
7112   setup_editor_el_dynamic               = TRUE;
7113
7114   // now disable all element sections not to be displayed
7115
7116   if (!setup.editor.el_classic)
7117   {
7118     setup_editor_el_players             = FALSE;
7119     setup_editor_el_boulderdash         = FALSE;
7120     setup_editor_el_boulderdash_native  = FALSE;
7121     setup_editor_el_boulderdash_effects = FALSE;
7122     setup_editor_el_emerald_mine        = FALSE;
7123     setup_editor_el_emerald_mine_club   = FALSE;
7124     setup_editor_el_more                = FALSE;
7125     setup_editor_el_sokoban             = FALSE;
7126     setup_editor_el_supaplex            = FALSE;
7127     setup_editor_el_diamond_caves       = FALSE;
7128     setup_editor_el_dx_boulderdash      = FALSE;
7129     setup_editor_el_mirror_magic        = FALSE;
7130     setup_editor_el_deflektor           = FALSE;
7131     setup_editor_el_chars               = FALSE;
7132     setup_editor_el_steel_chars         = FALSE;
7133   }
7134
7135   if (!setup.editor.el_custom)
7136   {
7137     setup_editor_el_custom              = FALSE;
7138   }
7139
7140   if (!setup.editor.el_user_defined)
7141   {
7142     setup_editor_el_user_defined        = FALSE;
7143   }
7144
7145   if (!setup.editor.el_dynamic)
7146   {
7147     setup_editor_el_dynamic             = FALSE;
7148   }
7149
7150   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7151   {
7152     setup_editor_el_boulderdash_native  = FALSE;
7153     setup_editor_el_boulderdash_effects = FALSE;
7154     setup_editor_el_mirror_magic        = FALSE;
7155     setup_editor_el_deflektor           = FALSE;
7156   }
7157   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7158   {
7159     setup_editor_el_players             = FALSE;
7160     setup_editor_el_boulderdash         = FALSE;
7161     setup_editor_el_emerald_mine        = FALSE;
7162     setup_editor_el_emerald_mine_club   = FALSE;
7163     setup_editor_el_more                = FALSE;
7164     setup_editor_el_sokoban             = FALSE;
7165     setup_editor_el_supaplex            = FALSE;
7166     setup_editor_el_diamond_caves       = FALSE;
7167     setup_editor_el_dx_boulderdash      = FALSE;
7168     setup_editor_el_mirror_magic        = FALSE;
7169     setup_editor_el_deflektor           = FALSE;
7170     setup_editor_el_chars               = FALSE;
7171     setup_editor_el_steel_chars         = FALSE;
7172
7173     setup_editor_el_custom              = FALSE;
7174   }
7175   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7176   {
7177     setup_editor_el_boulderdash         = FALSE;
7178     setup_editor_el_boulderdash_native  = FALSE;
7179     setup_editor_el_boulderdash_effects = FALSE;
7180     setup_editor_el_more                = FALSE;
7181     setup_editor_el_sokoban             = FALSE;
7182     setup_editor_el_supaplex            = FALSE;
7183     setup_editor_el_diamond_caves       = FALSE;
7184     setup_editor_el_dx_boulderdash      = FALSE;
7185     setup_editor_el_mirror_magic        = FALSE;
7186     setup_editor_el_deflektor           = FALSE;
7187     setup_editor_el_steel_chars         = FALSE;
7188
7189     setup_editor_el_custom              = FALSE;
7190   }
7191   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7192   {
7193     setup_editor_el_players             = FALSE;
7194     setup_editor_el_boulderdash         = FALSE;
7195     setup_editor_el_boulderdash_native  = FALSE;
7196     setup_editor_el_boulderdash_effects = FALSE;
7197     setup_editor_el_emerald_mine        = FALSE;
7198     setup_editor_el_emerald_mine_club   = FALSE;
7199     setup_editor_el_more                = FALSE;
7200     setup_editor_el_sokoban             = FALSE;
7201     setup_editor_el_diamond_caves       = FALSE;
7202     setup_editor_el_dx_boulderdash      = FALSE;
7203     setup_editor_el_mirror_magic        = FALSE;
7204     setup_editor_el_deflektor           = FALSE;
7205     setup_editor_el_chars               = FALSE;
7206     setup_editor_el_steel_chars         = FALSE;
7207
7208     setup_editor_el_custom              = FALSE;
7209   }
7210   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7211   {
7212     setup_editor_el_players             = FALSE;
7213     setup_editor_el_boulderdash         = FALSE;
7214     setup_editor_el_boulderdash_native  = FALSE;
7215     setup_editor_el_boulderdash_effects = FALSE;
7216     setup_editor_el_emerald_mine        = FALSE;
7217     setup_editor_el_emerald_mine_club   = FALSE;
7218     setup_editor_el_more                = FALSE;
7219     setup_editor_el_sokoban             = FALSE;
7220     setup_editor_el_supaplex            = FALSE;
7221     setup_editor_el_diamond_caves       = FALSE;
7222     setup_editor_el_dx_boulderdash      = FALSE;
7223     setup_editor_el_steel_chars         = FALSE;
7224
7225     setup_editor_el_custom              = FALSE;
7226   }
7227 }
7228
7229 static void ReinitializeElementList(void)
7230 {
7231   static boolean initialization_needed = TRUE;
7232   int pos = 0;
7233   int i, j;
7234
7235   ReinitializeElementList_EnableSections();
7236
7237   if (initialization_needed)
7238   {
7239     LoadSetup_EditorCascade();          // load last editor cascade state
7240
7241     // initialize editor cascade element from saved cascade state
7242     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7243     {
7244       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7245       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7246
7247       if (IS_EDITOR_CASCADE(*cascade_element))
7248         *cascade_element =
7249           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7250            EL_CASCADE_INACTIVE(*cascade_element));
7251     }
7252
7253     initialization_needed = FALSE;
7254   }
7255
7256   checked_free(editor_elements);
7257
7258   // reload optional user defined element list for each invocation of editor
7259   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7260                                    &num_editor_el_user_defined);
7261
7262   // initialize dynamic level element list for each invocation of editor
7263   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7264                                &num_editor_el_dynamic);
7265
7266   // initialize list of empty elements (used for padding, if needed)
7267   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7268     editor_el_empty[i] = EL_EMPTY;
7269
7270   // do some sanity checks for each element from element list
7271   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7272   {
7273     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7274     {
7275       int element = (*editor_elements_info[i].element_list)[j];
7276
7277       if (element >= NUM_FILE_ELEMENTS)
7278         Warn("editor element %d is runtime element", element);
7279
7280       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7281         Warn("no element description text for element %d", element);
7282     }
7283   }
7284
7285   num_editor_elements = 0;
7286   use_el_empty = FALSE;
7287
7288   // determine size of element list
7289   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7290   {
7291     if (*editor_elements_info[i].setup_value)
7292     {
7293       boolean found_inactive_cascade = FALSE;
7294
7295       if (setup.editor.el_headlines)
7296       {
7297         // required for correct padding of palette headline buttons
7298         if (*editor_elements_info[i].headline_list_size > 0)
7299           num_editor_elements += ED_ELEMENTLIST_COLS;
7300
7301         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7302         {
7303           int element = (*editor_elements_info[i].headline_list)[j];
7304
7305           if (IS_EDITOR_CASCADE_INACTIVE(element))
7306             found_inactive_cascade = TRUE;
7307         }
7308       }
7309
7310       if (found_inactive_cascade)
7311         continue;
7312
7313       // required for correct padding of palette element buttons
7314       int element_list_size = *editor_elements_info[i].element_list_size;
7315       int element_rows =
7316         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7317       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7318
7319       num_editor_elements += element_buttons;
7320     }
7321   }
7322
7323   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7324   {
7325     // offer at least as many elements as element buttons exist
7326     use_el_empty = TRUE;
7327     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7328
7329     num_editor_elements += num_editor_el_empty;
7330   }
7331   else
7332   {
7333     num_editor_el_empty = 0;
7334   }
7335
7336   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7337
7338   // fill element list
7339   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7340   {
7341     boolean found_inactive_cascade = FALSE;
7342
7343     if (*editor_elements_info[i].setup_value)
7344     {
7345       if (setup.editor.el_headlines)
7346       {
7347         // required for correct padding of palette headline buttons
7348         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7349                              ED_ELEMENTLIST_COLS : 0);
7350
7351         for (j = 0; j < headline_size; j++)
7352         {
7353           // use empty elements for padding of palette headline buttons
7354           int element = (j < *editor_elements_info[i].headline_list_size ?
7355                          (*editor_elements_info[i].headline_list)[j] :
7356                          editor_el_empty[0]);
7357
7358           editor_elements[pos++] = element;
7359
7360           if (IS_EDITOR_CASCADE_INACTIVE(element))
7361             found_inactive_cascade = TRUE;
7362         }
7363       }
7364
7365       if (found_inactive_cascade)
7366         continue;
7367
7368       // required for correct padding of palette element buttons
7369       int element_list_size = *editor_elements_info[i].element_list_size;
7370       int element_rows =
7371         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7372       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7373
7374       // copy all elements from element list
7375       for (j = 0; j < element_list_size; j++)
7376         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7377
7378       // use empty elements for padding of palette element buttons
7379       for (j = 0; j < element_buttons - element_list_size; j++)
7380         editor_elements[pos++] = editor_el_empty[0];
7381     }
7382   }
7383
7384   // (this function is also called before editor gadgets are initialized!)
7385   AdjustElementListScrollbar();
7386 }
7387
7388 void PrintEditorElementList(void)
7389 {
7390   boolean *stop = &setup_editor_el_user_defined;
7391   int i, j;
7392
7393   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7394   {
7395     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7396
7397     if (IS_EDITOR_CASCADE(cascade_element))
7398     {
7399       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7400       char *headline = element_info[cascade_element_show].editor_description;
7401
7402       PrintLineWithPrefix("# ", "-", 77);
7403       Print("# %s\n", headline);
7404       PrintLineWithPrefix("# ", "-", 77);
7405     }
7406
7407     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7408     {
7409       int element = (*editor_elements_info[i].headline_list)[j];
7410
7411       if (IS_EDITOR_CASCADE(element))
7412         element = EL_CHAR_MINUS;
7413
7414       Print("# %s\n", element_info[element].token_name);
7415     }
7416
7417     if (j > 0)
7418       Print("#\n");
7419
7420     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7421     {
7422       int element = (*editor_elements_info[i].element_list)[j];
7423
7424       Print("# %s\n", element_info[element].token_name);
7425     }
7426
7427     if (j > 0)
7428       Print("#\n");
7429   }
7430 }
7431
7432 static void ReinitializeElementListButtons(void)
7433 {
7434   static boolean last_setup_value_headlines = FALSE;
7435   static boolean initialization_needed = TRUE;
7436   int i;
7437
7438   if (!initialization_needed)   // check if editor element setup has changed
7439   {
7440     if (last_setup_value_headlines != setup.editor.el_headlines)
7441       initialization_needed = TRUE;
7442
7443     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7444       if (editor_elements_info[i].last_setup_value !=
7445           *editor_elements_info[i].setup_value)
7446         initialization_needed = TRUE;
7447   }
7448
7449   if (!initialization_needed)
7450     return;
7451
7452   FreeLevelEditorGadgets();
7453   CreateLevelEditorGadgets();
7454
7455   // store current setup values for next invocation of this function
7456   last_setup_value_headlines = setup.editor.el_headlines;
7457   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7458     editor_elements_info[i].last_setup_value =
7459       *editor_elements_info[i].setup_value;
7460
7461   initialization_needed = FALSE;
7462 }
7463
7464 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7465                               boolean input)
7466 {
7467   int border_graphic =
7468     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7469   struct GraphicInfo *g = &graphic_info[border_graphic];
7470   Bitmap *src_bitmap = g->bitmap;
7471   int src_x = g->src_x;
7472   int src_y = g->src_y;
7473   int border_size = g->border_size;
7474   int border_xpos = g->width  - border_size;
7475   int border_ypos = g->height - border_size;
7476   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7477   int i;
7478
7479   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7480              border_size, border_size,
7481              dest_x - border_size, dest_y - border_size);
7482   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7483              border_size, border_size,
7484              dest_x + width, dest_y - border_size);
7485   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7486              border_size, border_size,
7487              dest_x - border_size, dest_y + height);
7488   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7489              border_size, border_size,
7490              dest_x + width, dest_y + height);
7491
7492   for (i = 0; i < width / tilesize; i++)
7493   {
7494     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7495                tilesize, border_size,
7496                dest_x + i * tilesize, dest_y - border_size);
7497     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7498                tilesize, border_size,
7499                dest_x + i * tilesize, dest_y + height);
7500   }
7501
7502   for (i = 0; i < height / tilesize; i++)
7503   {
7504     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7505                border_size, tilesize,
7506                dest_x - border_size, dest_y + i * tilesize);
7507     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7508                border_size, tilesize,
7509                dest_x + width, dest_y + i * tilesize);
7510   }
7511
7512   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7513 }
7514
7515 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7516 {
7517   int xsize_tile = MAX(ed_tilesize, xsize);
7518   int ysize_tile = MAX(ed_tilesize, ysize);
7519   int xsize_full = xsize + 1;
7520   int ysize_full = ysize + 1;
7521   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7522   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7523   Pixel line_color = getTabulatorBarColor();
7524
7525   if (line_color == BLACK_PIXEL)                // black => transparent
7526     return;
7527
7528   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7529   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7530   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7531 }
7532
7533 static void DrawEditorLevelBorderLinesIfNeeded(void)
7534 {
7535   int xsize = lev_fieldx * ed_tilesize;
7536   int ysize = lev_fieldy * ed_tilesize;
7537   int line_size = getTabulatorBarHeight();
7538
7539   if (!suppressBorderElement())
7540     return;
7541
7542   // draw little border line around editable level playfield
7543
7544   if (xsize < SXSIZE)
7545     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7546
7547   if (ysize < SYSIZE)
7548     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7549
7550   if (xsize < SXSIZE && ysize < SYSIZE)
7551     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7552 }
7553
7554 static void DrawEditorElement(int x, int y, int element)
7555 {
7556   DrawSizedElement(x, y, element, ed_tilesize);
7557 }
7558
7559 static void DrawEditorElementThruMask(int x, int y, int element)
7560 {
7561   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7562 }
7563
7564 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7565 {
7566   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7567 }
7568
7569 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7570 {
7571   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7572   DrawEditorLevelBorderLinesIfNeeded();
7573 }
7574
7575 static void DrawDrawingArea(int id)
7576 {
7577   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7578   int x, y;
7579
7580   int *value = drawingarea_info[id].value;
7581   int area_xsize = drawingarea_info[id].area_xsize;
7582   int area_ysize = drawingarea_info[id].area_ysize;
7583   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7584
7585   for (x = 0; x < area_xsize; x++)
7586   {
7587     for (y = 0; y < area_ysize; y++)
7588     {
7589       int element = value[x * area_ysize + y];
7590       int graphic;
7591       int frame;
7592
7593       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7594
7595       DrawSizedGraphicExt(drawto,
7596                           gi->x + x * tilesize,
7597                           gi->y + y * tilesize,
7598                           graphic, frame, tilesize);
7599     }
7600   }
7601 }
7602
7603 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7604 {
7605   int x, y;
7606   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7607   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7608
7609   BlitBitmap(drawto, drawto,
7610              SX + (dx == -1 ? ed_tilesize : 0),
7611              SY + (dy == -1 ? ed_tilesize : 0),
7612              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7613              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7614              SX + (dx == +1 ? ed_tilesize : 0),
7615              SY + (dy == +1 ? ed_tilesize : 0));
7616
7617   if (dx)
7618   {
7619     x = (dx == 1 ? 0 : ed_fieldx - 1);
7620     for (y = 0; y < ed_fieldy; y++)
7621       DrawEditorElementOrWall(x, y, from_x, from_y);
7622   }
7623   else if (dy)
7624   {
7625     y = (dy == 1 ? 0 : ed_fieldy - 1);
7626     for (x = 0; x < ed_fieldx; x++)
7627       DrawEditorElementOrWall(x, y, from_x, from_y);
7628   }
7629
7630   redraw_mask |= REDRAW_FIELD;
7631   BackToFront();
7632 }
7633
7634 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7635 {
7636   if (use_editor_gfx)
7637   {
7638     *graphic = el2edimg(element);
7639     *frame = 0;
7640   }
7641   else
7642   {
7643     *graphic = el2img(element);
7644     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7645               custom_element.ce_value_fixed_initial :
7646               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7647               custom_element.collect_score_initial : FrameCounter);
7648   }
7649
7650   if (*graphic == IMG_UNKNOWN)
7651   {
7652     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7653     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7654     int element_bd = map_element_RND_to_BD_cave(element);
7655
7656     if (element_bd != O_UNKNOWN)
7657     {
7658       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7659
7660       *graphic = g_bd->graphic;
7661       *frame   = g_bd->frame;
7662     }
7663   }
7664 }
7665
7666 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7667                                    int *x, int *y)
7668 {
7669   int graphic;
7670   int frame;
7671
7672   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7673
7674   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7675 }
7676
7677 static void CreateControlButtons(void)
7678 {
7679   struct GadgetInfo *gi;
7680   int i;
7681
7682   // create toolbox buttons
7683   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7684   {
7685     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7686     int id = controlbutton_info[i].gadget_id;
7687     int type = controlbutton_info[i].gadget_type;
7688     int graphic = controlbutton_info[i].graphic;
7689     struct XYTileSize *pos = controlbutton_info[i].pos;
7690     struct GraphicInfo *gd = &graphic_info[graphic];
7691     Bitmap *deco_bitmap = NULL;
7692     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7693     int tile_size = 0, deco_shift = 0;
7694     boolean deco_masked = FALSE;
7695     int gd_x1 = gd->src_x;
7696     int gd_y1 = gd->src_y;
7697     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7698     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7699     int gd_x1a = gd->src_x + gd->active_xoffset;
7700     int gd_y1a = gd->src_y + gd->active_yoffset;
7701     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7702     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7703     int x = pos->x;
7704     int y = pos->y;
7705     unsigned int event_mask;
7706     int radio_button_nr = RADIO_NR_NONE;
7707     boolean checked = FALSE;
7708
7709     if (type_id != i)
7710       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7711
7712     if (type == GD_TYPE_RADIO_BUTTON)
7713     {
7714       event_mask = GD_EVENT_PRESSED;
7715       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7716
7717       if (id == drawing_function)
7718         checked = TRUE;
7719     }
7720     else
7721     {
7722       if (id == GADGET_ID_WRAP_LEFT ||
7723           id == GADGET_ID_WRAP_RIGHT ||
7724           id == GADGET_ID_WRAP_UP ||
7725           id == GADGET_ID_WRAP_DOWN)
7726         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7727       else
7728         event_mask = GD_EVENT_RELEASED;
7729     }
7730
7731     if (id == GADGET_ID_PROPERTIES ||
7732         id == GADGET_ID_PALETTE)
7733     {
7734       x += DX;
7735       y += DY;
7736     }
7737     else if (id == GADGET_ID_ELEMENT_LEFT ||
7738              id == GADGET_ID_ELEMENT_MIDDLE ||
7739              id == GADGET_ID_ELEMENT_RIGHT)
7740     {
7741       x += DX;
7742       y += DY;
7743
7744       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7745                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7746                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7747
7748       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7749                                    editor.button.element_left.tile_size :
7750                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7751                                    editor.button.element_middle.tile_size :
7752                                    id == GADGET_ID_ELEMENT_RIGHT ?
7753                                    editor.button.element_right.tile_size : 0);
7754
7755       // make sure that decoration does not overlap gadget border
7756       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7757
7758       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7759
7760       deco_xpos = (gd->width  - tile_size) / 2;
7761       deco_ypos = (gd->height - tile_size) / 2;
7762       deco_shift = 1;
7763       deco_masked = gd->draw_masked;
7764     }
7765     else
7766     {
7767       x += EX;
7768       y += EY;
7769     }
7770
7771     gi = CreateGadget(GDI_CUSTOM_ID, id,
7772                       GDI_CUSTOM_TYPE_ID, type_id,
7773                       GDI_IMAGE_ID, graphic,
7774                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7775                       GDI_X, x,
7776                       GDI_Y, y,
7777                       GDI_WIDTH, gd->width,
7778                       GDI_HEIGHT, gd->height,
7779                       GDI_TYPE, type,
7780                       GDI_STATE, GD_BUTTON_UNPRESSED,
7781                       GDI_RADIO_NR, radio_button_nr,
7782                       GDI_CHECKED, checked,
7783                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7784                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7785                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7786                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7787                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7788                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7789                       GDI_DECORATION_SIZE, tile_size, tile_size,
7790                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7791                       GDI_DECORATION_MASKED, deco_masked,
7792                       GDI_EVENT_MASK, event_mask,
7793                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7794                       GDI_CALLBACK_ACTION, HandleControlButtons,
7795                       GDI_END);
7796
7797     if (gi == NULL)
7798       Fail("cannot create gadget");
7799
7800     level_editor_gadget[id] = gi;
7801   }
7802
7803   // these values are not constant, but can change at runtime
7804   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7805   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7806   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7807   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7808   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7809   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7810   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7811   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7812   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7813   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7814   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7815   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7816
7817   // create buttons for scrolling of drawing area and element list
7818   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7819   {
7820     int id = scrollbutton_info[i].gadget_id;
7821     int type_id = scrollbutton_info[i].gadget_type_id;
7822     int graphic = scrollbutton_info[i].graphic;
7823     struct GraphicInfo *gd = &graphic_info[graphic];
7824     Bitmap *gd_bitmap = gd->bitmap;
7825     int gd_x1 = gd->src_x;
7826     int gd_y1 = gd->src_y;
7827     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7828     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7829     int width  = gd->width;
7830     int height = gd->height;
7831     int x = scrollbutton_pos[i].x;
7832     int y = scrollbutton_pos[i].y;
7833     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7834
7835     if (type_id != i)
7836       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7837
7838     if (id == GADGET_ID_SCROLL_LIST_UP ||
7839         id == GADGET_ID_SCROLL_LIST_DOWN)
7840     {
7841       x += PX;
7842       y += PY;
7843     }
7844     else
7845     {
7846       x += SX;
7847       y += SY;
7848     }
7849
7850     gi = CreateGadget(GDI_CUSTOM_ID, id,
7851                       GDI_CUSTOM_TYPE_ID, type_id,
7852                       GDI_IMAGE_ID, graphic,
7853                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7854                       GDI_X, x,
7855                       GDI_Y, y,
7856                       GDI_WIDTH, width,
7857                       GDI_HEIGHT, height,
7858                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7859                       GDI_STATE, GD_BUTTON_UNPRESSED,
7860                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7861                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7862                       GDI_EVENT_MASK, event_mask,
7863                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7864                       GDI_CALLBACK_ACTION, HandleControlButtons,
7865                       GDI_END);
7866
7867     if (gi == NULL)
7868       Fail("cannot create gadget");
7869
7870     level_editor_gadget[id] = gi;
7871   }
7872
7873   // create buttons for element list
7874   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7875   {
7876     int type_id = i;
7877     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
7878     int graphic = IMG_EDITOR_PALETTE_BUTTON;
7879     struct GraphicInfo *gd = &graphic_info[graphic];
7880     Bitmap *gd_bitmap = gd->bitmap;
7881     Bitmap *deco_bitmap;
7882     int deco_x, deco_y, deco_xpos, deco_ypos;
7883     int gd_x1 = gd->src_x;
7884     int gd_y1 = gd->src_y;
7885     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7886     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7887     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
7888     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
7889     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
7890     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
7891     int element = editor_elements[i];
7892     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
7893     unsigned int event_mask = GD_EVENT_RELEASED;
7894
7895     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
7896
7897     deco_xpos = (gd->width  - tile_size) / 2;
7898     deco_ypos = (gd->height - tile_size) / 2;
7899
7900     gi = CreateGadget(GDI_CUSTOM_ID, id,
7901                       GDI_CUSTOM_TYPE_ID, type_id,
7902                       GDI_IMAGE_ID, graphic,
7903                       GDI_INFO_TEXT, getElementInfoText(element),
7904                       GDI_X, x,
7905                       GDI_Y, y,
7906                       GDI_WIDTH, gd->width,
7907                       GDI_HEIGHT, gd->height,
7908                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7909                       GDI_STATE, GD_BUTTON_UNPRESSED,
7910                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7911                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7912                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7913                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7914                       GDI_DECORATION_SIZE, tile_size, tile_size,
7915                       GDI_DECORATION_SHIFTING, 1, 1,
7916                       GDI_EVENT_MASK, event_mask,
7917                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7918                       GDI_CALLBACK_ACTION, HandleControlButtons,
7919                       GDI_END);
7920
7921     if (gi == NULL)
7922       Fail("cannot create gadget");
7923
7924     level_editor_gadget[id] = gi;
7925   }
7926 }
7927
7928 static void CreateCounterButtons(void)
7929 {
7930   int max_infotext_len = getMaxInfoTextLength();
7931   int i;
7932
7933   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
7934   {
7935     int type_id = counterbutton_info[i].gadget_type_id;
7936     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
7937     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
7938     int j;
7939
7940     if (type_id != i)
7941       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
7942
7943     // determine horizontal position to the right of specified gadget
7944     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
7945       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
7946            ED_GADGET_TEXT_DISTANCE);
7947
7948     // determine horizontal offset for leading text
7949     if (counterbutton_info[i].text_left != NULL)
7950       x += getTextWidthForGadget(counterbutton_info[i].text_left);
7951
7952     for (j = 0; j < 2; j++)
7953     {
7954       struct GadgetInfo *gi;
7955       int id = (j == 0 ?
7956                 counterbutton_info[i].gadget_id_down :
7957                 counterbutton_info[i].gadget_id_up);
7958       int graphic;
7959       struct GraphicInfo *gd;
7960       int gd_x1, gd_x2, gd_y1, gd_y2;
7961       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7962       char infotext[max_infotext_len + 1];
7963
7964       if (i == ED_COUNTER_ID_SELECT_LEVEL)
7965       {
7966         graphic = (j == 0 ?
7967                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
7968                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
7969
7970         event_mask |= GD_EVENT_RELEASED;
7971
7972         if (j == 0)
7973         {
7974           x = DX + editor.button.prev_level.x;
7975           y = DY + editor.button.prev_level.y;
7976         }
7977         else
7978         {
7979           x = DX + editor.button.next_level.x;
7980           y = DY + editor.button.next_level.y;
7981         }
7982       }
7983       else
7984       {
7985         graphic = (j == 0 ?
7986                    IMG_EDITOR_COUNTER_DOWN :
7987                    IMG_EDITOR_COUNTER_UP);
7988       }
7989
7990       gd = &graphic_info[graphic];
7991
7992       gd_x1 = gd->src_x;
7993       gd_y1 = gd->src_y;
7994       gd_x2 = gd->src_x + gd->pressed_xoffset;
7995       gd_y2 = gd->src_y + gd->pressed_yoffset;
7996
7997       sprintf(infotext, "%s counter value by 1, 5 or 10",
7998               (j == 0 ? "Decrease" : "Increase"));
7999
8000       gi = CreateGadget(GDI_CUSTOM_ID, id,
8001                         GDI_CUSTOM_TYPE_ID, type_id,
8002                         GDI_IMAGE_ID, graphic,
8003                         GDI_INFO_TEXT, infotext,
8004                         GDI_X, x,
8005                         GDI_Y, y,
8006                         GDI_WIDTH, gd->width,
8007                         GDI_HEIGHT, gd->height,
8008                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8009                         GDI_STATE, GD_BUTTON_UNPRESSED,
8010                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8011                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8012                         GDI_EVENT_MASK, event_mask,
8013                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8014                         GDI_CALLBACK_ACTION, HandleCounterButtons,
8015                         GDI_END);
8016
8017       if (gi == NULL)
8018         Fail("cannot create gadget");
8019
8020       level_editor_gadget[id] = gi;
8021       right_gadget_border[id] =
8022         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8023
8024       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
8025
8026       if (j == 0)
8027       {
8028         int font_type = FONT_INPUT_1;
8029         int font_type_active = FONT_INPUT_1_ACTIVE;
8030
8031         id = counterbutton_info[i].gadget_id_text;
8032
8033         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8034
8035         if (i == ED_COUNTER_ID_SELECT_LEVEL)
8036         {
8037           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
8038
8039           font_type = FONT_LEVEL_NUMBER;
8040           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
8041
8042           x = DX + editor.input.level_number.x;
8043           y = DY + editor.input.level_number.y;
8044         }
8045         else
8046         {
8047           graphic = IMG_EDITOR_COUNTER_INPUT;
8048         }
8049
8050         gd = &graphic_info[graphic];
8051
8052         gd_x1 = gd->src_x;
8053         gd_y1 = gd->src_y;
8054         gd_x2 = gd->src_x + gd->active_xoffset;
8055         gd_y2 = gd->src_y + gd->active_yoffset;
8056
8057         gi = CreateGadget(GDI_CUSTOM_ID, id,
8058                           GDI_CUSTOM_TYPE_ID, type_id,
8059                           GDI_IMAGE_ID, graphic,
8060                           GDI_INFO_TEXT, "Enter counter value",
8061                           GDI_X, x,
8062                           GDI_Y, y,
8063                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
8064                           GDI_NUMBER_VALUE, 0,
8065                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
8066                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
8067                           GDI_TEXT_SIZE, 3,     // minimal counter text size
8068                           GDI_TEXT_FONT, font_type,
8069                           GDI_TEXT_FONT_ACTIVE, font_type_active,
8070                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8071                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8072                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8073                           GDI_DESIGN_WIDTH, gd->width,
8074                           GDI_EVENT_MASK, event_mask,
8075                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8076                           GDI_CALLBACK_ACTION, HandleCounterButtons,
8077                           GDI_END);
8078
8079         if (gi == NULL)
8080           Fail("cannot create gadget");
8081
8082         level_editor_gadget[id] = gi;
8083         right_gadget_border[id] =
8084           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
8085
8086         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
8087       }
8088     }
8089   }
8090 }
8091
8092 static void CreateDrawingAreas(void)
8093 {
8094   int i;
8095
8096   // these values are not constant, but can change at runtime
8097   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8098   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8099
8100   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8101   {
8102     struct GadgetInfo *gi;
8103     int id = drawingarea_info[i].gadget_id;
8104     int type_id = drawingarea_info[i].gadget_type_id;
8105     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8106     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8107     int area_xsize = drawingarea_info[i].area_xsize;
8108     int area_ysize = drawingarea_info[i].area_ysize;
8109     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8110                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8111     unsigned int event_mask =
8112       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8113       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8114
8115     if (type_id != i)
8116       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8117
8118     // determine horizontal position to the right of specified gadget
8119     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8120       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8121            ED_DRAWINGAREA_TEXT_DISTANCE);
8122
8123     // determine horizontal offset for leading text
8124     if (drawingarea_info[i].text_left != NULL)
8125       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8126
8127     gi = CreateGadget(GDI_CUSTOM_ID, id,
8128                       GDI_CUSTOM_TYPE_ID, type_id,
8129                       GDI_X, x,
8130                       GDI_Y, y,
8131                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8132                       GDI_AREA_SIZE, area_xsize, area_ysize,
8133                       GDI_ITEM_SIZE, item_size, item_size,
8134                       GDI_EVENT_MASK, event_mask,
8135                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8136                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8137                       GDI_END);
8138
8139     if (gi == NULL)
8140       Fail("cannot create gadget");
8141
8142     level_editor_gadget[id] = gi;
8143     right_gadget_border[id] =
8144       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8145   }
8146 }
8147
8148 static void CreateTextInputGadgets(void)
8149 {
8150   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8151   int max_infotext_len = getMaxInfoTextLength();
8152   int i;
8153
8154   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8155   {
8156     int gd_x1 = gd->src_x;
8157     int gd_y1 = gd->src_y;
8158     int gd_x2 = gd->src_x + gd->active_xoffset;
8159     int gd_y2 = gd->src_y + gd->active_yoffset;
8160     struct GadgetInfo *gi;
8161     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8162     char infotext[MAX_OUTPUT_LINESIZE + 1];
8163     int id = textinput_info[i].gadget_id;
8164     int type_id = textinput_info[i].gadget_type_id;
8165     int x, y;
8166
8167     if (type_id != i)
8168       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8169
8170     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8171     {
8172       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8173       int border_size = gd->border_size;
8174       int font_nr = FONT_INPUT_1;
8175       int font_height = getFontHeight(font_nr);
8176       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8177       int yoffset = element_border + (TILEY - font_height) / 2;
8178
8179       x = (editor.settings.element_name.x != -1 ?
8180            editor.settings.element_name.x :
8181            editor.settings.element_graphic.x + xoffset) - border_size;
8182       y = (editor.settings.element_name.y != -1 ?
8183            editor.settings.element_name.y :
8184            editor.settings.element_graphic.y + yoffset) - border_size;
8185     }
8186     else
8187     {
8188       x = ED_SETTINGS_X(textinput_info[i].x);
8189       y = ED_SETTINGS_Y(textinput_info[i].y);
8190     }
8191
8192     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8193     infotext[max_infotext_len] = '\0';
8194
8195     gi = CreateGadget(GDI_CUSTOM_ID, id,
8196                       GDI_CUSTOM_TYPE_ID, type_id,
8197                       GDI_INFO_TEXT, infotext,
8198                       GDI_X, SX + x,
8199                       GDI_Y, SY + y,
8200                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8201                       GDI_TEXT_VALUE, textinput_info[i].value,
8202                       GDI_TEXT_SIZE, textinput_info[i].size,
8203                       GDI_TEXT_FONT, FONT_INPUT_1,
8204                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_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, HandleTextInputGadgets,
8212                       GDI_END);
8213
8214     if (gi == NULL)
8215       Fail("cannot create gadget");
8216
8217     level_editor_gadget[id] = gi;
8218   }
8219 }
8220
8221 static void CreateTextAreaGadgets(void)
8222 {
8223   int max_infotext_len = getMaxInfoTextLength();
8224   int i;
8225
8226   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8227   {
8228     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8229     int gd_x1 = gd->src_x;
8230     int gd_y1 = gd->src_y;
8231     int gd_x2 = gd->src_x + gd->active_xoffset;
8232     int gd_y2 = gd->src_y + gd->active_yoffset;
8233     struct GadgetInfo *gi;
8234     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8235     char infotext[MAX_OUTPUT_LINESIZE + 1];
8236     int id = textarea_info[i].gadget_id;
8237     int type_id = textarea_info[i].gadget_type_id;
8238     int area_xsize = textarea_info[i].xsize;
8239     int area_ysize = textarea_info[i].ysize;
8240
8241     if (type_id != i)
8242       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8243
8244     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8245     infotext[max_infotext_len] = '\0';
8246
8247     gi = CreateGadget(GDI_CUSTOM_ID, id,
8248                       GDI_CUSTOM_TYPE_ID, type_id,
8249                       GDI_INFO_TEXT, infotext,
8250                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8251                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8252                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8253                       GDI_AREA_SIZE, area_xsize, area_ysize,
8254                       GDI_TEXT_FONT, FONT_INPUT_1,
8255                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8256                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8257                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8258                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8259                       GDI_DESIGN_WIDTH, gd->width,
8260                       GDI_EVENT_MASK, event_mask,
8261                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8262                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8263                       GDI_END);
8264
8265     if (gi == NULL)
8266       Fail("cannot create gadget");
8267
8268     level_editor_gadget[id] = gi;
8269   }
8270 }
8271
8272 static void CreateSelectboxGadgets(void)
8273 {
8274   int max_infotext_len = getMaxInfoTextLength();
8275
8276   int i, j;
8277
8278   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8279   {
8280     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8281     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8282     int gd_x1 = gd->src_x;
8283     int gd_y1 = gd->src_y;
8284     int gd_x2 = gd->src_x + gd->active_xoffset;
8285     int gd_y2 = gd->src_y + gd->active_yoffset;
8286     int selectbox_button_xsize = gd2->width;
8287     struct GadgetInfo *gi;
8288     char infotext[MAX_OUTPUT_LINESIZE + 1];
8289     int id = selectbox_info[i].gadget_id;
8290     int type_id = selectbox_info[i].gadget_type_id;
8291     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8292     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8293     unsigned int event_mask =
8294       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8295
8296     if (type_id != i)
8297       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8298
8299     if (selectbox_info[i].size == -1)   // dynamically determine size
8300     {
8301       // (we cannot use -1 for uninitialized values if we directly compare
8302       // with results from strlen(), because the '<' and '>' operation will
8303       // implicitely cast -1 to an unsigned integer value!)
8304       selectbox_info[i].size = 0;
8305
8306       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8307         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8308           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8309
8310       selectbox_info[i].size++;         // add one character empty space
8311     }
8312
8313     // determine horizontal position to the right of specified gadget
8314     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8315       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8316            ED_GADGET_TEXT_DISTANCE);
8317
8318     // determine horizontal offset for leading text
8319     if (selectbox_info[i].text_left != NULL)
8320       x += getTextWidthForGadget(selectbox_info[i].text_left);
8321
8322     sprintf(infotext, "%s", selectbox_info[i].infotext);
8323     infotext[max_infotext_len] = '\0';
8324
8325     gi = CreateGadget(GDI_CUSTOM_ID, id,
8326                       GDI_CUSTOM_TYPE_ID, type_id,
8327                       GDI_INFO_TEXT, infotext,
8328                       GDI_X, x,
8329                       GDI_Y, y,
8330                       GDI_TYPE, GD_TYPE_SELECTBOX,
8331                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8332                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8333                       GDI_TEXT_SIZE, selectbox_info[i].size,
8334                       GDI_TEXT_FONT, FONT_INPUT_1,
8335                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8336                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8337                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8338                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8339                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8340                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8341                       GDI_DESIGN_WIDTH, gd->width,
8342                       GDI_EVENT_MASK, event_mask,
8343                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8344                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8345                       GDI_END);
8346
8347     if (gi == NULL)
8348       Fail("cannot create gadget");
8349
8350     level_editor_gadget[id] = gi;
8351     right_gadget_border[id] =
8352       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8353   }
8354 }
8355
8356 static void CreateTextbuttonGadgets(void)
8357 {
8358   int max_infotext_len = getMaxInfoTextLength();
8359   int i;
8360
8361   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8362   {
8363     int id = textbutton_info[i].gadget_id;
8364     int type_id = textbutton_info[i].gadget_type_id;
8365     int is_tab_button =
8366       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8367        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8368     int graphic =
8369       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8370     int gadget_distance =
8371       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8372     struct GraphicInfo *gd = &graphic_info[graphic];
8373     int gd_x1 = gd->src_x;
8374     int gd_y1 = gd->src_y;
8375     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8376     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8377     int gd_x1a = gd->src_x + gd->active_xoffset;
8378     int gd_y1a = gd->src_y + gd->active_yoffset;
8379     int border_xsize = gd->border_size + gd->draw_xoffset;
8380     int border_ysize = gd->border_size;
8381     struct GadgetInfo *gi;
8382     unsigned int event_mask = GD_EVENT_RELEASED;
8383     char infotext[MAX_OUTPUT_LINESIZE + 1];
8384     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8385     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8386
8387     if (type_id != i)
8388       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8389
8390     if (textbutton_info[i].size == -1)  // dynamically determine size
8391       textbutton_info[i].size = strlen(textbutton_info[i].text);
8392
8393     sprintf(infotext, "%s", textbutton_info[i].infotext);
8394     infotext[max_infotext_len] = '\0';
8395
8396     // determine horizontal position to the right of specified gadget
8397     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8398     {
8399       int gadget_id_align = textbutton_info[i].gadget_id_align;
8400
8401       x = right_gadget_border[gadget_id_align] + gadget_distance;
8402
8403       if (textbutton_info[i].y == -1)
8404         y = level_editor_gadget[gadget_id_align]->y;
8405     }
8406
8407     // determine horizontal offset for leading text
8408     if (textbutton_info[i].text_left != NULL)
8409       x += getTextWidthForGadget(textbutton_info[i].text_left);
8410
8411     gi = CreateGadget(GDI_CUSTOM_ID, id,
8412                       GDI_CUSTOM_TYPE_ID, type_id,
8413                       GDI_IMAGE_ID, graphic,
8414                       GDI_INFO_TEXT, infotext,
8415                       GDI_X, x,
8416                       GDI_Y, y,
8417                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8418                       GDI_TEXT_VALUE, textbutton_info[i].text,
8419                       GDI_TEXT_SIZE, textbutton_info[i].size,
8420                       GDI_TEXT_FONT, FONT_INPUT_2,
8421                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8422                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8423                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8424                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8425                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8426                       GDI_DESIGN_WIDTH, gd->width,
8427                       GDI_DECORATION_SHIFTING, 1, 1,
8428                       GDI_EVENT_MASK, event_mask,
8429                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8430                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8431                       GDI_END);
8432
8433     if (gi == NULL)
8434       Fail("cannot create gadget");
8435
8436     level_editor_gadget[id] = gi;
8437     right_gadget_border[id] =
8438       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8439   }
8440 }
8441
8442 static void CreateGraphicbuttonGadgets(void)
8443 {
8444   struct GadgetInfo *gi;
8445   int i;
8446
8447   // create buttons for scrolling of drawing area and element list
8448   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8449   {
8450     int id = graphicbutton_info[i].gadget_id;
8451     int type_id = graphicbutton_info[i].gadget_type_id;
8452     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8453     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8454     int graphic = graphicbutton_info[i].graphic;
8455     struct GraphicInfo *gd = &graphic_info[graphic];
8456     int gd_x1 = gd->src_x;
8457     int gd_y1 = gd->src_y;
8458     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8459     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8460     unsigned int event_mask = GD_EVENT_RELEASED;
8461
8462     if (type_id != i)
8463       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8464
8465     // determine horizontal position to the right of specified gadget
8466     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8467       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8468            ED_GADGET_TEXT_DISTANCE);
8469
8470     // determine horizontal offset for leading text
8471     if (graphicbutton_info[i].text_left != NULL)
8472       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8473
8474     gi = CreateGadget(GDI_CUSTOM_ID, id,
8475                       GDI_CUSTOM_TYPE_ID, type_id,
8476                       GDI_IMAGE_ID, graphic,
8477                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8478                       GDI_X, x,
8479                       GDI_Y, y,
8480                       GDI_WIDTH, gd->width,
8481                       GDI_HEIGHT, gd->height,
8482                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8483                       GDI_STATE, GD_BUTTON_UNPRESSED,
8484                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8485                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8486                       GDI_EVENT_MASK, event_mask,
8487                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8488                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8489                       GDI_END);
8490
8491     if (gi == NULL)
8492       Fail("cannot create gadget");
8493
8494     level_editor_gadget[id] = gi;
8495     right_gadget_border[id] =
8496       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8497   }
8498 }
8499
8500 static void CreateScrollbarGadgets(void)
8501 {
8502   int i;
8503
8504   // these values are not constant, but can change at runtime
8505   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8506     SX + ED_SCROLL_HORIZONTAL_XPOS;
8507   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8508     SY + ED_SCROLL_HORIZONTAL_YPOS;
8509   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8510     ED_SCROLL_HORIZONTAL_XSIZE;
8511   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8512     ED_SCROLL_HORIZONTAL_YSIZE;
8513   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8514   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8515   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8516   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8517
8518   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8519     SX + ED_SCROLL_VERTICAL_XPOS;
8520   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8521     SY + ED_SCROLL_VERTICAL_YPOS;
8522   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8523     ED_SCROLL_VERTICAL_XSIZE;
8524   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8525     ED_SCROLL_VERTICAL_YSIZE;
8526   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8527   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8528   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8529   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8530
8531   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8532     PX + ED_SCROLL2_VERTICAL_XPOS;
8533   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8534     PY + ED_SCROLL2_VERTICAL_YPOS;
8535   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8536     ED_SCROLL2_VERTICAL_XSIZE;
8537   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8538     ED_SCROLL2_VERTICAL_YSIZE;
8539   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8540   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8541   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8542   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8543
8544   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8545   {
8546     int id = scrollbar_info[i].gadget_id;
8547     int type_id = scrollbar_info[i].gadget_type_id;
8548     int graphic = scrollbar_info[i].graphic;
8549     struct GraphicInfo *gd = &graphic_info[graphic];
8550     int gd_x1 = gd->src_x;
8551     int gd_y1 = gd->src_y;
8552     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8553     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8554     struct GadgetInfo *gi;
8555     int items_max, items_visible, item_position;
8556     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8557
8558     if (type_id != i)
8559       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8560
8561     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8562     {
8563       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8564       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8565       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8566     }
8567     else        // drawing area scrollbars
8568     {
8569       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8570       {
8571         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8572         items_visible = ed_fieldx;
8573         item_position = 0;
8574       }
8575       else
8576       {
8577         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8578         items_visible = ed_fieldy;
8579         item_position = 0;
8580       }
8581     }
8582
8583     gi = CreateGadget(GDI_CUSTOM_ID, id,
8584                       GDI_CUSTOM_TYPE_ID, type_id,
8585                       GDI_IMAGE_ID, graphic,
8586                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8587                       GDI_X, scrollbar_pos[i].x,
8588                       GDI_Y, scrollbar_pos[i].y,
8589                       GDI_WIDTH, scrollbar_pos[i].width,
8590                       GDI_HEIGHT, scrollbar_pos[i].height,
8591                       GDI_TYPE, scrollbar_info[i].type,
8592                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8593                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8594                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8595                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8596                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8597                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8598                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8599                       GDI_STATE, GD_BUTTON_UNPRESSED,
8600                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8601                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8602                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8603                       GDI_EVENT_MASK, event_mask,
8604                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8605                       GDI_CALLBACK_ACTION, HandleControlButtons,
8606                       GDI_END);
8607
8608     if (gi == NULL)
8609       Fail("cannot create gadget");
8610
8611     level_editor_gadget[id] = gi;
8612   }
8613 }
8614
8615 static void CreateCheckbuttonGadgets(void)
8616 {
8617   struct GadgetInfo *gi;
8618   int i;
8619
8620   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8621   {
8622     int id = checkbutton_info[i].gadget_id;
8623     int type_id = checkbutton_info[i].gadget_type_id;
8624     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8625                    IMG_EDITOR_CHECKBOX);
8626     struct GraphicInfo *gd = &graphic_info[graphic];
8627     int gd_x1 = gd->src_x;
8628     int gd_y1 = gd->src_y;
8629     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8630     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8631     int gd_x1a = gd->src_x + gd->active_xoffset;
8632     int gd_y1a = gd->src_y + gd->active_yoffset;
8633     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8634     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8635     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8636     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8637     unsigned int event_mask = GD_EVENT_PRESSED;
8638
8639     if (type_id != i)
8640       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8641
8642     // determine horizontal position to the right of specified gadget
8643     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8644       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8645            ED_GADGET_TEXT_DISTANCE);
8646
8647     // determine horizontal offset for leading text
8648     if (checkbutton_info[i].text_left != NULL)
8649       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8650
8651     gi = CreateGadget(GDI_CUSTOM_ID, id,
8652                       GDI_CUSTOM_TYPE_ID, type_id,
8653                       GDI_IMAGE_ID, graphic,
8654                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8655                       GDI_X, x,
8656                       GDI_Y, y,
8657                       GDI_WIDTH, gd->width,
8658                       GDI_HEIGHT, gd->height,
8659                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8660                       GDI_CHECKED, *checkbutton_info[i].value,
8661                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8662                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8663                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8664                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8665                       GDI_EVENT_MASK, event_mask,
8666                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8667                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8668                       GDI_END);
8669
8670     if (gi == NULL)
8671       Fail("cannot create gadget");
8672
8673     level_editor_gadget[id] = gi;
8674     right_gadget_border[id] =
8675       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8676   }
8677 }
8678
8679 static void CreateRadiobuttonGadgets(void)
8680 {
8681   int graphic = IMG_EDITOR_RADIOBUTTON;
8682   struct GraphicInfo *gd = &graphic_info[graphic];
8683   int gd_x1 = gd->src_x;
8684   int gd_y1 = gd->src_y;
8685   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8686   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8687   int gd_x1a = gd->src_x + gd->active_xoffset;
8688   int gd_y1a = gd->src_y + gd->active_yoffset;
8689   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8690   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8691   struct GadgetInfo *gi;
8692   int i;
8693
8694   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8695   {
8696     int id = radiobutton_info[i].gadget_id;
8697     int type_id = radiobutton_info[i].gadget_type_id;
8698     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8699     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8700     unsigned int event_mask = GD_EVENT_PRESSED;
8701
8702     if (type_id != i)
8703       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8704
8705     int checked =
8706       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8707
8708     // determine horizontal position to the right of specified gadget
8709     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8710       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8711            ED_GADGET_TEXT_DISTANCE);
8712
8713     // determine horizontal offset for leading text
8714     if (radiobutton_info[i].text_left != NULL)
8715       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8716
8717     gi = CreateGadget(GDI_CUSTOM_ID, id,
8718                       GDI_CUSTOM_TYPE_ID, type_id,
8719                       GDI_IMAGE_ID, graphic,
8720                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8721                       GDI_X, x,
8722                       GDI_Y, y,
8723                       GDI_WIDTH, gd->width,
8724                       GDI_HEIGHT, gd->height,
8725                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8726                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8727                       GDI_CHECKED, checked,
8728                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8729                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8730                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8731                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8732                       GDI_EVENT_MASK, event_mask,
8733                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8734                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8735                       GDI_END);
8736
8737     if (gi == NULL)
8738       Fail("cannot create gadget");
8739
8740     level_editor_gadget[id] = gi;
8741     right_gadget_border[id] =
8742       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8743   }
8744 }
8745
8746 void CreateLevelEditorGadgets(void)
8747 {
8748   // force EDITOR font inside level editor
8749   SetFontStatus(GAME_MODE_EDITOR);
8750
8751   // these values are not constant, but can change at runtime
8752   ed_fieldx = MAX_ED_FIELDX - 1;
8753   ed_fieldy = MAX_ED_FIELDY - 1;
8754
8755   num_editor_gadgets = NUM_EDITOR_GADGETS;
8756
8757   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8758
8759   level_editor_gadget =
8760     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8761   right_gadget_border =
8762     checked_calloc(num_editor_gadgets * sizeof(int));
8763
8764   // set number of empty (padding) element buttons to maximum number of buttons
8765   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8766
8767   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8768   editor_el_empty_ptr = editor_el_empty;
8769
8770   use_permanent_palette = !editor.palette.show_as_separate_screen;
8771
8772   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8773
8774   ReinitializeElementList();
8775
8776   CreateControlButtons();
8777   CreateScrollbarGadgets();
8778
8779   // order of function calls is important because of cross-references
8780   CreateCheckbuttonGadgets();
8781   CreateCounterButtons();
8782   CreateRadiobuttonGadgets();
8783   CreateTextInputGadgets();
8784   CreateTextAreaGadgets();
8785   CreateSelectboxGadgets();
8786   CreateGraphicbuttonGadgets();
8787   CreateTextbuttonGadgets();
8788   CreateDrawingAreas();
8789
8790   ResetFontStatus();
8791 }
8792
8793 void FreeLevelEditorGadgets(void)
8794 {
8795   int i;
8796
8797   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8798
8799   for (i = 0; i < num_editor_gadgets; i++)
8800   {
8801     FreeGadget(level_editor_gadget[i]);
8802
8803     level_editor_gadget[i] = NULL;
8804   }
8805
8806   checked_free(level_editor_gadget);
8807   checked_free(right_gadget_border);
8808
8809   checked_free(editor_el_empty);
8810 }
8811
8812 static void MapCounterButtons(int id)
8813 {
8814   int font_nr = FONT_TEXT_1;
8815   int font_height = getFontHeight(font_nr);
8816   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8817   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8818   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8819   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8820   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8821   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8822   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8823   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8824   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8825   int yoffset = (gi_down->height - font_height) / 2;
8826   int x_left = gi_down->x - xoffset_left;
8827   int x_right;  // set after gadget position was modified
8828   int y_above = gi_down->y - yoffset_above;
8829   int x = gi_down->x;
8830   int y;        // set after gadget position was modified
8831
8832   // counter limits must be changed first to prevent value truncation
8833   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8834                             counterbutton_info[id].max_value);
8835
8836   // right text position might have changed after setting position above
8837   x_right = gi_up->x + gi_up->width + xoffset_right;
8838
8839   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8840
8841   // set position for counter gadgets with dynamically determined position
8842   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8843   {
8844     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8845     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8846     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8847   }
8848
8849   // vertical position might have changed after setting position above
8850   y = gi_up->y + yoffset;
8851
8852   if (counterbutton_info[id].text_above)
8853     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8854
8855   if (counterbutton_info[id].text_left)
8856     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8857
8858   if (counterbutton_info[id].text_right)
8859     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8860
8861   MapGadget(gi_down);
8862   MapGadget(gi_text);
8863   MapGadget(gi_up);
8864 }
8865
8866 static void MapControlButtons(void)
8867 {
8868   int counter_id;
8869   int i;
8870
8871   // map toolbox buttons (excluding special CE toolbox buttons)
8872   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
8873     MapGadget(level_editor_gadget[i]);
8874
8875   // map toolbox buttons (element properties buttons)
8876   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
8877     MapGadget(level_editor_gadget[i]);
8878
8879   if (use_permanent_palette)
8880   {
8881     // map buttons to select elements
8882     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8883       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
8884     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
8885     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
8886     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
8887   }
8888
8889   // map buttons to select level
8890   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
8891   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
8892   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
8893   MapCounterButtons(counter_id);
8894 }
8895
8896 static void MapDrawingArea(int id)
8897 {
8898   int font_nr = FONT_TEXT_1;
8899   int font_height = getFontHeight(font_nr);
8900   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8901   int area_xsize = gi->drawing.area_xsize;
8902   int area_ysize = gi->drawing.area_ysize;
8903   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8904   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
8905   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
8906   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
8907   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
8908   int x_below = gi->x + (gi->width - xoffset_below) / 2;
8909   int y_side  = gi->y + (gi->height - font_height) / 2;
8910   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
8911   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
8912
8913   if (drawingarea_info[id].text_left)
8914     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
8915
8916   if (drawingarea_info[id].text_right)
8917     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
8918
8919   if (drawingarea_info[id].text_above)
8920     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
8921
8922   if (drawingarea_info[id].text_below)
8923     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
8924
8925   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
8926   {
8927     DrawElementBorder(gi->x, gi->y,
8928                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
8929                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
8930
8931     DrawDrawingArea(id);
8932   }
8933
8934   MapGadget(gi);
8935 }
8936
8937 static void MapTextInputGadget(int id)
8938 {
8939   int font_nr = FONT_TEXT_1;
8940   int font_height = getFontHeight(font_nr);
8941   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
8942   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8943   int x_above = ED_SETTINGS_X(textinput_info[id].x);
8944   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
8945
8946   if (textinput_info[id].text_above)
8947     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
8948
8949   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
8950
8951   MapGadget(gi);
8952 }
8953
8954 static void MapTextAreaGadget(int id)
8955 {
8956   int font_nr = FONT_TEXT_1;
8957   int font_height = getFontHeight(font_nr);
8958   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
8959   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8960   int x_above = ED_SETTINGS_X(textarea_info[id].x);
8961   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
8962   char *text_above = textarea_info[id].text_above;
8963
8964   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
8965     text_above = textarea_info[id].text_above_cropped;
8966
8967   if (text_above)
8968     DrawTextS(x_above, y_above, font_nr, text_above);
8969
8970   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
8971
8972   MapGadget(gi);
8973 }
8974
8975 static void MapSelectboxGadget(int id)
8976 {
8977   int font_nr = FONT_TEXT_1;
8978   int font_height = getFontHeight(font_nr);
8979   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
8980   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
8981   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8982   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8983   int yoffset = (gi->height - font_height) / 2;
8984   int x_left = gi->x - xoffset_left;
8985   int x_right = gi->x + gi->width + xoffset_right;
8986   int y_above = gi->y - yoffset_above;
8987   int x = gi->x;
8988   int y = gi->y + yoffset;
8989
8990   if (selectbox_info[id].text_above)
8991     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
8992
8993   if (selectbox_info[id].text_left)
8994     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
8995
8996   if (selectbox_info[id].text_right)
8997     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
8998
8999   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
9000
9001   MapGadget(gi);
9002 }
9003
9004 static void MapTextbuttonGadget(int id)
9005 {
9006   int font_nr = FONT_TEXT_1;
9007   int font_height = getFontHeight(font_nr);
9008   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
9009   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
9010   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9011   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9012   int yoffset = (gi->height - font_height) / 2;
9013   int x_left = gi->x - xoffset_left;
9014   int x_right = gi->x + gi->width + xoffset_right;
9015   int y_above = gi->y - yoffset_above;
9016   int x = gi->x;
9017   int y = gi->y + yoffset;
9018
9019   // only show button to delete change pages when more than minimum pages
9020   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
9021       custom_element.num_change_pages == MIN_CHANGE_PAGES)
9022     return;
9023
9024   if (textbutton_info[id].text_above)
9025     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
9026
9027   if (textbutton_info[id].text_left)
9028     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
9029
9030   if (textbutton_info[id].text_right)
9031     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
9032
9033   MapGadget(gi);
9034 }
9035
9036 static void MapGraphicbuttonGadget(int id)
9037 {
9038   int font_nr = FONT_TEXT_1;
9039   int font_height = getFontHeight(font_nr);
9040   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
9041   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
9042   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9043   int yoffset = (gi->height - font_height) / 2;
9044   int x_left = gi->x - xoffset_left;
9045   int x_right = gi->x + gi->width + xoffset_right;
9046   int y = gi->y + yoffset;
9047
9048   if (graphicbutton_info[id].text_left)
9049     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
9050
9051   if (graphicbutton_info[id].text_right)
9052     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
9053
9054   MapGadget(gi);
9055 }
9056
9057 static void MapRadiobuttonGadget(int id)
9058 {
9059   int font_nr = FONT_TEXT_1;
9060   int font_height = getFontHeight(font_nr);
9061   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
9062   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9063   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9064   int yoffset = (gi->height - font_height) / 2;
9065   int x_left = gi->x - xoffset_left;
9066   int x_right = gi->x + gi->width + xoffset_right;
9067   int y = gi->y + yoffset;
9068   boolean checked =
9069     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
9070
9071   if (radiobutton_info[id].text_left)
9072     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
9073
9074   if (radiobutton_info[id].text_right)
9075     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
9076
9077   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
9078
9079   MapGadget(gi);
9080 }
9081
9082 static void MapCheckbuttonGadget(int id)
9083 {
9084   int font_nr = FONT_TEXT_1;
9085   int font_height = getFontHeight(font_nr);
9086   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
9087   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
9088   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
9089   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
9090   int yoffset = (gi->height - font_height) / 2;
9091   int y_above = gi->y - yoffset_above;
9092   int x = gi->x;
9093   int x_left, x_right, y;       // set after gadget position was modified
9094
9095   // set position for gadgets with dynamically determined position
9096   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9097     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9098   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9099
9100   x_left = gi->x - xoffset_left;
9101   x_right = gi->x + gi->width + xoffset_right;
9102   y = gi->y + yoffset;
9103
9104   if (checkbutton_info[id].text_above)
9105     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9106
9107   if (checkbutton_info[id].text_left)
9108     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9109
9110   if (checkbutton_info[id].text_right)
9111     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9112
9113   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9114
9115   MapGadget(gi);
9116 }
9117
9118 static void MapMainDrawingArea(void)
9119 {
9120   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9121   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9122   int i;
9123
9124   if (suppressBorderElement())
9125   {
9126     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9127     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9128   }
9129
9130   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9131   {
9132     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9133           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9134          no_horizontal_scrollbar) ||
9135         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9136           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9137          no_vertical_scrollbar))
9138       continue;
9139
9140     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9141   }
9142
9143   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9144   {
9145     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9146         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9147       continue;
9148
9149     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9150   }
9151
9152   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9153 }
9154
9155 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9156 {
9157   int i;
9158
9159   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9160   {
9161     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9162         i == GADGET_ID_CUSTOM_COPY_TO ||
9163         i == GADGET_ID_CUSTOM_EXCHANGE ||
9164         i == GADGET_ID_CUSTOM_COPY ||
9165         i == GADGET_ID_CUSTOM_PASTE)
9166     {
9167       if (map)
9168         MapGadget(level_editor_gadget[i]);
9169       else
9170         UnmapGadget(level_editor_gadget[i]);
9171     }
9172   }
9173 }
9174
9175 static void MapLevelEditorToolboxCustomGadgets(void)
9176 {
9177   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9178 }
9179
9180 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9181 {
9182   if (IS_CUSTOM_ELEMENT(properties_element) ||
9183       IS_GROUP_ELEMENT(properties_element) ||
9184       IS_EMPTY_ELEMENT(properties_element))
9185     MapLevelEditorToolboxCustomGadgets();
9186 }
9187
9188 static void UnmapLevelEditorToolboxCustomGadgets(void)
9189 {
9190   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9191 }
9192
9193 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9194 {
9195   int i;
9196
9197   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9198   {
9199     if (i != GADGET_ID_SINGLE_ITEMS &&
9200         i != GADGET_ID_PICK_ELEMENT)
9201     {
9202       struct GadgetInfo *gi = level_editor_gadget[i];
9203
9204       if (map)
9205       {
9206         MapGadget(gi);
9207       }
9208       else
9209       {
9210         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9211         struct GraphicInfo *gd = &graphic_info[graphic];
9212
9213         UnmapGadget(gi);
9214
9215         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9216                    gi->width, gi->height, gi->x, gi->y);
9217
9218         redraw_mask |= REDRAW_DOOR_3;
9219       }
9220     }
9221   }
9222 }
9223
9224 static void MapLevelEditorToolboxDrawingGadgets(void)
9225 {
9226   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9227 }
9228
9229 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9230 {
9231   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9232 }
9233
9234 static void UnmapDrawingArea(int id)
9235 {
9236   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9237 }
9238
9239 static void UnmapLevelEditorFieldGadgets(void)
9240 {
9241   int i;
9242
9243   for (i = 0; i < num_editor_gadgets; i++)
9244     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9245                           level_editor_gadget[i]->y))
9246       UnmapGadget(level_editor_gadget[i]);
9247 }
9248
9249 void UnmapLevelEditorGadgets(void)
9250 {
9251   int i;
9252
9253   for (i = 0; i < num_editor_gadgets; i++)
9254     UnmapGadget(level_editor_gadget[i]);
9255 }
9256
9257 static void ResetUndoBuffer(void)
9258 {
9259   undo_buffer_position = -1;
9260   undo_buffer_steps = -1;
9261   redo_buffer_steps = 0;
9262
9263   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9264
9265   level.changed = FALSE;
9266 }
9267
9268 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9269 {
9270   if (remap_toolbox_gadgets)
9271   {
9272     ModifyEditorElementList();
9273     RedrawDrawingElements();
9274   }
9275
9276   if (edit_mode == ED_MODE_LEVELCONFIG)
9277     DrawLevelConfigWindow();
9278   else if (edit_mode == ED_MODE_PROPERTIES)
9279     DrawPropertiesWindow();
9280   else if (edit_mode == ED_MODE_PALETTE)
9281     DrawPaletteWindow();
9282   else  // edit_mode == ED_MODE_DRAWING
9283     DrawDrawingWindowExt(remap_toolbox_gadgets);
9284 }
9285
9286 static void DrawEditModeWindow(void)
9287 {
9288   DrawEditModeWindowExt(TRUE);
9289 }
9290
9291 static void DrawEditModeWindow_PlayfieldOnly(void)
9292 {
9293   DrawEditModeWindowExt(FALSE);
9294 }
9295
9296 static void ChangeEditModeWindow(int new_edit_mode)
9297 {
9298   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9299
9300   DrawEditModeWindow();
9301 }
9302
9303 static boolean LevelChanged(void)
9304 {
9305   boolean field_changed = FALSE;
9306   int x, y;
9307
9308   for (y = 0; y < lev_fieldy; y++) 
9309     for (x = 0; x < lev_fieldx; x++)
9310       if (Tile[x][y] != level.field[x][y])
9311         field_changed = TRUE;
9312
9313   return (level.changed || field_changed);
9314 }
9315
9316 static boolean PrepareSavingIntoPersonalLevelSet(void)
9317 {
9318   static LevelDirTree *last_copied_leveldir = NULL;
9319   static LevelDirTree *last_written_leveldir = NULL;
9320   static int last_copied_level_nr = -1;
9321   static int last_written_level_nr = -1;
9322   LevelDirTree *leveldir_former = leveldir_current;
9323   int level_nr_former = level_nr;
9324   int new_level_nr;
9325
9326   // remember last mod/save so that for current session, we write
9327   // back to the same personal copy, asking only about overwrite.
9328   if (leveldir_current == last_copied_leveldir &&
9329       level_nr == last_copied_level_nr)
9330   {
9331     // "cd" to personal level set dir (as used when writing last copy)
9332     leveldir_current = last_written_leveldir;
9333     level_nr = last_written_level_nr;
9334
9335     return TRUE;
9336   }
9337
9338   if (!Request("This level is read-only! "
9339                "Save into personal level set?", REQ_ASK))
9340     return FALSE;
9341
9342   // "cd" to personal level set dir (for writing copy the first time)
9343   leveldir_current =
9344     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9345
9346   // this may happen if "setup.internal.create_user_levelset" is FALSE
9347   // or if file "levelinfo.conf" is missing in personal user level set
9348   if (leveldir_current == NULL)
9349   {
9350     Request("Cannot find personal level set?!", REQ_CONFIRM);
9351
9352     leveldir_current = leveldir_former;
9353
9354     return FALSE;
9355   }
9356
9357   // find unused level number
9358   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9359   {
9360     static char *level_filename = NULL;
9361
9362     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9363
9364     if (!fileExists(level_filename))
9365       break;
9366   }
9367
9368   last_copied_leveldir = leveldir_former;
9369   last_copied_level_nr = level_nr_former;
9370
9371   last_written_leveldir = leveldir_current;
9372   last_written_level_nr = level_nr = new_level_nr;
9373
9374   return TRUE;
9375 }
9376
9377 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9378 {
9379   static char *filename_levelinfo = NULL, *mod_name = NULL;
9380   FILE *file;
9381
9382   // annotate this copy-and-mod in personal levelinfo.conf
9383   setString(&filename_levelinfo,
9384             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9385
9386   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9387   {
9388     fprintf(file, "\n");
9389     fprintf(file, "# level %d was modified from:\n", level_nr);
9390     fprintf(file, "# - previous level set name:    %s\n",
9391             former_name);
9392     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9393             level.file_info.nr, level.name);
9394     fprintf(file, "# - previous author:            %s\n",
9395             level.author);
9396     fprintf(file, "# - previous save date:         ");
9397
9398     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9399     {
9400       fprintf(file, "%04d-%02d-%02d\n",
9401               level.creation_date.year,
9402               level.creation_date.month,
9403               level.creation_date.day);
9404     }
9405     else
9406     {
9407       fprintf(file, "not recorded\n");
9408     }
9409
9410     fclose(file);
9411   }
9412
9413   if (level_nr > leveldir_current->last_level)
9414     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9415
9416   // else: allow the save even if annotation failed
9417
9418   // now... spray graffiti on the old level vital statistics
9419   // user can change these; just trying to set a good baseline
9420
9421   // don't truncate names for fear of making offensive or silly:
9422   // long-named original author only recorded in levelinfo.conf.
9423   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9424   if (!strEqual(level.author, leveldir_current->author))
9425   {
9426     setString(&mod_name, getStringCat3(leveldir_current->author,
9427                                        " after ", level.author));
9428
9429     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9430       setString(&mod_name,
9431                 getStringCat2(leveldir_current->author, " (ed.)"));
9432
9433     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9434       setString(&mod_name, leveldir_current->author);
9435
9436     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9437
9438     // less worried about truncation here
9439     setString(&mod_name, getStringCat2("Mod: ", level.name));
9440     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9441   }
9442 }
9443
9444 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9445                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9446 {
9447   int x, y;
9448
9449   for (x = 0; x < lev_fieldx; x++)
9450     for (y = 0; y < lev_fieldy; y++) 
9451       dst[x][y] = src[x][y];
9452 }
9453
9454 static int setSelectboxValue(int selectbox_id, int new_value)
9455 {
9456   int new_index_value = 0;
9457   int i;
9458
9459   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9460     if (selectbox_info[selectbox_id].options[i].value == new_value)
9461       new_index_value = i;
9462
9463   *selectbox_info[selectbox_id].value =
9464     selectbox_info[selectbox_id].options[new_index_value].value;
9465
9466   return new_index_value;
9467 }
9468
9469 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9470 {
9471   int i;
9472
9473   // change action mode and arg variables according to action type variable
9474   for (i = 0; action_arg_options[i].value != -1; i++)
9475   {
9476     if (action_arg_options[i].value == custom_element_change.action_type)
9477     {
9478       int mode = action_arg_options[i].mode;
9479
9480       // only change if corresponding selectbox has changed
9481       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9482           action_arg_modes[mode])
9483         custom_element_change.action_mode = -1;
9484
9485       // only change if corresponding selectbox has changed
9486       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9487           action_arg_options[i].options)
9488         custom_element_change.action_arg = -1;
9489
9490       break;
9491     }
9492   }
9493 }
9494
9495 static void setSelectboxSpecialActionOptions(void)
9496 {
9497   int i;
9498
9499   // change action mode and arg selectbox according to action type selectbox
9500   for (i = 0; action_arg_options[i].value != -1; i++)
9501   {
9502     if (action_arg_options[i].value == custom_element_change.action_type)
9503     {
9504       int mode = action_arg_options[i].mode;
9505
9506       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9507                                    action_arg_modes[mode]);
9508       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9509                                  custom_element_change.action_mode);
9510
9511       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9512                                    action_arg_options[i].options);
9513       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9514                                  custom_element_change.action_arg);
9515       break;
9516     }
9517   }
9518 }
9519
9520 static void copy_custom_element_settings(int element_from, int element_to)
9521 {
9522   struct ElementInfo *ei_from = &element_info[element_from];
9523   struct ElementInfo *ei_to = &element_info[element_to];
9524
9525   copyElementInfo(ei_from, ei_to);
9526 }
9527
9528 static void replace_custom_element_in_settings(int element_from,
9529                                                int element_to)
9530 {
9531   int i, j, x, y;
9532
9533   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9534   {
9535     struct ElementInfo *ei = &element_info[i];
9536
9537     for (y = 0; y < 3; y++)
9538       for (x = 0; x < 3; x++)
9539         if (ei->content.e[x][y] == element_from)
9540           ei->content.e[x][y] = element_to;
9541
9542     for (j = 0; j < ei->num_change_pages; j++)
9543     {
9544       struct ElementChangeInfo *change = &ei->change_page[j];
9545
9546       if (change->target_element == element_from)
9547         change->target_element = element_to;
9548
9549       if (change->initial_trigger_element == element_from)
9550         change->initial_trigger_element = element_to;
9551
9552       if (change->action_element == element_from)
9553         change->action_element = element_to;
9554
9555       for (y = 0; y < 3; y++)
9556         for (x = 0; x < 3; x++)
9557           if (change->target_content.e[x][y] == element_from)
9558             change->target_content.e[x][y] = element_to;
9559     }
9560
9561     if (ei->group != NULL)                              // group or internal
9562       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9563         if (ei->group->element[j] == element_from)
9564           ei->group->element[j] = element_to;
9565   }
9566 }
9567
9568 static void replace_custom_element_in_playfield(int element_from,
9569                                                 int element_to)
9570 {
9571   int x, y;
9572
9573   for (x = 0; x < lev_fieldx; x++)
9574     for (y = 0; y < lev_fieldy; y++)
9575       if (Tile[x][y] == element_from)
9576         Tile[x][y] = element_to;
9577 }
9578
9579 static boolean CopyCustomElement(int element_old, int element_new,
9580                                  int copy_mode)
9581 {
9582   int copy_mode_orig = copy_mode;
9583
9584   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9585   {
9586     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9587                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9588     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9589   }
9590   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9591   {
9592     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9593                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9594     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9595
9596     level.changed = TRUE;
9597   }
9598   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9599   {
9600     Request("Please choose custom element!", REQ_CONFIRM);
9601
9602     return FALSE;
9603   }
9604   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9605   {
9606     Request("Please choose group element!", REQ_CONFIRM);
9607
9608     return FALSE;
9609   }
9610   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9611   {
9612     Request("Please choose empty element!", REQ_CONFIRM);
9613
9614     return FALSE;
9615   }
9616   else
9617   {
9618     level.changed = TRUE;
9619   }
9620
9621   // when modifying custom/group element, ask for copying level template
9622   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9623   {
9624     if (!AskToCopyAndModifyLevelTemplate())
9625       return FALSE;
9626   }
9627
9628   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9629   {
9630     copy_custom_element_settings(element_new, element_old);
9631   }
9632   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9633   {
9634     copy_custom_element_settings(element_old, element_new);
9635   }
9636   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9637   {
9638     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9639     copy_custom_element_settings(element_new, element_old);
9640     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9641
9642     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9643     replace_custom_element_in_settings(element_new, element_old);
9644     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9645
9646     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9647     replace_custom_element_in_playfield(element_new, element_old);
9648     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9649   }
9650
9651   UpdateCustomElementGraphicGadgets();
9652   DrawPropertiesWindow();
9653
9654   return TRUE;
9655 }
9656
9657 static void CopyCustomElementPropertiesToEditor(int element)
9658 {
9659   int i;
9660   int current_change_page = element_info[element].current_change_page;
9661
9662   // dynamically (re)build selectbox for selecting change page
9663   for (i = 0; i < element_info[element].num_change_pages; i++)
9664   {
9665     sprintf(options_change_page_strings[i], "%d", i + 1);
9666
9667     options_change_page[i].value = i;
9668     options_change_page[i].text = options_change_page_strings[i];
9669   }
9670
9671   options_change_page[i].value = -1;
9672   options_change_page[i].text = NULL;
9673
9674   // needed here to initialize combined element properties
9675   InitElementPropertiesEngine(level.game_version);
9676
9677   element_info[element].change =
9678     &element_info[element].change_page[current_change_page];
9679
9680   custom_element = element_info[element];
9681   custom_element_change = *element_info[element].change;
9682
9683   // needed to initially set selectbox options for special action options
9684   setSelectboxSpecialActionOptions();
9685
9686   // needed to initially set selectbox value variables to reliable defaults
9687   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9688     setSelectboxValue(i, *selectbox_info[i].value);
9689
9690   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9691     custom_element_properties[i] = HAS_PROPERTY(element, i);
9692
9693   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9694     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9695
9696   // ---------- element settings: configure (custom elements) -----------------
9697
9698   // set accessible layer selectbox help value
9699   custom_element.access_type =
9700     (IS_WALKABLE(element) ? EP_WALKABLE :
9701      IS_PASSABLE(element) ? EP_PASSABLE :
9702      custom_element.access_type);
9703   custom_element.access_layer =
9704     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9705      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9706      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9707      custom_element.access_layer);
9708   custom_element.access_protected =
9709     (IS_PROTECTED(element) ? 1 : 0);
9710   custom_element_properties[EP_ACCESSIBLE] =
9711     (IS_ACCESSIBLE_OVER(element) ||
9712      IS_ACCESSIBLE_INSIDE(element) ||
9713      IS_ACCESSIBLE_UNDER(element));
9714
9715   // set walk-to-object action selectbox help value
9716   custom_element.walk_to_action =
9717     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9718      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9719      IS_DROPPABLE(element) ? EP_DROPPABLE :
9720      IS_THROWABLE(element) ? EP_THROWABLE :
9721      IS_PUSHABLE(element) ? EP_PUSHABLE :
9722      custom_element.walk_to_action);
9723   custom_element_properties[EP_WALK_TO_OBJECT] =
9724     (IS_DIGGABLE(element) ||
9725      IS_COLLECTIBLE_ONLY(element) ||
9726      IS_DROPPABLE(element) ||
9727      IS_THROWABLE(element) ||
9728      IS_PUSHABLE(element));
9729
9730   // set smash targets selectbox help value
9731   custom_element.smash_targets =
9732     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9733      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9734      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9735      custom_element.smash_targets);
9736   custom_element_properties[EP_CAN_SMASH] =
9737     (CAN_SMASH_EVERYTHING(element) ||
9738      CAN_SMASH_ENEMIES(element) ||
9739      CAN_SMASH_PLAYER(element));
9740
9741   // set deadliness selectbox help value
9742   custom_element.deadliness =
9743     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9744      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9745      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9746      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9747      custom_element.deadliness);
9748   custom_element_properties[EP_DEADLY] =
9749     (DONT_TOUCH(element) ||
9750      DONT_GET_HIT_BY(element) ||
9751      DONT_COLLIDE_WITH(element) ||
9752      DONT_RUN_INTO(element));
9753
9754   // ---------- element settings: advanced (custom elements) ------------------
9755
9756   // set "change by direct action" selectbox help value
9757   custom_element_change.direct_action =
9758     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9759      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9760      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9761      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9762      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9763      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9764      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9765      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9766      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9767      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9768      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9769      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9770      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9771      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9772      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9773      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9774      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9775      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9776      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9777      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9778      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9779      custom_element_change.direct_action);
9780
9781   // set "change by other element action" selectbox help value
9782   custom_element_change.other_action =
9783     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9784      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9785      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9786      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9787      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9788      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9789      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9790      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9791      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9792      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9793      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9794      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9795      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9796      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9797      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9798      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9799      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9800      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9801      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9802      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9803      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9804      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9805      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9806      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9807      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9808      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9809      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9810      custom_element_change.other_action);
9811 }
9812
9813 static void CopyGroupElementPropertiesToEditor(int element)
9814 {
9815   group_element_info = *element_info[element].group;
9816   custom_element = element_info[element];       // needed for description
9817 }
9818
9819 static void CopyEmptyElementPropertiesToEditor(int element)
9820 {
9821   custom_element = element_info[element];
9822 }
9823
9824 static void CopyClassicElementPropertiesToEditor(int element)
9825 {
9826   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9827     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9828       getMoveIntoAcidProperty(&level, element);
9829
9830   if (MAYBE_DONT_COLLIDE_WITH(element))
9831     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9832       getDontCollideWithProperty(&level, element);
9833 }
9834
9835 static void CopyElementPropertiesToEditor(int element)
9836 {
9837   if (IS_CUSTOM_ELEMENT(element))
9838     CopyCustomElementPropertiesToEditor(element);
9839   else if (IS_GROUP_ELEMENT(element))
9840     CopyGroupElementPropertiesToEditor(element);
9841   else if (IS_EMPTY_ELEMENT(element))
9842     CopyEmptyElementPropertiesToEditor(element);
9843   else
9844     CopyClassicElementPropertiesToEditor(element);
9845 }
9846
9847 static boolean AskToCopyAndModifyLevelTemplate(void)
9848 {
9849   if (Request("Copy and modify settings from level template?", REQ_ASK))
9850   {
9851     level.use_custom_template = FALSE;
9852
9853     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9854                  GDI_CHECKED, FALSE, GDI_END);
9855     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9856                  GDI_CHECKED, FALSE, GDI_END);
9857
9858     return TRUE;
9859   }
9860   else
9861   {
9862     LoadLevelTemplate(-1);      // this resets all element modifications ...
9863
9864     DrawEditModeWindow();       // ... and copies them to 'custom_element'
9865
9866     return FALSE;
9867   }
9868 }
9869
9870 static void CopyCustomElementPropertiesToGame(int element)
9871 {
9872   int i;
9873   int access_type_and_layer;
9874
9875   // mark that this custom element has been modified
9876   custom_element.modified_settings = TRUE;
9877   level.changed = TRUE;
9878
9879   if (level.use_custom_template)
9880     AskToCopyAndModifyLevelTemplate();
9881
9882   element_info[element] = custom_element;
9883   *element_info[element].change = custom_element_change;
9884
9885   // ---------- element settings: configure (custom elements) -----------------
9886
9887   // set accessible property from checkbox and selectbox
9888   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
9889   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
9890   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
9891   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
9892   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
9893   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
9894   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
9895                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
9896                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
9897   custom_element_properties[access_type_and_layer] =
9898     custom_element_properties[EP_ACCESSIBLE];
9899   custom_element_properties[EP_PROTECTED] =
9900     (custom_element.access_protected != 0 &&
9901      custom_element_properties[EP_ACCESSIBLE]);
9902
9903   // set walk-to-object property from checkbox and selectbox
9904   custom_element_properties[EP_DIGGABLE] = FALSE;
9905   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
9906   custom_element_properties[EP_DROPPABLE] = FALSE;
9907   custom_element_properties[EP_THROWABLE] = FALSE;
9908   custom_element_properties[EP_PUSHABLE] = FALSE;
9909   custom_element_properties[custom_element.walk_to_action] =
9910     custom_element_properties[EP_WALK_TO_OBJECT];
9911
9912   // set smash property from checkbox and selectbox
9913   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
9914   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
9915   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
9916   custom_element_properties[custom_element.smash_targets] =
9917     custom_element_properties[EP_CAN_SMASH];
9918
9919   // set deadliness property from checkbox and selectbox
9920   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
9921   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
9922   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
9923   custom_element_properties[EP_DONT_TOUCH] = FALSE;
9924   custom_element_properties[custom_element.deadliness] =
9925     custom_element_properties[EP_DEADLY];
9926
9927   // ---------- element settings: advanced (custom elements) ------------------
9928
9929   // set player change event from checkbox and selectbox
9930   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
9931   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
9932   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
9933   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
9934   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
9935   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
9936   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
9937   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
9938   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
9939   custom_element_change_events[CE_SWITCHED] = FALSE;
9940   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
9941   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
9942   custom_element_change_events[CE_BLOCKED] = FALSE;
9943   custom_element_change_events[CE_IMPACT] = FALSE;
9944   custom_element_change_events[CE_SMASHED] = FALSE;
9945   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
9946   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
9947   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
9948   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
9949   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
9950   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
9951   custom_element_change_events[custom_element_change.direct_action] =
9952     custom_element_change_events[CE_BY_DIRECT_ACTION];
9953
9954   // set other element action change event from checkbox and selectbox
9955   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
9956   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
9957   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
9958   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
9959   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
9960   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
9961   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
9962   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
9963   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
9964   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
9965   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
9966   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
9967   custom_element_change_events[CE_TOUCHING_X] = FALSE;
9968   custom_element_change_events[CE_HITTING_X] = FALSE;
9969   custom_element_change_events[CE_DIGGING_X] = FALSE;
9970   custom_element_change_events[CE_HIT_BY_X] = FALSE;
9971   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
9972   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
9973   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
9974   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
9975   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
9976   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
9977   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
9978   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
9979   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
9980   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
9981   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
9982   custom_element_change_events[custom_element_change.other_action] =
9983     custom_element_change_events[CE_BY_OTHER_ACTION];
9984
9985   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9986     SET_PROPERTY(element, i, custom_element_properties[i]);
9987
9988   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9989     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
9990
9991   // copy change events also to special level editor variable
9992   custom_element = element_info[element];
9993   custom_element_change = *element_info[element].change;
9994
9995   // needed here to restore runtime value "element_info[element].gfx_element"
9996   InitElementPropertiesGfxElement();
9997 }
9998
9999 static void CopyGroupElementPropertiesToGame(int element)
10000 {
10001   // mark that this group element has been modified
10002   custom_element.modified_settings = TRUE;
10003   level.changed = TRUE;
10004
10005   if (level.use_custom_template)
10006     AskToCopyAndModifyLevelTemplate();
10007
10008   element_info[element] = custom_element;
10009   *element_info[element].group = group_element_info;
10010
10011   // needed here to restore runtime value "element_info[element].gfx_element"
10012   InitElementPropertiesGfxElement();
10013 }
10014
10015 static void CopyEmptyElementPropertiesToGame(int element)
10016 {
10017   // mark that this empty element has been modified
10018   custom_element.modified_settings = TRUE;
10019   level.changed = TRUE;
10020
10021   if (level.use_custom_template)
10022     AskToCopyAndModifyLevelTemplate();
10023
10024   element_info[element] = custom_element;
10025
10026   // needed here to restore runtime value "element_info[element].gfx_element"
10027   InitElementPropertiesGfxElement();
10028 }
10029
10030 static void CopyClassicElementPropertiesToGame(int element)
10031 {
10032   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
10033     setMoveIntoAcidProperty(&level, element,
10034                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
10035
10036   if (MAYBE_DONT_COLLIDE_WITH(element))
10037     setDontCollideWithProperty(&level, element,
10038                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
10039 }
10040
10041 static void CopyElementPropertiesToGame(int element)
10042 {
10043   if (IS_CUSTOM_ELEMENT(element))
10044     CopyCustomElementPropertiesToGame(element);
10045   else if (IS_GROUP_ELEMENT(element))
10046     CopyGroupElementPropertiesToGame(element);
10047   else if (IS_EMPTY_ELEMENT(element))
10048     CopyEmptyElementPropertiesToGame(element);
10049   else
10050     CopyClassicElementPropertiesToGame(element);
10051 }
10052
10053 #if DEBUG
10054 static void CheckElementDescriptions(void)
10055 {
10056   int i;
10057
10058   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10059     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
10060       Warn("no element description file for element '%s'", EL_NAME(i));
10061 }
10062 #endif
10063
10064 static int getMaxEdFieldX(boolean has_scrollbar)
10065 {
10066   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
10067   int sxsize = SXSIZE - scrollbar_width;
10068   int max_ed_fieldx = sxsize / ed_tilesize;
10069
10070   return max_ed_fieldx;
10071 }
10072
10073 static int getMaxEdFieldY(boolean has_scrollbar)
10074 {
10075   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
10076                          INFOTEXT_YSIZE_FULL : 0);
10077   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
10078   int sysize = SYSIZE - scrollbar_height - infotext_height;
10079   int max_ed_fieldy = sysize / ed_tilesize;
10080
10081   return max_ed_fieldy;
10082 }
10083
10084 static void InitZoomLevelSettings(int zoom_tilesize)
10085 {
10086   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
10087
10088   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
10089   {
10090     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10091     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10092
10093     // make sure that tile size is always a power of 2
10094     ed_tilesize = (1 << log_2(ed_tilesize));
10095
10096     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10097     {
10098       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10099       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10100     }
10101   }
10102
10103   last_game_engine_type = level.game_engine_type;
10104
10105   // limit zoom tilesize by upper and lower bound
10106   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10107
10108   // store zoom tilesize in auto setup file only if it was manually changed
10109   if (zoom_tilesize != -1)
10110     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10111
10112   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10113   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10114 }
10115
10116 static void InitDrawingElements(void)
10117 {
10118   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10119
10120   if (level.game_engine_type == game_engine_type_last)
10121     return;
10122
10123   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10124   {
10125     new_element1 = EL_BD_WALL;
10126     new_element2 = EL_EMPTY;
10127     new_element3 = EL_BD_SAND;
10128   }
10129   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10130   {
10131     new_element1 = EL_SP_CHIP_SINGLE;
10132     new_element2 = EL_EMPTY;
10133     new_element3 = EL_SP_BASE;
10134   }
10135   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10136   {
10137     new_element1 = EL_MM_MIRROR_START;
10138     new_element2 = EL_EMPTY;
10139     new_element3 = EL_MM_WOODEN_WALL;
10140   }
10141   else
10142   {
10143     new_element1 = EL_WALL;
10144     new_element2 = EL_EMPTY;
10145     new_element3 = EL_SAND;
10146   }
10147
10148   game_engine_type_last = level.game_engine_type;
10149 }
10150
10151 static void InitLevelSetInfo(void)
10152 {
10153   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10154            "%s", leveldir_current->name);
10155   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10156            "%s", leveldir_current->author);
10157
10158   levelset_num_levels = leveldir_current->levels;
10159
10160   levelset_use_levelset_artwork = FALSE;
10161   levelset_copy_level_template = FALSE;
10162
10163   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10164 }
10165
10166 static void ChangeEditorToLevelSet(char *levelset_subdir)
10167 {
10168   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10169
10170   // the previous level set might have used custom artwork
10171   ReloadCustomArtwork(0);
10172
10173   LoadLevelSetup_SeriesInfo();
10174
10175   SaveLevelSetup_LastSeries();
10176   SaveLevelSetup_SeriesInfo();
10177
10178   TapeErase();
10179
10180   LoadLevel(level_nr);
10181   LoadScore(level_nr);
10182
10183   DrawLevelEd();
10184 }
10185
10186 static boolean useEditorDoorAnimation(void)
10187 {
10188   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10189   boolean door_1_viewport_unchanged =
10190     (vp_door_1->x      == DX     &&
10191      vp_door_1->y      == DY     &&
10192      vp_door_1->width  == DXSIZE &&
10193      vp_door_1->height == DYSIZE);
10194   boolean door_1_contains_toolbox =
10195     (EX >= DX &&
10196      EY >= DY &&
10197      EX + EXSIZE <= DX + DXSIZE &&
10198      EY + EYSIZE <= DY + DYSIZE);
10199
10200   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10201 }
10202
10203 static void DrawEditorDoorBackground(int graphic, int x, int y,
10204                                      int width, int height)
10205 {
10206   struct GraphicInfo *g = &graphic_info[graphic];
10207
10208   if (g->bitmap != NULL)
10209     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10210                MIN(width, g->width), MIN(height, g->height), x, y);
10211   else
10212     ClearRectangle(drawto, x, y, width, height);
10213 }
10214
10215 static void DrawEditorDoorContent(void)
10216 {
10217   // needed for gadgets drawn on background (like palette scrollbar)
10218   SetDoorBackgroundImage(IMG_UNDEFINED);
10219
10220   // copy default editor door content to main double buffer
10221   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10222
10223   // draw bigger door
10224   DrawSpecialEditorDoor();
10225
10226   // draw new control window
10227   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10228
10229   // draw all toolbox gadgets to editor doors
10230   MapControlButtons();
10231
10232   // when returning from test game to properties page, redraw toolbox gadgets
10233   if (edit_mode == ED_MODE_PROPERTIES)
10234   {
10235     UnmapLevelEditorToolboxDrawingGadgets();
10236     UnmapLevelEditorToolboxCustomGadgets();
10237
10238     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10239   }
10240
10241   // draw all palette gadgets to editor doors
10242   ModifyEditorElementList();
10243   RedrawDrawingElements();
10244
10245   // copy actual editor door content to door double buffer for OpenDoor()
10246   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10247 }
10248
10249 void DrawLevelEd(void)
10250 {
10251   int fade_mask = REDRAW_FIELD;
10252
10253   FadeSoundsAndMusic();
10254
10255   if (CheckFadeAll())
10256     fade_mask = REDRAW_ALL;
10257
10258   FadeOut(fade_mask);
10259
10260   // needed if different viewport properties defined for editor
10261   ChangeViewportPropertiesIfNeeded();
10262
10263   ClearField();
10264
10265   InitZoomLevelSettings(-1);
10266   InitDrawingElements();
10267   InitLevelSetInfo();
10268
10269 #if DEBUG
10270   CheckElementDescriptions();
10271 #endif
10272
10273   if (level_editor_test_game)
10274   {
10275     CopyPlayfield(level.field, Tile);
10276     CopyPlayfield(TileBackup, level.field);
10277
10278     level_editor_test_game = FALSE;
10279   }
10280   else
10281   {
10282     edit_mode = ED_MODE_DRAWING;
10283     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10284     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10285
10286     ResetUndoBuffer();
10287
10288     level_xpos = -1;
10289     level_ypos = -1;
10290   }
10291
10292   // redraw_mask |= REDRAW_ALL;
10293
10294   FreeLevelEditorGadgets();
10295   CreateLevelEditorGadgets();
10296
10297   ReinitializeElementList();            // update dynamic level element list
10298   ReinitializeElementListButtons();     // custom element may look different
10299
10300   InitElementPropertiesGfxElement();
10301
10302   UnmapAllGadgets();
10303
10304   DrawEditModeWindow_PlayfieldOnly();
10305
10306   DrawMaskedBorder(fade_mask);
10307
10308   // use door animation if door 1 viewport is unchanged and contains toolbox
10309   if (useEditorDoorAnimation())
10310   {
10311     FadeIn(fade_mask);
10312
10313     DrawEditorDoorContent();
10314
10315     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10316   }
10317   else
10318   {
10319     DrawEditorDoorContent();
10320
10321     FadeIn(fade_mask);
10322   }
10323
10324   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10325 }
10326
10327 static void AdjustDrawingAreaGadgets(void)
10328 {
10329   int ed_xsize = lev_fieldx + 2;
10330   int ed_ysize = lev_fieldy + 2;
10331   int max_ed_fieldx = MAX_ED_FIELDX;
10332   int max_ed_fieldy = MAX_ED_FIELDY;
10333   boolean horizontal_scrollbar_needed;
10334   boolean vertical_scrollbar_needed;
10335   int x, y, width, height;
10336
10337   if (suppressBorderElement())
10338   {
10339     ed_xsize = lev_fieldx;
10340     ed_ysize = lev_fieldy;
10341   }
10342
10343   // check if we need any scrollbars
10344   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10345   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10346
10347   // check if we have a smaller editor field because of scrollbars
10348   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10349   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10350
10351   // check again if we now need more scrollbars because of less space
10352   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10353   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10354
10355   // check if editor field gets even smaller after adding new scrollbars
10356   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10357   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10358
10359   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10360   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10361
10362   x = SX + ed_fieldx * ed_tilesize;
10363   y = SY + ed_fieldy * ed_tilesize;
10364
10365   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10366   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10367
10368   // adjust drawing area gadget
10369   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10370                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10371                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10372                GDI_END);
10373
10374   // adjust horizontal scrollbar gadgets
10375   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10376                GDI_Y, y,
10377                GDI_END);
10378   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10379                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10380                GDI_Y, y,
10381                GDI_END);
10382   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10383                GDI_Y, y,
10384                GDI_WIDTH, width,
10385                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10386                GDI_END);
10387
10388   // adjust vertical scrollbar gadgets
10389   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10390                GDI_X, x,
10391                GDI_END);
10392   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10393                GDI_X, x,
10394                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10395                GDI_END);
10396   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10397                GDI_X, x,
10398                GDI_HEIGHT, height,
10399                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10400                GDI_END);
10401 }
10402
10403 static void AdjustLevelScrollPosition(void)
10404 {
10405   if (level_xpos < -1)
10406     level_xpos = -1;
10407   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10408     level_xpos = lev_fieldx - ed_fieldx + 1;
10409   if (lev_fieldx < ed_fieldx - 2)
10410     level_xpos = -1;
10411
10412   if (level_ypos < -1)
10413     level_ypos = -1;
10414   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10415     level_ypos = lev_fieldy - ed_fieldy + 1;
10416   if (lev_fieldy < ed_fieldy - 2)
10417     level_ypos = -1;
10418
10419   if (suppressBorderElement())
10420   {
10421     level_xpos = 0;
10422     level_ypos = 0;
10423   }
10424 }
10425
10426 static void AdjustEditorScrollbar(int id)
10427 {
10428   struct GadgetInfo *gi = level_editor_gadget[id];
10429   int items_max, items_visible, item_position;
10430
10431   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10432   {
10433     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10434     items_visible = ed_fieldx;
10435     item_position = level_xpos + 1;
10436   }
10437   else
10438   {
10439     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10440     items_visible = ed_fieldy;
10441     item_position = level_ypos + 1;
10442   }
10443
10444   if (item_position > items_max - items_visible)
10445     item_position = items_max - items_visible;
10446
10447   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10448                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10449 }
10450
10451 static void AdjustElementListScrollbar(void)
10452 {
10453   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10454   int items_max, items_visible, item_position;
10455
10456   // correct position of element list scrollbar
10457   if (element_shift < 0)
10458     element_shift = 0;
10459   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10460     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10461
10462   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10463   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10464   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10465
10466   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10467                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10468                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10469 }
10470
10471 static void ModifyEditorCounterValue(int counter_id, int new_value)
10472 {
10473   int *counter_value = counterbutton_info[counter_id].value;
10474   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10475   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10476
10477   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10478
10479   if (counter_value != NULL)
10480     *counter_value = gi->textinput.number_value;
10481 }
10482
10483 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10484 {
10485   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10486   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10487
10488   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10489
10490   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10491       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10492   {
10493     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10494     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10495
10496     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10497     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10498                  GDI_END);
10499   }
10500 }
10501
10502 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10503 {
10504   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10505   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10506   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10507
10508   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10509 }
10510
10511 static void ModifyEditorSelectboxOptions(int selectbox_id,
10512                                          struct ValueTextInfo *options)
10513 {
10514   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10515   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10516
10517   selectbox_info[selectbox_id].options = options;
10518
10519   // set index to zero -- list may be shorter now (correct later, if needed)
10520   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10521                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10522 }
10523
10524 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10525 {
10526   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10527   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10528
10529   drawingarea_info[drawingarea_id].area_xsize = xsize;
10530   drawingarea_info[drawingarea_id].area_ysize = ysize;
10531
10532   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10533 }
10534
10535 static void ModifyEditorElementList(void)
10536 {
10537   int i;
10538
10539   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10540     return;
10541
10542   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10543   {
10544     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10545     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10546     struct GadgetDesign *gd = &gi->deco.design;
10547     int element = editor_elements[element_shift + i];
10548     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10549
10550     UnmapGadget(gi);
10551
10552     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10553
10554     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10555
10556     MapGadget(gi);
10557   }
10558 }
10559
10560 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10561 {
10562   int graphic = el2edimg(element);
10563   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10564
10565   if (pos->x == -1 &&
10566       pos->y == -1)
10567     return;
10568
10569   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10570 }
10571
10572 static void ModifyDrawingElementButton(int element, int id)
10573 {
10574   struct GadgetInfo *gi = level_editor_gadget[id];
10575   Bitmap *deco_bitmap;
10576   int deco_x, deco_y;
10577   int tile_size = gi->deco.width;
10578
10579   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10580
10581   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10582 }
10583
10584 static void PickDrawingElement(int button, int element)
10585 {
10586   struct
10587   {
10588     int *new_element;
10589     struct XYTileSize *pos;
10590     int id;
10591   } de, drawing_elements[] =
10592   {
10593     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10594     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10595     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10596   };
10597
10598   if (button < 1 || button > 3)
10599     return;
10600
10601   if (IS_MM_WALL(element))
10602     element = map_mm_wall_element(element);
10603
10604   de = drawing_elements[button - 1];
10605
10606   *de.new_element = element;    // update global drawing element variable
10607
10608   DrawDrawingElementGraphic(element, de.pos);
10609   ModifyDrawingElementButton(element, de.id);
10610
10611   redraw_mask |= REDRAW_DOOR_1;
10612 }
10613
10614 static void RedrawDrawingElements(void)
10615 {
10616   PickDrawingElement(1, new_element1);
10617   PickDrawingElement(2, new_element2);
10618   PickDrawingElement(3, new_element3);
10619 }
10620
10621 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10622 {
10623   stick_element_properties_window = FALSE;
10624
10625   SetMainBackgroundImage(IMG_UNDEFINED);
10626   ClearField();
10627
10628   UnmapLevelEditorFieldGadgets();
10629
10630   AdjustDrawingAreaGadgets();
10631   AdjustLevelScrollPosition();
10632   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10633   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10634
10635   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10636
10637   MapMainDrawingArea();
10638
10639   if (remap_toolbox_gadgets)
10640   {
10641     UnmapLevelEditorToolboxCustomGadgets();
10642     MapLevelEditorToolboxDrawingGadgets();
10643   }
10644 }
10645
10646 static void DrawDrawingWindow(void)
10647 {
10648   DrawDrawingWindowExt(TRUE);
10649 }
10650
10651 static int getTabulatorBarWidth(void)
10652 {
10653   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10654   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10655
10656   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10657 }
10658
10659 static int getTabulatorBarHeight(void)
10660 {
10661   return ED_TAB_BAR_HEIGHT;
10662 }
10663
10664 static Pixel getTabulatorBarColor(void)
10665 {
10666   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10667   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10668   int gd_x = gd->x + gd_gi1->border.width / 2;
10669   int gd_y = gd->y + gd_gi1->height - 1;
10670
10671   return GetPixel(gd->bitmap, gd_x, gd_y);
10672 }
10673
10674 static void DrawLevelConfigTabulatorGadgets(void)
10675 {
10676   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10677   Pixel tab_color = getTabulatorBarColor();
10678   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10679   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10680   int i;
10681
10682   // draw additional "engine" tabulator when using native BD engine
10683   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10684     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10685
10686   for (i = id_first; i <= id_last; i++)
10687   {
10688     int gadget_id = textbutton_info[i].gadget_id;
10689     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10690     boolean active = (i != edit_mode_levelconfig);
10691
10692     // draw background line below tabulator button
10693     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10694
10695     // draw solid line below inactive tabulator buttons
10696     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10697       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10698                     ED_GADGET_TINY_DISTANCE, tab_color);
10699
10700     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10701     MapTextbuttonGadget(i);
10702   }
10703
10704   // draw little border line below tabulator buttons
10705   if (tab_color != BLACK_PIXEL)                 // black => transparent
10706     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10707                   ED_GADGET_TINY_DISTANCE,
10708                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10709 }
10710
10711 static void DrawPropertiesTabulatorGadgets(void)
10712 {
10713   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10714   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10715   int gd_x = gd->x + gd_gi1->border.width / 2;
10716   int gd_y = gd->y + gd_gi1->height - 1;
10717   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10718   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10719   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10720   int i;
10721
10722   // draw two config tabulators for player elements
10723   if (IS_PLAYER_ELEMENT(properties_element))
10724     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10725
10726   // draw two config and one "change" tabulator for custom elements
10727   if (IS_CUSTOM_ELEMENT(properties_element))
10728     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10729
10730   for (i = id_first; i <= id_last; i++)
10731   {
10732     int gadget_id = textbutton_info[i].gadget_id;
10733     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10734     boolean active = (i != edit_mode_properties);
10735
10736     // use "config 1" and "config 2" instead of "config" for players and CEs
10737     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10738         (IS_PLAYER_ELEMENT(properties_element) ||
10739          IS_CUSTOM_ELEMENT(properties_element)))
10740       continue;
10741
10742     // draw background line below tabulator button
10743     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10744
10745     // draw solid line below inactive tabulator buttons
10746     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10747       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10748                     ED_GADGET_TINY_DISTANCE, tab_color);
10749
10750     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10751     MapTextbuttonGadget(i);
10752   }
10753
10754   // draw little border line below tabulator buttons
10755   if (tab_color != BLACK_PIXEL)                 // black => transparent
10756     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10757                   ED_GADGET_TINY_DISTANCE,
10758                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10759 }
10760
10761 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10762 {
10763   DrawText(SX + xpos, SY + ypos, text, font_nr);
10764 }
10765
10766 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10767                                            int xpos, int ypos)
10768 {
10769   int font_width = getFontWidth(font_nr);
10770   int font_height = getFontHeight(font_nr);
10771   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10772   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10773
10774   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10775                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10776                       TRUE, FALSE, FALSE);
10777 }
10778
10779 static void DrawLevelConfigLevel(void)
10780 {
10781   int i;
10782
10783   // draw counter gadgets
10784   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10785     MapCounterButtons(i);
10786
10787   // draw checkbutton gadgets
10788   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10789     MapCheckbuttonGadget(i);
10790
10791   // draw selectbox gadgets
10792   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10793     MapSelectboxGadget(i);
10794
10795   // draw text input gadgets
10796   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10797     MapTextInputGadget(i);
10798 }
10799
10800 static char *getLevelSubdirFromSaveMode(int save_mode)
10801 {
10802   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10803     return getNewUserLevelSubdir();
10804
10805   return leveldir_current->subdir;
10806 }
10807
10808 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10809 {
10810   char *directory_text = "Level set directory:";
10811   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10812   int font1_nr = FONT_TEXT_1;
10813   int font2_nr = FONT_TEXT_2;
10814   int font1_height = getFontHeight(font1_nr);
10815   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10816   int x = ED_LEVEL_SETTINGS_X(0);
10817   int y = ED_LEVEL_SETTINGS_Y(6);
10818
10819   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10820   PrintInfoText(directory_name, font2_nr, x, y);
10821 }
10822
10823 static void DrawLevelConfigLevelSet(void)
10824 {
10825   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10826   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10827   int i;
10828
10829   // draw counter gadgets
10830   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10831     MapCounterButtons(i);
10832
10833   // draw checkbutton gadgets
10834   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10835   {
10836     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10837         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10838         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10839       continue;
10840
10841     MapCheckbuttonGadget(i);
10842   }
10843
10844   // draw selectbox gadgets
10845   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10846     MapSelectboxGadget(i);
10847
10848   // draw text input gadgets
10849   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10850     MapTextInputGadget(i);
10851
10852   // draw textbutton gadgets
10853   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10854
10855   // draw info text
10856   DrawLevelConfigLevelSet_DirectoryInfo();
10857 }
10858
10859 static void DrawLevelConfigEditor(void)
10860 {
10861   int i;
10862
10863   // draw counter gadgets
10864   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
10865     MapCounterButtons(i);
10866
10867   // draw checkbutton gadgets
10868   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
10869     MapCheckbuttonGadget(i);
10870
10871   // draw radiobutton gadgets
10872   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
10873     MapRadiobuttonGadget(i);
10874
10875   // draw drawing area
10876   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
10877
10878   // draw textbutton gadgets
10879   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
10880 }
10881
10882 static void DrawLevelConfigEngine(void)
10883 {
10884   int i;
10885
10886   // draw counter gadgets
10887   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
10888   {
10889     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
10890     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
10891   }
10892   else
10893   {
10894     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
10895     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
10896   }
10897
10898   // draw checkbutton gadgets
10899   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
10900     MapCheckbuttonGadget(i);
10901
10902   // draw selectbox gadgets
10903   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
10904     MapSelectboxGadget(i);
10905 }
10906
10907 static void DrawLevelConfigWindow(void)
10908 {
10909   char *text = "Global Settings";
10910   int font_nr = FONT_TITLE_1;
10911   struct MenuPosInfo *pos = &editor.settings.headline;
10912   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
10913   int sy = SY + pos->y;
10914
10915   stick_element_properties_window = FALSE;
10916
10917   SetAutomaticNumberOfGemsNeeded();
10918
10919   UnmapLevelEditorFieldGadgets();
10920
10921   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
10922   ClearField();
10923
10924   DrawText(sx, sy, text, font_nr);
10925
10926   DrawLevelConfigTabulatorGadgets();
10927
10928   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
10929     DrawLevelConfigLevel();
10930   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
10931     DrawLevelConfigLevelSet();
10932   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
10933     DrawLevelConfigEditor();
10934   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
10935     DrawLevelConfigEngine();
10936 }
10937
10938 static void DrawCustomContentArea(void)
10939 {
10940   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
10941   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
10942   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
10943   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
10944   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
10945   int xoffset = ED_GADGET_SPACE_DISTANCE;
10946
10947   // add distance for potential left text (without drawing area border)
10948   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
10949
10950   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
10951
10952   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
10953 }
10954
10955 static void DrawCustomChangeContentArea(void)
10956 {
10957   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
10958   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
10959   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
10960   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
10961   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
10962   int xoffset = ED_GADGET_SPACE_DISTANCE;
10963
10964   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
10965
10966   MapDrawingArea(id);
10967 }
10968
10969 static void RemoveElementContentArea(int id, int font_height)
10970 {
10971   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
10972
10973   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
10974                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
10975                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
10976                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
10977                  ED_GADGET_TEXT_DISTANCE + font_height);
10978 }
10979
10980 static void DrawYamYamContentAreas(void)
10981 {
10982   int font_nr = FONT_TEXT_1;
10983   int font_height = getFontHeight(font_nr);
10984   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
10985   int yoffset = (tilesize - font_height) / 2;
10986   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
10987   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
10988   int i;
10989
10990   // display counter to choose number of element content areas
10991   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
10992
10993   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
10994   {
10995     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
10996
10997     if (i < level.num_yamyam_contents)
10998     {
10999       MapDrawingArea(id);
11000     }
11001     else
11002     {
11003       UnmapDrawingArea(id);
11004
11005       // delete content areas in case of reducing number of them
11006       RemoveElementContentArea(id, font_height);
11007     }
11008   }
11009
11010   DrawText(x, y + 0 * tilesize, "content", font_nr);
11011   DrawText(x, y + 1 * tilesize, "when",    font_nr);
11012   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
11013 }
11014
11015 static void DrawMagicBallContentAreas(void)
11016 {
11017   int font_nr = FONT_TEXT_1;
11018   int font_height = getFontHeight(font_nr);
11019   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
11020   int yoffset = (tilesize - font_height) / 2;
11021   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
11022   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
11023   int i;
11024
11025   // display counter to choose number of element content areas
11026   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
11027
11028   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
11029   {
11030     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
11031
11032     if (i < level.num_ball_contents)
11033     {
11034       MapDrawingArea(id);
11035     }
11036     else
11037     {
11038       UnmapDrawingArea(id);
11039
11040       // delete content areas in case of reducing number of them
11041       RemoveElementContentArea(id, font_height);
11042     }
11043   }
11044
11045   DrawText(x, y + 0 * tilesize, "generated", font_nr);
11046   DrawText(x, y + 1 * tilesize, "when",      font_nr);
11047   DrawText(x, y + 2 * tilesize, "active",    font_nr);
11048 }
11049
11050 static void DrawAndroidElementArea(void)
11051 {
11052   int id = ED_DRAWING_ID_ANDROID_CONTENT;
11053   int num_elements = level.num_android_clone_elements;
11054   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11055   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11056   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11057   int xsize = MAX_ANDROID_ELEMENTS;
11058   int ysize = 1;
11059
11060   // display counter to choose number of element areas
11061   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
11062
11063   if (drawingarea_info[id].text_left != NULL)
11064     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11065
11066   UnmapDrawingArea(id);
11067
11068   ModifyEditorDrawingArea(id, num_elements, 1);
11069
11070   // delete content areas in case of reducing number of them
11071   DrawBackground(sx, sy,
11072                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11073                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11074
11075   MapDrawingArea(id);
11076 }
11077
11078 static void DrawGroupElementArea(void)
11079 {
11080   int id = ED_DRAWING_ID_GROUP_CONTENT;
11081   int num_elements = group_element_info.num_elements;
11082   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11083   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11084   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11085   int xsize = MAX_ELEMENTS_IN_GROUP;
11086   int ysize = 1;
11087
11088   if (drawingarea_info[id].text_left != NULL)
11089     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11090
11091   UnmapDrawingArea(id);
11092
11093   ModifyEditorDrawingArea(id, num_elements, 1);
11094
11095   // delete content areas in case of reducing number of them
11096   DrawBackground(sx, sy,
11097                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11098                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11099
11100   MapDrawingArea(id);
11101 }
11102
11103 static void DrawPlayerInitialInventoryArea(int element)
11104 {
11105   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11106   int player_nr = GET_PLAYER_NR(element);
11107   int num_elements = level.initial_inventory_size[player_nr];
11108   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11109   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11110   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11111   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11112   int ysize = 1;
11113
11114   // determine horizontal position to the right of specified gadget
11115   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11116     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11117           ED_DRAWINGAREA_TEXT_DISTANCE);
11118
11119   // determine horizontal offset for leading text
11120   if (drawingarea_info[id].text_left != NULL)
11121     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11122
11123   UnmapDrawingArea(id);
11124
11125   ModifyEditorDrawingArea(id, num_elements, 1);
11126
11127   // delete content areas in case of reducing number of them
11128   DrawBackground(sx, sy,
11129                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11130                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11131
11132   MapDrawingArea(id);
11133 }
11134
11135 static void DrawMMBallContentArea(void)
11136 {
11137   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11138   int num_elements = level.num_mm_ball_contents;
11139   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11140   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11141   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11142   int xsize = MAX_MM_BALL_CONTENTS;
11143   int ysize = 1;
11144
11145   if (drawingarea_info[id].text_left != NULL)
11146     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11147
11148   UnmapDrawingArea(id);
11149
11150   ModifyEditorDrawingArea(id, num_elements, 1);
11151
11152   // delete content areas in case of reducing number of them
11153   DrawBackground(sx, sy,
11154                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11155                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11156
11157   MapDrawingArea(id);
11158 }
11159
11160 static void DrawEnvelopeTextArea(int envelope_nr)
11161 {
11162   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11163   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11164
11165   UnmapGadget(gi);
11166
11167   DrawBackground(gi->x, gi->y,
11168                  gi->textarea.crop_width, gi->textarea.crop_height);
11169
11170   if (envelope_nr != -1)
11171     textarea_info[id].value = level.envelope[envelope_nr].text;
11172
11173   ModifyGadget(gi, GDI_AREA_SIZE,
11174                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11175                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11176                GDI_END);
11177
11178   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11179 }
11180
11181 static void DrawPropertiesInfo(void)
11182 {
11183   static struct
11184   {
11185     int value;
11186     char *text;
11187   }
11188   properties[] =
11189   {
11190     // configurable properties
11191
11192     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11193     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11194     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11195     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11196     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11197     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11198     { EP_PROTECTED,             "- player is protected by it"           },
11199
11200     { EP_DIGGABLE,              "- can be digged away"                  },
11201     { EP_COLLECTIBLE,           "- can be collected"                    },
11202     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11203     { EP_THROWABLE,             "- can be thrown after collecting"      },
11204     { EP_PUSHABLE,              "- can be pushed"                       },
11205
11206     { EP_CAN_FALL,              "- can fall"                            },
11207     { EP_CAN_MOVE,              "- can move"                            },
11208
11209     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11210 #if 0
11211     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11212 #endif
11213     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11214
11215     { EP_SLIPPERY,              "- slippery for falling elements"       },
11216     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11217
11218     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11219     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11220     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11221     { EP_DONT_TOUCH,            "- deadly when touching"                },
11222
11223     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11224
11225     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11226     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11227     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11228
11229     { EP_CAN_CHANGE,            "- can change to other element"         },
11230
11231     // pre-defined properties
11232     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11233     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11234     { EP_SWITCHABLE,            "- can be switched"                     },
11235 #if 0
11236     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11237 #endif
11238
11239     { -1,                       NULL                                    }
11240   };
11241   char *filename = getElementDescriptionFilename(properties_element);
11242   char *num_elements_text = "In this level: ";
11243   char *num_similar_text = "Similar tiles: ";
11244   char *properties_text = "Standard properties: ";
11245   char *description_text = "Description:";
11246   char *no_description_text = "No description available.";
11247   char *none_text = "None";
11248   float percentage;
11249   int num_elements_in_level = 0;
11250   int num_similar_in_level = 0;
11251   int num_hires_tiles_in_level = 0;
11252   int num_standard_properties = 0;
11253   int font1_nr = FONT_TEXT_1;
11254   int font2_nr = FONT_TEXT_2;
11255   int font1_width = getFontWidth(font1_nr);
11256   int font1_height = getFontHeight(font1_nr);
11257   int font2_height = getFontHeight(font2_nr);
11258   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11259   int font2_yoffset = (font1_height - font2_height) / 2;
11260   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11261   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11262   int properties_text_len = strlen(properties_text) * font1_width;
11263   int xpos = ED_ELEMENT_SETTINGS_X(0);
11264   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11265   int i, x, y;
11266
11267   if (setup.editor.show_element_token)
11268   {
11269     int font3_nr = FONT_TEXT_3;
11270     int font3_height = getFontHeight(font3_nr);
11271
11272     DrawTextF(xpos, ypos, font3_nr,
11273               "[%s]", element_info[properties_element].token_name);
11274
11275     ypos += 2 * font3_height;
11276   }
11277
11278   // ----- print number of elements / percentage of this element in level
11279
11280   for (y = 0; y < lev_fieldy; y++)
11281   {
11282     for (x = 0; x < lev_fieldx; x++)
11283     {
11284       if (Tile[x][y] == properties_element)
11285       {
11286         num_elements_in_level++;
11287       }
11288       else if (IS_MM_WALL(Tile[x][y]) &&
11289                map_mm_wall_element(Tile[x][y]) == properties_element)
11290       {
11291         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11292       }
11293     }
11294   }
11295
11296   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11297
11298   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11299
11300   if (num_hires_tiles_in_level > 0)
11301     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11302               "%d wall tiles", num_hires_tiles_in_level);
11303   else if (num_elements_in_level > 0)
11304     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11305               "%d (%.2f %%)", num_elements_in_level, percentage);
11306   else
11307     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11308               none_text);
11309
11310   // ----- print number of similar elements / percentage of them in level
11311
11312   for (y = 0; y < lev_fieldy; y++)
11313   {
11314     for (x = 0; x < lev_fieldx; x++)
11315     {
11316       if (strEqual(element_info[Tile[x][y]].class_name,
11317                    element_info[properties_element].class_name))
11318       {
11319         num_similar_in_level++;
11320       }
11321     }
11322   }
11323
11324   if (num_similar_in_level != num_elements_in_level)
11325   {
11326     ypos += 1 * MAX(font1_height, font2_height);
11327
11328     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11329
11330     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11331
11332     if (num_similar_in_level > 0)
11333       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11334                 "%d (%.2f %%)", num_similar_in_level, percentage);
11335     else
11336       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11337                 none_text);
11338   }
11339
11340   ypos += 2 * MAX(font1_height, font2_height);
11341
11342   // ----- print standard properties of this element
11343
11344   DrawTextS(xpos, ypos, font1_nr, properties_text);
11345
11346   ypos += line1_height;
11347
11348   for (i = 0; properties[i].value != -1; i++)
11349   {
11350     if (!HAS_PROPERTY(properties_element, properties[i].value))
11351       continue;
11352
11353     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11354
11355     ypos += font2_height;
11356
11357     num_standard_properties++;
11358   }
11359
11360   if (num_standard_properties == 0)
11361   {
11362     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11363               font2_nr, none_text);
11364
11365     ypos -= (line1_height - font1_height);
11366   }
11367
11368   ypos += MAX(font1_height, font2_height);
11369
11370   // ----- print special description of this element
11371
11372   PrintInfoText(description_text, font1_nr, xpos, ypos);
11373
11374   ypos += line1_height;
11375
11376   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11377     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11378 }
11379
11380 #define TEXT_COLLECTING                 "Score for collecting"
11381 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11382 #define TEXT_SMASHING                   "Score for smashing"
11383 #define TEXT_SLURPING                   "Score for slurping robot"
11384 #define TEXT_CRACKING                   "Score for cracking"
11385 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11386 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11387 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11388 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11389 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11390 #define TEXT_DURATION                   "Duration when activated"
11391 #define TEXT_DELAY_ON                   "Delay before activating"
11392 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11393 #define TEXT_DELAY_CHANGING             "Delay before changing"
11394 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11395 #define TEXT_DELAY_MOVING               "Delay before moving"
11396 #define TEXT_BALL_DELAY                 "Element generation delay"
11397 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11398 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11399 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11400 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11401 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11402 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11403 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11404 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11405 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11406 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11407 #define TEXT_RANDOM_SEED                "slime random number seed"
11408 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11409 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11410 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11411 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11412 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11413 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11414 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11415 #define TEXT_AUTO_TURN_DELAY            "Creatures auto turn delay"
11416 #define TEXT_GRAVITY_DELAY              "Gravity switch change delay"
11417
11418 static struct
11419 {
11420   int element;
11421   int *value;
11422   char *text;
11423   int min_value;
11424   int max_value;
11425 } elements_with_counter[] =
11426 {
11427   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11428   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11429   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11430   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11431   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11432   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11433   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11434   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11435   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11436   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11437   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11438   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11439   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11440   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11441   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11442   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11443   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11444   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11445   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11446   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11447   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11448   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11449   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11450   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11451   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11452   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11453   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11454   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11455   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11456   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11457   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11458   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11459   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11460   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11461   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11462   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11463   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11464   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11465   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11466   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11467   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11468   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11469   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11470   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11471   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11472   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11473   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11474   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11475   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11476   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11477   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11478   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11479   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11480   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11481   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11482   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11483   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11484   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11485   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11486   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11487   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11488   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11489   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11490   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11491   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11492   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11493   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11494   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11495   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11496   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11497   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11498   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11499   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11500   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11501   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11502   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11503   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11504   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11505   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11506   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11507   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11508   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11509   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11510                                 0, 100                                                          },
11511   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11512                                 0, 100                                                          },
11513   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11514   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11515   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11516                                 0, 100                                                          },
11517   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11518                                 0, 100                                                          },
11519   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11520   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11521   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11522   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11523   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11524   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11525   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11526   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11527   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11528   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11529   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11530                                 -100, 100                                                       },
11531   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11532                                 0, 100                                                          },
11533   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11534                                 0, 100                                                          },
11535   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11536                                 0, 255                                                          },
11537   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11538                                 -1, 65535                                                       },
11539   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11540                                 0, 100                                                          },
11541   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11542                                 0, 3                                                            },
11543   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11544                                 0, 3                                                            },
11545   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11546                                 0, 3                                                            },
11547   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11548                                 0, 3                                                            },
11549   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11550                                 0, 3                                                            },
11551   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11552                                 0, 100                                                          },
11553   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11554                                 1, 100                                                          },
11555   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11556                                 1, 200                                                          },
11557   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11558                                 0, 50                                                           },
11559   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11560                                 0, 50                                                           },
11561   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11562                                 0, 10                                                           },
11563   { EL_BD_CREATURE_SWITCH,      &level.bd_creatures_auto_turn_delay,    TEXT_AUTO_TURN_DELAY    },
11564   { EL_BD_GRAVITY_SWITCH,       &level.bd_gravity_switch_delay,         TEXT_GRAVITY_DELAY,
11565                                 1, 60                                                           },
11566   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11567   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11568   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11569   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11570   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11571   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11572   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11573   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11574   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11575   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11576   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11577   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11578   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11579   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11580   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11581   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11582   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11583   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11584   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11585   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11586   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11587   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11588   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11589   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11590   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11591
11592   { -1,                         NULL,                                   NULL                    }
11593 };
11594
11595 static boolean checkPropertiesConfig(int element)
11596 {
11597   int i;
11598
11599   // special case: empty space customization only available in R'n'D game engine
11600   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11601     return FALSE;
11602
11603   // special case: BD style rock customization only available in BD game engine
11604   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11605     return FALSE;
11606
11607   if (IS_GEM(element) ||
11608       IS_CUSTOM_ELEMENT(element) ||
11609       IS_GROUP_ELEMENT(element) ||
11610       IS_EMPTY_ELEMENT(element) ||
11611       IS_BALLOON_ELEMENT(element) ||
11612       IS_ENVELOPE(element) ||
11613       IS_MM_ENVELOPE(element) ||
11614       IS_MM_MCDUFFIN(element) ||
11615       IS_DF_LASER(element) ||
11616       IS_PLAYER_ELEMENT(element) ||
11617       IS_BD_PLAYER_ELEMENT(element) ||
11618       IS_BD_EXPANDABLE_WALL(properties_element) ||
11619       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11620       IS_BD_CONVEYOR_BELT(properties_element) ||
11621       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11622       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11623       HAS_EDITOR_CONTENT(element) ||
11624       CAN_GROW(element) ||
11625       COULD_MOVE_INTO_ACID(element) ||
11626       MAYBE_DONT_COLLIDE_WITH(element) ||
11627       element == EL_BD_SAND ||
11628       element == EL_BD_ROCK ||
11629       element == EL_BD_MEGA_ROCK ||
11630       element == EL_BD_SWEET ||
11631       element == EL_BD_VOODOO_DOLL ||
11632       element == EL_BD_WATER ||
11633       element == EL_BD_GRAVITY_SWITCH)
11634   {
11635     return TRUE;
11636   }
11637   else
11638   {
11639     for (i = 0; elements_with_counter[i].element != -1; i++)
11640       if (elements_with_counter[i].element == element)
11641         return TRUE;
11642   }
11643
11644   return FALSE;
11645 }
11646
11647 static void SetAutomaticNumberOfGemsNeeded(void)
11648 {
11649   int x, y;
11650
11651   if (!level.auto_count_gems)
11652     return;
11653
11654   level.gems_needed = 0;
11655
11656   for (x = 0; x < lev_fieldx; x++)
11657   {
11658     for (y = 0; y < lev_fieldy; y++)
11659     {
11660       int element = Tile[x][y];
11661
11662       switch (element)
11663       {
11664         case EL_EMERALD:
11665         case EL_EMERALD_YELLOW:
11666         case EL_EMERALD_RED:
11667         case EL_EMERALD_PURPLE:
11668         case EL_BD_DIAMOND:
11669         case EL_WALL_EMERALD:
11670         case EL_WALL_EMERALD_YELLOW:
11671         case EL_WALL_EMERALD_RED:
11672         case EL_WALL_EMERALD_PURPLE:
11673         case EL_WALL_BD_DIAMOND:
11674         case EL_NUT:
11675         case EL_SP_INFOTRON:
11676         case EL_MM_KETTLE:
11677         case EL_DF_CELL:
11678           level.gems_needed++;
11679           break;
11680
11681         case EL_DIAMOND:
11682         case EL_WALL_DIAMOND:
11683           level.gems_needed += 3;
11684           break;
11685
11686         case EL_PEARL:
11687         case EL_WALL_PEARL:
11688           level.gems_needed += 5;
11689           break;
11690
11691         case EL_CRYSTAL:
11692         case EL_WALL_CRYSTAL:
11693           level.gems_needed += 8;
11694           break;
11695
11696         default:
11697           break;
11698       }
11699     }
11700   }
11701
11702   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11703 }
11704
11705 static void DrawPropertiesConfig(void)
11706 {
11707   boolean draw_footer_line = FALSE;
11708   int max_num_element_counters = 4;
11709   int num_element_counters = 0;
11710   int i;
11711
11712   if (!checkPropertiesConfig(properties_element))
11713   {
11714     int xpos = ED_ELEMENT_SETTINGS_X(0);
11715     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11716
11717     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11718
11719     return;
11720   }
11721
11722   // check if there are elements where a value can be chosen for
11723   for (i = 0; elements_with_counter[i].element != -1; i++)
11724   {
11725     if (elements_with_counter[i].element != properties_element)
11726       continue;
11727
11728     // special case: score for extra diamonds only available in BD game engine
11729     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11730         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11731         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11732       continue;
11733
11734     // special case: some amoeba counters only available in BD game engine
11735     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11736         elements_with_counter[i].value != &level.amoeba_speed &&
11737         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11738       continue;
11739
11740     // special case: some amoeba counters only available in R'n'D game engine
11741     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11742         elements_with_counter[i].value == &level.amoeba_speed &&
11743         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11744       continue;
11745
11746     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11747
11748     counterbutton_info[counter_id].y =
11749       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11750                                (CAN_GROW(properties_element)                ? 1 : 0) +
11751                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11752                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11753                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11754                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11755                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11756                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11757                                (properties_element == EL_BD_CREATURE_SWITCH ? 2 : 0) +
11758                                (properties_element == EL_BD_GRAVITY_SWITCH  ? 2 : 0) +
11759                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11760                                num_element_counters);
11761
11762     // special case: set magic wall counter for BD game engine separately
11763     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11764       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11765
11766     // special case: set amoeba counters for BD game engine separately
11767     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11768         (properties_element == EL_BD_AMOEBA_2))
11769       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11770
11771     // special case: set position for delay counter for reappearing hammered walls
11772     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11773       counterbutton_info[counter_id].y += 1;
11774
11775     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11776     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11777     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11778     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11779
11780     // default: counter values between 0 and 999
11781     if (counterbutton_info[counter_id].max_value == 0)
11782       counterbutton_info[counter_id].max_value = 999;
11783
11784     MapCounterButtons(counter_id);
11785
11786     num_element_counters++;
11787     if (num_element_counters >= max_num_element_counters)
11788       break;
11789   }
11790
11791   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11792   {
11793     // draw stickybutton gadget
11794     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11795
11796     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11797     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11798
11799     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11800     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11801     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11802     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11803     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11804     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11805     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11806   }
11807
11808   if (HAS_EDITOR_CONTENT(properties_element))
11809   {
11810     // draw stickybutton gadget
11811     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11812
11813     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11814     {
11815       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11816       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11817
11818       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11819       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11820     }
11821     else if (properties_element == EL_BD_AMOEBA_2)
11822     {
11823       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11824       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11825       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11826
11827       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11828       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11829       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11830       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11831     }
11832     else if (IS_AMOEBOID(properties_element))
11833       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11834     else if (properties_element == EL_BD_ACID)
11835     {
11836       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11837       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11838     }
11839     else if (IS_BD_BITER(properties_element))
11840     {
11841       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11842     }
11843     else if (properties_element == EL_BD_BLADDER)
11844     {
11845       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11846     }
11847     else if (properties_element == EL_YAMYAM ||
11848              properties_element == EL_YAMYAM_LEFT ||
11849              properties_element == EL_YAMYAM_RIGHT ||
11850              properties_element == EL_YAMYAM_UP ||
11851              properties_element == EL_YAMYAM_DOWN)
11852       DrawYamYamContentAreas();
11853     else if (properties_element == EL_EMC_MAGIC_BALL)
11854     {
11855       DrawMagicBallContentAreas();
11856
11857       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
11858       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
11859     }
11860     else if (properties_element == EL_EMC_ANDROID)
11861       DrawAndroidElementArea();
11862     else if (properties_element == EL_MM_GRAY_BALL)
11863     {
11864       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
11865       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
11866       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
11867       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
11868
11869       DrawMMBallContentArea();
11870     }
11871   }
11872
11873   if (IS_PLAYER_ELEMENT(properties_element))
11874   {
11875     int player_nr = GET_PLAYER_NR(properties_element);
11876
11877     // these properties can be set for every player individually
11878
11879     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
11880     {
11881       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
11882         &level.start_element[player_nr];
11883       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
11884         &level.artwork_element[player_nr];
11885       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
11886         &level.explosion_element[player_nr];
11887
11888       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
11889         &level.use_start_element[player_nr];
11890       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
11891         &level.use_artwork_element[player_nr];
11892       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
11893         &level.use_explosion_element[player_nr];
11894       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
11895         &level.initial_player_gravity[player_nr];
11896
11897       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
11898         &level.initial_player_stepsize[player_nr];
11899
11900       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
11901       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
11902                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
11903                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
11904       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
11905       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
11906       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
11907       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
11908       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
11909       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
11910       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
11911       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
11912       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
11913       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
11914       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
11915
11916       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
11917       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
11918       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
11919
11920       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
11921     }
11922     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
11923     {
11924       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
11925         &level.initial_inventory_content[player_nr][0];
11926
11927       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
11928         &level.initial_inventory_size[player_nr];
11929
11930       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
11931         &level.use_initial_inventory[player_nr];
11932
11933       // draw checkbutton gadgets
11934       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
11935       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
11936       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
11937
11938       // draw counter gadgets
11939       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
11940
11941       // draw drawing area gadgets
11942       DrawPlayerInitialInventoryArea(properties_element);
11943     }
11944   }
11945
11946   if (IS_BD_PLAYER_ELEMENT(properties_element))
11947   {
11948     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
11949       ED_ELEMENT_SETTINGS_YPOS(2);
11950     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11951       ED_ELEMENT_SETTINGS_YPOS(3);
11952     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
11953       ED_ELEMENT_SETTINGS_YPOS(4);
11954
11955     // draw checkbutton gadgets
11956     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
11957     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
11958     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
11959
11960     // draw counter gadgets
11961     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
11962     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
11963
11964     // draw drawing area gadgets
11965     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
11966   }
11967
11968   if (properties_element == EL_BD_SAND)
11969   {
11970     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
11971   }
11972
11973   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11974   {
11975     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
11976       ED_ELEMENT_SETTINGS_YPOS(0);
11977     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11978       ED_ELEMENT_SETTINGS_YPOS(1);
11979
11980     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
11981     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
11982
11983     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
11984     MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
11985   }
11986
11987   if (properties_element == EL_BD_DIAMOND && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11988   {
11989     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
11990     MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
11991   }
11992
11993   if (properties_element == EL_BD_MEGA_ROCK ||
11994       properties_element == EL_BD_SWEET)
11995   {
11996     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11997       ED_ELEMENT_SETTINGS_YPOS(0);
11998     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
11999       ED_ELEMENT_SETTINGS_YPOS(1);
12000
12001     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
12002     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
12003   }
12004
12005   if (properties_element == EL_BD_VOODOO_DOLL)
12006   {
12007     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
12008     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
12009     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
12010     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
12011   }
12012
12013   if (properties_element == EL_BD_SLIME)
12014   {
12015     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
12016
12017     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
12018     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
12019     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
12020     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
12021     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
12022     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
12023   }
12024
12025   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
12026       IS_BD_EXPANDABLE_STEELWALL(properties_element))
12027   {
12028     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
12029
12030     if (IS_BD_EXPANDABLE_WALL(properties_element))
12031       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
12032   }
12033
12034   if (properties_element == EL_BD_REPLICATOR)
12035   {
12036     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
12037   }
12038
12039   if (IS_BD_CONVEYOR_BELT(properties_element) ||
12040       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
12041   {
12042     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
12043     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
12044   }
12045
12046   if (properties_element == EL_BD_WATER)
12047   {
12048     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
12049   }
12050
12051   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
12052   {
12053     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
12054   }
12055
12056   if (properties_element == EL_BD_CREATURE_SWITCH)
12057   {
12058     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
12059     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
12060   }
12061
12062   if (properties_element == EL_BD_GRAVITY_SWITCH)
12063   {
12064     MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
12065
12066     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
12067     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
12068   }
12069
12070   if (properties_element == EL_BD_NUT)
12071   {
12072     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
12073   }
12074
12075   // special case: slippery walls option for gems only available in R'n'D game engine
12076   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
12077     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
12078
12079   if (properties_element == EL_EM_DYNAMITE)
12080     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
12081
12082   if (COULD_MOVE_INTO_ACID(properties_element) &&
12083       !IS_PLAYER_ELEMENT(properties_element) &&
12084       (!IS_CUSTOM_ELEMENT(properties_element) ||
12085        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
12086   {
12087     // set position for checkbutton for "can move into acid"
12088     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
12089       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
12090     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
12091       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
12092                                IS_BALLOON_ELEMENT(properties_element) ||
12093                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12094
12095     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
12096   }
12097
12098   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
12099     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
12100
12101   if (properties_element == EL_SPRING ||
12102       properties_element == EL_SPRING_LEFT ||
12103       properties_element == EL_SPRING_RIGHT)
12104     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
12105
12106   if (properties_element == EL_TIME_ORB_FULL)
12107     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
12108
12109   if (properties_element == EL_GAME_OF_LIFE ||
12110       properties_element == EL_BIOMAZE)
12111     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
12112
12113   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
12114   {
12115     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
12116       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
12117
12118     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
12119   }
12120
12121   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12122     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12123
12124   if (properties_element == EL_SOKOBAN_OBJECT)
12125     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12126
12127   if (properties_element == EL_SOKOBAN_OBJECT ||
12128       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12129       properties_element == EL_SOKOBAN_FIELD_FULL)
12130   {
12131     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12132       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12133                                0 : 1);
12134
12135     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12136   }
12137
12138   if (IS_BALLOON_ELEMENT(properties_element))
12139     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12140
12141   if (IS_ENVELOPE(properties_element) ||
12142       IS_MM_ENVELOPE(properties_element))
12143   {
12144     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12145     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12146     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12147     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12148     int envelope_nr = ENVELOPE_NR(properties_element);
12149
12150     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12151     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12152
12153     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12154     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12155
12156     // display counter to choose size of envelope text area
12157     MapCounterButtons(counter1_id);
12158     MapCounterButtons(counter2_id);
12159
12160     // display checkbuttons to choose auto-wrap and alignment properties
12161     MapCheckbuttonGadget(button1_id);
12162     MapCheckbuttonGadget(button2_id);
12163
12164     DrawEnvelopeTextArea(envelope_nr);
12165   }
12166
12167   if (IS_MM_MCDUFFIN(properties_element))
12168   {
12169     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12170     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12171     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12172   }
12173
12174   if (IS_DF_LASER(properties_element))
12175   {
12176     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12177     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12178     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12179   }
12180
12181   if (IS_CUSTOM_ELEMENT(properties_element))
12182   {
12183     // draw stickybutton gadget
12184     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12185
12186     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12187     {
12188       // draw checkbutton gadgets
12189       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12190            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12191         MapCheckbuttonGadget(i);
12192
12193       // draw counter gadgets
12194       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12195            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12196         MapCounterButtons(i);
12197
12198       // draw selectbox gadgets
12199       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12200            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12201         MapSelectboxGadget(i);
12202
12203       // draw textbutton gadgets
12204       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12205
12206       // draw text input gadgets
12207       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12208
12209       // draw drawing area gadgets
12210       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12211
12212       draw_footer_line = TRUE;
12213     }
12214     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12215     {
12216       // draw checkbutton gadgets
12217       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12218            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12219         MapCheckbuttonGadget(i);
12220
12221       // draw counter gadgets
12222       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12223            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12224         MapCounterButtons(i);
12225
12226       // draw selectbox gadgets
12227       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12228            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12229         MapSelectboxGadget(i);
12230
12231       // draw drawing area gadgets
12232       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12233       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12234       DrawCustomContentArea();
12235     }
12236   }
12237   else if (IS_GROUP_ELEMENT(properties_element))
12238   {
12239     // draw stickybutton gadget
12240     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12241
12242     // draw checkbutton gadgets
12243     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12244     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12245
12246     // draw counter gadgets
12247     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12248
12249     // draw selectbox gadgets
12250     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12251
12252     // draw textbutton gadgets
12253     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12254
12255     // draw drawing area gadgets
12256     DrawGroupElementArea();
12257
12258     // draw text input gadgets
12259     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12260
12261     // draw drawing area gadgets
12262     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12263
12264     draw_footer_line = TRUE;
12265   }
12266   else if (IS_EMPTY_ELEMENT(properties_element))
12267   {
12268     // draw stickybutton gadget
12269     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12270
12271     // draw checkbutton gadgets
12272     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12273     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12274
12275     // draw textbutton gadgets
12276     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12277
12278     // draw drawing area gadgets
12279     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12280
12281     draw_footer_line = TRUE;
12282   }
12283
12284   // draw little footer border line above CE/GE use/save template gadgets
12285   if (draw_footer_line)
12286   {
12287     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12288     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12289     int gd_x = gd->x + gd_gi1->border.width / 2;
12290     int gd_y = gd->y + gd_gi1->height - 1;
12291     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12292
12293     if (tab_color != BLACK_PIXEL)               // black => transparent
12294       FillRectangle(drawto,
12295                     SX + ED_ELEMENT_SETTINGS_X(0),
12296                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12297                     ED_TAB_BAR_HEIGHT,
12298                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12299   }
12300 }
12301
12302 static void DrawPropertiesChangeDrawingAreas(void)
12303 {
12304   if (IS_CUSTOM_ELEMENT(properties_element))
12305   {
12306     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12307     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12308     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12309
12310     DrawCustomChangeContentArea();
12311   }
12312
12313   redraw_mask |= REDRAW_FIELD;
12314 }
12315
12316 static void DrawPropertiesChange(void)
12317 {
12318   int i;
12319
12320   // needed to initially set selectbox options for special action options
12321   setSelectboxSpecialActionOptions();
12322
12323   // draw stickybutton gadget
12324   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12325
12326   // draw checkbutton gadgets
12327   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12328        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12329     MapCheckbuttonGadget(i);
12330
12331   // draw counter gadgets
12332   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12333        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12334     MapCounterButtons(i);
12335
12336   // draw selectbox gadgets
12337   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12338        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12339     MapSelectboxGadget(i);
12340
12341   // draw textbutton gadgets
12342   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12343        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12344     MapTextbuttonGadget(i);
12345
12346   // draw graphicbutton gadgets
12347   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12348        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12349     MapGraphicbuttonGadget(i);
12350
12351   // draw drawing area gadgets
12352   DrawPropertiesChangeDrawingAreas();
12353 }
12354
12355 static void DrawEditorElementAnimation(int x, int y)
12356 {
12357   int graphic;
12358   int frame;
12359
12360   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12361
12362   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12363 }
12364
12365 static void DrawEditorElementName(int x, int y, int font_nr)
12366 {
12367   char *element_name = getElementInfoText(properties_element);
12368   int font_width = getFontWidth(font_nr);
12369   int font_height = getFontHeight(font_nr);
12370   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12371   int max_chars_per_line = max_text_width / font_width;
12372
12373   if (strlen(element_name) <= max_chars_per_line)
12374     DrawTextS(x, y, font_nr, element_name);
12375   else
12376   {
12377     char buffer[max_chars_per_line + 1];
12378     int next_pos = max_chars_per_line;
12379
12380     strncpy(buffer, element_name, max_chars_per_line);
12381     buffer[max_chars_per_line] = '\0';
12382
12383     if (element_name[max_chars_per_line] == ' ')
12384       next_pos++;
12385     else
12386     {
12387       int i;
12388
12389       for (i = max_chars_per_line - 1; i >= 0; i--)
12390         if (buffer[i] == ' ')
12391           break;
12392
12393       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12394       {
12395         buffer[i] = '\0';
12396         next_pos = i + 1;
12397       }
12398     }
12399
12400     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12401
12402     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12403     buffer[max_chars_per_line] = '\0';
12404
12405     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12406   }
12407 }
12408
12409 static void DrawPropertiesWindow(void)
12410 {
12411   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12412   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12413   int border_size = gd->border_size;
12414   int font_nr = FONT_TEXT_1;
12415   int font_height = getFontHeight(font_nr);
12416   int xoffset = TILEX + element_border + 3 * border_size;
12417   int yoffset = (TILEY - font_height) / 2;
12418   int x1 = editor.settings.element_graphic.x + element_border;
12419   int y1 = editor.settings.element_graphic.y + element_border;
12420   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12421             editor.settings.element_name.x);
12422   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12423             editor.settings.element_name.y);
12424   char *text = "Element Settings";
12425   int font2_nr = FONT_TITLE_1;
12426   struct MenuPosInfo *pos = &editor.settings.headline;
12427   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12428   int sy = SY + pos->y;
12429
12430   stick_element_properties_window = FALSE;
12431
12432   // make sure that previous properties edit mode exists for this element
12433   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12434       !IS_CUSTOM_ELEMENT(properties_element))
12435     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12436
12437   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12438       !IS_PLAYER_ELEMENT(properties_element) &&
12439       !IS_CUSTOM_ELEMENT(properties_element))
12440     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12441
12442   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12443       (IS_PLAYER_ELEMENT(properties_element) ||
12444        IS_CUSTOM_ELEMENT(properties_element)))
12445     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12446
12447   CopyElementPropertiesToEditor(properties_element);
12448
12449   UnmapLevelEditorFieldGadgets();
12450   UnmapLevelEditorToolboxDrawingGadgets();
12451   UnmapLevelEditorToolboxCustomGadgets();
12452
12453   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12454
12455   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12456   ClearField();
12457
12458   DrawText(sx, sy, text, font2_nr);
12459
12460   FrameCounter = 0;     // restart animation frame counter
12461
12462   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12463   DrawEditorElementAnimation(SX + x1, SY + y1);
12464   DrawEditorElementName(x2, y2, font_nr);
12465
12466   DrawPropertiesTabulatorGadgets();
12467
12468   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12469     DrawPropertiesInfo();
12470   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12471     DrawPropertiesChange();
12472   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12473     DrawPropertiesConfig();
12474 }
12475
12476 static void DrawPaletteWindow(void)
12477 {
12478   int i;
12479
12480   UnmapLevelEditorFieldGadgets();
12481
12482   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12483   ClearField();
12484
12485   // map buttons to select elements
12486   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12487     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12488   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12489   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12490   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12491 }
12492
12493 static void UpdateCustomElementGraphicGadgets(void)
12494 {
12495   int i;
12496
12497   InitElementPropertiesGfxElement();
12498
12499   ModifyEditorElementList();
12500   RedrawDrawingElements();
12501
12502   // force redraw of all mapped drawing area gadgets
12503   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12504   {
12505     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12506
12507     if (gi->mapped)
12508       MapDrawingArea(i);
12509   }
12510 }
12511
12512 static int getOpenDirectionFromTube(int element)
12513 {
12514   switch (element)
12515   {
12516     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12517     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12518     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12519     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12520     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12521     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12522     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12523     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12524     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12525     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12526     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12527   }
12528
12529   return MV_NONE;
12530 }
12531
12532 static int getTubeFromOpenDirection(int direction)
12533 {
12534   switch (direction)
12535   {
12536     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12537     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12538     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12539     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12540     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12541     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12542     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12543     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12544     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12545     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12546     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12547
12548     // if only one direction, fall back to simple tube with that direction
12549     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12550     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12551     case (MV_UP):                       return EL_TUBE_VERTICAL;
12552     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12553   }
12554
12555   return EL_EMPTY;
12556 }
12557
12558 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12559 {
12560   int element_new = getTubeFromOpenDirection(direction);
12561
12562   return (element_new != EL_EMPTY ? element_new : element_old);
12563 }
12564
12565 static int getOpenDirectionFromBelt(int element)
12566 {
12567   int belt_dir = getBeltDirFromBeltElement(element);
12568
12569   return (belt_dir == MV_LEFT ? MV_RIGHT :
12570           belt_dir == MV_RIGHT ? MV_LEFT :
12571           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12572 }
12573
12574 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12575 {
12576   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12577                   direction == MV_RIGHT ? MV_LEFT :
12578                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12579
12580   if (direction == MV_NONE)
12581     return EL_EMPTY;
12582
12583   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12584 }
12585
12586 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12587                                                  int element_old)
12588 {
12589   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12590
12591   return (element_new != EL_EMPTY ? element_new : element_old);
12592 }
12593
12594 static int getOpenDirectionFromPool(int element)
12595 {
12596   switch (element)
12597   {
12598     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12599     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12600     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12601     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12602     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12603     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12604   }
12605
12606   return MV_NONE;
12607 }
12608
12609 static int getPoolFromOpenDirection(int direction)
12610 {
12611   switch (direction)
12612   {
12613     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12614     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12615     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12616     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12617     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12618     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12619   }
12620
12621   return EL_EMPTY;
12622 }
12623
12624 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12625 {
12626   int element = getPoolFromOpenDirection(direction);
12627   int help_direction = getOpenDirectionFromPool(help_element);
12628
12629   if (element == EL_EMPTY)
12630   {
12631     int help_direction_vertical = help_direction & MV_VERTICAL;
12632
12633     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12634   }
12635
12636   if (element == EL_EMPTY)
12637   {
12638     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12639
12640     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12641   }
12642
12643   return element;
12644 }
12645
12646 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12647 {
12648   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12649
12650   return (element_new != EL_EMPTY ? element_new : element_old);
12651 }
12652
12653 static int getOpenDirectionFromPillar(int element)
12654 {
12655   switch (element)
12656   {
12657     case EL_EMC_WALL_1:                 return (MV_DOWN);
12658     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12659     case EL_EMC_WALL_3:                 return (MV_UP);
12660   }
12661
12662   return MV_NONE;
12663 }
12664
12665 static int getPillarFromOpenDirection(int direction)
12666 {
12667   switch (direction)
12668   {
12669     case (MV_DOWN):                     return EL_EMC_WALL_1;
12670     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12671     case (MV_UP):                       return EL_EMC_WALL_3;
12672   }
12673
12674   return EL_EMPTY;
12675 }
12676
12677 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12678 {
12679   int element_new = getPillarFromOpenDirection(direction);
12680
12681   return (element_new != EL_EMPTY ? element_new : element_old);
12682 }
12683
12684 static int getOpenDirectionFromSteel2(int element)
12685 {
12686   switch (element)
12687   {
12688     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12689     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12690     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12691     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12692     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12693     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12694     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12695     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12696   }
12697
12698   return MV_NONE;
12699 }
12700
12701 static int getSteel2FromOpenDirection(int direction)
12702 {
12703   switch (direction)
12704   {
12705     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12706     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12707     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12708     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12709     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12710     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12711     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12712     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12713   }
12714
12715   return EL_EMPTY;
12716 }
12717
12718 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12719 {
12720   int element_new = getSteel2FromOpenDirection(direction);
12721
12722   return (element_new != EL_EMPTY ? element_new : element_old);
12723 }
12724
12725 static int getOpenDirectionFromChip(int element)
12726 {
12727   switch (element)
12728   {
12729     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12730     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12731     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12732     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12733     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12734   }
12735
12736   return MV_NONE;
12737 }
12738
12739 static int getChipFromOpenDirection(int direction)
12740 {
12741   switch (direction)
12742   {
12743     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12744     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12745     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12746     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12747     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12748   }
12749
12750   return EL_EMPTY;
12751 }
12752
12753 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12754 {
12755   int element_new = getChipFromOpenDirection(direction);
12756
12757   return (element_new != EL_EMPTY ? element_new : element_old);
12758 }
12759
12760 static int getClosedTube(int x, int y)
12761 {
12762   struct XY *xy = xy_directions;
12763   int element_old = IntelliDrawBuffer[x][y];
12764   int direction_old = getOpenDirectionFromTube(element_old);
12765   int direction_new = MV_NONE;
12766   int i;
12767
12768   for (i = 0; i < NUM_DIRECTIONS; i++)
12769   {
12770     int xx = x + xy[i].x;
12771     int yy = y + xy[i].y;
12772     int dir = MV_DIR_FROM_BIT(i);
12773     int dir_opposite = MV_DIR_OPPOSITE(dir);
12774
12775     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12776         (direction_old & dir) &&
12777         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12778       direction_new |= dir;
12779   }
12780
12781   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12782 }
12783
12784 static int getClosedBelt(int x, int y)
12785 {
12786   struct XY *xy = xy_directions;
12787   int element_old = IntelliDrawBuffer[x][y];
12788   int nr = getBeltNrFromBeltElement(element_old);
12789   int direction_old = getOpenDirectionFromBelt(element_old);
12790   int direction_new = MV_NONE;
12791   int i;
12792
12793   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12794   {
12795     int xx = x + xy[i].x;
12796     int yy = y + xy[i].y;
12797     int dir = MV_DIR_FROM_BIT(i);
12798     int dir_opposite = MV_DIR_OPPOSITE(dir);
12799
12800     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12801         (direction_old & dir) &&
12802         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12803       direction_new |= dir;
12804   }
12805
12806   return getBeltFromNrAndOpenDirection(nr, direction_new);
12807 }
12808
12809 static int getClosedPool(int x, int y)
12810 {
12811   struct XY *xy = xy_directions;
12812   int element_old = IntelliDrawBuffer[x][y];
12813   int direction_old = getOpenDirectionFromPool(element_old);
12814   int direction_new = MV_NONE;
12815   int i;
12816
12817   for (i = 0; i < NUM_DIRECTIONS; i++)
12818   {
12819     int xx = x + xy[i].x;
12820     int yy = y + xy[i].y;
12821     int dir = MV_DIR_FROM_BIT(i);
12822     int dir_opposite = MV_DIR_OPPOSITE(dir);
12823
12824     if (IN_LEV_FIELD(xx, yy) &&
12825         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
12826         (direction_old & dir) &&
12827         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12828       direction_new |= dir;
12829   }
12830
12831   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
12832 }
12833
12834 static int getClosedPillar(int x, int y)
12835 {
12836   struct XY *xy = xy_directions;
12837   int element_old = IntelliDrawBuffer[x][y];
12838   int direction_old = getOpenDirectionFromPillar(element_old);
12839   int direction_new = MV_NONE;
12840   int i;
12841
12842   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
12843   {
12844     int xx = x + xy[i].x;
12845     int yy = y + xy[i].y;
12846     int dir = MV_DIR_FROM_BIT(i);
12847     int dir_opposite = MV_DIR_OPPOSITE(dir);
12848
12849     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
12850         (direction_old & dir) &&
12851         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12852       direction_new |= dir;
12853   }
12854
12855   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
12856 }
12857
12858 static int getClosedSteel2(int x, int y)
12859 {
12860   struct XY *xy = xy_directions;
12861   int element_old = IntelliDrawBuffer[x][y];
12862   int direction_old = getOpenDirectionFromSteel2(element_old);
12863   int direction_new = MV_NONE;
12864   int i;
12865
12866   for (i = 0; i < NUM_DIRECTIONS; i++)
12867   {
12868     int xx = x + xy[i].x;
12869     int yy = y + xy[i].y;
12870     int dir = MV_DIR_FROM_BIT(i);
12871     int dir_opposite = MV_DIR_OPPOSITE(dir);
12872
12873     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
12874         (direction_old & dir) &&
12875         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12876       direction_new |= dir;
12877   }
12878
12879   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
12880 }
12881
12882 static int getClosedChip(int x, int y)
12883 {
12884   struct XY *xy = xy_directions;
12885   int element_old = IntelliDrawBuffer[x][y];
12886   int direction_old = getOpenDirectionFromChip(element_old);
12887   int direction_new = MV_NONE;
12888   int i;
12889
12890   for (i = 0; i < NUM_DIRECTIONS; i++)
12891   {
12892     int xx = x + xy[i].x;
12893     int yy = y + xy[i].y;
12894     int dir = MV_DIR_FROM_BIT(i);
12895     int dir_opposite = MV_DIR_OPPOSITE(dir);
12896
12897     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
12898         (direction_old & dir) &&
12899         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12900       direction_new |= dir;
12901   }
12902
12903   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
12904 }
12905
12906 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
12907                                 boolean change_level)
12908 {
12909   int sx = x - level_xpos;
12910   int sy = y - level_ypos;
12911   int old_element = Tile[x][y];
12912   int new_element = element;
12913   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
12914   boolean draw_masked = FALSE;
12915
12916   if (IS_MM_WALL_EDITOR(element))
12917   {
12918     element = map_mm_wall_element_editor(element) | new_bitmask;
12919
12920     if (IS_MM_WALL(old_element))
12921       element |= MM_WALL_BITS(old_element);
12922
12923     if (!change_level)
12924       draw_masked = TRUE;
12925   }
12926   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
12927   {
12928     int element_changed = old_element & ~new_bitmask;
12929
12930     if (MM_WALL_BITS(element_changed) != 0)
12931       element = element_changed;
12932   }
12933
12934   IntelliDrawBuffer[x][y] = element;
12935
12936   if (change_level)
12937     Tile[x][y] = element;
12938
12939   if (IN_ED_FIELD(sx, sy))
12940   {
12941     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
12942       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
12943     else if (draw_masked)
12944       DrawEditorElementThruMask(sx, sy, element);
12945     else
12946       DrawEditorElement(sx, sy, element);
12947   }
12948 }
12949
12950 static void SetElementSimple(int x, int y, int element, boolean change_level)
12951 {
12952   SetElementSimpleExt(x, y, 0, 0, element, change_level);
12953 }
12954
12955 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
12956                                            int x2, int y2, int *element2,
12957                                            int (*close_function)(int, int),
12958                                            boolean change_level)
12959 {
12960   // set neighbour elements to newly determined connections
12961   SetElementSimple(x1, y1, *element1, change_level);
12962   SetElementSimple(x2, y2, *element2, change_level);
12963
12964   // remove all open connections of neighbour elements
12965   *element1 = close_function(x1, y1);
12966   *element2 = close_function(x2, y2);
12967
12968   // set neighbour elements to new, minimized connections
12969   SetElementSimple(x1, y1, *element1, change_level);
12970   SetElementSimple(x2, y2, *element2, change_level);
12971 }
12972
12973 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
12974                                   boolean change_level, int button)
12975 {
12976   struct XY *xy = xy_directions;
12977   static int last_x = -1;
12978   static int last_y = -1;
12979
12980   if (new_element == EL_UNDEFINED)
12981   {
12982     last_x = -1;
12983     last_y = -1;
12984
12985     return;
12986   }
12987
12988   int old_element = IntelliDrawBuffer[x][y];
12989
12990   if (IS_TUBE(new_element))
12991   {
12992     int last_element_new = EL_UNDEFINED;
12993     int direction = MV_NONE;
12994     int i;
12995
12996     // if old element is of same kind, keep all existing directions
12997     if (IS_TUBE(old_element))
12998       direction |= getOpenDirectionFromTube(old_element);
12999
13000     for (i = 0; i < NUM_DIRECTIONS; i++)
13001     {
13002       int xx = x + xy[i].x;
13003       int yy = y + xy[i].y;
13004
13005       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13006           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
13007       {
13008         int dir = MV_DIR_FROM_BIT(i);
13009         int dir_opposite = MV_DIR_OPPOSITE(dir);
13010         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13011         int last_direction_old = getOpenDirectionFromTube(last_element_old);
13012         int last_direction_new = last_direction_old | dir_opposite;
13013
13014         last_element_new = getTubeFromOpenDirection(last_direction_new);
13015
13016         direction |= dir;
13017       }
13018     }
13019
13020     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
13021
13022     if (last_element_new != EL_UNDEFINED)
13023       MergeAndCloseNeighbourElements(x, y, &new_element,
13024                                      last_x, last_y, &last_element_new,
13025                                      getClosedTube, change_level);
13026   }
13027   else if (IS_BELT(new_element))
13028   {
13029     int belt_nr = getBeltNrFromBeltElement(new_element);
13030     int last_element_new = EL_UNDEFINED;
13031     int direction = MV_NONE;
13032     int i;
13033
13034     // if old element is of same kind, keep all existing directions
13035     if (IS_BELT(old_element))
13036       direction |= getOpenDirectionFromBelt(old_element);
13037
13038     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
13039     {
13040       int xx = x + xy[i].x;
13041       int yy = y + xy[i].y;
13042
13043       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13044           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
13045       {
13046         int dir = MV_DIR_FROM_BIT(i);
13047         int dir_opposite = MV_DIR_OPPOSITE(dir);
13048         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13049         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
13050         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
13051         int last_direction_new = last_direction_old | dir_opposite;
13052
13053         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
13054                                                          last_direction_new);
13055         direction |= dir;
13056       }
13057     }
13058
13059     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
13060                                                         new_element);
13061     if (last_element_new != EL_UNDEFINED)
13062       MergeAndCloseNeighbourElements(x, y, &new_element,
13063                                      last_x, last_y, &last_element_new,
13064                                      getClosedBelt, change_level);
13065   }
13066   else if (IS_ACID_POOL_OR_ACID(new_element))
13067   {
13068     int last_element_new = EL_UNDEFINED;
13069     int direction = MV_NONE;
13070     int i;
13071
13072     // if old element is of same kind, keep all existing directions
13073     if (IS_ACID_POOL_OR_ACID(old_element))
13074       direction |= getOpenDirectionFromPool(old_element);
13075
13076     for (i = 0; i < NUM_DIRECTIONS; i++)
13077     {
13078       int xx = x + xy[i].x;
13079       int yy = y + xy[i].y;
13080
13081       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13082           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
13083       {
13084         int dir = MV_DIR_FROM_BIT(i);
13085         int dir_opposite = MV_DIR_OPPOSITE(dir);
13086         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13087         int last_direction_old = getOpenDirectionFromPool(last_element_old);
13088         int last_direction_new = last_direction_old | dir_opposite;
13089
13090         last_element_new = getPoolFromOpenDirection(last_direction_new);
13091
13092         direction |= dir;
13093       }
13094     }
13095
13096     // special corrections needed for intuitively correct acid pool drawing
13097     if (last_element_new == EL_EMPTY)
13098       last_element_new = new_element;
13099     else if (last_element_new != EL_UNDEFINED)
13100       new_element = last_element_new;
13101
13102     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
13103
13104     if (last_element_new != EL_UNDEFINED)
13105       MergeAndCloseNeighbourElements(x, y, &new_element,
13106                                      last_x, last_y, &last_element_new,
13107                                      getClosedPool, change_level);
13108   }
13109   else if (IS_EMC_PILLAR(new_element))
13110   {
13111     int last_element_new = EL_UNDEFINED;
13112     int direction = MV_NONE;
13113     int i;
13114
13115     // if old element is of same kind, keep all existing directions
13116     if (IS_EMC_PILLAR(old_element))
13117       direction |= getOpenDirectionFromPillar(old_element);
13118
13119     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
13120     {
13121       int xx = x + xy[i].x;
13122       int yy = y + xy[i].y;
13123
13124       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13125           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13126       {
13127         int dir = MV_DIR_FROM_BIT(i);
13128         int dir_opposite = MV_DIR_OPPOSITE(dir);
13129         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13130         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13131         int last_direction_new = last_direction_old | dir_opposite;
13132
13133         last_element_new = getPillarFromOpenDirection(last_direction_new);
13134
13135         direction |= dir;
13136       }
13137     }
13138
13139     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13140
13141     if (last_element_new != EL_UNDEFINED)
13142       MergeAndCloseNeighbourElements(x, y, &new_element,
13143                                      last_x, last_y, &last_element_new,
13144                                      getClosedPillar, change_level);
13145   }
13146   else if (IS_DC_STEELWALL_2(new_element))
13147   {
13148     int last_element_new = EL_UNDEFINED;
13149     int direction = MV_NONE;
13150     int i;
13151
13152     // if old element is of same kind, keep all existing directions
13153     if (IS_DC_STEELWALL_2(old_element))
13154       direction |= getOpenDirectionFromSteel2(old_element);
13155
13156     for (i = 0; i < NUM_DIRECTIONS; i++)
13157     {
13158       int xx = x + xy[i].x;
13159       int yy = y + xy[i].y;
13160
13161       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13162           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13163       {
13164         int dir = MV_DIR_FROM_BIT(i);
13165         int dir_opposite = MV_DIR_OPPOSITE(dir);
13166         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13167         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13168         int last_direction_new = last_direction_old | dir_opposite;
13169
13170         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13171
13172         direction |= dir;
13173       }
13174     }
13175
13176     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13177
13178     if (last_element_new != EL_UNDEFINED)
13179       MergeAndCloseNeighbourElements(x, y, &new_element,
13180                                      last_x, last_y, &last_element_new,
13181                                      getClosedSteel2, change_level);
13182   }
13183   else if (IS_SP_CHIP(new_element))
13184   {
13185     int last_element_new = EL_UNDEFINED;
13186     int direction = MV_NONE;
13187     int i;
13188
13189     // (do not keep existing directions, regardless of kind of old element)
13190
13191     for (i = 0; i < NUM_DIRECTIONS; i++)
13192     {
13193       int xx = x + xy[i].x;
13194       int yy = y + xy[i].y;
13195
13196       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13197           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13198       {
13199         int dir = MV_DIR_FROM_BIT(i);
13200         int dir_opposite = MV_DIR_OPPOSITE(dir);
13201         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13202         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13203         int last_direction_new = last_direction_old | dir_opposite;
13204
13205         if (last_direction_old == MV_NONE)
13206         {
13207           last_element_new = getChipFromOpenDirection(last_direction_new);
13208           direction |= dir;
13209         }
13210         else if (last_direction_old & (dir | dir_opposite))
13211         {
13212           direction |= MV_DIR_OPPOSITE(last_direction_old);
13213         }
13214         else
13215         {
13216           direction |= MV_DIR_OPPOSITE(dir);
13217         }
13218       }
13219     }
13220
13221     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13222
13223     if (last_element_new != EL_UNDEFINED)
13224       MergeAndCloseNeighbourElements(x, y, &new_element,
13225                                      last_x, last_y, &last_element_new,
13226                                      getClosedChip, change_level);
13227   }
13228   else if (IS_SP_HARDWARE_BASE(new_element))
13229   {
13230     int nr = GetSimpleRandom(6);
13231
13232     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13233                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13234                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13235                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13236                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13237   }
13238   else if (new_element == EL_SP_HARDWARE_GREEN ||
13239            new_element == EL_SP_HARDWARE_BLUE ||
13240            new_element == EL_SP_HARDWARE_RED)
13241   {
13242     int nr = GetSimpleRandom(3);
13243
13244     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13245                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13246   }
13247   else if (IS_GROUP_ELEMENT(new_element))
13248   {
13249     boolean connected_drawing = FALSE;
13250     int i;
13251
13252     for (i = 0; i < NUM_DIRECTIONS; i++)
13253     {
13254       int xx = x + xy[i].x;
13255       int yy = y + xy[i].y;
13256
13257       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13258           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13259         connected_drawing = TRUE;
13260     }
13261
13262     if (!connected_drawing)
13263       ResolveGroupElement(new_element);
13264
13265     new_element = GetElementFromGroupElement(new_element);
13266   }
13267   else if (IS_BELT_SWITCH(old_element))
13268   {
13269     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13270     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13271
13272     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13273                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13274
13275     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13276   }
13277   else
13278   {
13279     static int swappable_elements[][2] =
13280     {
13281       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13282       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13283       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13284       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13285       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13286       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13287       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13288       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13289       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13290       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13291       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13292       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13293       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13294       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13295       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13296       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13297       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13298       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13299       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13300       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13301       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13302       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13303       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13304       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13305       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13306       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13307       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13308       { EL_PEARL,                       EL_WALL_PEARL                   },
13309       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13310       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13311       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13312       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13313       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13314       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13315       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13316       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13317       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13318       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13319       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13320       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13321       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13322       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13323       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13324       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13325
13326       { -1,                             -1                              },
13327     };
13328     static int rotatable_elements_4[][4] =
13329     {
13330       {
13331         EL_BUG_UP,
13332         EL_BUG_RIGHT,
13333         EL_BUG_DOWN,
13334         EL_BUG_LEFT
13335       },
13336       {
13337         EL_SPACESHIP_UP,
13338         EL_SPACESHIP_RIGHT,
13339         EL_SPACESHIP_DOWN,
13340         EL_SPACESHIP_LEFT
13341       },
13342       {
13343         EL_BD_BUTTERFLY_UP,
13344         EL_BD_BUTTERFLY_RIGHT,
13345         EL_BD_BUTTERFLY_DOWN,
13346         EL_BD_BUTTERFLY_LEFT
13347       },
13348       {
13349         EL_BD_FIREFLY_UP,
13350         EL_BD_FIREFLY_RIGHT,
13351         EL_BD_FIREFLY_DOWN,
13352         EL_BD_FIREFLY_LEFT
13353       },
13354       {
13355         EL_PACMAN_UP,
13356         EL_PACMAN_RIGHT,
13357         EL_PACMAN_DOWN,
13358         EL_PACMAN_LEFT
13359       },
13360       {
13361         EL_YAMYAM_UP,
13362         EL_YAMYAM_RIGHT,
13363         EL_YAMYAM_DOWN,
13364         EL_YAMYAM_LEFT
13365       },
13366       {
13367         EL_ARROW_UP,
13368         EL_ARROW_RIGHT,
13369         EL_ARROW_DOWN,
13370         EL_ARROW_LEFT
13371       },
13372       {
13373         EL_SP_PORT_UP,
13374         EL_SP_PORT_RIGHT,
13375         EL_SP_PORT_DOWN,
13376         EL_SP_PORT_LEFT
13377       },
13378       {
13379         EL_SP_GRAVITY_PORT_UP,
13380         EL_SP_GRAVITY_PORT_RIGHT,
13381         EL_SP_GRAVITY_PORT_DOWN,
13382         EL_SP_GRAVITY_PORT_LEFT
13383       },
13384       {
13385         EL_SP_GRAVITY_ON_PORT_UP,
13386         EL_SP_GRAVITY_ON_PORT_RIGHT,
13387         EL_SP_GRAVITY_ON_PORT_DOWN,
13388         EL_SP_GRAVITY_ON_PORT_LEFT
13389       },
13390       {
13391         EL_SP_GRAVITY_OFF_PORT_UP,
13392         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13393         EL_SP_GRAVITY_OFF_PORT_DOWN,
13394         EL_SP_GRAVITY_OFF_PORT_LEFT
13395       },
13396       {
13397         EL_MOLE_UP,
13398         EL_MOLE_RIGHT,
13399         EL_MOLE_DOWN,
13400         EL_MOLE_LEFT
13401       },
13402       {
13403         EL_BALLOON_SWITCH_UP,
13404         EL_BALLOON_SWITCH_RIGHT,
13405         EL_BALLOON_SWITCH_DOWN,
13406         EL_BALLOON_SWITCH_LEFT
13407       },
13408       {
13409         EL_MM_MCDUFFIN_UP,
13410         EL_MM_MCDUFFIN_RIGHT,
13411         EL_MM_MCDUFFIN_DOWN,
13412         EL_MM_MCDUFFIN_LEFT
13413       },
13414       {
13415         EL_MM_MIRROR_FIXED_1,
13416         EL_MM_MIRROR_FIXED_4,
13417         EL_MM_MIRROR_FIXED_3,
13418         EL_MM_MIRROR_FIXED_2
13419       },
13420       {
13421         EL_MM_STEEL_GRID_FIXED_1,
13422         EL_MM_STEEL_GRID_FIXED_4,
13423         EL_MM_STEEL_GRID_FIXED_2,
13424         EL_MM_STEEL_GRID_FIXED_3
13425       },
13426       {
13427         EL_MM_WOODEN_GRID_FIXED_1,
13428         EL_MM_WOODEN_GRID_FIXED_4,
13429         EL_MM_WOODEN_GRID_FIXED_2,
13430         EL_MM_WOODEN_GRID_FIXED_3
13431       },
13432       {
13433         EL_MM_POLARIZER_CROSS_1,
13434         EL_MM_POLARIZER_CROSS_4,
13435         EL_MM_POLARIZER_CROSS_3,
13436         EL_MM_POLARIZER_CROSS_2
13437       },
13438       {
13439         EL_MM_PACMAN_UP,
13440         EL_MM_PACMAN_RIGHT,
13441         EL_MM_PACMAN_DOWN,
13442         EL_MM_PACMAN_LEFT
13443       },
13444       {
13445         EL_DF_LASER_UP,
13446         EL_DF_LASER_RIGHT,
13447         EL_DF_LASER_DOWN,
13448         EL_DF_LASER_LEFT
13449       },
13450       {
13451         EL_DF_RECEIVER_UP,
13452         EL_DF_RECEIVER_RIGHT,
13453         EL_DF_RECEIVER_DOWN,
13454         EL_DF_RECEIVER_LEFT
13455       },
13456       {
13457         EL_DF_SLOPE_1,
13458         EL_DF_SLOPE_4,
13459         EL_DF_SLOPE_3,
13460         EL_DF_SLOPE_2
13461       },
13462
13463       {
13464         -1,
13465       },
13466     };
13467     static int rotatable_elements_8[][8] =
13468     {
13469       {
13470         EL_DF_STEEL_GRID_FIXED_1,
13471         EL_DF_STEEL_GRID_FIXED_8,
13472         EL_DF_STEEL_GRID_FIXED_7,
13473         EL_DF_STEEL_GRID_FIXED_6,
13474         EL_DF_STEEL_GRID_FIXED_5,
13475         EL_DF_STEEL_GRID_FIXED_4,
13476         EL_DF_STEEL_GRID_FIXED_3,
13477         EL_DF_STEEL_GRID_FIXED_2
13478       },
13479       {
13480         EL_DF_WOODEN_GRID_FIXED_1,
13481         EL_DF_WOODEN_GRID_FIXED_8,
13482         EL_DF_WOODEN_GRID_FIXED_7,
13483         EL_DF_WOODEN_GRID_FIXED_6,
13484         EL_DF_WOODEN_GRID_FIXED_5,
13485         EL_DF_WOODEN_GRID_FIXED_4,
13486         EL_DF_WOODEN_GRID_FIXED_3,
13487         EL_DF_WOODEN_GRID_FIXED_2
13488       },
13489       {
13490         EL_DF_STEEL_GRID_ROTATING_1,
13491         EL_DF_STEEL_GRID_ROTATING_8,
13492         EL_DF_STEEL_GRID_ROTATING_7,
13493         EL_DF_STEEL_GRID_ROTATING_6,
13494         EL_DF_STEEL_GRID_ROTATING_5,
13495         EL_DF_STEEL_GRID_ROTATING_4,
13496         EL_DF_STEEL_GRID_ROTATING_3,
13497         EL_DF_STEEL_GRID_ROTATING_2
13498       },
13499       {
13500         EL_DF_WOODEN_GRID_ROTATING_1,
13501         EL_DF_WOODEN_GRID_ROTATING_8,
13502         EL_DF_WOODEN_GRID_ROTATING_7,
13503         EL_DF_WOODEN_GRID_ROTATING_6,
13504         EL_DF_WOODEN_GRID_ROTATING_5,
13505         EL_DF_WOODEN_GRID_ROTATING_4,
13506         EL_DF_WOODEN_GRID_ROTATING_3,
13507         EL_DF_WOODEN_GRID_ROTATING_2
13508       },
13509
13510       {
13511         -1,
13512       },
13513     };
13514     static int rotatable_elements_16[][16] =
13515     {
13516       {
13517         EL_MM_MIRROR_1,
13518         EL_MM_MIRROR_16,
13519         EL_MM_MIRROR_15,
13520         EL_MM_MIRROR_14,
13521         EL_MM_MIRROR_13,
13522         EL_MM_MIRROR_12,
13523         EL_MM_MIRROR_11,
13524         EL_MM_MIRROR_10,
13525         EL_MM_MIRROR_9,
13526         EL_MM_MIRROR_8,
13527         EL_MM_MIRROR_7,
13528         EL_MM_MIRROR_6,
13529         EL_MM_MIRROR_5,
13530         EL_MM_MIRROR_4,
13531         EL_MM_MIRROR_3,
13532         EL_MM_MIRROR_2
13533       },
13534       {
13535         EL_MM_TELEPORTER_5,
13536         EL_MM_TELEPORTER_4,
13537         EL_MM_TELEPORTER_3,
13538         EL_MM_TELEPORTER_2,
13539         EL_MM_TELEPORTER_1,
13540         EL_MM_TELEPORTER_16,
13541         EL_MM_TELEPORTER_15,
13542         EL_MM_TELEPORTER_14,
13543         EL_MM_TELEPORTER_13,
13544         EL_MM_TELEPORTER_12,
13545         EL_MM_TELEPORTER_11,
13546         EL_MM_TELEPORTER_10,
13547         EL_MM_TELEPORTER_9,
13548         EL_MM_TELEPORTER_8,
13549         EL_MM_TELEPORTER_7,
13550         EL_MM_TELEPORTER_6
13551       },
13552       {
13553         EL_MM_TELEPORTER_RED_5,
13554         EL_MM_TELEPORTER_RED_4,
13555         EL_MM_TELEPORTER_RED_3,
13556         EL_MM_TELEPORTER_RED_2,
13557         EL_MM_TELEPORTER_RED_1,
13558         EL_MM_TELEPORTER_RED_16,
13559         EL_MM_TELEPORTER_RED_15,
13560         EL_MM_TELEPORTER_RED_14,
13561         EL_MM_TELEPORTER_RED_13,
13562         EL_MM_TELEPORTER_RED_12,
13563         EL_MM_TELEPORTER_RED_11,
13564         EL_MM_TELEPORTER_RED_10,
13565         EL_MM_TELEPORTER_RED_9,
13566         EL_MM_TELEPORTER_RED_8,
13567         EL_MM_TELEPORTER_RED_7,
13568         EL_MM_TELEPORTER_RED_6
13569       },
13570       {
13571         EL_MM_TELEPORTER_YELLOW_5,
13572         EL_MM_TELEPORTER_YELLOW_4,
13573         EL_MM_TELEPORTER_YELLOW_3,
13574         EL_MM_TELEPORTER_YELLOW_2,
13575         EL_MM_TELEPORTER_YELLOW_1,
13576         EL_MM_TELEPORTER_YELLOW_16,
13577         EL_MM_TELEPORTER_YELLOW_15,
13578         EL_MM_TELEPORTER_YELLOW_14,
13579         EL_MM_TELEPORTER_YELLOW_13,
13580         EL_MM_TELEPORTER_YELLOW_12,
13581         EL_MM_TELEPORTER_YELLOW_11,
13582         EL_MM_TELEPORTER_YELLOW_10,
13583         EL_MM_TELEPORTER_YELLOW_9,
13584         EL_MM_TELEPORTER_YELLOW_8,
13585         EL_MM_TELEPORTER_YELLOW_7,
13586         EL_MM_TELEPORTER_YELLOW_6
13587       },
13588       {
13589         EL_MM_TELEPORTER_GREEN_5,
13590         EL_MM_TELEPORTER_GREEN_4,
13591         EL_MM_TELEPORTER_GREEN_3,
13592         EL_MM_TELEPORTER_GREEN_2,
13593         EL_MM_TELEPORTER_GREEN_1,
13594         EL_MM_TELEPORTER_GREEN_16,
13595         EL_MM_TELEPORTER_GREEN_15,
13596         EL_MM_TELEPORTER_GREEN_14,
13597         EL_MM_TELEPORTER_GREEN_13,
13598         EL_MM_TELEPORTER_GREEN_12,
13599         EL_MM_TELEPORTER_GREEN_11,
13600         EL_MM_TELEPORTER_GREEN_10,
13601         EL_MM_TELEPORTER_GREEN_9,
13602         EL_MM_TELEPORTER_GREEN_8,
13603         EL_MM_TELEPORTER_GREEN_7,
13604         EL_MM_TELEPORTER_GREEN_6
13605       },
13606       {
13607         EL_MM_TELEPORTER_BLUE_5,
13608         EL_MM_TELEPORTER_BLUE_4,
13609         EL_MM_TELEPORTER_BLUE_3,
13610         EL_MM_TELEPORTER_BLUE_2,
13611         EL_MM_TELEPORTER_BLUE_1,
13612         EL_MM_TELEPORTER_BLUE_16,
13613         EL_MM_TELEPORTER_BLUE_15,
13614         EL_MM_TELEPORTER_BLUE_14,
13615         EL_MM_TELEPORTER_BLUE_13,
13616         EL_MM_TELEPORTER_BLUE_12,
13617         EL_MM_TELEPORTER_BLUE_11,
13618         EL_MM_TELEPORTER_BLUE_10,
13619         EL_MM_TELEPORTER_BLUE_9,
13620         EL_MM_TELEPORTER_BLUE_8,
13621         EL_MM_TELEPORTER_BLUE_7,
13622         EL_MM_TELEPORTER_BLUE_6
13623       },
13624       {
13625         EL_MM_POLARIZER_1,
13626         EL_MM_POLARIZER_16,
13627         EL_MM_POLARIZER_15,
13628         EL_MM_POLARIZER_14,
13629         EL_MM_POLARIZER_13,
13630         EL_MM_POLARIZER_12,
13631         EL_MM_POLARIZER_11,
13632         EL_MM_POLARIZER_10,
13633         EL_MM_POLARIZER_9,
13634         EL_MM_POLARIZER_8,
13635         EL_MM_POLARIZER_7,
13636         EL_MM_POLARIZER_6,
13637         EL_MM_POLARIZER_5,
13638         EL_MM_POLARIZER_4,
13639         EL_MM_POLARIZER_3,
13640         EL_MM_POLARIZER_2
13641       },
13642       {
13643         EL_DF_MIRROR_1,
13644         EL_DF_MIRROR_16,
13645         EL_DF_MIRROR_15,
13646         EL_DF_MIRROR_14,
13647         EL_DF_MIRROR_13,
13648         EL_DF_MIRROR_12,
13649         EL_DF_MIRROR_11,
13650         EL_DF_MIRROR_10,
13651         EL_DF_MIRROR_9,
13652         EL_DF_MIRROR_8,
13653         EL_DF_MIRROR_7,
13654         EL_DF_MIRROR_6,
13655         EL_DF_MIRROR_5,
13656         EL_DF_MIRROR_4,
13657         EL_DF_MIRROR_3,
13658         EL_DF_MIRROR_2
13659       },
13660       {
13661         EL_DF_MIRROR_ROTATING_1,
13662         EL_DF_MIRROR_ROTATING_16,
13663         EL_DF_MIRROR_ROTATING_15,
13664         EL_DF_MIRROR_ROTATING_14,
13665         EL_DF_MIRROR_ROTATING_13,
13666         EL_DF_MIRROR_ROTATING_12,
13667         EL_DF_MIRROR_ROTATING_11,
13668         EL_DF_MIRROR_ROTATING_10,
13669         EL_DF_MIRROR_ROTATING_9,
13670         EL_DF_MIRROR_ROTATING_8,
13671         EL_DF_MIRROR_ROTATING_7,
13672         EL_DF_MIRROR_ROTATING_6,
13673         EL_DF_MIRROR_ROTATING_5,
13674         EL_DF_MIRROR_ROTATING_4,
13675         EL_DF_MIRROR_ROTATING_3,
13676         EL_DF_MIRROR_ROTATING_2
13677       },
13678       {
13679         EL_DF_MIRROR_FIXED_1,
13680         EL_DF_MIRROR_FIXED_16,
13681         EL_DF_MIRROR_FIXED_15,
13682         EL_DF_MIRROR_FIXED_14,
13683         EL_DF_MIRROR_FIXED_13,
13684         EL_DF_MIRROR_FIXED_12,
13685         EL_DF_MIRROR_FIXED_11,
13686         EL_DF_MIRROR_FIXED_10,
13687         EL_DF_MIRROR_FIXED_9,
13688         EL_DF_MIRROR_FIXED_8,
13689         EL_DF_MIRROR_FIXED_7,
13690         EL_DF_MIRROR_FIXED_6,
13691         EL_DF_MIRROR_FIXED_5,
13692         EL_DF_MIRROR_FIXED_4,
13693         EL_DF_MIRROR_FIXED_3,
13694         EL_DF_MIRROR_FIXED_2
13695       },
13696
13697       {
13698         -1,
13699       },
13700     };
13701     int i, j;
13702
13703     for (i = 0; swappable_elements[i][0] != -1; i++)
13704     {
13705       int element1 = swappable_elements[i][0];
13706       int element2 = swappable_elements[i][1];
13707
13708       if (old_element == element1 || old_element == element2)
13709         new_element = (old_element == element1 ? element2 : element1);
13710     }
13711
13712     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13713     {
13714       for (j = 0; j < 4; j++)
13715       {
13716         int element = rotatable_elements_4[i][j];
13717
13718         if (old_element == element)
13719           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13720                          button == 2 ? rotatable_elements_4[i][0]           :
13721                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13722                          old_element);
13723       }
13724     }
13725
13726     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13727     {
13728       for (j = 0; j < 8; j++)
13729       {
13730         int element = rotatable_elements_8[i][j];
13731
13732         if (old_element == element)
13733           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13734                          button == 2 ? rotatable_elements_8[i][0]           :
13735                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13736                          old_element);
13737       }
13738     }
13739
13740     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13741     {
13742       for (j = 0; j < 16; j++)
13743       {
13744         int element = rotatable_elements_16[i][j];
13745
13746         if (old_element == element)
13747           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13748                          button == 2 ? rotatable_elements_16[i][0]             :
13749                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13750                          old_element);
13751       }
13752     }
13753
13754     if (old_element != new_element)
13755     {
13756       int max_infotext_len = getMaxInfoTextLength();
13757       char infotext[MAX_OUTPUT_LINESIZE + 1];
13758
13759       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13760       infotext[max_infotext_len] = '\0';
13761
13762       ClearEditorGadgetInfoText();
13763
13764       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13765                 infotext);
13766     }
13767   }
13768
13769   if (IS_MM_WALL_EDITOR(new_element))
13770     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13771   else
13772     SetElementSimple(x, y, new_element, change_level);
13773
13774   last_x = x;
13775   last_y = y;
13776 }
13777
13778 static void ResetIntelliDraw(void)
13779 {
13780   int x, y;
13781
13782   for (x = 0; x < lev_fieldx; x++)
13783     for (y = 0; y < lev_fieldy; y++)
13784       IntelliDrawBuffer[x][y] = Tile[x][y];
13785
13786   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13787 }
13788
13789 static boolean draw_mode_hires = FALSE;
13790
13791 static boolean isHiresTileElement(int element)
13792 {
13793   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13794 }
13795
13796 static boolean isHiresDrawElement(int element)
13797 {
13798   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13799 }
13800
13801 static int numHiresTiles(int element)
13802 {
13803   if (IS_MM_WALL(element))
13804     return get_number_of_bits(MM_WALL_BITS(element));
13805
13806   return 1;
13807 }
13808
13809 static void SetDrawModeHiRes(int element)
13810 {
13811   draw_mode_hires =
13812     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13813      isHiresDrawElement(element));
13814 }
13815
13816 static boolean getDrawModeHiRes(void)
13817 {
13818   return draw_mode_hires;
13819 }
13820
13821 static int getLoResScreenPos(int pos)
13822 {
13823   return (getDrawModeHiRes() ? pos / 2 : pos);
13824 }
13825
13826 static int getLoResScreenMod(int pos)
13827 {
13828   return (getDrawModeHiRes() ? pos % 2 : 0);
13829 }
13830
13831 static void SetElementExt(int x, int y, int dx, int dy, int element,
13832                           boolean change_level, int button)
13833 {
13834   if (element < 0)
13835     SetElementSimple(x, y, Tile[x][y], change_level);
13836   else if (GetKeyModState() & KMOD_Shift)
13837     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
13838   else
13839     SetElementSimpleExt(x, y, dx, dy, element, change_level);
13840 }
13841
13842 static void SetElement(int x, int y, int element)
13843 {
13844   SetElementExt(x, y, 0, 0, element, TRUE, -1);
13845 }
13846
13847 static void SetElementButton(int x, int y, int dx, int dy, int element,
13848                              int button)
13849 {
13850   SetElementExt(x, y, dx, dy, element, TRUE, button);
13851 }
13852
13853 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
13854 {
13855   int lx = getLoResScreenPos(sx2) + level_xpos;
13856   int ly = getLoResScreenPos(sy2) + level_ypos;
13857   int dx = getLoResScreenMod(sx2);
13858   int dy = getLoResScreenMod(sy2);
13859
13860   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
13861 }
13862
13863 static void SetLevelElementHiRes(int lx2, int ly2, int element)
13864 {
13865   int lx = lx2 / 2;
13866   int ly = ly2 / 2;
13867   int dx = lx2 % 2;
13868   int dy = ly2 % 2;
13869
13870   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
13871 }
13872
13873 static int getLevelElementHiRes(int lx2, int ly2)
13874 {
13875   int lx = lx2 / 2;
13876   int ly = ly2 / 2;
13877   int dx = lx2 % 2;
13878   int dy = ly2 % 2;
13879   int element = Tile[lx][ly];
13880   unsigned int bitmask = (dx + 1) << (dy * 2);
13881
13882   if (IS_MM_WALL(element))
13883   {
13884     if (element & bitmask)
13885       return map_mm_wall_element(element);
13886     else
13887       return EL_EMPTY;
13888   }
13889
13890   return element;
13891 }
13892
13893 static void DrawLineElement(int x, int y, int element, boolean change_level)
13894 {
13895   SetElementHiRes(x, y, element, change_level);
13896 }
13897
13898 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
13899                      int element, boolean change_level)
13900 {
13901   int xsize = ABS(to_x - from_x);
13902   int ysize = ABS(to_y - from_y);
13903   int dx = (to_x < from_x ? -1 : +1);
13904   int dy = (to_y < from_y ? -1 : +1);
13905   int i;
13906
13907   if (from_y == to_y)                   // horizontal line
13908   {
13909     for (i = 0; i <= xsize; i++)
13910       DrawLineElement(from_x + i * dx, from_y, element, change_level);
13911   }
13912   else if (from_x == to_x)              // vertical line
13913   {
13914     for (i = 0; i <= ysize; i++)
13915       DrawLineElement(from_x, from_y + i * dy, element, change_level);
13916   }
13917   else                                  // diagonal line
13918   {
13919     if (ysize < xsize)                  // a < 1
13920     {
13921       float a = (float)ysize / (float)xsize;
13922
13923       for (i = 0; i <= xsize; i++)
13924       {
13925         int x = dx * i;
13926         int y = dy * (int)(a * i + 0.5);
13927
13928         DrawLineElement(from_x + x, from_y + y, element, change_level);
13929       }
13930     }
13931     else                                // a >= 1
13932     {
13933       float a = (float)xsize / (float)ysize;
13934
13935       for (i = 0; i <= ysize; i++)
13936       {
13937         int x = dx * (int)(a * i + 0.5);
13938         int y = dy * i;
13939
13940         DrawLineElement(from_x + x, from_y + y, element, change_level);
13941       }
13942     }
13943   }
13944 }
13945
13946 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
13947                     int element, boolean change_level)
13948 {
13949   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
13950   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
13951   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
13952   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
13953 }
13954
13955 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
13956                           int element, boolean change_level)
13957 {
13958   int y;
13959
13960   if (from_y > to_y)
13961     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
13962
13963   for (y = from_y; y <= to_y; y++)
13964     DrawLine(from_x, y, to_x, y, element, change_level);
13965 }
13966
13967 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
13968                        int element, boolean change_level)
13969 {
13970   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
13971   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
13972   int len_x = ABS(to_x - from_x);
13973   int len_y = ABS(to_y - from_y);
13974   int radius, x, y;
13975
13976   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
13977
13978   // not optimal (some points get drawn twice) but simple,
13979   // and fast enough for the few points we are drawing
13980
13981   for (x = 0; x <= radius; x++)
13982   {
13983     int sx, sy, sx2, sy2, lx, ly;
13984
13985     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
13986
13987     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
13988     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
13989     sx = getLoResScreenPos(sx2);
13990     sy = getLoResScreenPos(sy2);
13991     lx = sx + level_xpos;
13992     ly = sy + level_ypos;
13993
13994     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
13995       DrawLineElement(sx2, sy2, element, change_level);
13996   }
13997
13998   for (y = 0; y <= radius; y++)
13999   {
14000     int sx, sy, sx2, sy2, lx, ly;
14001
14002     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
14003
14004     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
14005     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
14006     sx = getLoResScreenPos(sx2);
14007     sy = getLoResScreenPos(sy2);
14008     lx = sx + level_xpos;
14009     ly = sy + level_ypos;
14010
14011     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14012       DrawLineElement(sx2, sy2, element, change_level);
14013   }
14014 }
14015
14016 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
14017                     int element, boolean change_level)
14018 {
14019   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14020   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14021
14022   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14023 }
14024
14025 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
14026
14027 #if DRAW_CIRCLES_BUTTON_AVAILABLE
14028 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
14029                        int element, boolean change_level)
14030 {
14031   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
14032   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
14033   int mirror_to_x2 = from_x - (to_x2 - from_x);
14034   int mirror_to_y2 = from_y - (to_y2 - from_y);
14035
14036   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
14037   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
14038   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
14039   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
14040 }
14041 #endif
14042
14043 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
14044 {
14045   int from_sx, from_sy;
14046   int to_sx, to_sy;
14047
14048   if (from_x > to_x)
14049     swap_numbers(&from_x, &to_x);
14050
14051   if (from_y > to_y)
14052     swap_numbers(&from_y, &to_y);
14053
14054   from_sx = SX + from_x * ed_tilesize;
14055   from_sy = SY + from_y * ed_tilesize;
14056   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
14057   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
14058
14059   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
14060   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
14061   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
14062   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
14063
14064   if (from_x == to_x && from_y == to_y)
14065     MarkTileDirty(from_x/2, from_y/2);
14066   else
14067     redraw_mask |= REDRAW_FIELD;
14068 }
14069
14070 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
14071                         int element, boolean change_level)
14072 {
14073   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
14074 }
14075
14076 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
14077                        int element, boolean change_level)
14078 {
14079   if (element == -1 || change_level)
14080     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
14081   else
14082     DrawAreaBorder(from_x, from_y, to_x, to_y);
14083 }
14084
14085 // values for CopyBrushExt()
14086 #define CB_AREA_TO_BRUSH                0
14087 #define CB_BRUSH_TO_CURSOR              1
14088 #define CB_BRUSH_TO_LEVEL               2
14089 #define CB_DELETE_OLD_CURSOR            3
14090 #define CB_DUMP_BRUSH                   4
14091 #define CB_DUMP_BRUSH_SMALL             5
14092 #define CB_CLIPBOARD_TO_BRUSH           6
14093 #define CB_BRUSH_TO_CLIPBOARD           7
14094 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
14095 #define CB_UPDATE_BRUSH_POSITION        9
14096 #define CB_FLIP_BRUSH_X                 10
14097 #define CB_FLIP_BRUSH_Y                 11
14098 #define CB_FLIP_BRUSH_XY                12
14099
14100 #define MAX_CB_PART_SIZE        10
14101 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
14102 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
14103 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
14104                                  MAX_CB_NUM_LINES *     \
14105                                  MAX_CB_PART_SIZE)
14106
14107 static int getFlippedTileExt(int map[], int element)
14108 {
14109   int i;
14110
14111   for (i = 0; map[i] != -1; i++)
14112     if (map[i] == element)
14113       return map[i ^ 1];        // get flipped element by flipping LSB of index
14114
14115   return element;
14116 }
14117
14118 static int getFlippedTileX(int element)
14119 {
14120   int map[] =
14121   {
14122     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14123     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14124     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14125     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14126     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14127     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14128     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14129     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14130     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14131     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14132     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14133     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14134     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14135     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14136     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14137     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14138     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14139     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14140     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14141     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14142     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14143     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14144     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14145     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14146     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14147     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14148     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14149     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14150     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14151     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14152
14153     -1
14154   };
14155
14156   return getFlippedTileExt(map, element);
14157 }
14158
14159 static int getFlippedTileY(int element)
14160 {
14161   int map[] =
14162   {
14163     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14164     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14165     EL_BUG_UP,                          EL_BUG_DOWN,
14166     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14167     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14168     EL_ARROW_UP,                        EL_ARROW_DOWN,
14169     EL_MOLE_UP,                         EL_MOLE_DOWN,
14170     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14171     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14172     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14173     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14174     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14175     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14176     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14177     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14178     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14179     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14180     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14181     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14182     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14183     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14184     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14185     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14186     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14187
14188     -1
14189   };
14190
14191   return getFlippedTileExt(map, element);
14192 }
14193
14194 static int getFlippedTileXY(int element)
14195 {
14196   int map[] =
14197   {
14198     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14199     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14200     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14201     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14202     EL_BUG_LEFT,                        EL_BUG_UP,
14203     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14204     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14205     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14206     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14207     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14208     EL_ARROW_LEFT,                      EL_ARROW_UP,
14209     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14210     EL_MOLE_LEFT,                       EL_MOLE_UP,
14211     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14212     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14213     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14214     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14215     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14216     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14217     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14218     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14219     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14220     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14221     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14222     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14223     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14224     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14225     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14226     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14227     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14228     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14229     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14230     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14231     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14232     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14233     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14234     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14235     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14236     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14237     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14238     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14239     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14240
14241     -1
14242   };
14243
14244   return getFlippedTileExt(map, element);
14245 }
14246
14247 static int getFlippedTile(int element, int mode)
14248 {
14249   if (IS_MM_ELEMENT(element))
14250   {
14251     // get MM game element
14252     element = map_element_RND_to_MM(element);
14253
14254     // get flipped game element
14255     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14256                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14257                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14258                element);
14259
14260     // get RND game element again
14261     element = map_element_MM_to_RND(element);
14262   }
14263   else
14264   {
14265     // get flipped game element
14266     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14267                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14268                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14269                element);
14270   }
14271
14272   return element;
14273 }
14274
14275 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14276 {
14277   // flip tiles
14278   short tile1_flipped = getFlippedTile(*tile1, mode);
14279   short tile2_flipped = getFlippedTile(*tile2, mode);
14280
14281   // swap tiles
14282   *tile1 = tile2_flipped;
14283   *tile2 = tile1_flipped;
14284 }
14285
14286 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14287 {
14288   DrawLineElement(sx, sy, element, change_level);
14289 }
14290
14291 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14292                          int button, int mode)
14293 {
14294   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14295   static int brush_width, brush_height;
14296   static int last_cursor_x = -1, last_cursor_y = -1;
14297   static boolean delete_old_brush = FALSE;
14298   int new_element = BUTTON_ELEMENT(button);
14299   int x, y;
14300
14301   if (mode == CB_DUMP_BRUSH ||
14302       mode == CB_DUMP_BRUSH_SMALL ||
14303       mode == CB_BRUSH_TO_CLIPBOARD ||
14304       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14305   {
14306     if (edit_mode != ED_MODE_DRAWING)
14307       return;
14308
14309     char part[MAX_CB_PART_SIZE + 1] = "";
14310     char text[MAX_CB_TEXT_SIZE + 1] = "";
14311     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14312     int height = (draw_with_brush ? brush_height : lev_fieldy);
14313     char *format = "%s%03d";
14314
14315     for (y = 0; y < height; y++)
14316       for (x = 0; x < width; x++)
14317         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14318           format = "%s%04d";
14319
14320     for (y = 0; y < height; y++)
14321     {
14322       for (x = 0; x < width; x++)
14323       {
14324         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14325         char *prefix = (mode == CB_DUMP_BRUSH ||
14326                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14327
14328         if (element >= NUM_FILE_ELEMENTS)
14329           element = EL_UNKNOWN;
14330
14331         // copy brush to level sketch text buffer for the R'n'D forum:
14332         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14333         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14334         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14335         strcat(text, part);
14336       }
14337
14338       strcat(text, "\n");
14339     }
14340
14341     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14342         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14343       SDL_SetClipboardText(text);
14344     else
14345       Print("%s", text);        // print brush data to console and log file
14346
14347     return;
14348   }
14349
14350   if (mode == CB_CLIPBOARD_TO_BRUSH)
14351   {
14352     if (edit_mode != ED_MODE_DRAWING)
14353       return;
14354
14355     if (!SDL_HasClipboardText())
14356     {
14357       Request("Clipboard is empty!", REQ_CONFIRM);
14358
14359       return;
14360     }
14361
14362     boolean copy_to_brush = (draw_with_brush ||
14363                              drawing_function == GADGET_ID_GRAB_BRUSH);
14364
14365     // this will delete the old brush, if already drawing with a brush
14366     if (copy_to_brush)
14367       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14368
14369     // initialization is required for "odd" (incomplete) clipboard content
14370     for (x = 0; x < MAX_LEV_FIELDX; x++)
14371       for (y = 0; y < MAX_LEV_FIELDY; y++)
14372         brush_buffer[x][y] = EL_EMPTY;
14373
14374     brush_width  = 0;
14375     brush_height = 0;
14376     x = 0;
14377     y = 0;
14378
14379     char *clipboard_text = SDL_GetClipboardText();
14380     char *ptr = clipboard_text;
14381     boolean allow_new_row = FALSE;
14382     boolean stop = FALSE;
14383
14384     while (*ptr && !stop)
14385     {
14386       boolean prefix_found = FALSE;
14387       boolean start_new_row = FALSE;
14388
14389       // level sketch element number prefixes (may be multi-byte characters)
14390       char *prefix_list[] = { "`", "¸" };
14391       int i;
14392
14393       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14394       {
14395         char *prefix = prefix_list[i];
14396
14397         // check if string is large enough for prefix
14398         if (strlen(ptr) < strlen(prefix))
14399         {
14400           stop = TRUE;
14401
14402           break;
14403         }
14404
14405         // check if string starts with prefix
14406         if (strPrefix(ptr, prefix))
14407         {
14408           ptr += strlen(prefix);
14409
14410           prefix_found = TRUE;
14411
14412           break;
14413         }
14414       }
14415
14416       // check if prefix found and followed by (at least) three digits
14417       if (prefix_found &&
14418           strlen(ptr) >= 3 &&
14419           ptr[0] >= '0' && ptr[0] <= '9' &&
14420           ptr[1] >= '0' && ptr[1] <= '9' &&
14421           ptr[2] >= '0' && ptr[2] <= '9')
14422       {
14423         int element = ((ptr[0] - '0') * 100 +
14424                        (ptr[1] - '0') * 10 +
14425                        (ptr[2] - '0'));
14426
14427         ptr += 3;
14428
14429         // level sketch element number might consist of four digits
14430         if (ptr[0] >= '0' && ptr[0] <= '9')
14431         {
14432           element = element * 10 + (ptr[0] - '0');
14433           ptr++;
14434         }
14435
14436         // remap some (historic, now obsolete) elements
14437         element = getMappedElement(element);
14438
14439         if (element >= NUM_FILE_ELEMENTS)
14440           element = EL_UNKNOWN;
14441
14442         brush_buffer[x][y] = element;
14443
14444         brush_width  = MAX(x + 1, brush_width);
14445         brush_height = MAX(y + 1, brush_height);
14446
14447         x++;
14448
14449         if (x >= MAX_LEV_FIELDX)
14450           start_new_row = TRUE;
14451
14452         allow_new_row = TRUE;
14453       }
14454       else
14455       {
14456         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14457           start_new_row = TRUE;
14458
14459         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14460       }
14461
14462       if (start_new_row)
14463       {
14464         x = 0;
14465         y++;
14466
14467         if (y >= MAX_LEV_FIELDY)
14468           stop = TRUE;
14469
14470         allow_new_row = FALSE;
14471       }
14472     }
14473
14474     SDL_free(clipboard_text);
14475
14476     if (brush_width == 0 || brush_height == 0)
14477     {
14478       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14479
14480       return;
14481     }
14482
14483     if (copy_to_brush)
14484     {
14485       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14486       int mx, my;
14487
14488       SDL_GetMouseState(&mx, &my);
14489
14490       // if inside drawing area, activate and draw brush at last mouse position
14491       if (mx >= gi->x && mx < gi->x + gi->width &&
14492           my >= gi->y && my < gi->y + gi->height)
14493         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14494
14495       draw_with_brush = TRUE;
14496     }
14497     else
14498     {
14499       char request[100];
14500
14501       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14502               brush_width, brush_height);
14503
14504       if (!Request(request, REQ_ASK))
14505         return;
14506
14507       for (x = 0; x < MAX_LEV_FIELDX; x++)
14508         for (y = 0; y < MAX_LEV_FIELDY; y++)
14509           Tile[x][y] = brush_buffer[x][y];
14510
14511       lev_fieldx = level.fieldx = brush_width;
14512       lev_fieldy = level.fieldy = brush_height;
14513
14514       boolean use_bd_engine = TRUE;
14515       boolean use_em_engine = TRUE;
14516       boolean use_sp_engine = TRUE;
14517       boolean use_mm_engine = TRUE;
14518
14519       for (x = 0; x < MAX_LEV_FIELDX; x++)
14520       {
14521         for (y = 0; y < MAX_LEV_FIELDY; y++)
14522         {
14523           int element = Tile[x][y];
14524
14525           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14526             use_bd_engine = FALSE;
14527
14528           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14529             use_em_engine = FALSE;
14530
14531           if (!IS_SP_ELEMENT(element))
14532             use_sp_engine = FALSE;
14533
14534           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14535             use_mm_engine = FALSE;
14536         }
14537       }
14538
14539       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14540                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14541                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14542                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14543                                 GAME_ENGINE_TYPE_RND);
14544
14545       // update element selection list
14546       ReinitializeElementList();
14547       ModifyEditorElementList();
14548
14549       SetBorderElement();
14550
14551       DrawEditModeWindow();
14552       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14553     }
14554
14555     return;
14556   }
14557
14558   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14559     return;
14560
14561   if (mode == CB_AREA_TO_BRUSH)
14562   {
14563     int from_lx, from_ly;
14564
14565     if (from_x > to_x)
14566       swap_numbers(&from_x, &to_x);
14567
14568     if (from_y > to_y)
14569       swap_numbers(&from_y, &to_y);
14570
14571     brush_width = to_x - from_x + 1;
14572     brush_height = to_y - from_y + 1;
14573
14574     from_lx = from_x + level_xpos;
14575     from_ly = from_y + level_ypos;
14576
14577     for (y = 0; y < brush_height; y++)
14578     {
14579       for (x = 0; x < brush_width; x++)
14580       {
14581         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14582
14583         if (button != 1)
14584           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14585       }
14586     }
14587
14588     if (button != 1)
14589       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14590
14591     delete_old_brush = FALSE;
14592   }
14593   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14594            mode == CB_BRUSH_TO_LEVEL)
14595   {
14596     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14597     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14598     int cursor_from_x = cursor_x - brush_width / 2;
14599     int cursor_from_y = cursor_y - brush_height / 2;
14600     int border_from_x = cursor_x, border_from_y = cursor_y;
14601     int border_to_x = cursor_x, border_to_y = cursor_y;
14602
14603     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14604       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14605
14606     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14607         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14608     {
14609       delete_old_brush = FALSE;
14610
14611       return;
14612     }
14613
14614     for (y = 0; y < brush_height; y++)
14615     {
14616       for (x = 0; x < brush_width; x++)
14617       {
14618         int sx = cursor_from_x + x;
14619         int sy = cursor_from_y + y;
14620         int lx = sx + level_xpos;
14621         int ly = sy + level_ypos;
14622         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14623         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14624                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14625                        brush_buffer[x][y] : new_element);
14626
14627         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14628         {
14629           if (sx < border_from_x)
14630             border_from_x = sx;
14631           else if (sx > border_to_x)
14632             border_to_x = sx;
14633           if (sy < border_from_y)
14634             border_from_y = sy;
14635           else if (sy > border_to_y)
14636             border_to_y = sy;
14637
14638           DrawBrushElement(sx, sy, element, change_level);
14639         }
14640       }
14641     }
14642
14643     if (mode != CB_DELETE_OLD_CURSOR)
14644       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14645
14646     last_cursor_x = cursor_x;
14647     last_cursor_y = cursor_y;
14648
14649     delete_old_brush = TRUE;
14650   }
14651   else if (mode == CB_FLIP_BRUSH_X)
14652   {
14653     for (y = 0; y < brush_height; y++)
14654       for (x = 0; x < (brush_width + 1) / 2; x++)
14655         SwapFlippedTiles(&brush_buffer[x][y],
14656                          &brush_buffer[brush_width - x - 1][y], mode);
14657
14658     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14659   }
14660   else if (mode == CB_FLIP_BRUSH_Y)
14661   {
14662     for (y = 0; y < (brush_height + 1) / 2; y++)
14663       for (x = 0; x < brush_width; x++)
14664         SwapFlippedTiles(&brush_buffer[x][y],
14665                          &brush_buffer[x][brush_height - y - 1], mode);
14666
14667     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14668   }
14669   else if (mode == CB_FLIP_BRUSH_XY)
14670   {
14671     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14672
14673     for (y = 0; y < MAX(brush_width, brush_height); y++)
14674       for (x = 0; x <= y; x++)
14675         SwapFlippedTiles(&brush_buffer[x][y],
14676                          &brush_buffer[y][x], mode);
14677
14678     swap_numbers(&brush_width, &brush_height);
14679
14680     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14681   }
14682
14683   if (mode == CB_UPDATE_BRUSH_POSITION)
14684   {
14685     last_cursor_x = from_x;
14686     last_cursor_y = from_y;
14687   }
14688 }
14689
14690 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14691                             int button)
14692 {
14693   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14694 }
14695
14696 static void CopyBrushToLevel(int x, int y, int button)
14697 {
14698   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14699 }
14700
14701 static void CopyBrushToCursor(int x, int y)
14702 {
14703   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14704 }
14705
14706 static void UpdateBrushPosition(int x, int y)
14707 {
14708   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14709 }
14710
14711 static void DeleteBrushFromCursor(void)
14712 {
14713   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14714 }
14715
14716 static void FlipBrushX(void)
14717 {
14718   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14719 }
14720
14721 static void FlipBrushY(void)
14722 {
14723   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14724 }
14725
14726 static void RotateBrush(void)
14727 {
14728   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14729   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14730 }
14731
14732 void DumpBrush(void)
14733 {
14734   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14735 }
14736
14737 void DumpBrush_Small(void)
14738 {
14739   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14740 }
14741
14742 void CopyClipboardToBrush(void)
14743 {
14744   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14745 }
14746
14747 void CopyBrushToClipboard(void)
14748 {
14749   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14750 }
14751
14752 void CopyBrushToClipboard_Small(void)
14753 {
14754   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14755 }
14756
14757 void UndoLevelEditorOperation(void)
14758 {
14759   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14760 }
14761
14762 void RedoLevelEditorOperation(void)
14763 {
14764   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14765 }
14766
14767 static void FloodFill(int from_x, int from_y, int fill_element)
14768 {
14769   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14770 }
14771
14772 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14773 {
14774   int from_x = from_sx2 + 2 * level_xpos;
14775   int from_y = from_sy2 + 2 * level_ypos;
14776   int max_fillx = lev_fieldx * 2;
14777   int max_filly = lev_fieldy * 2;
14778   short Fill[max_fillx][max_filly];
14779   int x, y;
14780
14781   for (x = 0; x < max_fillx; x++)
14782     for (y = 0; y < max_filly; y++)
14783       Fill[x][y] = getLevelElementHiRes(x, y);
14784
14785   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14786                     Fill, max_fillx, max_filly);
14787
14788   for (x = 0; x < max_fillx; x++)
14789     for (y = 0; y < max_filly; y++)
14790       if (Fill[x][y] == fill_element)
14791         SetLevelElementHiRes(x, y, Fill[x][y]);
14792 }
14793
14794 // values for DrawLevelText() modes
14795 #define TEXT_INIT               0
14796 #define TEXT_SETCURSOR          1
14797 #define TEXT_WRITECHAR          2
14798 #define TEXT_BACKSPACE          3
14799 #define TEXT_NEWLINE            4
14800 #define TEXT_END                5
14801 #define TEXT_QUERY_TYPING       6
14802
14803 static int DrawLevelText(int sx, int sy, char letter, int mode)
14804 {
14805   static short delete_buffer[MAX_LEV_FIELDX];
14806   static int start_sx;
14807   static int last_sx, last_sy;
14808   static boolean typing = FALSE;
14809   int letter_element;
14810   int lx = 0, ly = 0;
14811
14812   // map lower case letters to upper case and convert special characters
14813   if (letter >= 'a' && letter <= 'z')
14814     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
14815   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
14816     letter_element = EL_CHAR_AUMLAUT;
14817   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
14818     letter_element = EL_CHAR_OUMLAUT;
14819   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
14820     letter_element = EL_CHAR_UUMLAUT;
14821   else if (letter == '^')
14822     letter_element = EL_CHAR_COPYRIGHT;
14823   else
14824     letter_element = EL_CHAR_ASCII0 + letter;
14825
14826   if (mode != TEXT_INIT)
14827   {
14828     if (!typing)
14829       return FALSE;
14830
14831     if (mode != TEXT_SETCURSOR)
14832     {
14833       sx = last_sx;
14834       sy = last_sy;
14835     }
14836
14837     lx = last_sx + level_xpos;
14838     ly = last_sy + level_ypos;
14839   }
14840
14841   switch (mode)
14842   {
14843     case TEXT_INIT:
14844       if (typing)
14845         DrawLevelText(0, 0, 0, TEXT_END);
14846
14847       typing = TRUE;
14848       start_sx = sx;
14849       last_sx = sx;
14850       last_sy = sy;
14851       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
14852       break;
14853
14854     case TEXT_SETCURSOR:
14855       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
14856       DrawAreaBorder(sx, sy, sx, sy);
14857       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
14858                      ed_tilesize, ed_tilesize);
14859       last_sx = sx;
14860       last_sy = sy;
14861       break;
14862
14863     case TEXT_WRITECHAR:
14864       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
14865       {
14866         if (new_element1 >= EL_STEEL_CHAR_START &&
14867             new_element1 <= EL_STEEL_CHAR_END)
14868           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
14869
14870         delete_buffer[sx - start_sx] = Tile[lx][ly];
14871         Tile[lx][ly] = letter_element;
14872
14873         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
14874           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
14875         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
14876           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
14877         else
14878           DrawLevelText(0, 0, 0, TEXT_END);
14879
14880         level.changed = TRUE;
14881       }
14882       break;
14883
14884     case TEXT_BACKSPACE:
14885       if (sx > start_sx)
14886       {
14887         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
14888         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
14889         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
14890       }
14891       break;
14892
14893     case TEXT_NEWLINE:
14894       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
14895         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
14896       else
14897         DrawLevelText(0, 0, 0, TEXT_END);
14898       break;
14899
14900     case TEXT_END:
14901       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14902       DrawEditorElement(sx, sy, Tile[lx][ly]);
14903       StopTextInput();
14904       typing = FALSE;
14905       break;
14906
14907     case TEXT_QUERY_TYPING:
14908       break;
14909
14910     default:
14911       break;
14912   }
14913
14914   return typing;
14915 }
14916
14917 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
14918                           int element, boolean change_level)
14919 {
14920   int lx = sx + level_xpos;
14921   int ly = sy + level_ypos;
14922
14923   if (element == -1)
14924     DrawEditorElement(sx, sy, Tile[lx][ly]);
14925   else
14926     DrawAreaBorder(sx, sy, sx, sy);
14927 }
14928
14929 static void CheckLevelBorderElement(boolean redraw_playfield)
14930 {
14931   int last_border_element = BorderElement;
14932
14933   SetBorderElement();
14934
14935   if (redraw_playfield && BorderElement != last_border_element)
14936     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14937 }
14938
14939 static void CopyLevelToUndoBuffer(int mode)
14940 {
14941   static boolean accumulated_undo = FALSE;
14942   boolean new_undo_buffer_position = TRUE;
14943   int x, y;
14944
14945   if (undo_buffer_steps == 0)
14946     accumulated_undo = FALSE;
14947
14948   switch (mode)
14949   {
14950     case UNDO_IMMEDIATE:
14951       accumulated_undo = FALSE;
14952       break;
14953
14954     case UNDO_ACCUMULATE:
14955       if (accumulated_undo)
14956         new_undo_buffer_position = FALSE;
14957       accumulated_undo = TRUE;
14958       break;
14959
14960     default:
14961       break;
14962   }
14963
14964   if (new_undo_buffer_position)
14965   {
14966     // advance position in undo buffer ring
14967     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
14968
14969     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
14970       undo_buffer_steps++;
14971   }
14972
14973   // always reset redo buffer when storing level change into undo buffer
14974   redo_buffer_steps = 0;
14975
14976   for (x = 0; x < lev_fieldx; x++)
14977     for (y = 0; y < lev_fieldy; y++)
14978       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
14979
14980   // check if drawing operation forces change of border style
14981   CheckLevelBorderElement(TRUE);
14982
14983   level.changed = TRUE;
14984 }
14985
14986 static void RandomPlacement(int new_element)
14987 {
14988   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14989   int num_free_positions = 0;
14990   int num_percentage, num_elements;
14991   int x, y;
14992
14993   ResetIntelliDraw();
14994
14995   // determine number of free positions for randomly placing the new element
14996   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
14997   {
14998     free_position[x][y] =
14999       (random_placement_background_restricted ?
15000        Tile[x][y] == random_placement_background_element :
15001        Tile[x][y] != new_element);
15002
15003     if (free_position[x][y])
15004       num_free_positions++;
15005   }
15006
15007   // determine number of new elements to place there
15008   num_percentage = num_free_positions * random_placement_value / 100;
15009   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
15010                   num_percentage : random_placement_value);
15011
15012   // if less free positions than elements to place, fill all these positions
15013   if (num_free_positions < num_elements)
15014   {
15015     for (x = 0; x < lev_fieldx; x++)
15016       for (y = 0; y < lev_fieldy; y++)
15017         if (free_position[x][y])
15018           SetElement(x, y, new_element);
15019   }
15020   else
15021   {
15022     while (num_elements > 0)
15023     {
15024       x = GetSimpleRandom(lev_fieldx);
15025       y = GetSimpleRandom(lev_fieldy);
15026
15027       // don't place element at the same position twice
15028       if (free_position[x][y])
15029       {
15030         free_position[x][y] = FALSE;
15031         SetElement(x, y, new_element);
15032         num_elements--;
15033       }
15034     }
15035   }
15036
15037   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15038   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15039 }
15040
15041 static void WrapLevel(int dx, int dy)
15042 {
15043   int wrap_dx = lev_fieldx - dx;
15044   int wrap_dy = lev_fieldy - dy;
15045   int x, y;
15046
15047   for (x = 0; x < lev_fieldx; x++)
15048     for (y = 0; y < lev_fieldy; y++)
15049       TileBackup[x][y] = Tile[x][y];
15050
15051   for (x = 0; x < lev_fieldx; x++)
15052     for (y = 0; y < lev_fieldy; y++)
15053       Tile[x][y] =
15054         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
15055
15056   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15057   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
15058 }
15059
15060 static void DrawAreaElementHighlight(boolean highlighted,
15061                                      boolean highlighted_similar)
15062 {
15063   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15064
15065   if (!highlighted)
15066     return;
15067
15068   int x, y;
15069
15070   for (x = 0; x < ed_fieldx; x++)
15071   {
15072     for (y = 0; y < ed_fieldy; y++)
15073     {
15074       boolean highlight = FALSE;
15075       int lx = x + level_xpos;
15076       int ly = y + level_ypos;
15077
15078       if (!IN_LEV_FIELD(lx, ly))
15079         continue;
15080
15081       // check if element is the same
15082       if (Tile[lx][ly] == new_element1)
15083         highlight = TRUE;
15084
15085       // check if element is similar
15086       if (highlighted_similar &&
15087           strEqual(element_info[Tile[lx][ly]].class_name,
15088                    element_info[new_element1].class_name))
15089         highlight = TRUE;
15090
15091       // check if element is matching MM style wall
15092       if (IS_MM_WALL(Tile[lx][ly]) &&
15093           map_mm_wall_element(Tile[lx][ly]) == new_element1)
15094         highlight = TRUE;
15095
15096       if (!highlight)
15097         continue;
15098
15099       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
15100       {
15101         int i;
15102
15103         for (i = 0; i < 4; i++)
15104         {
15105           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
15106             continue;
15107
15108           int xx = x * 2 + (i % 2);
15109           int yy = y * 2 + (i / 2);
15110           int sx = SX + xx * ed_tilesize / 2;
15111           int sy = SY + yy * ed_tilesize / 2;
15112           int from_sx = sx;
15113           int from_sy = sy;
15114           int to_sx = sx + ed_tilesize / 2 - 1;
15115           int to_sy = sy + ed_tilesize / 2 - 1;
15116
15117           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15118           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15119           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15120           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15121         }
15122       }
15123       else
15124       {
15125         int sx = SX + x * ed_tilesize;
15126         int sy = SY + y * ed_tilesize;
15127         int from_sx = sx;
15128         int from_sy = sy;
15129         int to_sx = sx + ed_tilesize - 1;
15130         int to_sy = sy + ed_tilesize - 1;
15131
15132         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15133         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15134         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15135         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15136       }
15137     }
15138   }
15139 }
15140
15141 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15142 {
15143   char *template_filename_old = getLocalLevelTemplateFilename();
15144   char *template_filename_new =
15145     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15146
15147   if (copyFile(template_filename_old, template_filename_new) != 0)
15148     Request("Cannot copy level template!", REQ_CONFIRM);
15149
15150   free(template_filename_new);
15151 }
15152
15153 static void HandleDrawingAreas(struct GadgetInfo *gi)
15154 {
15155   static boolean started_inside_drawing_area = FALSE;
15156   static int last_sx = -1;
15157   static int last_sy = -1;
15158   static int last_sx2 = -1;
15159   static int last_sy2 = -1;
15160   int id = gi->custom_id;
15161   int type_id = gi->custom_type_id;
15162   boolean button_press_event;
15163   boolean button_release_event;
15164   boolean inside_drawing_area = !gi->event.off_borders;
15165   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15166   int actual_drawing_function;
15167   int button = gi->event.button;
15168   int new_element = BUTTON_ELEMENT(button);
15169   int sx = gi->event.x, sy = gi->event.y;
15170   int min_sx = 0, min_sy = 0;
15171   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15172   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15173   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15174   int sx2 = gi->event.mx / mini_item_xsize;
15175   int sy2 = gi->event.my / mini_item_ysize;
15176   int dx = sx2 % 2;
15177   int dy = sy2 % 2;
15178   int lx = 0, ly = 0;
15179   int x, y;
15180
15181   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15182   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15183
15184   // make sure to stay inside drawing area boundaries
15185   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15186   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15187
15188   if (draw_level)
15189   {
15190     int min_lx = 0, min_ly = 0;
15191     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15192
15193     // get positions inside level field
15194     lx = sx + level_xpos;
15195     ly = sy + level_ypos;
15196
15197     if (!IN_LEV_FIELD(lx, ly))
15198       inside_drawing_area = FALSE;
15199
15200     // make sure to stay inside level field boundaries
15201     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15202     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15203
15204     // correct drawing area positions accordingly
15205     sx = lx - level_xpos;
15206     sy = ly - level_ypos;
15207   }
15208
15209   // also correct MM wall-sized (double) drawing area positions accordingly
15210   if (sx2 / 2 < sx || sx2 / 2 > sx)
15211   {
15212     dx = (sx2 / 2 < sx ? 0 : 1);
15213     sx2 = sx * 2 + dx;
15214   }
15215   if (sy2 / 2 < sy || sy2 / 2 > sy)
15216   {
15217     dy = (sy2 / 2 < sy ? 0 : 1);
15218     sy2 = sy * 2 + dy;
15219   }
15220
15221   if (!button_press_event && !button_release_event)
15222   {
15223     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15224     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15225                              isHiresTileElement(old_element) &&
15226                              isHiresDrawElement(new_element));
15227
15228     // prevent handling events for every pixel position when moving mouse
15229     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15230         (sx2 == last_sx2 && sy2 == last_sy2))
15231       return;
15232   }
15233
15234   last_sx = sx;
15235   last_sy = sy;
15236   last_sx2 = sx2;
15237   last_sy2 = sy2;
15238
15239   if (button_press_event)
15240     started_inside_drawing_area = inside_drawing_area;
15241
15242   if (!started_inside_drawing_area)
15243     return;
15244
15245   if (!IS_VALID_BUTTON(button))
15246     return;
15247
15248   // handle info callback for each invocation of action callback
15249   gi->callback_info(gi);
15250
15251   // automatically switch to 'single item' drawing mode, if needed
15252   actual_drawing_function =
15253     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15254      drawing_function : GADGET_ID_SINGLE_ITEMS);
15255
15256   // clicking into drawing area with pressed Control key picks element
15257   if (GetKeyModState() & KMOD_Control)
15258   {
15259     last_drawing_function = drawing_function;
15260     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15261   }
15262
15263   if (GetKeyModState() & KMOD_Shift)
15264   {
15265     if (button_press_event || button_release_event)
15266       ResetIntelliDraw();
15267   }
15268
15269   SetDrawModeHiRes(-1);         // reset to normal draw mode
15270
15271   switch (actual_drawing_function)
15272   {
15273     case GADGET_ID_SINGLE_ITEMS:
15274       if (draw_level)
15275       {
15276         if (button_release_event)
15277         {
15278           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15279
15280           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15281               !inside_drawing_area)
15282             DeleteBrushFromCursor();
15283
15284           break;
15285         }
15286
15287         if (draw_with_brush)
15288         {
15289           CopyBrushToLevel(sx, sy, button);
15290         }
15291         else
15292         {
15293           SetDrawModeHiRes(new_element);
15294
15295           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15296           {
15297             // remove player at old position
15298             for (y = 0; y < lev_fieldy; y++)
15299             {
15300               for (x = 0; x < lev_fieldx; x++)
15301               {
15302                 int old_element = Tile[x][y];
15303
15304                 if (IS_PLAYER_ELEMENT(old_element) &&
15305                     IS_PLAYER_ELEMENT(new_element))
15306                 {
15307                   int replaced_with_element =
15308                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15309                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15310
15311                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15312                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15313
15314                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15315                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15316
15317                      new_element >= EL_PLAYER_1 &&
15318                      new_element <= EL_PLAYER_4 &&
15319                      new_element == old_element ? EL_EMPTY :
15320
15321                      old_element);
15322
15323                   SetElement(x, y, replaced_with_element);
15324                 }
15325                 else if (IS_MM_MCDUFFIN(old_element) &&
15326                          IS_MM_MCDUFFIN(new_element))
15327                 {
15328                   // remove McDuffin at old position
15329                   SetElement(x, y, EL_EMPTY);
15330                 }
15331               }
15332             }
15333           }
15334
15335           SetElementButton(lx, ly, dx, dy, new_element, button);
15336         }
15337       }
15338       else if (!button_release_event)
15339       {
15340         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15341
15342         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15343           DrawMiniGraphicExt(drawto,
15344                              gi->x + sx * MINI_TILEX,
15345                              gi->y + sy * MINI_TILEY,
15346                              el2edimg(new_element));
15347         else
15348           DrawFixedGraphicExt(drawto,
15349                               gi->x + sx * TILEX,
15350                               gi->y + sy * TILEY,
15351                               el2edimg(new_element), 0);
15352
15353         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15354           new_element = GFX_ELEMENT(new_element);
15355
15356         drawingarea_info[type_id].value[pos] = new_element;
15357
15358         CopyElementPropertiesToGame(properties_element);
15359
15360         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15361         {
15362           UpdateCustomElementGraphicGadgets();
15363
15364           FrameCounter = 0;     // restart animation frame counter
15365         }
15366       }
15367       break;
15368
15369     case GADGET_ID_CONNECTED_ITEMS:
15370       {
15371         static int last_sx = -1;
15372         static int last_sy = -1;
15373
15374         if (button_release_event)
15375           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15376
15377         SetDrawModeHiRes(new_element);
15378
15379         if (getDrawModeHiRes())
15380         {
15381           sx = sx2;
15382           sy = sy2;
15383         }
15384
15385         if (!button_press_event)
15386           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15387
15388         last_sx = sx;
15389         last_sy = sy;
15390       }
15391       break;
15392
15393     case GADGET_ID_LINE:
15394     case GADGET_ID_ARC:
15395     case GADGET_ID_RECTANGLE:
15396     case GADGET_ID_FILLED_BOX:
15397       SetDrawModeHiRes(new_element);
15398
15399       if (getDrawModeHiRes())
15400       {
15401         sx = sx2;
15402         sy = sy2;
15403       }
15404       // FALLTHROUGH
15405     case GADGET_ID_GRAB_BRUSH:
15406     case GADGET_ID_TEXT:
15407       {
15408         static int last_sx = -1;
15409         static int last_sy = -1;
15410         static int start_sx = -1;
15411         static int start_sy = -1;
15412         void (*draw_func)(int, int, int, int, int, boolean);
15413
15414         if (drawing_function == GADGET_ID_LINE)
15415           draw_func = DrawLine;
15416         else if (drawing_function == GADGET_ID_ARC)
15417           draw_func = DrawArc;
15418         else if (drawing_function == GADGET_ID_RECTANGLE)
15419           draw_func = DrawBox;
15420         else if (drawing_function == GADGET_ID_FILLED_BOX)
15421           draw_func = DrawFilledBox;
15422         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15423           draw_func = SelectArea;
15424         else // (drawing_function == GADGET_ID_TEXT)
15425           draw_func = SetTextCursor;
15426
15427         if (button_press_event)
15428         {
15429           draw_func(sx, sy, sx, sy, new_element, FALSE);
15430           start_sx = last_sx = sx;
15431           start_sy = last_sy = sy;
15432
15433           if (drawing_function == GADGET_ID_TEXT)
15434             DrawLevelText(0, 0, 0, TEXT_END);
15435         }
15436         else if (button_release_event)
15437         {
15438           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15439           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15440           {
15441             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15442             CopyBrushToCursor(sx, sy);
15443             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15444                           MB_LEFTBUTTON);
15445             draw_with_brush = TRUE;
15446           }
15447           else if (drawing_function == GADGET_ID_TEXT)
15448             DrawLevelText(sx, sy, 0, TEXT_INIT);
15449           else
15450             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15451         }
15452         else if (last_sx != sx || last_sy != sy)
15453         {
15454           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15455           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15456             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15457           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15458           last_sx = sx;
15459           last_sy = sy;
15460         }
15461       }
15462       break;
15463
15464     case GADGET_ID_FLOOD_FILL:
15465       if (button_press_event && Tile[lx][ly] != new_element)
15466       {
15467         if (IS_MM_WALL_EDITOR(new_element))
15468           FloodFillWall_MM(sx2, sy2, new_element);
15469         else
15470           FloodFill(lx, ly, new_element);
15471
15472         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15473         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15474       }
15475       break;
15476
15477     case GADGET_ID_PICK_ELEMENT:
15478       if (button_release_event)
15479         ClickOnGadget(level_editor_gadget[last_drawing_function],
15480                       MB_LEFTBUTTON);
15481       else if (draw_level)
15482         PickDrawingElement(button, Tile[lx][ly]);
15483       else
15484       {
15485         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15486
15487         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15488       }
15489
15490     default:
15491       break;
15492   }
15493
15494   // do not mark level as modified for certain non-level-changing gadgets
15495   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15496        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15497       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15498       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15499     return;
15500
15501   level.changed = TRUE;
15502 }
15503
15504 static void HandleCounterButtons(struct GadgetInfo *gi)
15505 {
15506   int gadget_id = gi->custom_id;
15507   int counter_id = gi->custom_type_id;
15508   int button = gi->event.button;
15509   int *counter_value = counterbutton_info[counter_id].value;
15510   int step = BUTTON_STEPSIZE(button) *
15511     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15512
15513   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15514   {
15515     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15516     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15517     boolean level_changed = LevelChanged();
15518
15519     if ((level_changed && pressed) || (!level_changed && released))
15520       return;
15521
15522     if (level_changed && !Request("Level has changed! Discard changes?",
15523                                   REQ_ASK))
15524     {
15525       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15526         ModifyEditorCounterValue(counter_id, *counter_value);
15527
15528       return;
15529     }
15530   }
15531
15532   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15533     *counter_value = gi->textinput.number_value;
15534   else
15535     ModifyEditorCounterValue(counter_id, *counter_value + step);
15536
15537   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15538   {
15539     int last_game_engine_type = level.game_engine_type;
15540
15541     LoadLevel(level_nr);
15542     LoadScore(level_nr);
15543
15544     SaveLevelSetup_SeriesInfo();
15545
15546     TapeErase();
15547
15548     ResetUndoBuffer();
15549     DrawEditModeWindow();
15550
15551     if (level.game_engine_type != last_game_engine_type)
15552     {
15553       // update element selection list
15554       ReinitializeElementList();
15555       ModifyEditorElementList();
15556     }
15557
15558     return;
15559   }
15560
15561   switch (counter_id)
15562   {
15563     case ED_COUNTER_ID_YAMYAM_CONTENT:
15564       DrawYamYamContentAreas();
15565       break;
15566
15567     case ED_COUNTER_ID_BALL_CONTENT:
15568       DrawMagicBallContentAreas();
15569       break;
15570
15571     case ED_COUNTER_ID_ANDROID_CONTENT:
15572       DrawAndroidElementArea();
15573       break;
15574
15575     case ED_COUNTER_ID_GROUP_CONTENT:
15576       DrawGroupElementArea();
15577       CopyGroupElementPropertiesToGame(properties_element);
15578       break;
15579
15580     case ED_COUNTER_ID_INVENTORY_SIZE:
15581       DrawPlayerInitialInventoryArea(properties_element);
15582       break;
15583
15584     case ED_COUNTER_ID_MM_BALL_CONTENT:
15585       DrawMMBallContentArea();
15586       break;
15587
15588     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15589     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15590       DrawEnvelopeTextArea(-1);
15591       break;
15592
15593     case ED_COUNTER_ID_LEVEL_XSIZE:
15594     case ED_COUNTER_ID_LEVEL_YSIZE:
15595       lev_fieldx = level.fieldx;
15596       lev_fieldy = level.fieldy;
15597
15598       // check if resizing of level results in change of border border
15599       SetBorderElement();
15600
15601       break;
15602
15603     default:
15604       break;
15605   }
15606
15607   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15608        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15609       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15610        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15611     CopyElementPropertiesToGame(properties_element);
15612
15613   // do not mark level as modified for certain non-level-changing gadgets
15614   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15615        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15616       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15617        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15618     return;
15619
15620   level.changed = TRUE;
15621 }
15622
15623 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15624 {
15625   int type_id = gi->custom_type_id;
15626
15627   strcpy(textinput_info[type_id].value, gi->textinput.value);
15628
15629   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15630   {
15631     CopyElementPropertiesToGame(properties_element);
15632
15633     ModifyEditorElementList();  // update changed button info text
15634   }
15635
15636   // do not mark level as modified for certain non-level-changing gadgets
15637   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15638       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15639     return;
15640
15641   level.changed = TRUE;
15642 }
15643
15644 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15645 {
15646   int type_id = gi->custom_type_id;
15647
15648   strncpy(textarea_info[type_id].value, gi->textarea.value,
15649           MAX_ENVELOPE_TEXT_LEN);
15650   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15651
15652   level.changed = TRUE;
15653 }
15654
15655 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15656 {
15657   int type_id = gi->custom_type_id;
15658   int value_old = *selectbox_info[type_id].value;
15659   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15660
15661   *selectbox_info[type_id].value = value_new;
15662
15663   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15664   {
15665     DrawLevelConfigWindow();
15666   }
15667   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15668   {
15669     element_info[properties_element].current_change_page = gi->selectbox.index;
15670
15671     DrawPropertiesWindow();
15672   }
15673   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15674             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15675            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15676             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15677            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15678   {
15679     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15680     {
15681       // when changing action type, also check action mode and action arg
15682       if (value_old != value_new)
15683         setSelectboxSpecialActionVariablesIfNeeded();
15684
15685       DrawPropertiesChange();
15686     }
15687
15688     CopyElementPropertiesToGame(properties_element);
15689   }
15690   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15691   {
15692     // show or hide "engine" tabulator depending on game engine type
15693     DrawLevelConfigWindow();
15694
15695     // update element selection list depending on game engine type
15696     ReinitializeElementList();
15697     ModifyEditorElementList();
15698   }
15699   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15700   {
15701     // update BD cycle delay counter gadgets depending on BD scheduling type
15702     DrawLevelConfigWindow();
15703   }
15704
15705   // do not mark level as modified for certain non-level-changing gadgets
15706   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15707       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15708     return;
15709
15710   level.changed = TRUE;
15711 }
15712
15713 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15714 {
15715   int type_id = gi->custom_type_id;
15716   int i;
15717
15718   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15719       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15720   {
15721     edit_mode_levelconfig = gi->custom_type_id;
15722
15723     DrawLevelConfigWindow();
15724   }
15725   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15726            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15727   {
15728     edit_mode_properties = gi->custom_type_id;
15729
15730     DrawPropertiesWindow();
15731   }
15732   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15733            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15734   {
15735     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15736
15737     // backup original "level.field" (needed to track playfield changes)
15738     CopyPlayfield(level.field, TileBackup);
15739
15740     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15741     CopyPlayfield(Tile, level.field);
15742
15743     if (new_template ||
15744         Request("Save this template and kill the old?", REQ_ASK))
15745       SaveLevelTemplate();
15746
15747     if (new_template)
15748       Request("Template saved!", REQ_CONFIRM);
15749
15750     // restore original "level.field" (needed to track playfield changes)
15751     CopyPlayfield(TileBackup, level.field);
15752   }
15753   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15754   {
15755     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15756
15757     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15758         leveldir_current->readonly)
15759     {
15760       Request("This level set is read-only!", REQ_CONFIRM);
15761
15762       return;
15763     }
15764
15765     if (strEqual(levelset_name, ""))
15766     {
15767       Request("Please enter level set title!", REQ_CONFIRM);
15768
15769       return;
15770     }
15771
15772     if (strEqual(levelset_author, ""))
15773     {
15774       Request("Please enter level set author!", REQ_CONFIRM);
15775
15776       return;
15777     }
15778
15779     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15780     {
15781       if (UpdateUserLevelSet(levelset_subdir,
15782                              levelset_name,
15783                              levelset_author,
15784                              levelset_num_levels))
15785       {
15786         Request("Level set updated!", REQ_CONFIRM);
15787       }
15788       else
15789       {
15790         Request("Updating level set failed!", REQ_CONFIRM);
15791       }
15792     }
15793     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15794     {
15795       if (level.changed && !Request("Level has changed! Discard changes?",
15796                                      REQ_ASK))
15797         return;
15798
15799       if (CreateUserLevelSet(levelset_subdir,
15800                              levelset_name,
15801                              levelset_author,
15802                              levelset_num_levels,
15803                              levelset_use_levelset_artwork))
15804       {
15805         if (levelset_copy_level_template)
15806           CopyLevelTemplateToUserLevelSet(levelset_subdir);
15807
15808         Request("New level set created!", REQ_CONFIRM);
15809
15810         AddUserLevelSetToLevelInfo(levelset_subdir);
15811         ChangeEditorToLevelSet(levelset_subdir);
15812       }
15813       else
15814       {
15815         Request("Creating new level set failed!", REQ_CONFIRM);
15816       }
15817     }
15818   }
15819   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
15820            custom_element.num_change_pages < MAX_CHANGE_PAGES)
15821   {
15822     struct ElementInfo *ei = &element_info[properties_element];
15823
15824     // when modifying custom element, ask for copying level template
15825     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15826       return;
15827
15828     setElementChangePages(ei, ei->num_change_pages + 1);
15829
15830     // set new change page to be new current change page
15831     ei->current_change_page = ei->num_change_pages - 1;
15832     ei->change = &ei->change_page[ei->current_change_page];
15833
15834     setElementChangeInfoToDefaults(ei->change);
15835
15836     DrawPropertiesWindow();
15837
15838     level.changed = TRUE;
15839   }
15840   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
15841            custom_element.num_change_pages > MIN_CHANGE_PAGES)
15842   {
15843     struct ElementInfo *ei = &element_info[properties_element];
15844
15845     // when modifying custom element, ask for copying level template
15846     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15847       return;
15848
15849     // copy all change pages after change page to be deleted
15850     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
15851       ei->change_page[i] = ei->change_page[i + 1];
15852
15853     setElementChangePages(ei, ei->num_change_pages - 1);
15854
15855     DrawPropertiesWindow();
15856
15857     level.changed = TRUE;
15858   }
15859 }
15860
15861 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
15862 {
15863   int type_id = gi->custom_type_id;
15864
15865   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
15866       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
15867   {
15868     struct ElementInfo *ei = &element_info[properties_element];
15869     int step = BUTTON_STEPSIZE(gi->event.button);
15870
15871     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
15872     ei->current_change_page += step;
15873
15874     if (ei->current_change_page < 0)
15875       ei->current_change_page = 0;
15876     else if (ei->current_change_page >= ei->num_change_pages)
15877       ei->current_change_page = ei->num_change_pages - 1;
15878
15879     DrawPropertiesWindow();
15880   }
15881   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
15882            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
15883   {
15884     struct ElementInfo *ei = &element_info[properties_element];
15885     int current_change_page = ei->current_change_page;
15886
15887     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
15888     {
15889       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
15890         ei->change_page[current_change_page];
15891     }
15892     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
15893     {
15894       // when modifying custom element, ask for copying level template
15895       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15896         return;
15897
15898       ei->change_page[current_change_page] =
15899         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
15900
15901       level.changed = TRUE;
15902     }
15903
15904     DrawPropertiesWindow();
15905   }
15906 }
15907
15908 static void HandleRadiobuttons(struct GadgetInfo *gi)
15909 {
15910   int type_id = gi->custom_type_id;
15911
15912   *radiobutton_info[type_id].value =
15913     radiobutton_info[type_id].checked_value;
15914
15915   // do not mark level as modified for certain non-level-changing gadgets
15916   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
15917       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
15918     return;
15919
15920   level.changed = TRUE;
15921 }
15922
15923 static void HandleCheckbuttons(struct GadgetInfo *gi)
15924 {
15925   int type_id = gi->custom_type_id;
15926
15927   *checkbutton_info[type_id].value ^= TRUE;
15928
15929   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
15930       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
15931       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
15932       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
15933          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
15934         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
15935          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
15936        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
15937   {
15938     CopyElementPropertiesToGame(properties_element);
15939   }
15940
15941   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
15942   {
15943     UpdateCustomElementGraphicGadgets();
15944   }
15945   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
15946            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
15947   {
15948     boolean template_related_changes_found = FALSE;
15949     int i;
15950
15951     // check if any custom, group or empty elements have been changed
15952     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
15953       if ((IS_CUSTOM_ELEMENT(i) ||
15954            IS_GROUP_ELEMENT(i) ||
15955            IS_EMPTY_ELEMENT(i)) &&
15956           element_info[i].modified_settings)
15957         template_related_changes_found = TRUE;
15958
15959     if (level.use_custom_template &&
15960         !fileExists(getGlobalLevelTemplateFilename()))
15961     {
15962       Request("No level template found!", REQ_CONFIRM);
15963
15964       level.use_custom_template = FALSE;
15965
15966       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
15967
15968       return;
15969     }
15970
15971     if (level.use_custom_template &&
15972         template_related_changes_found &&
15973         !Request("Discard changes and use level template?", REQ_ASK))
15974     {
15975       level.use_custom_template = FALSE;
15976
15977       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
15978
15979       return;
15980     }
15981
15982     if (!level.use_custom_template &&
15983         Request("Copy settings from level template?", REQ_ASK))
15984     {
15985       return;
15986     }
15987
15988     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
15989
15990     DrawEditModeWindow();
15991   }
15992   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
15993   {
15994     if (setup.editor.use_template_for_new_levels &&
15995         !fileExists(getGlobalLevelTemplateFilename()))
15996     {
15997       Request("No level template found!", REQ_CONFIRM);
15998
15999       return;
16000     }
16001
16002     if (setup.editor.use_template_for_new_levels &&
16003         level.changed &&
16004         !Request("Discard level and load template?", REQ_ASK))
16005     {
16006       return;
16007     }
16008
16009     if (!setup.editor.use_template_for_new_levels &&
16010         level.changed &&
16011         !Request("Discard level and use empty level?", REQ_ASK))
16012     {
16013       return;
16014     }
16015
16016     LoadLevel(level_nr);
16017     LoadScore(level_nr);
16018
16019     TapeErase();
16020
16021     ResetUndoBuffer();
16022     DrawEditModeWindow();
16023   }
16024   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
16025   {
16026     SetAutomaticNumberOfGemsNeeded();
16027   }
16028
16029   // do not mark level as modified for certain non-level-changing gadgets
16030   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
16031        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
16032       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
16033        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
16034        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
16035       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
16036     return;
16037
16038   level.changed = TRUE;
16039 }
16040
16041 static void HandleControlButtons(struct GadgetInfo *gi)
16042 {
16043   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
16044   static int last_edit_mode = ED_MODE_DRAWING;
16045   static int last_custom_copy_mode = -1;
16046   static int last_button = 0;
16047   int id = gi->custom_id;
16048   int button = gi->event.button;
16049   int step = BUTTON_STEPSIZE(button);
16050   int new_element = BUTTON_ELEMENT(button);
16051   int last_properties_element = properties_element;
16052   int x, y;
16053
16054   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
16055     DrawLevelText(0, 0, 0, TEXT_END);
16056
16057   if (id < ED_NUM_CTRL1_BUTTONS &&
16058       id != GADGET_ID_SINGLE_ITEMS &&
16059       id != GADGET_ID_PICK_ELEMENT &&
16060       edit_mode != ED_MODE_DRAWING &&
16061       drawing_function != GADGET_ID_PICK_ELEMENT &&
16062       !(GetKeyModState() & KMOD_Control))
16063     ChangeEditModeWindow(ED_MODE_DRAWING);
16064
16065   // element copy mode active, but no element button pressed => deactivate
16066   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
16067     last_custom_copy_mode = -1;
16068
16069   // when showing palette on element buttons, change element of button used
16070   if (editor.palette.show_on_element_buttons &&
16071       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
16072   {
16073     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
16074
16075     id = GADGET_ID_PALETTE;
16076   }
16077
16078   switch (id)
16079   {
16080     case GADGET_ID_SCROLL_LEFT:
16081       if (level_xpos >= 0)
16082       {
16083         if (lev_fieldx < ed_fieldx - 2)
16084           break;
16085
16086         level_xpos -= step;
16087         if (level_xpos < -1)
16088           level_xpos = -1;
16089         if (button == 1)
16090           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
16091         else
16092           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16093
16094         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16095                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16096       }
16097       break;
16098
16099     case GADGET_ID_SCROLL_RIGHT:
16100       if (level_xpos <= lev_fieldx - ed_fieldx)
16101       {
16102         if (lev_fieldx < ed_fieldx - 2)
16103           break;
16104
16105         level_xpos += step;
16106         if (level_xpos > lev_fieldx - ed_fieldx + 1)
16107           level_xpos = lev_fieldx - ed_fieldx + 1;
16108         if (button == 1)
16109           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
16110         else
16111           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16112
16113         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
16114                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
16115       }
16116       break;
16117
16118     case GADGET_ID_SCROLL_UP:
16119       if (level_ypos >= 0)
16120       {
16121         if (lev_fieldy < ed_fieldy - 2)
16122           break;
16123
16124         level_ypos -= step;
16125         if (level_ypos < -1)
16126           level_ypos = -1;
16127         if (button == 1)
16128           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16129         else
16130           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16131
16132         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16133                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16134       }
16135       break;
16136
16137     case GADGET_ID_SCROLL_DOWN:
16138       if (level_ypos <= lev_fieldy - ed_fieldy)
16139       {
16140         if (lev_fieldy < ed_fieldy - 2)
16141           break;
16142
16143         level_ypos += step;
16144         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16145           level_ypos = lev_fieldy - ed_fieldy + 1;
16146         if (button == 1)
16147           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16148         else
16149           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16150
16151         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16152                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16153       }
16154       break;
16155
16156     case GADGET_ID_SCROLL_HORIZONTAL:
16157       level_xpos = gi->event.item_position - 1;
16158
16159       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16160       BackToFront();
16161
16162       break;
16163
16164     case GADGET_ID_SCROLL_VERTICAL:
16165       level_ypos = gi->event.item_position - 1;
16166
16167       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16168       BackToFront();
16169
16170       break;
16171
16172     case GADGET_ID_SCROLL_LIST_UP:
16173     case GADGET_ID_SCROLL_LIST_DOWN:
16174     case GADGET_ID_SCROLL_LIST_VERTICAL:
16175       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16176         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16177       else
16178       {
16179         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16180         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16181
16182         if (element_shift < 0)
16183           element_shift = 0;
16184         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16185           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16186
16187         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16188                      GDI_SCROLLBAR_ITEM_POSITION,
16189                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16190       }
16191
16192       ModifyEditorElementList();
16193
16194       break;
16195
16196     case GADGET_ID_PROPERTIES:
16197       // always switch off element properties when they are already displayed
16198       last_properties_element = new_element;
16199     case GADGET_ID_ELEMENT_LEFT:
16200     case GADGET_ID_ELEMENT_MIDDLE:
16201     case GADGET_ID_ELEMENT_RIGHT:
16202       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16203                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16204                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16205                             new_element);
16206
16207       if (edit_mode != ED_MODE_PROPERTIES)
16208       {
16209         last_edit_mode = edit_mode;
16210
16211         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16212
16213         last_level_drawing_function = drawing_function;
16214         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16215                       MB_LEFTBUTTON);
16216       }
16217       else if (properties_element != last_properties_element)
16218       {
16219         DrawEditModeWindow();
16220       }
16221       else
16222       {
16223         ChangeEditModeWindow(ED_MODE_DRAWING);
16224
16225         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16226                       MB_LEFTBUTTON);
16227       }
16228       break;
16229
16230     case GADGET_ID_PALETTE:
16231       if (edit_mode != ED_MODE_PALETTE)
16232       {
16233         last_edit_mode = edit_mode;
16234
16235         ChangeEditModeWindow(ED_MODE_PALETTE);
16236       }
16237       else
16238       {
16239         ChangeEditModeWindow(last_edit_mode);
16240       }
16241       break;
16242
16243     case GADGET_ID_WRAP_LEFT:
16244       WrapLevel(-step, 0);
16245       break;
16246
16247     case GADGET_ID_WRAP_RIGHT:
16248       WrapLevel(step, 0);
16249       break;
16250
16251     case GADGET_ID_WRAP_UP:
16252       WrapLevel(0, -step);
16253       break;
16254
16255     case GADGET_ID_WRAP_DOWN:
16256       WrapLevel(0, step);
16257       break;
16258
16259     case GADGET_ID_SINGLE_ITEMS:
16260     case GADGET_ID_CONNECTED_ITEMS:
16261     case GADGET_ID_LINE:
16262     case GADGET_ID_ARC:
16263     case GADGET_ID_TEXT:
16264     case GADGET_ID_RECTANGLE:
16265     case GADGET_ID_FILLED_BOX:
16266     case GADGET_ID_FLOOD_FILL:
16267     case GADGET_ID_GRAB_BRUSH:
16268     case GADGET_ID_PICK_ELEMENT:
16269       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16270         last_drawing_function = drawing_function;
16271       drawing_function = id;
16272       draw_with_brush = FALSE;
16273       break;
16274
16275     case GADGET_ID_RANDOM_PLACEMENT:
16276       RandomPlacement(new_element);
16277       break;
16278
16279     case GADGET_ID_ZOOM:
16280       // zoom level editor tile size in or out (or reset to default size)
16281       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16282                      button == 2 ? ed_tilesize_default :
16283                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16284
16285       // when using touch device, cycle through all zoom tilesizes
16286       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16287         ed_tilesize = MICRO_TILESIZE;
16288
16289       // limit zoom level by upper and lower bound
16290       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16291
16292       InitZoomLevelSettings(ed_tilesize);
16293
16294       if (edit_mode == ED_MODE_DRAWING)
16295       {
16296         DrawDrawingWindow();
16297
16298         // redraw zoom gadget info text
16299         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16300       }
16301
16302       // save current editor zoom tilesize
16303       SaveSetup_AutoSetup();
16304
16305       break;
16306
16307     case GADGET_ID_CUSTOM_COPY_FROM:
16308     case GADGET_ID_CUSTOM_COPY_TO:
16309     case GADGET_ID_CUSTOM_EXCHANGE:
16310       last_custom_copy_mode = id;
16311       last_drawing_function = drawing_function;
16312       break;
16313
16314     case GADGET_ID_CUSTOM_COPY:
16315       CopyCustomElement(properties_element, -1, id);
16316       break;
16317
16318     case GADGET_ID_CUSTOM_PASTE:
16319       CopyCustomElement(-1, properties_element, id);
16320       break;
16321
16322     case GADGET_ID_UNDO:
16323       if (button < 0)   // keep button value (even if modifier keys are pressed)
16324         button = -button;
16325       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16326         button = 3;
16327
16328       if (button == 1 && undo_buffer_steps == 0)
16329       {
16330         Request("Undo buffer empty!", REQ_CONFIRM);
16331
16332         break;
16333       }
16334       else if (button == 2)
16335       {
16336         break;
16337       }
16338       else if (button == 3 && redo_buffer_steps == 0)
16339       {
16340         Request("Redo buffer empty!", REQ_CONFIRM);
16341
16342         break;
16343       }
16344
16345       if (edit_mode != ED_MODE_DRAWING)
16346         ChangeEditModeWindow(ED_MODE_DRAWING);
16347
16348       if (button == 1)
16349       {
16350         // undo
16351
16352         undo_buffer_position =
16353           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16354
16355         undo_buffer_steps--;
16356         redo_buffer_steps++;
16357       }
16358       else
16359       {
16360         // redo
16361
16362         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16363
16364         undo_buffer_steps++;
16365         redo_buffer_steps--;
16366       }
16367
16368       for (x = 0; x < lev_fieldx; x++)
16369         for (y = 0; y < lev_fieldy; y++)
16370           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16371
16372       // check if undo operation forces change of border style
16373       CheckLevelBorderElement(FALSE);
16374
16375       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16376
16377       break;
16378
16379     case GADGET_ID_CONF:
16380       if (edit_mode != ED_MODE_LEVELCONFIG)
16381       {
16382         last_edit_mode = edit_mode;
16383
16384         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16385       }
16386       else
16387       {
16388         ChangeEditModeWindow(ED_MODE_DRAWING);
16389       }
16390       break;
16391
16392     case GADGET_ID_CLEAR:
16393       if (edit_mode != ED_MODE_DRAWING)
16394         ChangeEditModeWindow(ED_MODE_DRAWING);
16395
16396       for (x = 0; x < MAX_LEV_FIELDX; x++)
16397         for (y = 0; y < MAX_LEV_FIELDY; y++)
16398           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16399
16400       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16401
16402       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16403       break;
16404
16405     case GADGET_ID_SAVE:
16406     {
16407       // saving read-only levels into personal level set modifies global vars
16408       // "leveldir_current" and "level_nr"; restore them after saving level
16409       LevelDirTree *leveldir_former = leveldir_current;
16410       int level_nr_former = level_nr;
16411       char *level_filename;
16412       boolean new_level;
16413
16414       if (leveldir_current->readonly &&
16415           !PrepareSavingIntoPersonalLevelSet())
16416         break;
16417
16418       level_filename = getDefaultLevelFilename(level_nr);
16419       new_level = !fileExists(level_filename);
16420
16421       if (new_level ||
16422           Request("Save this level and kill the old?", REQ_ASK))
16423       {
16424         if (leveldir_former->readonly)
16425           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16426
16427         SetAutomaticNumberOfGemsNeeded();
16428
16429         CopyPlayfield(Tile, level.field);
16430         SaveLevel(level_nr);
16431
16432         level.changed = FALSE;
16433
16434         if (new_level)
16435         {
16436           char level_saved_msg[64];
16437
16438           if (leveldir_former->readonly)
16439             sprintf(level_saved_msg,
16440                     "Level saved as level %d into personal level set!",
16441                     level_nr);
16442           else
16443             strcpy(level_saved_msg, "Level saved!");
16444
16445           Request(level_saved_msg, REQ_CONFIRM);
16446         }
16447       }
16448
16449       // "cd" back to copied-from levelset (in case of saved read-only level)
16450       leveldir_current = leveldir_former;
16451       level_nr = level_nr_former;
16452
16453       break;
16454     }
16455
16456     case GADGET_ID_TEST:
16457       if (LevelChanged())
16458         level.game_version = GAME_VERSION_ACTUAL;
16459
16460       CopyPlayfield(level.field, TileBackup);
16461       CopyPlayfield(Tile, level.field);
16462
16463       CopyNativeLevel_RND_to_Native(&level);
16464
16465       UnmapLevelEditorGadgets();
16466       UndrawSpecialEditorDoor();
16467
16468       CloseDoor(DOOR_CLOSE_ALL);
16469
16470       // needed before playing if editor playfield area has different size
16471       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16472
16473       // redraw_mask = REDRAW_ALL;
16474
16475       level_editor_test_game = TRUE;
16476
16477       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16478
16479       break;
16480
16481     case GADGET_ID_EXIT:
16482       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16483       break;
16484
16485     default:
16486       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16487           id <= GADGET_ID_ELEMENTLIST_LAST)
16488       {
16489         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16490
16491         new_element = editor_elements[element_position + element_shift];
16492
16493         if (IS_EDITOR_CASCADE(new_element))
16494         {
16495           int i;
16496
16497           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16498           {
16499             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16500             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16501
16502             if (*cascade_element == new_element)
16503             {
16504               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16505               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16506
16507               // update element selection list
16508               ReinitializeElementList();
16509               ModifyEditorElementList();
16510
16511               // update cascading gadget info text
16512               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16513
16514               // save current editor cascading state
16515               SaveSetup_EditorCascade();
16516
16517               break;
16518             }
16519           }
16520
16521           break;
16522         }
16523
16524         if (last_custom_copy_mode != -1)
16525         {
16526           if (CopyCustomElement(properties_element, new_element,
16527                                 last_custom_copy_mode))
16528           {
16529             ClickOnGadget(level_editor_gadget[last_drawing_function],
16530                           MB_LEFTBUTTON);
16531
16532             last_custom_copy_mode = -1;
16533           }
16534
16535           break;
16536         }
16537
16538         // change element of button used to show palette
16539         if (editor.palette.show_on_element_buttons)
16540           button = last_button;
16541
16542         PickDrawingElement(button, new_element);
16543
16544         if (!stick_element_properties_window &&
16545             drawing_function != GADGET_ID_PICK_ELEMENT &&
16546             !(GetKeyModState() & KMOD_Control))
16547         {
16548           properties_element = new_element;
16549           if (edit_mode == ED_MODE_PROPERTIES)
16550             DrawPropertiesWindow();
16551         }
16552
16553         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16554           ClickOnGadget(level_editor_gadget[last_drawing_function],
16555                         MB_LEFTBUTTON);
16556
16557         if (!use_permanent_palette)
16558           ChangeEditModeWindow(last_edit_mode);
16559       }
16560 #ifdef DEBUG
16561       else if (gi->event.type == GD_EVENT_PRESSED)
16562         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16563       else if (gi->event.type == GD_EVENT_RELEASED)
16564         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16565       else if (gi->event.type == GD_EVENT_MOVING)
16566         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16567       else
16568         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16569 #endif
16570       break;
16571   }
16572 }
16573
16574 void HandleLevelEditorKeyInput(Key key)
16575 {
16576   char letter = getCharFromKey(key);
16577
16578   if (drawing_function == GADGET_ID_TEXT &&
16579       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16580   {
16581     if (letter)
16582       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16583     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16584       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16585     else if (key == KSYM_Return)
16586       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16587     else if (key == KSYM_Escape)
16588       DrawLevelText(0, 0, 0, TEXT_END);
16589
16590     return;
16591   }
16592
16593   int id = GADGET_ID_NONE;
16594   int new_element_shift = element_shift;
16595   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16596   int button = MB_LEFTBUTTON;
16597   int i;
16598
16599   switch (key)
16600   {
16601     case KSYM_Left:
16602       id = GADGET_ID_SCROLL_LEFT;
16603       break;
16604     case KSYM_Right:
16605       id = GADGET_ID_SCROLL_RIGHT;
16606       break;
16607     case KSYM_Up:
16608       id = GADGET_ID_SCROLL_UP;
16609       break;
16610     case KSYM_Down:
16611       id = GADGET_ID_SCROLL_DOWN;
16612       break;
16613
16614     case KSYM_Page_Up:
16615     case KSYM_Page_Down:
16616       step *= (key == KSYM_Page_Up ? -1 : +1);
16617       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16618
16619       if (element_shift < 0)
16620         element_shift = 0;
16621       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16622         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16623
16624       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16625                    GDI_SCROLLBAR_ITEM_POSITION,
16626                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16627
16628       ModifyEditorElementList();
16629
16630       break;
16631
16632     case KSYM_Home:
16633     case KSYM_End:
16634       element_shift = (key == KSYM_Home ? 0 :
16635                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16636
16637       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16638                    GDI_SCROLLBAR_ITEM_POSITION,
16639                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16640
16641       ModifyEditorElementList();
16642
16643       break;
16644
16645     case KSYM_Insert:
16646     case KSYM_Delete:
16647
16648       // this is needed to prevent interference with running "True X-Mouse"
16649       if (GetKeyModStateFromEvents() & KMOD_Control)
16650         break;
16651
16652       // check for last or next editor cascade block in element list
16653       for (i = 0; i < num_editor_elements; i++)
16654       {
16655         if ((key == KSYM_Insert && i == element_shift) ||
16656             (key == KSYM_Delete && new_element_shift > element_shift))
16657           break;
16658
16659         // jump to next cascade block (or to start of element list)
16660         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16661           new_element_shift = i;
16662       }
16663
16664       if (i < num_editor_elements)
16665         element_shift = new_element_shift;
16666
16667       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16668         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16669
16670       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16671                    GDI_SCROLLBAR_ITEM_POSITION,
16672                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16673
16674       ModifyEditorElementList();
16675
16676       break;
16677
16678     case KSYM_Escape:
16679       if (edit_mode == ED_MODE_DRAWING)
16680         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16681       else if (edit_mode == ED_MODE_LEVELCONFIG)
16682         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16683       else if (edit_mode == ED_MODE_PROPERTIES)
16684         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16685       else if (edit_mode == ED_MODE_PALETTE)
16686         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16687       else              // should never happen
16688         ChangeEditModeWindow(ED_MODE_DRAWING);
16689
16690       break;
16691
16692     default:
16693       break;
16694   }
16695
16696   if (id != GADGET_ID_NONE)
16697     ClickOnGadget(level_editor_gadget[id], button);
16698   else if (letter == '1' || letter == '?')
16699     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16700   else if (letter == '2')
16701     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16702   else if (letter == '3')
16703     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16704   else if (letter == '.')
16705     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16706   else if (letter == 'U')
16707     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16708   else if (letter == '-' || key == KSYM_KP_Subtract)
16709     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16710   else if (letter == '0' || key == KSYM_KP_0)
16711     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16712   else if (letter == '+' || key == KSYM_KP_Add ||
16713            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16714     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16715   else if (key == KSYM_Return ||
16716            key == KSYM_space ||
16717            key == setup.shortcut.toggle_pause)
16718     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16719   else
16720     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16721       if (letter && letter == controlbutton_info[i].shortcut)
16722         if (!anyTextGadgetActive())
16723           ClickOnGadget(level_editor_gadget[i], button);
16724
16725   if (draw_with_brush)
16726   {
16727     if (letter == 'x')
16728       FlipBrushX();
16729     else if (letter == 'y')
16730       FlipBrushY();
16731     else if (letter == 'z')
16732       RotateBrush();
16733   }
16734 }
16735
16736 static void HandleLevelEditorIdle_Properties(void)
16737 {
16738   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16739   int x = editor.settings.element_graphic.x + element_border;
16740   int y = editor.settings.element_graphic.y + element_border;
16741   static DelayCounter action_delay = { 0 };
16742   int i;
16743
16744   action_delay.value = GameFrameDelay;
16745
16746   if (!DelayReached(&action_delay))
16747     return;
16748
16749   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16750   {
16751     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16752
16753     if (gi->mapped && gi->active && gi->selectbox.open)
16754       return;
16755   }
16756
16757   DrawEditorElementAnimation(SX + x, SY + y);
16758
16759   redraw_mask |= REDRAW_FIELD;
16760
16761   FrameCounter++;       // increase animation frame counter
16762 }
16763
16764 static void HandleLevelEditorIdle_Drawing(void)
16765 {
16766   static boolean last_highlighted = FALSE;
16767   static boolean last_highlighted_similar = FALSE;
16768   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16769   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16770
16771   if (highlighted != last_highlighted ||
16772       (highlighted && highlighted_similar != last_highlighted_similar))
16773   {
16774     DrawAreaElementHighlight(highlighted, highlighted_similar);
16775
16776     redraw_mask |= REDRAW_FIELD;
16777   }
16778
16779   last_highlighted = highlighted;
16780   last_highlighted_similar = highlighted_similar;
16781 }
16782
16783 void HandleLevelEditorIdle(void)
16784 {
16785   if (edit_mode == ED_MODE_PROPERTIES)
16786     HandleLevelEditorIdle_Properties();
16787   else if (edit_mode == ED_MODE_DRAWING)
16788     HandleLevelEditorIdle_Drawing();
16789 }
16790
16791 static void ClearEditorGadgetInfoText(void)
16792 {
16793   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16794 }
16795
16796 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16797 {
16798   char infotext[MAX_OUTPUT_LINESIZE + 1];
16799   int max_infotext_len = getMaxInfoTextLength();
16800
16801   if (gi == NULL || strlen(gi->info_text) == 0)
16802     return;
16803
16804   strncpy(infotext, gi->info_text, max_infotext_len);
16805   infotext[max_infotext_len] = '\0';
16806
16807   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
16808   {
16809     int key = controlbutton_info[gi->custom_id].shortcut;
16810
16811     if (key)
16812     {
16813       char shortcut[MAX_OUTPUT_LINESIZE + 1];
16814
16815       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
16816         sprintf(shortcut, " ('.' or '%c')", key);
16817       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
16818         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
16819       else if (gi->custom_id == GADGET_ID_TEST)
16820         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
16821       else if (gi->custom_id == GADGET_ID_UNDO)
16822         sprintf(shortcut, " ('%c/Shift-U')", key);
16823       else if (gi->custom_id == GADGET_ID_ZOOM)
16824         sprintf(shortcut, " ('%c', '0', '-')", key);
16825       else
16826         sprintf(shortcut, " ('%s%c')",
16827                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
16828
16829       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
16830         strcat(infotext, shortcut);
16831     }
16832   }
16833
16834   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
16835 }
16836
16837 void HandleEditorGadgetInfoText(void *ptr)
16838 {
16839   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
16840
16841   if (game_status != GAME_MODE_EDITOR)
16842     return;
16843
16844   ClearEditorGadgetInfoText();
16845
16846   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
16847     return;
16848
16849   // misuse this function to delete brush cursor, if needed
16850   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
16851     DeleteBrushFromCursor();
16852
16853   PrintEditorGadgetInfoText(gi);
16854 }
16855
16856 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
16857 {
16858   int id = gi->custom_id;
16859   int type_id = gi->custom_type_id;
16860   int sx = gi->event.x;
16861   int sy = gi->event.y;
16862   int lx = sx + level_xpos;
16863   int ly = sy + level_ypos;
16864   int min_sx = 0, min_sy = 0;
16865   int max_sx = gi->drawing.area_xsize - 1;
16866   int max_sy = gi->drawing.area_ysize - 1;
16867   int actual_drawing_function = drawing_function;
16868   int max_infotext_len = getMaxInfoTextLength();
16869   char infotext[MAX_OUTPUT_LINESIZE + 1];
16870
16871   infotext[0] = '\0';           // start with empty info text
16872
16873   // pressed Control key: simulate picking element
16874   if (GetKeyModState() & KMOD_Control)
16875     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
16876
16877   ClearEditorGadgetInfoText();
16878
16879   if (gi->event.type == GD_EVENT_INFO_LEAVING)
16880     return;
16881
16882   // make sure to stay inside drawing area boundaries
16883   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
16884   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
16885
16886   if (id == GADGET_ID_DRAWING_LEVEL)
16887   {
16888     if (button_status)
16889     {
16890       int min_lx = 0, min_ly = 0;
16891       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
16892
16893       // get positions inside level field
16894       lx = sx + level_xpos;
16895       ly = sy + level_ypos;
16896
16897       // make sure to stay inside level field boundaries
16898       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
16899       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
16900
16901       // correct drawing area positions accordingly
16902       sx = lx - level_xpos;
16903       sy = ly - level_ypos;
16904     }
16905
16906     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
16907     {
16908       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
16909       {
16910         static int start_lx = 0;
16911         static int start_ly = 0;
16912         char *text;
16913
16914         if (gi->event.type == GD_EVENT_PRESSED)
16915         {
16916           start_lx = lx;
16917           start_ly = ly;
16918         }
16919
16920         switch (actual_drawing_function)
16921         {
16922           case GADGET_ID_SINGLE_ITEMS:
16923             text = "Drawing single items";
16924             break;
16925           case GADGET_ID_CONNECTED_ITEMS:
16926             text = "Drawing connected items";
16927             break;
16928           case GADGET_ID_LINE:
16929             text = "Drawing line";
16930             break;
16931           case GADGET_ID_ARC:
16932             text = "Drawing arc";
16933             break;
16934           case GADGET_ID_TEXT:
16935             text = "Setting text cursor";
16936             break;
16937           case GADGET_ID_RECTANGLE:
16938             text = "Drawing rectangle";
16939             break;
16940           case GADGET_ID_FILLED_BOX:
16941             text = "Drawing filled box";
16942             break;
16943           case GADGET_ID_FLOOD_FILL:
16944             text = "Flood fill";
16945             break;
16946           case GADGET_ID_GRAB_BRUSH:
16947             text = "Grabbing brush";
16948             break;
16949           case GADGET_ID_PICK_ELEMENT:
16950             text = "Picking element";
16951             break;
16952
16953           default:
16954             text = "Drawing position";
16955             break;
16956         }
16957
16958         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16959           sprintf(infotext, "%s: %d, %d", text, lx, ly);
16960         else
16961           sprintf(infotext, "%s: %d, %d", text,
16962                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
16963       }
16964       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16965         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
16966       else
16967         sprintf(infotext, "Level position: %d, %d", lx, ly);
16968     }
16969
16970     // misuse this function to draw brush cursor, if needed
16971     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
16972     {
16973       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
16974         CopyBrushToCursor(sx, sy);
16975       else
16976         DeleteBrushFromCursor();
16977     }
16978
16979     if (!draw_with_brush)
16980       UpdateBrushPosition(sx, sy);
16981   }
16982   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16983   {
16984     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
16985     int element = drawingarea_info[type_id].value[pos];
16986
16987     strncpy(infotext, getElementInfoText(element), max_infotext_len);
16988   }
16989   else
16990   {
16991     if (id == GADGET_ID_CUSTOM_CONTENT)
16992       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
16993     else if (id == GADGET_ID_GROUP_CONTENT)
16994       sprintf(infotext, "group element position: %d", sx + 1);
16995     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
16996              id <= GADGET_ID_YAMYAM_CONTENT_7)
16997       sprintf(infotext, "content area %d position: %d, %d",
16998               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
16999     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
17000              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
17001       sprintf(infotext, "content area %d position: %d, %d",
17002               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
17003     else if (id == GADGET_ID_ANDROID_CONTENT)
17004       sprintf(infotext, "android element position: %d", sx + 1);
17005     else if (drawingarea_info[type_id].infotext != NULL)
17006       strcpy(infotext, drawingarea_info[type_id].infotext);
17007   }
17008
17009   infotext[max_infotext_len] = '\0';
17010
17011   if (strlen(infotext) > 0)
17012     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
17013 }
17014
17015 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
17016                             boolean quick_quit)
17017 {
17018   if (!ask_if_level_has_changed ||
17019       !LevelChanged() ||
17020       Request("Level has changed! Exit without saving?",
17021               REQ_ASK | REQ_STAY_OPEN))
17022   {
17023     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
17024     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
17025
17026     // draw normal door
17027     UndrawSpecialEditorDoor();
17028
17029     // use door animation if door 1 viewport is unchanged and contains toolbox
17030     if (useEditorDoorAnimation())
17031       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
17032
17033     // close editor doors if viewport definition is the same as in main menu
17034     if (vp_door_1->x      == DX     &&
17035         vp_door_1->y      == DY     &&
17036         vp_door_1->width  == DXSIZE &&
17037         vp_door_1->height == DYSIZE &&
17038         vp_door_2->x      == VX     &&
17039         vp_door_2->y      == VY     &&
17040         vp_door_2->width  == VXSIZE &&
17041         vp_door_2->height == VYSIZE)
17042       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
17043     else
17044       SetDoorState(DOOR_CLOSE_ALL);
17045
17046     BackToFront();
17047
17048     if (quick_quit)
17049       FadeSkipNextFadeIn();
17050
17051     SetGameStatus(GAME_MODE_MAIN);
17052
17053     DrawMainMenu();
17054   }
17055   else
17056   {
17057     if (!global.use_envelope_request)
17058     {
17059       CloseDoor(DOOR_CLOSE_1);
17060       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
17061     }
17062   }
17063 }