added preprocessor macros to improve code readability
[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_START_ELEMENT,
587   GADGET_ID_ARTWORK_ELEMENT,
588   GADGET_ID_EXPLOSION_ELEMENT,
589   GADGET_ID_INVENTORY_CONTENT,
590   GADGET_ID_MM_BALL_CONTENT,
591   GADGET_ID_CUSTOM_GRAPHIC,
592   GADGET_ID_CUSTOM_CONTENT,
593   GADGET_ID_CUSTOM_MOVE_ENTER,
594   GADGET_ID_CUSTOM_MOVE_LEAVE,
595   GADGET_ID_CUSTOM_CHANGE_TARGET,
596   GADGET_ID_CUSTOM_CHANGE_CONTENT,
597   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
598   GADGET_ID_CUSTOM_CHANGE_ACTION,
599   GADGET_ID_GROUP_CONTENT,
600   GADGET_ID_RANDOM_BACKGROUND,
601
602   // text input identifiers
603
604   GADGET_ID_LEVEL_NAME,
605   GADGET_ID_LEVEL_AUTHOR,
606   GADGET_ID_LEVELSET_NAME,
607   GADGET_ID_LEVELSET_AUTHOR,
608   GADGET_ID_ELEMENT_NAME,
609
610   // text area identifiers
611
612   GADGET_ID_ENVELOPE_INFO,
613
614   // selectbox identifiers
615
616   GADGET_ID_TIME_OR_STEPS,
617   GADGET_ID_TIME_SCORE_BASE,
618   GADGET_ID_GAME_ENGINE_TYPE,
619   GADGET_ID_BD_SCHEDULING_TYPE,
620   GADGET_ID_LEVELSET_SAVE_MODE,
621   GADGET_ID_WIND_DIRECTION,
622   GADGET_ID_PLAYER_SPEED,
623   GADGET_ID_MM_BALL_CHOICE_MODE,
624   GADGET_ID_CUSTOM_WALK_TO_ACTION,
625   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
626   GADGET_ID_CUSTOM_DEADLINESS,
627   GADGET_ID_CUSTOM_MOVE_PATTERN,
628   GADGET_ID_CUSTOM_MOVE_DIRECTION,
629   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
630   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
631   GADGET_ID_CUSTOM_SMASH_TARGETS,
632   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
633   GADGET_ID_CUSTOM_ACCESS_TYPE,
634   GADGET_ID_CUSTOM_ACCESS_LAYER,
635   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
636   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
637   GADGET_ID_CHANGE_TIME_UNITS,
638   GADGET_ID_CHANGE_DIRECT_ACTION,
639   GADGET_ID_CHANGE_OTHER_ACTION,
640   GADGET_ID_CHANGE_SIDE,
641   GADGET_ID_CHANGE_PLAYER,
642   GADGET_ID_CHANGE_PAGE,
643   GADGET_ID_CHANGE_REPLACE_WHEN,
644   GADGET_ID_ACTION_TYPE,
645   GADGET_ID_ACTION_MODE,
646   GADGET_ID_ACTION_ARG,
647   GADGET_ID_SELECT_CHANGE_PAGE,
648   GADGET_ID_GROUP_CHOICE_MODE,
649
650   // textbutton identifiers
651
652   GADGET_ID_LEVELCONFIG_LEVEL,
653   GADGET_ID_LEVELCONFIG_LEVELSET,
654   GADGET_ID_LEVELCONFIG_EDITOR,
655   GADGET_ID_LEVELCONFIG_ENGINE,
656   GADGET_ID_PROPERTIES_INFO,
657   GADGET_ID_PROPERTIES_CONFIG,
658   GADGET_ID_PROPERTIES_CONFIG_1,
659   GADGET_ID_PROPERTIES_CONFIG_2,
660   GADGET_ID_PROPERTIES_CHANGE,
661   GADGET_ID_SAVE_AS_TEMPLATE_1,
662   GADGET_ID_SAVE_AS_TEMPLATE_2,
663   GADGET_ID_SAVE_LEVELSET,
664   GADGET_ID_ADD_CHANGE_PAGE,
665   GADGET_ID_DEL_CHANGE_PAGE,
666
667   // graphicbutton identifiers
668
669   GADGET_ID_PREV_CHANGE_PAGE,
670   GADGET_ID_NEXT_CHANGE_PAGE,
671   GADGET_ID_COPY_CHANGE_PAGE,
672   GADGET_ID_PASTE_CHANGE_PAGE,
673
674   // gadgets for scrolling of drawing area
675
676   GADGET_ID_SCROLL_UP,
677   GADGET_ID_SCROLL_DOWN,
678   GADGET_ID_SCROLL_LEFT,
679   GADGET_ID_SCROLL_RIGHT,
680   GADGET_ID_SCROLL_HORIZONTAL,
681   GADGET_ID_SCROLL_VERTICAL,
682
683   // gadgets for scrolling element list
684
685   GADGET_ID_SCROLL_LIST_UP,
686   GADGET_ID_SCROLL_LIST_DOWN,
687   GADGET_ID_SCROLL_LIST_VERTICAL,
688
689   // checkbuttons/radiobuttons for level/element properties
690
691   GADGET_ID_AUTO_COUNT_GEMS,
692   GADGET_ID_RATE_TIME_OVER_SCORE,
693   GADGET_ID_USE_LEVELSET_ARTWORK,
694   GADGET_ID_COPY_LEVEL_TEMPLATE,
695   GADGET_ID_RANDOM_PERCENTAGE,
696   GADGET_ID_RANDOM_QUANTITY,
697   GADGET_ID_RANDOM_RESTRICTED,
698   GADGET_ID_BD_INTERMISSION,
699   GADGET_ID_BD_PAL_TIMING,
700   GADGET_ID_BD_LINE_SHIFTING_BORDERS,
701   GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
702   GADGET_ID_BD_SHORT_EXPLOSIONS,
703   GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
704   GADGET_ID_STICK_ELEMENT,
705   GADGET_ID_EM_SLIPPERY_GEMS,
706   GADGET_ID_EM_EXPLODES_BY_FIRE,
707   GADGET_ID_USE_SPRING_BUG,
708   GADGET_ID_USE_TIME_ORB_BUG,
709   GADGET_ID_USE_LIFE_BUGS,
710   GADGET_ID_RANDOM_BALL_CONTENT,
711   GADGET_ID_INITIAL_BALL_ACTIVE,
712   GADGET_ID_GROW_INTO_DIGGABLE,
713   GADGET_ID_SB_FIELDS_NEEDED,
714   GADGET_ID_SB_OBJECTS_NEEDED,
715   GADGET_ID_AUTO_EXIT_SOKOBAN,
716   GADGET_ID_SOLVED_BY_ONE_PLAYER,
717   GADGET_ID_FINISH_DIG_COLLECT,
718   GADGET_ID_KEEP_WALKABLE_CE,
719   GADGET_ID_CONTINUOUS_SNAPPING,
720   GADGET_ID_BLOCK_SNAP_FIELD,
721   GADGET_ID_BLOCK_LAST_FIELD,
722   GADGET_ID_SP_BLOCK_LAST_FIELD,
723   GADGET_ID_INSTANT_RELOCATION,
724   GADGET_ID_SHIFTED_RELOCATION,
725   GADGET_ID_LAZY_RELOCATION,
726   GADGET_ID_USE_START_ELEMENT,
727   GADGET_ID_USE_ARTWORK_ELEMENT,
728   GADGET_ID_USE_EXPLOSION_ELEMENT,
729   GADGET_ID_INITIAL_GRAVITY,
730   GADGET_ID_USE_INITIAL_INVENTORY,
731   GADGET_ID_CAN_PASS_TO_WALKABLE,
732   GADGET_ID_CAN_FALL_INTO_ACID,
733   GADGET_ID_CAN_MOVE_INTO_ACID,
734   GADGET_ID_DONT_COLLIDE_WITH,
735   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
736   GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
737   GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
738   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
739   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
740   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
741   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
742   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
743   GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
744   GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
745   GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
746   GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
747   GADGET_ID_BD_SLIME_IS_PREDICTABLE,
748   GADGET_ID_BD_CHANGE_EXPANDING_WALL,
749   GADGET_ID_BD_REPLICATORS_ACTIVE,
750   GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
751   GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
752   GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
753   GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
754   GADGET_ID_ENVELOPE_AUTOWRAP,
755   GADGET_ID_ENVELOPE_CENTERED,
756   GADGET_ID_MM_LASER_RED,
757   GADGET_ID_MM_LASER_GREEN,
758   GADGET_ID_MM_LASER_BLUE,
759   GADGET_ID_DF_LASER_RED,
760   GADGET_ID_DF_LASER_GREEN,
761   GADGET_ID_DF_LASER_BLUE,
762   GADGET_ID_ROTATE_MM_BALL_CONTENT,
763   GADGET_ID_EXPLODE_MM_BALL,
764   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
765   GADGET_ID_CUSTOM_CAN_EXPLODE,
766   GADGET_ID_CUSTOM_EXPLODE_FIRE,
767   GADGET_ID_CUSTOM_EXPLODE_SMASH,
768   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
769   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
770   GADGET_ID_CUSTOM_DEADLY,
771   GADGET_ID_CUSTOM_CAN_MOVE,
772   GADGET_ID_CUSTOM_CAN_FALL,
773   GADGET_ID_CUSTOM_CAN_SMASH,
774   GADGET_ID_CUSTOM_SLIPPERY,
775   GADGET_ID_CUSTOM_ACCESSIBLE,
776   GADGET_ID_CUSTOM_GRAV_REACHABLE,
777   GADGET_ID_CUSTOM_USE_LAST_VALUE,
778   GADGET_ID_CUSTOM_USE_GRAPHIC,
779   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
780   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
781   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
782   GADGET_ID_CUSTOM_CAN_CHANGE,
783   GADGET_ID_CHANGE_USE_CONTENT,
784   GADGET_ID_CHANGE_USE_EXPLOSION,
785   GADGET_ID_CHANGE_ONLY_COMPLETE,
786   GADGET_ID_CHANGE_USE_RANDOM,
787   GADGET_ID_CHANGE_HAS_ACTION,
788   GADGET_ID_CHANGE_DELAY,
789   GADGET_ID_CHANGE_BY_DIRECT_ACT,
790   GADGET_ID_CHANGE_BY_OTHER_ACT,
791
792   NUM_STATIC_GADGET_IDS
793 };
794
795 // gadgets for buttons in element list (dynamic)
796 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
797 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
798                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
799
800 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
801
802 // radio button numbers
803 enum
804 {
805   RADIO_NR_NONE,
806   RADIO_NR_DRAWING_TOOLBOX,
807   RADIO_NR_RANDOM_ELEMENTS
808 };
809
810 // values for counter gadgets
811 enum
812 {
813   ED_COUNTER_ID_SELECT_LEVEL,
814   ED_COUNTER_ID_LEVEL_XSIZE,
815   ED_COUNTER_ID_LEVEL_YSIZE,
816   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
817   ED_COUNTER_ID_LEVEL_TIMELIMIT,
818   ED_COUNTER_ID_LEVEL_TIMESCORE,
819   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
820   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
821   ED_COUNTER_ID_LEVEL_RANDOM,
822   ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
823   ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
824   ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
825   ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
826   ED_COUNTER_ID_BD_PUSHING_PROB,
827   ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
828   ED_COUNTER_ID_ELEMENT_VALUE1,
829   ED_COUNTER_ID_ELEMENT_VALUE2,
830   ED_COUNTER_ID_ELEMENT_VALUE3,
831   ED_COUNTER_ID_ELEMENT_VALUE4,
832   ED_COUNTER_ID_YAMYAM_CONTENT,
833   ED_COUNTER_ID_BALL_CONTENT,
834   ED_COUNTER_ID_ANDROID_CONTENT,
835   ED_COUNTER_ID_ENVELOPE_XSIZE,
836   ED_COUNTER_ID_ENVELOPE_YSIZE,
837   ED_COUNTER_ID_INVENTORY_SIZE,
838   ED_COUNTER_ID_MM_BALL_CONTENT,
839   ED_COUNTER_ID_CUSTOM_SCORE,
840   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
841   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
842   ED_COUNTER_ID_CUSTOM_VALUE_RND,
843   ED_COUNTER_ID_PUSH_DELAY_FIX,
844   ED_COUNTER_ID_PUSH_DELAY_RND,
845   ED_COUNTER_ID_DROP_DELAY_FIX,
846   ED_COUNTER_ID_DROP_DELAY_RND,
847   ED_COUNTER_ID_MOVE_DELAY_FIX,
848   ED_COUNTER_ID_MOVE_DELAY_RND,
849   ED_COUNTER_ID_STEP_DELAY_FIX,
850   ED_COUNTER_ID_STEP_DELAY_RND,
851   ED_COUNTER_ID_EXPLOSION_DELAY,
852   ED_COUNTER_ID_IGNITION_DELAY,
853   ED_COUNTER_ID_GROUP_CONTENT,
854   ED_COUNTER_ID_CHANGE_DELAY_FIX,
855   ED_COUNTER_ID_CHANGE_DELAY_RND,
856   ED_COUNTER_ID_CHANGE_CONT_RND,
857
858   ED_NUM_COUNTERBUTTONS
859 };
860
861 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
862 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
863 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
864 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
865 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
866 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
867
868 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
869 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
870 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
871 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
872 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
873 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
874
875 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
876 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
877
878 // values for scrollbutton gadgets
879 enum
880 {
881   ED_SCROLLBUTTON_ID_AREA_UP,
882   ED_SCROLLBUTTON_ID_AREA_DOWN,
883   ED_SCROLLBUTTON_ID_AREA_LEFT,
884   ED_SCROLLBUTTON_ID_AREA_RIGHT,
885   ED_SCROLLBUTTON_ID_LIST_UP,
886   ED_SCROLLBUTTON_ID_LIST_DOWN,
887
888   ED_NUM_SCROLLBUTTONS
889 };
890
891 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
892 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
893
894 // values for scrollbar gadgets
895 enum
896 {
897   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
898   ED_SCROLLBAR_ID_AREA_VERTICAL,
899   ED_SCROLLBAR_ID_LIST_VERTICAL,
900
901   ED_NUM_SCROLLBARS
902 };
903
904 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
905 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
906
907 // values for text input gadgets
908 enum
909 {
910   ED_TEXTINPUT_ID_LEVEL_NAME,
911   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
912   ED_TEXTINPUT_ID_LEVELSET_NAME,
913   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
914   ED_TEXTINPUT_ID_ELEMENT_NAME,
915
916   ED_NUM_TEXTINPUT
917 };
918
919 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
920 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
921
922 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
923 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
924
925 // values for text area gadgets
926 enum
927 {
928   ED_TEXTAREA_ID_ENVELOPE_INFO,
929
930   ED_NUM_TEXTAREAS
931 };
932
933 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
934 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
935
936 // values for selectbox gadgets
937 enum
938 {
939   ED_SELECTBOX_ID_TIME_OR_STEPS,
940   ED_SELECTBOX_ID_TIME_SCORE_BASE,
941   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
942   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
943   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
944   ED_SELECTBOX_ID_WIND_DIRECTION,
945   ED_SELECTBOX_ID_PLAYER_SPEED,
946   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
947   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
948   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
949   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
950   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
951   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
952   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
953   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
954   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
955   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
956   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
957   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
958   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
959   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
960   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
961   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
962   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
963   ED_SELECTBOX_ID_CHANGE_SIDE,
964   ED_SELECTBOX_ID_CHANGE_PLAYER,
965   ED_SELECTBOX_ID_CHANGE_PAGE,
966   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
967   ED_SELECTBOX_ID_ACTION_TYPE,
968   ED_SELECTBOX_ID_ACTION_MODE,
969   ED_SELECTBOX_ID_ACTION_ARG,
970   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
971   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
972
973   ED_NUM_SELECTBOX
974 };
975
976 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
977 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
978
979 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
980 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
981
982 #define ED_SELECTBOX_ID_ENGINE_FIRST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
983 #define ED_SELECTBOX_ID_ENGINE_LAST     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
984
985 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
986 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
987 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
988 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
989 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
990 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
991
992 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
993 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
994
995 // values for textbutton gadgets
996 enum
997 {
998   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
999   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
1000   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
1001   ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
1002   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
1003   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
1004   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
1005   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
1006   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
1007   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
1008   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
1009   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
1010   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
1011   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
1012
1013   ED_NUM_TEXTBUTTONS
1014 };
1015
1016 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1017 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1018
1019 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
1020 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1021
1022 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
1023 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
1024
1025 // values for graphicbutton gadgets
1026 enum
1027 {
1028   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
1029   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
1030   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
1031   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
1032
1033   ED_NUM_GRAPHICBUTTONS
1034 };
1035
1036 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
1037 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
1038
1039 // values for checkbutton gadgets
1040 enum
1041 {
1042   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
1043   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
1044   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
1045   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
1046   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
1047   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
1048   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
1049   ED_CHECKBUTTON_ID_BD_INTERMISSION,
1050   ED_CHECKBUTTON_ID_BD_PAL_TIMING,
1051   ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
1052   ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
1053   ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
1054   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
1055   ED_CHECKBUTTON_ID_STICK_ELEMENT,
1056   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
1057   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
1058   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
1059   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
1060   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
1061   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
1062   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
1063   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
1064   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
1065   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
1066   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
1067   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
1068   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
1069   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
1070   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
1071   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
1072   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
1073   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
1074   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
1075   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
1076   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
1077   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
1078   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
1079   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
1080   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
1081   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
1082   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
1083   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
1084   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
1085   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
1086   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
1087   ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
1088   ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
1089   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
1090   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
1091   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
1092   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
1093   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
1094   ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
1095   ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
1096   ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
1097   ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
1098   ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
1099   ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
1100   ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
1101   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
1102   ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
1103   ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
1104   ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
1105   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1106   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1107   ED_CHECKBUTTON_ID_MM_LASER_RED,
1108   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1109   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1110   ED_CHECKBUTTON_ID_DF_LASER_RED,
1111   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1112   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1113   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1114   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1115   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1116   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1117   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1118   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1119   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1120   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1121   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1122   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1123   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1124   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1125   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1126   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1127   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1128   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1129   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1130   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1131   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1132   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1133   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1134   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1135   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1136   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1137   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1138   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1139   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1140
1141   ED_NUM_CHECKBUTTONS
1142 };
1143
1144 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1145 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1146
1147 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1148 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1149
1150 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1151 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1152
1153 #define ED_CHECKBUTTON_ID_ENGINE_FIRST  ED_CHECKBUTTON_ID_BD_INTERMISSION
1154 #define ED_CHECKBUTTON_ID_ENGINE_LAST   ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL
1155
1156 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1157 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1158 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1159 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1160 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1161 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1162
1163 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1164 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1165
1166 // values for radiobutton gadgets
1167 enum
1168 {
1169   ED_RADIOBUTTON_ID_PERCENTAGE,
1170   ED_RADIOBUTTON_ID_QUANTITY,
1171
1172   ED_NUM_RADIOBUTTONS
1173 };
1174
1175 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1176 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1177
1178 // values for drawing area gadgets
1179 enum
1180 {
1181   ED_DRAWING_ID_DRAWING_LEVEL,
1182   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1183   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1184   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1185   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1186   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1187   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1188   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1189   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1190   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1191   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1192   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1193   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1194   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1195   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1196   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1197   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1198   ED_DRAWING_ID_ANDROID_CONTENT,
1199   ED_DRAWING_ID_AMOEBA_CONTENT,
1200   ED_DRAWING_ID_BD_SNAP_ELEMENT,
1201   ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
1202   ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
1203   ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
1204   ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
1205   ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
1206   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
1207   ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
1208   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
1209   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
1210   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
1211   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
1212   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
1213   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
1214   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
1215   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
1216   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
1217   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
1218   ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
1219   ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
1220   ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
1221   ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
1222   ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
1223   ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
1224   ED_DRAWING_ID_BD_NUT_CONTENT,
1225   ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
1226   ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
1227   ED_DRAWING_ID_START_ELEMENT,
1228   ED_DRAWING_ID_ARTWORK_ELEMENT,
1229   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1230   ED_DRAWING_ID_INVENTORY_CONTENT,
1231   ED_DRAWING_ID_MM_BALL_CONTENT,
1232   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1233   ED_DRAWING_ID_CUSTOM_CONTENT,
1234   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1235   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1236   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1237   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1238   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1239   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1240   ED_DRAWING_ID_GROUP_CONTENT,
1241   ED_DRAWING_ID_RANDOM_BACKGROUND,
1242
1243   ED_NUM_DRAWING_AREAS
1244 };
1245
1246 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1247 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1248
1249
1250 // ----------------------------------------------------------------------------
1251 // some internally used definitions
1252 // ----------------------------------------------------------------------------
1253
1254 // values for CopyLevelToUndoBuffer()
1255 #define UNDO_IMMEDIATE                  0
1256 #define UNDO_ACCUMULATE                 1
1257
1258 // values for scrollbars
1259 #define ED_SCROLL_NO                    0
1260 #define ED_SCROLL_LEFT                  1
1261 #define ED_SCROLL_RIGHT                 2
1262 #define ED_SCROLL_UP                    4
1263 #define ED_SCROLL_DOWN                  8
1264
1265 // screens in the level editor
1266 #define ED_MODE_DRAWING                 0
1267 #define ED_MODE_LEVELCONFIG             1
1268 #define ED_MODE_PROPERTIES              2
1269 #define ED_MODE_PALETTE                 3
1270
1271 // sub-screens in the global settings section
1272 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1273 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1274 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1275 #define ED_MODE_LEVELCONFIG_ENGINE      ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
1276
1277 // sub-screens in the element properties section
1278 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1279 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1280 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1281 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1282 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1283
1284 // how many steps can be cancelled
1285 #define NUM_UNDO_STEPS                  (64 + 1)
1286
1287 // values for elements with score for certain actions
1288 #define MIN_SCORE                       0
1289 #define MAX_SCORE                       999
1290
1291 // values for elements with count for collecting
1292 #define MIN_COLLECT_COUNT               0
1293 #define MAX_COLLECT_COUNT               999
1294
1295 // values for random placement
1296 #define RANDOM_USE_PERCENTAGE           0
1297 #define RANDOM_USE_QUANTITY             1
1298
1299 // values for level set save mode
1300 #define LEVELSET_SAVE_MODE_UPDATE       0
1301 #define LEVELSET_SAVE_MODE_CREATE       1
1302
1303 // default value for element tile size in drawing area
1304 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1305 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1306
1307
1308 // ----------------------------------------------------------------------------
1309 // some internally used data structure definitions
1310 // ----------------------------------------------------------------------------
1311
1312 static struct
1313 {
1314   int graphic;
1315   int gadget_id;
1316   struct XYTileSize *pos;
1317   int gadget_type;
1318   char *infotext;
1319   char shortcut;
1320 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1321 {
1322   // note: some additional characters are already reserved for "cheat mode"
1323   // shortcuts (":XYZ" style) -- for details, see "events.c"
1324
1325   // ---------- toolbox control buttons ---------------------------------------
1326
1327   {
1328     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1329     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1330     "Draw single items",                        's'
1331   },
1332   {
1333     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1334     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1335     "Draw connected items",                     'd'
1336   },
1337   {
1338     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1339     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1340     "Draw lines",                               'l'
1341   },
1342   {
1343     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1344     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1345     "Draw arcs",                                'a'
1346   },
1347   {
1348     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1349     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1350     "Draw outline rectangles",                  'r'
1351   },
1352   {
1353     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1354     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1355     "Draw filled rectangles",                   'R'
1356   },
1357   {
1358     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1359     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1360     "Wrap (rotate) level up",                   0
1361   },
1362   {
1363     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1364     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1365     "Enter text elements",                      't'
1366   },
1367   {
1368     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1369     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1370     "Flood fill",                               'f'
1371   },
1372   {
1373     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1374     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1375     "Wrap (rotate) level left",                 0
1376   },
1377   {
1378     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1379     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1380     "Zoom level tile size",                     '+'
1381   },
1382   {
1383     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1384     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1385     "Wrap (rotate) level right",                0
1386   },
1387   {
1388     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1389     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1390     "Random element placement",                 0
1391   },
1392   {
1393     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1394     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1395     "Grab brush",                               'b'
1396   },
1397   {
1398     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1399     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1400     "Wrap (rotate) level down",                 0
1401   },
1402   {
1403     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1404     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1405     "Pick drawing element",                     ','
1406   },
1407
1408   // ---------- level control buttons -----------------------------------------
1409
1410   {
1411     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1412     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1413     "Undo/redo last operation",                 'u'
1414   },
1415   {
1416     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1417     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1418     "Level and editor settings",                'I'
1419   },
1420   {
1421     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1422     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1423     "Save level",                               'S'
1424   },
1425   {
1426     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1427     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1428     "Clear level",                              'C'
1429   },
1430   {
1431     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1432     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1433     "Test level",                               'T'
1434   },
1435   {
1436     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1437     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1438     "Exit level editor",                        'E'
1439   },
1440
1441   // ---------- CE and GE control buttons -------------------------------------
1442
1443   {
1444     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1445     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1446     "Copy settings from other element",         0
1447   },
1448   {
1449     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1450     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1451     "Copy settings to other element",           0
1452   },
1453   {
1454     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1455     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1456     "Exchange element with other element",      0
1457   },
1458   {
1459     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1460     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1461     "Copy settings from this element",          0
1462   },
1463   {
1464     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1465     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1466     "Paste settings to this element",           0
1467   },
1468
1469   // ---------- palette control buttons ---------------------------------------
1470
1471   {
1472     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1473     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1474     "Properties of drawing element",            'p'
1475   },
1476   {
1477     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1478     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1479     "Properties of drawing element 1",          '1'
1480   },
1481   {
1482     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1483     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1484     "Properties of drawing element 2",          '2'
1485   },
1486   {
1487     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1488     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1489     "Properties of drawing element 3",          '3'
1490   },
1491   {
1492     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1493     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1494     "Show list of elements",                    'e'
1495   }
1496 };
1497
1498 static int random_placement_value = 10;
1499 static int random_placement_method = RANDOM_USE_QUANTITY;
1500 static int random_placement_background_element = EL_SAND;
1501 static boolean random_placement_background_restricted = FALSE;
1502 static boolean stick_element_properties_window = FALSE;
1503 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1504 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1505 static struct ElementChangeInfo custom_element_change;
1506 static struct ElementGroupInfo group_element_info;
1507 static struct ElementInfo custom_element;
1508
1509 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1510 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1511 static int levelset_num_levels = 100;
1512 static boolean levelset_use_levelset_artwork = FALSE;
1513 static boolean levelset_copy_level_template = FALSE;
1514 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1515
1516 static struct
1517 {
1518   int gadget_type_id;
1519   int x, y;
1520   int min_value, max_value;
1521   int gadget_id_down, gadget_id_up;
1522   int gadget_id_text;
1523   int gadget_id_align;
1524   int *value;
1525   char *text_above, *text_left, *text_right;
1526 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1527 {
1528   // ---------- current level number ------------------------------------------
1529
1530   {
1531     ED_COUNTER_ID_SELECT_LEVEL,
1532     -1, -1,     // these values are not constant, but can change at runtime
1533     1,                                  100,
1534     GADGET_ID_SELECT_LEVEL_DOWN,        GADGET_ID_SELECT_LEVEL_UP,
1535     GADGET_ID_SELECT_LEVEL_TEXT,        GADGET_ID_NONE,
1536     &level_nr,
1537     NULL,                               NULL, NULL
1538   },
1539
1540   // ---------- level and editor settings -------------------------------------
1541
1542   {
1543     ED_COUNTER_ID_LEVEL_XSIZE,
1544     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1545     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
1546     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
1547     GADGET_ID_LEVEL_XSIZE_TEXT,         GADGET_ID_NONE,
1548     &level.fieldx,
1549     "Playfield size:",                  NULL, "Width",
1550   },
1551   {
1552     ED_COUNTER_ID_LEVEL_YSIZE,
1553     -1,                                 ED_LEVEL_SETTINGS_YPOS(4),
1554     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
1555     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
1556     GADGET_ID_LEVEL_YSIZE_TEXT,         GADGET_ID_LEVEL_XSIZE_UP,
1557     &level.fieldy,
1558     NULL,                               " ", "Height",
1559   },
1560   {
1561     ED_COUNTER_ID_LEVEL_GEMSLIMIT,
1562     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
1563     0,                                  999,
1564     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,     GADGET_ID_LEVEL_GEMSLIMIT_UP,
1565     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,     GADGET_ID_NONE,
1566     &level.gems_needed,
1567     NULL,                               "Number of gems to collect:", NULL
1568   },
1569   {
1570     ED_COUNTER_ID_LEVEL_TIMELIMIT,
1571     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(8),
1572     0,                                  9999,
1573     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
1574     GADGET_ID_LEVEL_TIMELIMIT_TEXT,     GADGET_ID_NONE,
1575     &level.time,
1576     "Time or step limit to solve level:", NULL, NULL
1577   },
1578   {
1579     ED_COUNTER_ID_LEVEL_TIMESCORE,
1580     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
1581     0,                                  999,
1582     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
1583     GADGET_ID_LEVEL_TIMESCORE_TEXT,     GADGET_ID_NONE,
1584     &level.score[SC_TIME_BONUS],
1585     "Score for time or steps left:",    NULL, NULL
1586   },
1587   {
1588     ED_COUNTER_ID_LEVEL_RANDOM_SEED,
1589     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(13),
1590     0,                                  9999,
1591     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,   GADGET_ID_LEVEL_RANDOM_SEED_UP,
1592     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,   GADGET_ID_NONE,
1593     &level.random_seed,
1594     NULL,                               "Random seed:", "(0 => random)"
1595   },
1596   {
1597     ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
1598     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1599     1,                                  MAX_LEVELS,
1600     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN, GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1601     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT, GADGET_ID_NONE,
1602     &levelset_num_levels,
1603     "Number of levels:",                NULL, NULL,
1604   },
1605   {
1606     ED_COUNTER_ID_LEVEL_RANDOM,
1607     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1608     1,                                  100,
1609     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
1610     GADGET_ID_LEVEL_RANDOM_TEXT,        GADGET_ID_NONE,
1611     &random_placement_value,
1612     "Random element placement:",        NULL, "in"
1613   },
1614   {
1615     ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
1616     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(3),
1617     50,                                 500,
1618     GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,   GADGET_ID_BD_CYCLE_DELAY_MS_UP,
1619     GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,   GADGET_ID_NONE,
1620     &level.bd_cycle_delay_ms,
1621     NULL,                               NULL, "Game cycle delay (ms)"
1622   },
1623   {
1624     ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
1625     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(3),
1626     0,                                  32,
1627     GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,  GADGET_ID_BD_CYCLE_DELAY_C64_UP,
1628     GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,  GADGET_ID_NONE,
1629     &level.bd_cycle_delay_c64,
1630     NULL,                               NULL, "Game cycle delay (C64-style)"
1631   },
1632   {
1633     ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
1634     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1635     1,                                  40,
1636     GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,    GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
1637     GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,    GADGET_ID_NONE,
1638     &level.bd_hatching_delay_cycles,
1639     NULL,                               NULL, "Hatching delay (cycles)"
1640   },
1641   {
1642     ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
1643     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1644     1,                                  40,
1645     GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,   GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
1646     GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,   GADGET_ID_NONE,
1647     &level.bd_hatching_delay_seconds,
1648     NULL,                               NULL, "Hatching delay (seconds)"
1649   },
1650
1651   // ---------- element settings: configure (various elements) ----------------
1652
1653   {
1654     ED_COUNTER_ID_BD_PUSHING_PROB,
1655     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1656     0,                                  100,
1657     GADGET_ID_BD_PUSHING_PROB_DOWN,     GADGET_ID_BD_PUSHING_PROB_UP,
1658     GADGET_ID_BD_PUSHING_PROB_TEXT,     GADGET_ID_NONE,
1659     &level.bd_pushing_prob,
1660     NULL,                               NULL, "Push probability"
1661   },
1662   {
1663     ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
1664     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1665     0,                                  100,
1666     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
1667     GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,  GADGET_ID_NONE,
1668     &level.bd_pushing_prob_with_sweet,
1669     NULL,                               NULL, "Push probability with sweet"
1670   },
1671   {
1672     ED_COUNTER_ID_ELEMENT_VALUE1,
1673     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1674     MIN_SCORE,                          MAX_SCORE,
1675     GADGET_ID_ELEMENT_VALUE1_DOWN,      GADGET_ID_ELEMENT_VALUE1_UP,
1676     GADGET_ID_ELEMENT_VALUE1_TEXT,      GADGET_ID_NONE,
1677     NULL,                               // will be set when used
1678     NULL,                               NULL, NULL
1679   },
1680   {
1681     ED_COUNTER_ID_ELEMENT_VALUE2,
1682     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
1683     MIN_SCORE,                          MAX_SCORE,
1684     GADGET_ID_ELEMENT_VALUE2_DOWN,      GADGET_ID_ELEMENT_VALUE2_UP,
1685     GADGET_ID_ELEMENT_VALUE2_TEXT,      GADGET_ID_NONE,
1686     NULL,                               // will be set when used
1687     NULL,                               NULL, NULL
1688   },
1689   {
1690     ED_COUNTER_ID_ELEMENT_VALUE3,
1691     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1692     MIN_SCORE,                          MAX_SCORE,
1693     GADGET_ID_ELEMENT_VALUE3_DOWN,      GADGET_ID_ELEMENT_VALUE3_UP,
1694     GADGET_ID_ELEMENT_VALUE3_TEXT,      GADGET_ID_NONE,
1695     NULL,                               // will be set when used
1696     NULL,                               NULL, NULL
1697   },
1698   {
1699     ED_COUNTER_ID_ELEMENT_VALUE4,
1700     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1701     MIN_SCORE,                          MAX_SCORE,
1702     GADGET_ID_ELEMENT_VALUE4_DOWN,      GADGET_ID_ELEMENT_VALUE4_UP,
1703     GADGET_ID_ELEMENT_VALUE4_TEXT,      GADGET_ID_NONE,
1704     NULL,                               // will be set when used
1705     NULL,                               NULL, NULL
1706   },
1707   {
1708     ED_COUNTER_ID_YAMYAM_CONTENT,
1709     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1710     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1711     GADGET_ID_YAMYAM_CONTENT_DOWN,      GADGET_ID_YAMYAM_CONTENT_UP,
1712     GADGET_ID_YAMYAM_CONTENT_TEXT,      GADGET_ID_NONE,
1713     &level.num_yamyam_contents,
1714     NULL,                               NULL, "Number of content areas"
1715   },
1716   {
1717     ED_COUNTER_ID_BALL_CONTENT,
1718     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1719     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1720     GADGET_ID_BALL_CONTENT_DOWN,        GADGET_ID_BALL_CONTENT_UP,
1721     GADGET_ID_BALL_CONTENT_TEXT,        GADGET_ID_NONE,
1722     &level.num_ball_contents,
1723     NULL,                               NULL, "Number of content areas"
1724   },
1725   {
1726     ED_COUNTER_ID_ANDROID_CONTENT,
1727     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1728     MIN_ANDROID_ELEMENTS,               MAX_ANDROID_ELEMENTS,
1729     GADGET_ID_ANDROID_CONTENT_DOWN,     GADGET_ID_ANDROID_CONTENT_UP,
1730     GADGET_ID_ANDROID_CONTENT_TEXT,     GADGET_ID_NONE,
1731     &level.num_android_clone_elements,
1732     NULL,                               NULL, "Number of clonable elements"
1733   },
1734   {
1735     ED_COUNTER_ID_ENVELOPE_XSIZE,
1736     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1737     MIN_ENVELOPE_XSIZE,                 MAX_ENVELOPE_XSIZE,
1738     GADGET_ID_ENVELOPE_XSIZE_DOWN,      GADGET_ID_ENVELOPE_XSIZE_UP,
1739     GADGET_ID_ENVELOPE_XSIZE_TEXT,      GADGET_ID_NONE,
1740     NULL,                               // will be set when used
1741     NULL,                               NULL, "Width",
1742   },
1743   {
1744     ED_COUNTER_ID_ENVELOPE_YSIZE,
1745     -1,                                 ED_ELEMENT_SETTINGS_YPOS(0),
1746     MIN_ENVELOPE_YSIZE,                 MAX_ENVELOPE_YSIZE,
1747     GADGET_ID_ENVELOPE_YSIZE_DOWN,      GADGET_ID_ENVELOPE_YSIZE_UP,
1748     GADGET_ID_ENVELOPE_YSIZE_TEXT,      GADGET_ID_ENVELOPE_XSIZE_UP,
1749     NULL,                               // will be set when used
1750     NULL,                               " ", "Height",
1751   },
1752   {
1753     ED_COUNTER_ID_INVENTORY_SIZE,
1754     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1755     MIN_INITIAL_INVENTORY_SIZE,         MAX_INITIAL_INVENTORY_SIZE,
1756     GADGET_ID_INVENTORY_SIZE_DOWN,      GADGET_ID_INVENTORY_SIZE_UP,
1757     GADGET_ID_INVENTORY_SIZE_TEXT,      GADGET_ID_NONE,
1758     &level.initial_inventory_size[0],
1759     NULL,                               NULL, "Number of inventory elements"
1760   },
1761   {
1762     ED_COUNTER_ID_MM_BALL_CONTENT,
1763     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1764     MIN_ELEMENTS_IN_GROUP,              MAX_MM_BALL_CONTENTS,
1765     GADGET_ID_MM_BALL_CONTENT_DOWN,     GADGET_ID_MM_BALL_CONTENT_UP,
1766     GADGET_ID_MM_BALL_CONTENT_TEXT,     GADGET_ID_NONE,
1767     &level.num_mm_ball_contents,
1768     NULL,                               NULL, "Number of content elements"
1769   },
1770
1771   // ---------- element settings: configure 1 (custom elements) ---------------
1772
1773   {
1774     ED_COUNTER_ID_CUSTOM_SCORE,
1775     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1776     MIN_SCORE,                          MAX_SCORE,
1777     GADGET_ID_CUSTOM_SCORE_DOWN,        GADGET_ID_CUSTOM_SCORE_UP,
1778     GADGET_ID_CUSTOM_SCORE_TEXT,        GADGET_ID_NONE,
1779     &custom_element.collect_score_initial,
1780     NULL,                               "CE score", " "
1781   },
1782   {
1783     ED_COUNTER_ID_CUSTOM_GEMCOUNT,
1784     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1785     MIN_COLLECT_COUNT,                  MAX_COLLECT_COUNT,
1786     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,     GADGET_ID_CUSTOM_GEMCOUNT_UP,
1787     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,     GADGET_ID_CUSTOM_SCORE_UP,
1788     &custom_element.collect_count_initial,
1789     NULL,                               "CE count", NULL
1790   },
1791   {
1792     ED_COUNTER_ID_CUSTOM_VALUE_FIX,
1793     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1794     0,                                  9999,
1795     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1796     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,    GADGET_ID_NONE,
1797     &custom_element.ce_value_fixed_initial,
1798     NULL,                               "CE value", NULL
1799   },
1800   {
1801     ED_COUNTER_ID_CUSTOM_VALUE_RND,
1802     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1803     0,                                  9999,
1804     GADGET_ID_CUSTOM_VALUE_RND_DOWN,    GADGET_ID_CUSTOM_VALUE_RND_UP,
1805     GADGET_ID_CUSTOM_VALUE_RND_TEXT,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1806     &custom_element.ce_value_random_initial,
1807     NULL,                               "+random", NULL
1808   },
1809   {
1810     ED_COUNTER_ID_PUSH_DELAY_FIX,
1811     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1812     0,                                  999,
1813     GADGET_ID_PUSH_DELAY_FIX_DOWN,      GADGET_ID_PUSH_DELAY_FIX_UP,
1814     GADGET_ID_PUSH_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1815     &custom_element.push_delay_fixed,
1816     NULL,                               "Push delay", NULL
1817   },
1818   {
1819     ED_COUNTER_ID_PUSH_DELAY_RND,
1820     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1821     0,                                  999,
1822     GADGET_ID_PUSH_DELAY_RND_DOWN,      GADGET_ID_PUSH_DELAY_RND_UP,
1823     GADGET_ID_PUSH_DELAY_RND_TEXT,      GADGET_ID_PUSH_DELAY_FIX_UP,
1824     &custom_element.push_delay_random,
1825     NULL,                               "+random", NULL
1826   },
1827   {
1828     ED_COUNTER_ID_DROP_DELAY_FIX,
1829     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(7),
1830     0,                                  999,
1831     GADGET_ID_DROP_DELAY_FIX_DOWN,      GADGET_ID_DROP_DELAY_FIX_UP,
1832     GADGET_ID_DROP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1833     &custom_element.drop_delay_fixed,
1834     NULL,                               "Drop delay", NULL
1835   },
1836   {
1837     ED_COUNTER_ID_DROP_DELAY_RND,
1838     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
1839     0,                                  999,
1840     GADGET_ID_DROP_DELAY_RND_DOWN,      GADGET_ID_DROP_DELAY_RND_UP,
1841     GADGET_ID_DROP_DELAY_RND_TEXT,      GADGET_ID_DROP_DELAY_FIX_UP,
1842     &custom_element.drop_delay_random,
1843     NULL,                               "+random", NULL
1844   },
1845
1846   // ---------- element settings: configure 2 (custom elements) ---------------
1847
1848   {
1849     ED_COUNTER_ID_MOVE_DELAY_FIX,
1850     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1851     0,                                  999,
1852     GADGET_ID_MOVE_DELAY_FIX_DOWN,      GADGET_ID_MOVE_DELAY_FIX_UP,
1853     GADGET_ID_MOVE_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1854     &custom_element.move_delay_fixed,
1855     NULL,                               "Move delay", NULL
1856   },
1857   {
1858     ED_COUNTER_ID_MOVE_DELAY_RND,
1859     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1860     0,                                  999,
1861     GADGET_ID_MOVE_DELAY_RND_DOWN,      GADGET_ID_MOVE_DELAY_RND_UP,
1862     GADGET_ID_MOVE_DELAY_RND_TEXT,      GADGET_ID_MOVE_DELAY_FIX_UP,
1863     &custom_element.move_delay_random,
1864     NULL,                               "+random", NULL
1865   },
1866   {
1867     ED_COUNTER_ID_STEP_DELAY_FIX,
1868     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1869     0,                                  999,
1870     GADGET_ID_STEP_DELAY_FIX_DOWN,      GADGET_ID_STEP_DELAY_FIX_UP,
1871     GADGET_ID_STEP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1872     &custom_element.step_delay_fixed,
1873     NULL,                               "Step delay", NULL
1874   },
1875   {
1876     ED_COUNTER_ID_STEP_DELAY_RND,
1877     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1878     0,                                  999,
1879     GADGET_ID_STEP_DELAY_RND_DOWN,      GADGET_ID_STEP_DELAY_RND_UP,
1880     GADGET_ID_STEP_DELAY_RND_TEXT,      GADGET_ID_STEP_DELAY_FIX_UP,
1881     &custom_element.step_delay_random,
1882     NULL,                               "+random", NULL
1883   },
1884   {
1885     ED_COUNTER_ID_EXPLOSION_DELAY,
1886     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
1887     0,                                  999,
1888     GADGET_ID_EXPLOSION_DELAY_DOWN,     GADGET_ID_EXPLOSION_DELAY_UP,
1889     GADGET_ID_EXPLOSION_DELAY_TEXT,     GADGET_ID_NONE,
1890     &custom_element.explosion_delay,
1891     NULL,                               "Explosion delay", NULL
1892   },
1893   {
1894     ED_COUNTER_ID_IGNITION_DELAY,
1895     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
1896     0,                                  999,
1897     GADGET_ID_IGNITION_DELAY_DOWN,      GADGET_ID_IGNITION_DELAY_UP,
1898     GADGET_ID_IGNITION_DELAY_TEXT,      GADGET_ID_NONE,
1899     &custom_element.ignition_delay,
1900     NULL,                               "Ignition delay", "(by fire)"
1901   },
1902
1903   // ---------- element settings: configure (group elements) ------------------
1904
1905   {
1906     ED_COUNTER_ID_GROUP_CONTENT,
1907     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1908     MIN_ELEMENTS_IN_GROUP,              MAX_ELEMENTS_IN_GROUP,
1909     GADGET_ID_GROUP_CONTENT_DOWN,       GADGET_ID_GROUP_CONTENT_UP,
1910     GADGET_ID_GROUP_CONTENT_TEXT,       GADGET_ID_NONE,
1911     &group_element_info.num_elements,
1912     NULL,                               NULL, "Number of elements in group"
1913   },
1914
1915   // ---------- element settings: advanced (custom elements) ------------------
1916
1917   {
1918     ED_COUNTER_ID_CHANGE_DELAY_FIX,
1919     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(2),
1920     0,                                  999,
1921     GADGET_ID_CHANGE_DELAY_FIX_DOWN,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1922     GADGET_ID_CHANGE_DELAY_FIX_TEXT,    GADGET_ID_NONE,
1923     &custom_element_change.delay_fixed,
1924     NULL,                               "CE delay", NULL,
1925   },
1926   {
1927     ED_COUNTER_ID_CHANGE_DELAY_RND,
1928     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
1929     0,                                  999,
1930     GADGET_ID_CHANGE_DELAY_RND_DOWN,    GADGET_ID_CHANGE_DELAY_RND_UP,
1931     GADGET_ID_CHANGE_DELAY_RND_TEXT,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1932     &custom_element_change.delay_random,
1933     NULL,                               "+random", NULL
1934   },
1935   {
1936     ED_COUNTER_ID_CHANGE_CONT_RND,
1937     ED_ELEMENT_SETTINGS_XPOS(3),        ED_ELEMENT_SETTINGS_YPOS(12),
1938     0,                                  100,
1939     GADGET_ID_CHANGE_CONT_RND_DOWN,     GADGET_ID_CHANGE_CONT_RND_UP,
1940     GADGET_ID_CHANGE_CONT_RND_TEXT,     GADGET_ID_NONE,
1941     &custom_element_change.random_percentage,
1942     NULL,                               "Use random replace:", "%"
1943   },
1944 };
1945
1946 static struct
1947 {
1948   int gadget_type_id;
1949   int x, y;
1950   int gadget_id;
1951   int size;
1952   char *value;
1953   char *text_above, *infotext;
1954 } textinput_info[ED_NUM_TEXTINPUT] =
1955 {
1956   {
1957     ED_TEXTINPUT_ID_LEVEL_NAME,
1958     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1959     GADGET_ID_LEVEL_NAME,
1960     MAX_LEVEL_NAME_LEN,
1961     level.name,
1962     "Title:", "Title for this level"
1963   },
1964   {
1965     ED_TEXTINPUT_ID_LEVEL_AUTHOR,
1966     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1967     GADGET_ID_LEVEL_AUTHOR,
1968     MAX_LEVEL_AUTHOR_LEN,
1969     level.author,
1970     "Author:", "Author for this level"
1971   },
1972   {
1973     ED_TEXTINPUT_ID_LEVELSET_NAME,
1974     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1975     GADGET_ID_LEVELSET_NAME,
1976     MAX_LEVEL_NAME_LEN,
1977     levelset_name,
1978     "Title:", "Title for this or new level set"
1979   },
1980   {
1981     ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
1982     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1983     GADGET_ID_LEVELSET_AUTHOR,
1984     MAX_LEVEL_AUTHOR_LEN,
1985     levelset_author,
1986     "Author:", "Author for this or new level set"
1987   },
1988   {
1989     ED_TEXTINPUT_ID_ELEMENT_NAME,
1990     -1, -1,     // these values are not constant, but can change at runtime
1991     GADGET_ID_ELEMENT_NAME,
1992     MAX_ELEMENT_NAME_LEN - 2,           // currently 2 chars less editable
1993     custom_element.description,
1994     NULL, "Element name"
1995   }
1996 };
1997
1998 static struct
1999 {
2000   int gadget_type_id;
2001   int x, y;
2002   int gadget_id;
2003   int xsize, ysize;
2004   char *value;
2005   char *text_above, *text_above_cropped, *infotext;
2006 } textarea_info[ED_NUM_TEXTAREAS] =
2007 {
2008   {
2009     ED_TEXTAREA_ID_ENVELOPE_INFO,
2010     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
2011     GADGET_ID_ENVELOPE_INFO,
2012     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
2013     NULL,
2014     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
2015   }
2016 };
2017
2018 static struct ValueTextInfo options_time_or_steps[] =
2019 {
2020   { 0,                          "seconds"                       },
2021   { 1,                          "steps"                         },
2022
2023   { -1,                         NULL                            }
2024 };
2025
2026 static struct ValueTextInfo options_time_score_base[] =
2027 {
2028   { 1,                          "per second/step"               },
2029   { 10,                         "per 10 seconds/steps"          },
2030
2031   { -1,                         NULL                            }
2032 };
2033
2034 static struct ValueTextInfo options_game_engine_type[] =
2035 {
2036   { GAME_ENGINE_TYPE_RND,       "Rocks'n'Diamonds"              },
2037   { GAME_ENGINE_TYPE_BD,        "Boulder Dash"                  },
2038   { GAME_ENGINE_TYPE_EM,        "Emerald Mine"                  },
2039   { GAME_ENGINE_TYPE_SP,        "Supaplex"                      },
2040   { GAME_ENGINE_TYPE_MM,        "Mirror Magic"                  },
2041
2042   { -1,                         NULL                            }
2043 };
2044
2045 static struct ValueTextInfo options_levelset_save_mode[] =
2046 {
2047   { LEVELSET_SAVE_MODE_UPDATE,  "Update this level set"         },
2048   { LEVELSET_SAVE_MODE_CREATE,  "Create new level set"          },
2049
2050   { -1,                         NULL                            }
2051 };
2052
2053 static struct ValueTextInfo options_wind_direction[] =
2054 {
2055   { MV_START_NONE,              "none"                          },
2056   { MV_START_LEFT,              "left"                          },
2057   { MV_START_RIGHT,             "right"                         },
2058   { MV_START_UP,                "up"                            },
2059   { MV_START_DOWN,              "down"                          },
2060
2061   { -1,                         NULL                            }
2062 };
2063
2064 static struct ValueTextInfo options_player_speed[] =
2065 {
2066   { 0,                          "frozen"                        },
2067   { 1,                          "very slow"                     },
2068   { 2,                          "slow"                          },
2069   { 4,                          "normal"                        },
2070   { 8,                          "fast"                          },
2071   { 16,                         "very fast"                     },
2072   { 32,                         "ultrafast"                     },
2073
2074   { -1,                         NULL                            }
2075 };
2076
2077 static struct ValueTextInfo options_access_type[] =
2078 {
2079   { EP_WALKABLE,                "walkable"                      },
2080   { EP_PASSABLE,                "passable"                      },
2081
2082   { -1,                         NULL                            }
2083 };
2084
2085 static struct ValueTextInfo options_access_layer[] =
2086 {
2087   { EP_ACCESSIBLE_OVER,         "over"                          },
2088   { EP_ACCESSIBLE_INSIDE,       "inside"                        },
2089   { EP_ACCESSIBLE_UNDER,        "under"                         },
2090
2091   { -1,                         NULL                            }
2092 };
2093
2094 static struct ValueTextInfo options_access_protected[] =
2095 {
2096   { 0,                          "unprotected"                   },
2097   { 1,                          "protected"                     },
2098
2099   { -1,                         NULL                            }
2100 };
2101
2102 static struct ValueTextInfo options_access_direction[] =
2103 {
2104   { MV_NO_DIRECTION,            "no direction"                  },
2105   { MV_LEFT,                    "left"                          },
2106   { MV_RIGHT,                   "right"                         },
2107   { MV_UP,                      "up"                            },
2108   { MV_DOWN,                    "down"                          },
2109   { MV_LEFT  | MV_UP,           "left + up"                     },
2110   { MV_LEFT  | MV_DOWN,         "left + down"                   },
2111   { MV_RIGHT | MV_UP,           "right + up"                    },
2112   { MV_RIGHT | MV_DOWN,         "right + down"                  },
2113   { MV_HORIZONTAL,              "horizontal"                    },
2114   { MV_VERTICAL,                "vertical"                      },
2115   { MV_HORIZONTAL | MV_UP,      "horizontal + up"               },
2116   { MV_HORIZONTAL | MV_DOWN,    "horizontal + down"             },
2117   { MV_VERTICAL   | MV_LEFT,    "vertical + left"               },
2118   { MV_VERTICAL   | MV_RIGHT,   "vertical + right"              },
2119   { MV_ALL_DIRECTIONS,          "all directions"                },
2120
2121   { -1,                         NULL                            }
2122 };
2123
2124 static struct ValueTextInfo options_walk_to_action[] =
2125 {
2126   { EP_DIGGABLE,                "diggable"                      },
2127   { EP_COLLECTIBLE_ONLY,        "collectible"                   },
2128   { EP_DROPPABLE,               "collectible & droppable"       },
2129   { EP_THROWABLE,               "collectible & throwable"       },
2130   { EP_PUSHABLE,                "pushable"                      },
2131
2132   { -1,                         NULL                            }
2133 };
2134
2135 static struct ValueTextInfo options_move_pattern[] =
2136 {
2137   { MV_LEFT,                    "left"                          },
2138   { MV_RIGHT,                   "right"                         },
2139   { MV_UP,                      "up"                            },
2140   { MV_DOWN,                    "down"                          },
2141   { MV_HORIZONTAL,              "horizontal"                    },
2142   { MV_VERTICAL,                "vertical"                      },
2143   { MV_ALL_DIRECTIONS,          "all directions"                },
2144   { MV_WIND_DIRECTION,          "wind direction"                },
2145   { MV_TOWARDS_PLAYER,          "towards player"                },
2146   { MV_AWAY_FROM_PLAYER,        "away from player"              },
2147   { MV_ALONG_LEFT_SIDE,         "along left side"               },
2148   { MV_ALONG_RIGHT_SIDE,        "along right side"              },
2149   { MV_TURNING_LEFT,            "turning left"                  },
2150   { MV_TURNING_RIGHT,           "turning right"                 },
2151   { MV_TURNING_LEFT_RIGHT,      "turning left, right"           },
2152   { MV_TURNING_RIGHT_LEFT,      "turning right, left"           },
2153   { MV_TURNING_RANDOM,          "turning random"                },
2154   { MV_MAZE_RUNNER,             "maze runner style"             },
2155   { MV_MAZE_HUNTER,             "maze hunter style"             },
2156   { MV_WHEN_PUSHED,             "when pushed"                   },
2157   { MV_WHEN_DROPPED,            "when dropped/thrown"           },
2158
2159   { -1,                         NULL                            }
2160 };
2161
2162 static struct ValueTextInfo options_move_direction[] =
2163 {
2164   { MV_START_AUTOMATIC,         "automatic"                     },
2165   { MV_START_LEFT,              "left"                          },
2166   { MV_START_RIGHT,             "right"                         },
2167   { MV_START_UP,                "up"                            },
2168   { MV_START_DOWN,              "down"                          },
2169   { MV_START_RANDOM,            "random"                        },
2170   { MV_START_PREVIOUS,          "previous"                      },
2171
2172   { -1,                         NULL                            }
2173 };
2174
2175 static struct ValueTextInfo options_move_stepsize[] =
2176 {
2177   { 0,                          "not moving"                    },
2178   { 1,                          "very slow"                     },
2179   { 2,                          "slow"                          },
2180   { 4,                          "normal"                        },
2181   { 8,                          "fast"                          },
2182   { 16,                         "very fast"                     },
2183   { 32,                         "even faster"                   },
2184
2185   { -1,                         NULL                            }
2186 };
2187
2188 static struct ValueTextInfo options_move_leave_type[] =
2189 {
2190   { LEAVE_TYPE_UNLIMITED,       "leave behind"                  },
2191   { LEAVE_TYPE_LIMITED,         "change it to"                  },
2192
2193   { -1,                         NULL                            }
2194 };
2195
2196 static struct ValueTextInfo options_smash_targets[] =
2197 {
2198   { EP_CAN_SMASH_PLAYER,        "player"                        },
2199 #if 0
2200   { EP_CAN_SMASH_ENEMIES,       "enemies"                       },
2201 #endif
2202   { EP_CAN_SMASH_EVERYTHING,    "everything"                    },
2203
2204   { -1,                         NULL                            }
2205 };
2206
2207 static struct ValueTextInfo options_slippery_type[] =
2208 {
2209   { SLIPPERY_ANY_RANDOM,        "random"                        },
2210   { SLIPPERY_ANY_LEFT_RIGHT,    "left, right"                   },
2211   { SLIPPERY_ANY_RIGHT_LEFT,    "right, left"                   },
2212   { SLIPPERY_ONLY_LEFT,         "only left"                     },
2213   { SLIPPERY_ONLY_RIGHT,        "only right"                    },
2214
2215   { -1,                         NULL                            }
2216 };
2217
2218 static struct ValueTextInfo options_deadliness[] =
2219 {
2220   { EP_DONT_RUN_INTO,           "running into"                  },
2221   { EP_DONT_COLLIDE_WITH,       "colliding with"                },
2222   { EP_DONT_GET_HIT_BY,         "getting hit by"                },
2223   { EP_DONT_TOUCH,              "touching"                      },
2224
2225   { -1,                         NULL                            }
2226 };
2227
2228 static struct ValueTextInfo options_explosion_type[] =
2229 {
2230   { EXPLODES_3X3,               "3x3"                           },
2231   { EXPLODES_CROSS,             "3+3"                           },
2232   { EXPLODES_1X1,               "1x1"                           },
2233
2234   { -1,                         NULL                            }
2235 };
2236
2237 static struct ValueTextInfo options_time_units[] =
2238 {
2239   { 1,                          "frames"                        },
2240   { FRAMES_PER_SECOND,          "seconds"                       },
2241
2242   { -1,                         NULL                            }
2243 };
2244
2245 static struct ValueTextInfo options_change_direct_action[] =
2246 {
2247   { CE_TOUCHED_BY_PLAYER,       "touched by player"             },
2248   { CE_PRESSED_BY_PLAYER,       "pressed by player"             },
2249   { CE_SWITCHED_BY_PLAYER,      "switched by player"            },
2250   { CE_SNAPPED_BY_PLAYER,       "snapped by player"             },
2251   { CE_PUSHED_BY_PLAYER,        "pushed by player"              },
2252   { CE_ENTERED_BY_PLAYER,       "entered by player"             },
2253   { CE_LEFT_BY_PLAYER,          "left by player"                },
2254   { CE_DROPPED_BY_PLAYER,       "dropped/thrown by player"      },
2255   { CE_SWITCHED,                "switched"                      },
2256   { CE_HITTING_SOMETHING,       "hitting something"             },
2257   { CE_HIT_BY_SOMETHING,        "hit by something"              },
2258 #if 0
2259   { CE_BLOCKED,                 "blocked"                       },
2260 #endif
2261   { CE_IMPACT,                  "impact (on something)"         },
2262   { CE_SMASHED,                 "smashed (from above)"          },
2263 #if 0
2264   { CE_VALUE_CHANGES,           "CE value changes"              },
2265   { CE_SCORE_CHANGES,           "CE score changes"              },
2266 #endif
2267   { CE_VALUE_GETS_ZERO,         "CE value gets 0"               },
2268   { CE_SCORE_GETS_ZERO,         "CE score gets 0"               },
2269   { CE_UNDEFINED,               " "                             },
2270   { CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]"                },
2271   { CE_CLICKED_BY_MOUSE,        "clicked by mouse"              },
2272   { CE_PRESSED_BY_MOUSE,        "pressed by mouse"              },
2273   { CE_UNDEFINED,               " "                             },
2274   { CE_HEADLINE_SPECIAL_EVENTS, "[static states]"               },
2275   { CE_NEXT_TO_PLAYER,          "next to player"                },
2276
2277   { -1,                         NULL                            }
2278 };
2279
2280 static struct ValueTextInfo options_change_other_action[] =
2281 {
2282   { CE_PLAYER_TOUCHES_X,        "player touches"                },
2283   { CE_PLAYER_PRESSES_X,        "player presses"                },
2284   { CE_PLAYER_SWITCHES_X,       "player switches"               },
2285   { CE_PLAYER_SNAPS_X,          "player snaps"                  },
2286   { CE_PLAYER_PUSHES_X,         "player pushes"                 },
2287   { CE_PLAYER_ENTERS_X,         "player enters"                 },
2288   { CE_PLAYER_LEAVES_X,         "player leaves"                 },
2289   { CE_PLAYER_DIGS_X,           "player digs"                   },
2290   { CE_PLAYER_COLLECTS_X,       "player collects"               },
2291   { CE_PLAYER_DROPS_X,          "player drops/throws"           },
2292   { CE_TOUCHING_X,              "touching"                      },
2293   { CE_HITTING_X,               "hitting"                       },
2294   { CE_DIGGING_X,               "digging"                       },
2295   { CE_HIT_BY_X,                "hit by"                        },
2296   { CE_SWITCH_OF_X,             "switch of"                     },
2297   { CE_CHANGE_OF_X,             "change by page of"             },
2298   { CE_EXPLOSION_OF_X,          "explosion of"                  },
2299   { CE_MOVE_OF_X,               "move of"                       },
2300   { CE_CREATION_OF_X,           "creation of"                   },
2301   { CE_VALUE_CHANGES_OF_X,      "CE value changes of"           },
2302   { CE_SCORE_CHANGES_OF_X,      "CE score changes of"           },
2303   { CE_VALUE_GETS_ZERO_OF_X,    "CE value gets 0 of"            },
2304   { CE_SCORE_GETS_ZERO_OF_X,    "CE score gets 0 of"            },
2305   { CE_UNDEFINED,               " "                             },
2306   { CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]"                },
2307   { CE_MOUSE_CLICKED_ON_X,      "mouse clicked on"              },
2308   { CE_MOUSE_PRESSED_ON_X,      "mouse pressed on"              },
2309   { CE_UNDEFINED,               " "                             },
2310   { CE_HEADLINE_SPECIAL_EVENTS, "[static states]"               },
2311   { CE_PLAYER_NEXT_TO_X,        "player next to"                },
2312   { CE_NEXT_TO_X,               "next to"                       },
2313
2314   { -1,                         NULL                            }
2315 };
2316
2317 static struct ValueTextInfo options_change_trigger_side[] =
2318 {
2319   { CH_SIDE_LEFT,               "left"                          },
2320   { CH_SIDE_RIGHT,              "right"                         },
2321   { CH_SIDE_TOP,                "top"                           },
2322   { CH_SIDE_BOTTOM,             "bottom"                        },
2323   { CH_SIDE_LEFT_RIGHT,         "left/right"                    },
2324   { CH_SIDE_TOP_BOTTOM,         "top/bottom"                    },
2325   { CH_SIDE_ANY,                "any"                           },
2326
2327   { -1,                         NULL                            }
2328 };
2329
2330 static struct ValueTextInfo options_change_trigger_player[] =
2331 {
2332   { CH_PLAYER_1,                "1"                             },
2333   { CH_PLAYER_2,                "2"                             },
2334   { CH_PLAYER_3,                "3"                             },
2335   { CH_PLAYER_4,                "4"                             },
2336   { CH_PLAYER_ANY,              "any"                           },
2337
2338   { -1,                         NULL                            }
2339 };
2340
2341 static struct ValueTextInfo options_change_trigger_page[] =
2342 {
2343   { (1u << 0),                  "1"                             },
2344   { (1u << 1),                  "2"                             },
2345   { (1u << 2),                  "3"                             },
2346   { (1u << 3),                  "4"                             },
2347   { (1u << 4),                  "5"                             },
2348   { (1u << 5),                  "6"                             },
2349   { (1u << 6),                  "7"                             },
2350   { (1u << 7),                  "8"                             },
2351   { (1u << 8),                  "9"                             },
2352   { (1u << 9),                  "10"                            },
2353   { (1u << 10),                 "11"                            },
2354   { (1u << 11),                 "12"                            },
2355   { (1u << 12),                 "13"                            },
2356   { (1u << 13),                 "14"                            },
2357   { (1u << 14),                 "15"                            },
2358   { (1u << 15),                 "16"                            },
2359   { (1u << 16),                 "17"                            },
2360   { (1u << 17),                 "18"                            },
2361   { (1u << 18),                 "19"                            },
2362   { (1u << 19),                 "20"                            },
2363   { (1u << 20),                 "21"                            },
2364   { (1u << 21),                 "22"                            },
2365   { (1u << 22),                 "23"                            },
2366   { (1u << 23),                 "24"                            },
2367   { (1u << 24),                 "25"                            },
2368   { (1u << 25),                 "26"                            },
2369   { (1u << 26),                 "27"                            },
2370   { (1u << 27),                 "28"                            },
2371   { (1u << 28),                 "29"                            },
2372   { (1u << 29),                 "30"                            },
2373   { (1u << 30),                 "31"                            },
2374   { (1u << 31),                 "32"                            },
2375   { CH_PAGE_ANY,                "any"                           },
2376
2377   { -1,                         NULL                            }
2378 };
2379
2380 static struct ValueTextInfo options_change_replace_when[] =
2381 {
2382   { CP_WHEN_EMPTY,              "empty"                         },
2383   { CP_WHEN_WALKABLE,           "walkable"                      },
2384   { CP_WHEN_DIGGABLE,           "diggable"                      },
2385   { CP_WHEN_COLLECTIBLE,        "collectible"                   },
2386   { CP_WHEN_REMOVABLE,          "removable"                     },
2387   { CP_WHEN_DESTRUCTIBLE,       "destructible"                  },
2388
2389   { -1,                         NULL                            }
2390 };
2391
2392 static struct ValueTextInfo options_action_type[] =
2393 {
2394   { CA_NO_ACTION,               "no action"                     },
2395   { CA_UNDEFINED,               " "                             },
2396   { CA_HEADLINE_LEVEL_ACTIONS,  "[level]"                       },
2397   { CA_RESTART_LEVEL,           "restart level"                 },
2398   { CA_SHOW_ENVELOPE,           "show envelope"                 },
2399   { CA_SET_LEVEL_TIME,          "set time"                      },
2400   { CA_SET_LEVEL_SCORE,         "set score"                     },
2401   { CA_SET_LEVEL_GEMS,          "set gems"                      },
2402   { CA_SET_LEVEL_WIND,          "set wind dir."                 },
2403   { CA_SET_LEVEL_RANDOM_SEED,   "set random seed"               },
2404   { CA_UNDEFINED,               " "                             },
2405   { CA_HEADLINE_PLAYER_ACTIONS, "[player]"                      },
2406   { CA_MOVE_PLAYER,             "move player"                   },
2407   { CA_MOVE_PLAYER_NEW,         "move player new"               },
2408   { CA_EXIT_PLAYER,             "exit player"                   },
2409   { CA_KILL_PLAYER,             "kill player"                   },
2410   { CA_SET_PLAYER_KEYS,         "set keys"                      },
2411   { CA_SET_PLAYER_SPEED,        "set speed"                     },
2412   { CA_SET_PLAYER_SHIELD,       "set shield"                    },
2413   { CA_SET_PLAYER_GRAVITY,      "set gravity"                   },
2414   { CA_SET_PLAYER_ARTWORK,      "set artwork"                   },
2415   { CA_SET_PLAYER_INVENTORY,    "set inventory"                 },
2416   { CA_UNDEFINED,               " "                             },
2417   { CA_HEADLINE_CE_ACTIONS,     "[CE]"                          },
2418   { CA_SET_CE_VALUE,            "set CE value"                  },
2419   { CA_SET_CE_SCORE,            "set CE score"                  },
2420   { CA_SET_CE_ARTWORK,          "set CE artwork"                },
2421   { CA_UNDEFINED,               " "                             },
2422   { CA_HEADLINE_ENGINE_ACTIONS, "[engine]"                      },
2423   { CA_SET_ENGINE_SCAN_MODE,    "set scan mode"                 },
2424
2425   { -1,                         NULL                            }
2426 };
2427
2428 static struct ValueTextInfo options_action_mode_none[] =
2429 {
2430   { CA_MODE_UNDEFINED,          " "                             },
2431
2432   { -1,                         NULL                            }
2433 };
2434
2435 static struct ValueTextInfo options_action_mode_assign[] =
2436 {
2437   { CA_MODE_SET,                "="                             },
2438
2439   { -1,                         NULL                            }
2440 };
2441
2442 static struct ValueTextInfo options_action_mode_add_remove[] =
2443 {
2444   { CA_MODE_ADD,                "+"                             },
2445   { CA_MODE_SUBTRACT,           "-"                             },
2446
2447   { -1,                         NULL                            }
2448 };
2449
2450 static struct ValueTextInfo options_action_mode_calculate[] =
2451 {
2452   { CA_MODE_SET,                "="                             },
2453   { CA_MODE_ADD,                "+"                             },
2454   { CA_MODE_SUBTRACT,           "-"                             },
2455   { CA_MODE_MULTIPLY,           "*"                             },
2456   { CA_MODE_DIVIDE,             "/"                             },
2457   { CA_MODE_MODULO,             "%"                             },
2458
2459   { -1,                         NULL                            }
2460 };
2461
2462 static struct ValueTextInfo options_action_arg_none[] =
2463 {
2464   { CA_ARG_UNDEFINED,           "         "                     },
2465
2466   { -1,                         NULL                            }
2467 };
2468
2469 static struct ValueTextInfo options_action_arg_player[] =
2470 {
2471   { CA_ARG_PLAYER_HEADLINE,     "[player]"                      },
2472   { CA_ARG_PLAYER_1,            "1"                             },
2473   { CA_ARG_PLAYER_2,            "2"                             },
2474   { CA_ARG_PLAYER_3,            "3"                             },
2475   { CA_ARG_PLAYER_4,            "4"                             },
2476   { CA_ARG_PLAYER_ANY,          "any"                           },
2477   { CA_ARG_PLAYER_TRIGGER,      "trigger"                       },
2478   { CA_ARG_PLAYER_ACTION,       "action ->"                     },
2479
2480   { -1,                         NULL                            }
2481 };
2482
2483 static struct ValueTextInfo options_action_arg_number[] =
2484 {
2485   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2486   { CA_ARG_0,                   "0"                             },
2487   { CA_ARG_1,                   "1"                             },
2488   { CA_ARG_2,                   "2"                             },
2489   { CA_ARG_3,                   "3"                             },
2490   { CA_ARG_4,                   "4"                             },
2491   { CA_ARG_5,                   "5"                             },
2492   { CA_ARG_10,                  "10"                            },
2493   { CA_ARG_100,                 "100"                           },
2494   { CA_ARG_1000,                "1000"                          },
2495   { CA_ARG_UNDEFINED,           " "                             },
2496   { CA_ARG_NUMBER_MIN,          "min"                           },
2497   { CA_ARG_NUMBER_MAX,          "max"                           },
2498   { CA_ARG_UNDEFINED,           " "                             },
2499   { CA_ARG_NUMBER_RESET,        "reset"                         },
2500   { CA_ARG_UNDEFINED,           " "                             },
2501   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
2502   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
2503   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2504   { CA_ARG_UNDEFINED,           " "                             },
2505   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2506   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2507   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2508   { CA_ARG_UNDEFINED,           " "                             },
2509   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2510   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2511   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2512   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2513   { CA_ARG_UNDEFINED,           " "                             },
2514   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2515   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2516   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2517   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2518
2519   { -1,                         NULL                            }
2520 };
2521
2522 static struct ValueTextInfo options_action_arg_value[] =
2523 {
2524   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2525   { CA_ARG_0,                   "0"                             },
2526   { CA_ARG_1,                   "1"                             },
2527   { CA_ARG_2,                   "2"                             },
2528   { CA_ARG_3,                   "3"                             },
2529   { CA_ARG_4,                   "4"                             },
2530   { CA_ARG_5,                   "5"                             },
2531   { CA_ARG_10,                  "10"                            },
2532   { CA_ARG_100,                 "100"                           },
2533   { CA_ARG_1000,                "1000"                          },
2534   { CA_ARG_UNDEFINED,           " "                             },
2535   { CA_ARG_NUMBER_MIN,          "min"                           },
2536   { CA_ARG_NUMBER_MAX,          "max"                           },
2537   { CA_ARG_UNDEFINED,           " "                             },
2538   { CA_ARG_NUMBER_RESET,        "reset"                         },
2539   { CA_ARG_UNDEFINED,           " "                             },
2540   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
2541   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
2542   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2543   { CA_ARG_UNDEFINED,           " "                             },
2544   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2545   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2546   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2547   { CA_ARG_UNDEFINED,           " "                             },
2548   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2549   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2550   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2551   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2552   { CA_ARG_UNDEFINED,           " "                             },
2553   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2554   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2555   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2556   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2557   { CA_ARG_UNDEFINED,           " "                             },
2558   { CA_ARG_ELEMENT_NR_HEADLINE, "[element]"                     },
2559   { CA_ARG_ELEMENT_NR_TARGET,   "target"                        },
2560   { CA_ARG_ELEMENT_NR_TRIGGER,  "trigger"                       },
2561   { CA_ARG_ELEMENT_NR_ACTION,   "action ->"                     },
2562
2563   { -1,                         NULL                            }
2564 };
2565
2566 static struct ValueTextInfo options_action_arg_envelope[] =
2567 {
2568   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2569   { CA_ARG_1,                   "1"                             },
2570   { CA_ARG_2,                   "2"                             },
2571   { CA_ARG_3,                   "3"                             },
2572   { CA_ARG_4,                   "4"                             },
2573   { CA_ARG_UNDEFINED,           " "                             },
2574   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2575   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2576   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2577   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2578
2579   { -1,                         NULL                            }
2580 };
2581
2582 static struct ValueTextInfo options_action_arg_key[] =
2583 {
2584   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2585   { CA_ARG_1,                   "1"                             },
2586   { CA_ARG_2,                   "2"                             },
2587   { CA_ARG_3,                   "3"                             },
2588   { CA_ARG_4,                   "4"                             },
2589   { CA_ARG_5,                   "5"                             },
2590   { CA_ARG_6,                   "6"                             },
2591   { CA_ARG_7,                   "7"                             },
2592   { CA_ARG_8,                   "8"                             },
2593   { CA_ARG_UNDEFINED,           " "                             },
2594   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2595   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2596   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2597   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2598
2599   { -1,                         NULL                            }
2600 };
2601
2602 static struct ValueTextInfo options_action_arg_speed[] =
2603 {
2604   { CA_ARG_SPEED_HEADLINE,      "[speed]"                       },
2605   { CA_ARG_SPEED_NOT_MOVING,    "frozen"                        },
2606   { CA_ARG_SPEED_VERY_SLOW,     "very slow"                     },
2607   { CA_ARG_SPEED_SLOW,          "slow"                          },
2608   { CA_ARG_SPEED_NORMAL,        "normal"                        },
2609   { CA_ARG_SPEED_FAST,          "fast"                          },
2610   { CA_ARG_SPEED_VERY_FAST,     "very fast"                     },
2611   { CA_ARG_SPEED_EVEN_FASTER,   "ultrafast"                     },
2612   { CA_ARG_UNDEFINED,           " "                             },
2613   { CA_ARG_SPEED_SLOWER,        "slower"                        },
2614   { CA_ARG_SPEED_FASTER,        "faster"                        },
2615   { CA_ARG_UNDEFINED,           " "                             },
2616   { CA_ARG_SPEED_RESET,         "reset"                         },
2617
2618   { -1,                         NULL                            }
2619 };
2620
2621 static struct ValueTextInfo options_action_arg_shield[] =
2622 {
2623   { CA_ARG_SHIELD_HEADLINE,     "[shield]"                      },
2624   { CA_ARG_SHIELD_OFF,          "off"                           },
2625   { CA_ARG_SHIELD_NORMAL,       "normal"                        },
2626   { CA_ARG_SHIELD_DEADLY,       "deadly"                        },
2627
2628   { -1,                         NULL                            }
2629 };
2630
2631 static struct ValueTextInfo options_action_arg_artwork[] =
2632 {
2633   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2634   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2635   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2636   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2637   { CA_ARG_UNDEFINED,           " "                             },
2638   { CA_ARG_ELEMENT_RESET,       "reset"                         },
2639
2640   { -1,                         NULL                            }
2641 };
2642
2643 static struct ValueTextInfo options_action_arg_gravity[] =
2644 {
2645   { CA_ARG_GRAVITY_HEADLINE,    "[gravity]"                     },
2646   { CA_ARG_GRAVITY_ON,          "on"                            },
2647   { CA_ARG_GRAVITY_OFF,         "off"                           },
2648   { CA_ARG_GRAVITY_TOGGLE,      "toggle"                        },
2649
2650   { -1,                         NULL                            }
2651 };
2652
2653 static struct ValueTextInfo options_action_arg_direction[] =
2654 {
2655   { CA_ARG_DIRECTION_HEADLINE,  "[dir.]"                        },
2656   { CA_ARG_DIRECTION_NONE,      "none"                          },
2657   { CA_ARG_DIRECTION_LEFT,      "left"                          },
2658   { CA_ARG_DIRECTION_RIGHT,     "right"                         },
2659   { CA_ARG_DIRECTION_UP,        "up"                            },
2660   { CA_ARG_DIRECTION_DOWN,      "down"                          },
2661   { CA_ARG_DIRECTION_TRIGGER,   "trigger"                       },
2662   { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                   },
2663
2664   { -1,                         NULL                            }
2665 };
2666
2667 static struct ValueTextInfo options_action_arg_scan_mode[] =
2668 {
2669   { CA_ARG_SCAN_MODE_HEADLINE,  "[mode]"                        },
2670   { CA_ARG_SCAN_MODE_NORMAL,    "normal"                        },
2671   { CA_ARG_SCAN_MODE_REVERSE,   "reverse"                       },
2672
2673   { -1,                         NULL                            }
2674 };
2675
2676 static struct ValueTextInfo options_action_arg_inventory[] =
2677 {
2678   { CA_ARG_INVENTORY_HEADLINE,  "[add]"                         },
2679   { CA_ARG_ELEMENT_TARGET,      "+ target"                      },
2680   { CA_ARG_ELEMENT_TRIGGER,     "+ trigger"                     },
2681   { CA_ARG_ELEMENT_ACTION,      "+ action"                      },
2682   { CA_ARG_UNDEFINED,           " "                             },
2683   { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]"                     },
2684   { CA_ARG_INVENTORY_RM_TARGET, "- target"                      },
2685   { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger"                     },
2686   { CA_ARG_INVENTORY_RM_ACTION, "- action"                      },
2687   { CA_ARG_INVENTORY_RM_FIRST,  "- first"                       },
2688   { CA_ARG_INVENTORY_RM_LAST,   "- last"                        },
2689   { CA_ARG_INVENTORY_RM_ALL,    "- all"                         },
2690   { CA_ARG_UNDEFINED,           " "                             },
2691   { CA_ARG_INVENTORY_RESET,     "reset"                         },
2692
2693   { -1,                         NULL                            }
2694 };
2695
2696 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2697 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2698 {
2699   { -1,                         NULL                            }
2700 };
2701
2702 static struct ValueTextInfo options_group_choice_mode[] =
2703 {
2704   { ANIM_RANDOM,                "random"                        },
2705   { ANIM_LOOP,                  "loop"                          },
2706   { ANIM_LINEAR,                "linear"                        },
2707   { ANIM_PINGPONG,              "pingpong"                      },
2708   { ANIM_PINGPONG2,             "pingpong 2"                    },
2709   { ANIM_LEVEL_NR,              "level number"                  },
2710
2711   { -1,                         NULL                            }
2712 };
2713
2714 static struct ValueTextInfo options_bd_scheduling_type[] =
2715 {
2716   { GD_SCHEDULING_MILLISECONDS,   "Milliseconds"                },
2717   { GD_SCHEDULING_BD1,            "BD1"                         },
2718   { GD_SCHEDULING_BD2,            "BD2"                         },
2719   { GD_SCHEDULING_PLCK,           "Construction Kit"            },
2720   { GD_SCHEDULING_CRDR,           "Crazy Dream 7"               },
2721   { GD_SCHEDULING_BD1_ATARI,      "Atari BD1"                   },
2722   { GD_SCHEDULING_BD2_PLCK_ATARI, "Atari BD2 / PLCK"            },
2723
2724   { -1,                           NULL                          }
2725 };
2726
2727 static struct ValueTextInfo *action_arg_modes[] =
2728 {
2729   options_action_mode_none,
2730   options_action_mode_assign,
2731   options_action_mode_add_remove,
2732   options_action_mode_calculate,
2733 };
2734
2735 static struct
2736 {
2737   int value;
2738   int mode;
2739   struct ValueTextInfo *options;
2740 }
2741 action_arg_options[] =
2742 {
2743   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2744   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2745   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2746   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2747   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2748   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2749   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2750   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2751   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2752   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2753   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2754   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2755   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2756   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2757   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2758   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2759   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2760   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2761   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2762   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2763   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2764   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2765
2766   { -1,                         FALSE,  NULL                            }
2767 };
2768
2769 static struct
2770 {
2771   int gadget_type_id;
2772   int x, y;
2773   int gadget_id;
2774   int gadget_id_align;
2775   int size;     // char size of selectbox or '-1' (dynamically determined)
2776   struct ValueTextInfo *options;
2777   int *value;
2778   char *text_above, *text_left, *text_right, *infotext;
2779 } selectbox_info[ED_NUM_SELECTBOX] =
2780 {
2781   // ---------- level and editor settings -------------------------------------
2782
2783   {
2784     ED_SELECTBOX_ID_TIME_OR_STEPS,
2785     -1,                                 ED_LEVEL_SETTINGS_YPOS(8),
2786     GADGET_ID_TIME_OR_STEPS,            GADGET_ID_LEVEL_TIMELIMIT_UP,
2787     -1,
2788     options_time_or_steps,
2789     &level.use_step_counter,
2790     NULL, NULL, "(0 => no limit)",      "Select time or step limit"
2791   },
2792   {
2793     ED_SELECTBOX_ID_TIME_SCORE_BASE,
2794     -1,                                 ED_LEVEL_SETTINGS_YPOS(10),
2795     GADGET_ID_TIME_SCORE_BASE,          GADGET_ID_LEVEL_TIMESCORE_UP,
2796     -1,
2797     options_time_score_base,
2798     &level.time_score_base,
2799     NULL, NULL, NULL,                   "Select time score for 1 or 10 seconds/steps"
2800   },
2801   {
2802     ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
2803     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(12),
2804     GADGET_ID_GAME_ENGINE_TYPE,         GADGET_ID_NONE,
2805     -1,
2806     options_game_engine_type,
2807     &level.game_engine_type,
2808     NULL, "Game engine:", NULL,         "Select game engine"
2809   },
2810   {
2811     ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
2812     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(1),
2813     GADGET_ID_BD_SCHEDULING_TYPE,       GADGET_ID_NONE,
2814     -1,
2815     options_bd_scheduling_type,
2816     &level.bd_scheduling_type,
2817     NULL, "Scheduling type:", NULL,     "Select level timing"
2818   },
2819   {
2820     ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
2821     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
2822     GADGET_ID_LEVELSET_SAVE_MODE,       GADGET_ID_NONE,
2823     -1,
2824     options_levelset_save_mode,
2825     &levelset_save_mode,
2826     "Action:", NULL, NULL,              "Select action when saving level set"
2827   },
2828
2829   // ---------- element settings: configure (several elements) ----------------
2830
2831   {
2832     ED_SELECTBOX_ID_WIND_DIRECTION,
2833     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2834     GADGET_ID_WIND_DIRECTION,           GADGET_ID_NONE,
2835     -1,
2836     options_wind_direction,
2837     &level.wind_direction_initial,
2838     NULL, "Initial wind direction:", NULL,      "Select initial wind direction"
2839   },
2840   {
2841     ED_SELECTBOX_ID_PLAYER_SPEED,
2842     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
2843     GADGET_ID_PLAYER_SPEED,             GADGET_ID_NONE,
2844     -1,
2845     options_player_speed,
2846     &level.initial_player_stepsize[0],
2847     NULL, "Initial player speed:", NULL,        "Select initial player speed"
2848   },
2849   {
2850     ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
2851     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2852     GADGET_ID_MM_BALL_CHOICE_MODE,      GADGET_ID_NONE,
2853     -1,
2854     options_group_choice_mode,
2855     &level.mm_ball_choice_mode,
2856     NULL, "Choice type:", NULL,         "Select type of content choice"
2857   },
2858
2859   // ---------- element settings: configure 1 (custom elements) ---------------
2860
2861   {
2862     ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
2863     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2864     GADGET_ID_CUSTOM_ACCESS_TYPE,       GADGET_ID_NONE,
2865     -1,
2866     options_access_type,
2867     &custom_element.access_type,
2868     NULL, NULL, NULL,                   "Select type of access to this field"
2869   },
2870   {
2871     ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
2872     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2873     GADGET_ID_CUSTOM_ACCESS_LAYER,      GADGET_ID_CUSTOM_ACCESS_TYPE,
2874     -1,
2875     options_access_layer,
2876     &custom_element.access_layer,
2877     NULL, NULL, NULL,                   "Select layer of access for this field"
2878   },
2879   {
2880     ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
2881     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2882     GADGET_ID_CUSTOM_ACCESS_PROTECTED,  GADGET_ID_CUSTOM_ACCESS_LAYER,
2883     -1,
2884     options_access_protected,
2885     &custom_element.access_protected,
2886     NULL, NULL, NULL,                   "Select protected access for this field"
2887   },
2888   {
2889     ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
2890     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2891     GADGET_ID_CUSTOM_ACCESS_DIRECTION,  GADGET_ID_NONE,
2892     -1,
2893     options_access_direction,
2894     &custom_element.access_direction,
2895     NULL, "from", NULL,                 "Select access direction for this field"
2896   },
2897   {
2898     ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
2899     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2900     GADGET_ID_CUSTOM_WALK_TO_ACTION,    GADGET_ID_NONE,
2901     -1,
2902     options_walk_to_action,
2903     &custom_element.walk_to_action,
2904     NULL, NULL, NULL,                   "Select diggable/collectible/pushable"
2905   },
2906
2907   // ---------- element settings: configure 2 (custom elements) ---------------
2908
2909   {
2910     ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
2911     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(1),
2912     GADGET_ID_CUSTOM_MOVE_PATTERN,      GADGET_ID_NONE,
2913     -1,
2914     options_move_pattern,
2915     &custom_element.move_pattern,
2916     NULL, "Can move", NULL,             "Select element move pattern"
2917   },
2918   {
2919     ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
2920     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2921     GADGET_ID_CUSTOM_MOVE_DIRECTION,    GADGET_ID_NONE,
2922     -1,
2923     options_move_direction,
2924     &custom_element.move_direction_initial,
2925     NULL, "Starts moving", NULL,        "Select initial element move direction"
2926   },
2927   {
2928     ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
2929     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2930     GADGET_ID_CUSTOM_MOVE_STEPSIZE,     GADGET_ID_NONE,
2931     -1,
2932     options_move_stepsize,
2933     &custom_element.move_stepsize,
2934     NULL, "Move/fall speed", NULL,      "Select speed of element movement"
2935   },
2936   {
2937     ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
2938     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2939     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,   GADGET_ID_NONE,
2940     -1,
2941     options_move_leave_type,
2942     &custom_element.move_leave_type,
2943     // left text with leading spaces to place gadget next to "can dig" gadget
2944     // (needed because drawing area gadgets created after selectbox gadgets)
2945     // NULL, "can dig:    can", ":",    "leave behind or change element"
2946     NULL, "            Can", ":",       "Select leave behind or change element"
2947   },
2948   {
2949     ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
2950     -1,                                 ED_ELEMENT_SETTINGS_YPOS(8),
2951     GADGET_ID_CUSTOM_SMASH_TARGETS,     GADGET_ID_CUSTOM_CAN_SMASH,
2952     -1,
2953     options_smash_targets,
2954     &custom_element.smash_targets,
2955     NULL, "Can smash", NULL,            "Select elements that can be smashed"
2956   },
2957   {
2958     ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
2959     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
2960     GADGET_ID_CUSTOM_SLIPPERY_TYPE,     GADGET_ID_NONE,
2961     -1,
2962     options_slippery_type,
2963     &custom_element.slippery_type,
2964     NULL, "Slippery", NULL,             "Select where other elements fall down"
2965   },
2966   {
2967     ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
2968     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(10),
2969     GADGET_ID_CUSTOM_DEADLINESS,        GADGET_ID_NONE,
2970     -1,
2971     options_deadliness,
2972     &custom_element.deadliness,
2973     NULL, "Deadly when", NULL,          "Select deadliness of element"
2974   },
2975   {
2976     ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
2977     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(11),
2978     GADGET_ID_CUSTOM_EXPLOSION_TYPE,    GADGET_ID_NONE,
2979     -1,
2980     options_explosion_type,
2981     &custom_element.explosion_type,
2982     NULL, "Can explode", NULL,          "Select explosion type"
2983   },
2984
2985   // ---------- element settings: advanced (custom elements) ------------------
2986
2987   {
2988     ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
2989     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(3),
2990     GADGET_ID_CHANGE_TIME_UNITS,        GADGET_ID_NONE,
2991     -1,
2992     options_time_units,
2993     &custom_element_change.delay_frames,
2994     NULL, "Delay time given in", NULL,  "Select delay time units for change"
2995   },
2996   {
2997     ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
2998     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(4),
2999     GADGET_ID_CHANGE_DIRECT_ACTION,     GADGET_ID_NONE,
3000     -1,
3001     options_change_direct_action,
3002     &custom_element_change.direct_action,
3003     NULL, NULL, NULL,                   "Select type of direct action"
3004   },
3005   {
3006     ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
3007     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(5),
3008     GADGET_ID_CHANGE_OTHER_ACTION,      GADGET_ID_NONE,
3009     -1,
3010     options_change_other_action,
3011     &custom_element_change.other_action,
3012     NULL, NULL, "element:",             "Select type of other element action"
3013   },
3014   {
3015     ED_SELECTBOX_ID_CHANGE_SIDE,
3016     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(6),
3017     GADGET_ID_CHANGE_SIDE,              GADGET_ID_NONE,
3018     -1,
3019     options_change_trigger_side,
3020     &custom_element_change.trigger_side,
3021     NULL, "at", "side",                 "Select element side triggering change"
3022   },
3023   {
3024     ED_SELECTBOX_ID_CHANGE_PLAYER,
3025     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
3026     GADGET_ID_CHANGE_PLAYER,            GADGET_ID_NONE,
3027     -1,
3028     options_change_trigger_player,
3029     &custom_element_change.trigger_player,
3030     NULL, "Player:", " ",               "Select player that causes change"
3031   },
3032   {
3033     ED_SELECTBOX_ID_CHANGE_PAGE,
3034     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
3035     GADGET_ID_CHANGE_PAGE,              GADGET_ID_CHANGE_PLAYER,
3036     -1,
3037     options_change_trigger_page,
3038     &custom_element_change.trigger_page,
3039     NULL, "Page:", NULL,                "Select change page that causes change"
3040   },
3041   {
3042     ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
3043     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(10),
3044     GADGET_ID_CHANGE_REPLACE_WHEN,      GADGET_ID_NONE,
3045     -1,
3046     options_change_replace_when,
3047     &custom_element_change.replace_when,
3048     NULL, "Replace when", NULL,         "Select which elements can be replaced"
3049   },
3050   {
3051     ED_SELECTBOX_ID_ACTION_TYPE,
3052     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
3053     GADGET_ID_ACTION_TYPE,              GADGET_ID_NONE,
3054     15,
3055     options_action_type,
3056     &custom_element_change.action_type,
3057     NULL, NULL, NULL,                   "Select action on specified condition"
3058   },
3059   {
3060     ED_SELECTBOX_ID_ACTION_MODE,
3061     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
3062     GADGET_ID_ACTION_MODE,              GADGET_ID_ACTION_TYPE,
3063     -1,
3064     options_action_mode_none,
3065     &custom_element_change.action_mode,
3066     NULL, NULL, NULL,                   "Select action operator"
3067   },
3068   {
3069     ED_SELECTBOX_ID_ACTION_ARG,
3070     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
3071     GADGET_ID_ACTION_ARG,               GADGET_ID_ACTION_MODE,
3072     -1,
3073     options_action_arg_none,
3074     &custom_element_change.action_arg,
3075     NULL, NULL, NULL,                   "Select action parameter"
3076   },
3077   {
3078     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
3079     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
3080     GADGET_ID_SELECT_CHANGE_PAGE,       GADGET_ID_NONE,
3081     3,
3082     options_change_page,
3083     &custom_element.current_change_page,
3084     NULL, NULL, NULL,                   "Select element change page"
3085   },
3086
3087   // ---------- element settings: configure (group elements) ------------------
3088
3089   {
3090     ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
3091     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3092     GADGET_ID_GROUP_CHOICE_MODE,        GADGET_ID_NONE,
3093     -1,
3094     options_group_choice_mode,
3095     &group_element_info.choice_mode,
3096     NULL, "Choice type:", NULL,         "Select type of group element choice"
3097   },
3098 };
3099
3100 static struct
3101 {
3102   int gadget_type_id;
3103   int x, y;
3104   int gadget_id;
3105   int gadget_id_align;
3106   int size;
3107   char *text;
3108   char *text_above, *text_left, *text_right, *infotext;
3109 } textbutton_info[ED_NUM_TEXTBUTTONS] =
3110 {
3111   // ---------- level and editor settings (tabs) ------------------------------
3112
3113   {
3114     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
3115     ED_LEVEL_TABS_XPOS(0),              ED_LEVEL_TABS_YPOS(0),
3116     GADGET_ID_LEVELCONFIG_LEVEL,        GADGET_ID_NONE,
3117     8,                                  "Level",
3118     NULL, NULL, NULL,                   "Configure level settings"
3119   },
3120   {
3121     ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
3122     -1,                                 -1,
3123     GADGET_ID_LEVELCONFIG_LEVELSET,     GADGET_ID_LEVELCONFIG_LEVEL,
3124     8,                                  "Levelset",
3125     NULL, NULL, NULL,                   "Update this or create new level set"
3126   },
3127   {
3128     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
3129     -1,                                 -1,
3130     GADGET_ID_LEVELCONFIG_EDITOR,       GADGET_ID_LEVELCONFIG_LEVELSET,
3131     8,                                  "Editor",
3132     NULL, NULL, NULL,                   "Configure editor settings"
3133   },
3134   {
3135     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
3136     -1,                                 -1,
3137     GADGET_ID_LEVELCONFIG_ENGINE,       GADGET_ID_LEVELCONFIG_EDITOR,
3138     8,                                  "Engine",
3139     NULL, NULL, NULL,                   "Configure engine settings"
3140   },
3141
3142   // ---------- element settings (tabs) ---------------------------------------
3143
3144   {
3145     ED_TEXTBUTTON_ID_PROPERTIES_INFO,
3146     ED_ELEMENT_TABS_XPOS(0),            ED_ELEMENT_TABS_YPOS(0),
3147     GADGET_ID_PROPERTIES_INFO,          GADGET_ID_NONE,
3148     8,                                  "Info",
3149     NULL, NULL, NULL,                   "Show information about element"
3150   },
3151   {
3152     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
3153     -1,                                 -1,
3154     GADGET_ID_PROPERTIES_CONFIG,        GADGET_ID_PROPERTIES_INFO,
3155     8,                                  "Config",
3156     NULL, NULL, NULL,                   "Configure element properties"
3157   },
3158   {
3159     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
3160     -1,                                 -1,
3161     GADGET_ID_PROPERTIES_CONFIG_1,      GADGET_ID_PROPERTIES_INFO,
3162     8,                                  "Config 1",
3163     NULL, NULL, NULL,                   "Configure element properties, part 1"
3164   },
3165   {
3166     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
3167     -1,                                 -1,
3168     GADGET_ID_PROPERTIES_CONFIG_2,      GADGET_ID_PROPERTIES_CONFIG_1,
3169     8,                                  "Config 2",
3170     NULL, NULL, NULL,                   "Configure element properties, part 2"
3171   },
3172   {
3173     ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
3174     -1,                                 -1,
3175     GADGET_ID_PROPERTIES_CHANGE,        GADGET_ID_PROPERTIES_CONFIG_2,
3176     8,                                  "Change",
3177     NULL, NULL, NULL,                   "Configure custom element change pages"
3178   },
3179
3180   // ---------- level and editor settings (buttons) ---------------------------
3181
3182   {
3183     ED_TEXTBUTTON_ID_SAVE_LEVELSET,
3184     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
3185     GADGET_ID_SAVE_LEVELSET,            GADGET_ID_LEVELSET_SAVE_MODE,
3186     -1,                                 "Save",
3187     NULL, NULL, NULL,                   "Update or create level set"
3188   },
3189   {
3190     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
3191     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(6),
3192     GADGET_ID_SAVE_AS_TEMPLATE_2,       GADGET_ID_NONE,
3193     -1,                                 "Save",
3194     NULL, NULL,                         "this level as level template",
3195     "Save current settings as new template"
3196   },
3197
3198   // ---------- element settings (buttons) ------------------------------------
3199
3200   {
3201     ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
3202     -1,                                 -1,
3203     GADGET_ID_SAVE_AS_TEMPLATE_1,       GADGET_ID_CUSTOM_USE_TEMPLATE_1,
3204     -1,                                 "Save",
3205     NULL, " ",                          "As Template",
3206     "Save current settings as new template"
3207   },
3208   {
3209     ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
3210     -1,                                 -1,
3211     GADGET_ID_ADD_CHANGE_PAGE,          GADGET_ID_PASTE_CHANGE_PAGE,
3212     -1,                                 "New",
3213     NULL, NULL, NULL,                   "Add new change page"
3214   },
3215   {
3216     ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
3217     -1,                                 -1,
3218     GADGET_ID_DEL_CHANGE_PAGE,          GADGET_ID_ADD_CHANGE_PAGE,
3219     -1,                                 "Delete",
3220     NULL, NULL, NULL,                   "Delete current change page"
3221   },
3222 };
3223
3224 static struct
3225 {
3226   int gadget_type_id;
3227   int graphic;
3228   int x, y;
3229   int gadget_id;
3230   int gadget_id_align;
3231   char *text_left, *text_right, *infotext;
3232 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
3233 {
3234   {
3235     ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
3236     IMG_EDITOR_COUNTER_DOWN,
3237     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
3238     GADGET_ID_PREV_CHANGE_PAGE,         GADGET_ID_NONE,
3239     NULL, NULL,                         "Select previous change page"
3240   },
3241   {
3242     ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
3243     IMG_EDITOR_COUNTER_UP,
3244     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
3245     GADGET_ID_NEXT_CHANGE_PAGE,         GADGET_ID_SELECT_CHANGE_PAGE,
3246     NULL, "Change page",                "Select next change page"
3247   },
3248   {
3249     ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
3250     IMG_GFX_EDITOR_BUTTON_CP_COPY,
3251     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
3252     GADGET_ID_COPY_CHANGE_PAGE,         GADGET_ID_NEXT_CHANGE_PAGE,
3253     " ", NULL,                          "Copy settings from this change page"
3254   },
3255   {
3256     ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
3257     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
3258     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
3259     GADGET_ID_PASTE_CHANGE_PAGE,        GADGET_ID_COPY_CHANGE_PAGE,
3260     NULL, NULL,                         "Paste settings to this change page"
3261   },
3262 };
3263
3264 static struct
3265 {
3266   int x, y;
3267 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
3268
3269 static struct
3270 {
3271   int gadget_type_id;
3272   int graphic;
3273   int gadget_id;
3274   char *infotext;
3275 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
3276 {
3277   {
3278     ED_SCROLLBUTTON_ID_AREA_UP,
3279     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
3280     GADGET_ID_SCROLL_UP,
3281     "Scroll level editing area up"
3282   },
3283   {
3284     ED_SCROLLBUTTON_ID_AREA_DOWN,
3285     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
3286     GADGET_ID_SCROLL_DOWN,
3287     "Scroll level editing area down"
3288   },
3289   {
3290     ED_SCROLLBUTTON_ID_AREA_LEFT,
3291     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
3292     GADGET_ID_SCROLL_LEFT,
3293     "Scroll level editing area left"
3294   },
3295   {
3296     ED_SCROLLBUTTON_ID_AREA_RIGHT,
3297     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
3298     GADGET_ID_SCROLL_RIGHT,
3299     "Scroll level editing area right"
3300   },
3301   {
3302     ED_SCROLLBUTTON_ID_LIST_UP,
3303     IMG_EDITOR_PALETTE_SCROLL_UP,
3304     GADGET_ID_SCROLL_LIST_UP,
3305     "Scroll element list up ('Page Up')"
3306   },
3307   {
3308     ED_SCROLLBUTTON_ID_LIST_DOWN,
3309     IMG_EDITOR_PALETTE_SCROLL_DOWN,
3310     GADGET_ID_SCROLL_LIST_DOWN,
3311     "Scroll element list down ('Page Down')"
3312   },
3313 };
3314
3315 static struct
3316 {
3317   int x, y;
3318   int width, height;
3319   int wheel_x, wheel_y;
3320   int wheel_width, wheel_height;
3321 } scrollbar_pos[ED_NUM_SCROLLBARS];
3322
3323 static struct
3324 {
3325   int gadget_type_id;
3326   int graphic;
3327   int type;
3328   int gadget_id;
3329   char *infotext;
3330 } scrollbar_info[ED_NUM_SCROLLBARS] =
3331 {
3332   {
3333     ED_SCROLLBAR_ID_AREA_HORIZONTAL,
3334     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3335     GD_TYPE_SCROLLBAR_HORIZONTAL,
3336     GADGET_ID_SCROLL_HORIZONTAL,
3337     "Scroll level editing area horizontally"
3338   },
3339   {
3340     ED_SCROLLBAR_ID_AREA_VERTICAL,
3341     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3342     GD_TYPE_SCROLLBAR_VERTICAL,
3343     GADGET_ID_SCROLL_VERTICAL,
3344     "Scroll level editing area vertically"
3345   },
3346   {
3347     ED_SCROLLBAR_ID_LIST_VERTICAL,
3348     IMG_EDITOR_PALETTE_SCROLLBAR,
3349     GD_TYPE_SCROLLBAR_VERTICAL,
3350     GADGET_ID_SCROLL_LIST_VERTICAL,
3351     "Scroll element list vertically"
3352   }
3353 };
3354
3355
3356 static struct
3357 {
3358   int gadget_type_id;
3359   int x, y;
3360   int gadget_id;
3361   int gadget_id_align;
3362   int radio_button_nr;
3363   int *value;
3364   int checked_value;
3365   char *text_left, *text_right, *infotext;
3366 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3367 {
3368   {
3369     ED_RADIOBUTTON_ID_PERCENTAGE,
3370     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
3371     GADGET_ID_RANDOM_PERCENTAGE,        GADGET_ID_LEVEL_RANDOM_UP,
3372     RADIO_NR_RANDOM_ELEMENTS,
3373     &random_placement_method,           RANDOM_USE_PERCENTAGE,
3374     " ", "percentage",                  "Use percentage for random elements"
3375   },
3376   {
3377     ED_RADIOBUTTON_ID_QUANTITY,
3378     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
3379     GADGET_ID_RANDOM_QUANTITY,          GADGET_ID_RANDOM_PERCENTAGE,
3380     RADIO_NR_RANDOM_ELEMENTS,
3381     &random_placement_method,           RANDOM_USE_QUANTITY,
3382     " ", "quantity",                    "Use quantity for random elements"
3383   }
3384 };
3385
3386 static struct
3387 {
3388   int gadget_type_id;
3389   int x, y;
3390   int gadget_id;
3391   int gadget_id_align;
3392   boolean *value;
3393   char *text_above, *text_left, *text_right, *infotext;
3394 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3395 {
3396   // ---------- level and editor settings -------------------------------------
3397
3398   {
3399     ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
3400     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(6),
3401     GADGET_ID_AUTO_COUNT_GEMS,          GADGET_ID_NONE,
3402     &level.auto_count_gems,
3403     NULL, NULL,
3404     "Automatically count gems needed",  "Set counter to number of gems"
3405   },
3406   {
3407     ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
3408     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(11),
3409     GADGET_ID_RATE_TIME_OVER_SCORE,     GADGET_ID_NONE,
3410     &level.rate_time_over_score,
3411     NULL, NULL,
3412     "Rate time/steps used over score",  "Sort high scores by playing time/steps"
3413   },
3414   {
3415     ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
3416     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(7),
3417     GADGET_ID_USE_LEVELSET_ARTWORK,     GADGET_ID_NONE,
3418     &levelset_use_levelset_artwork,
3419     NULL, NULL,
3420     "Use current custom artwork",       "Use custom artwork of this level set"
3421   },
3422   {
3423     ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
3424     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(8),
3425     GADGET_ID_COPY_LEVEL_TEMPLATE,      GADGET_ID_NONE,
3426     &levelset_copy_level_template,
3427     NULL, NULL,
3428     "Copy current level template",      "Copy level template of this level set"
3429   },
3430   {
3431     ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
3432     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(1),
3433     GADGET_ID_RANDOM_RESTRICTED,        GADGET_ID_NONE,
3434     &random_placement_background_restricted,
3435     NULL, NULL,
3436     "Restrict random placement to:",    "Set random placement restriction"
3437   },
3438   {
3439     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
3440     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
3441     GADGET_ID_CUSTOM_USE_TEMPLATE_3,    GADGET_ID_NONE,
3442     &setup.editor.use_template_for_new_levels,
3443     "Template for new levels and CE/GE:", NULL,
3444     "Use template for new levels",      "Use template for level properties"
3445   },
3446   {
3447     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
3448     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
3449     GADGET_ID_CUSTOM_USE_TEMPLATE_2,    GADGET_ID_NONE,
3450     &level.use_custom_template,
3451     NULL, NULL,
3452     "Use template for custom elements", "Use template for custom properties"
3453   },
3454   {
3455     ED_CHECKBUTTON_ID_BD_INTERMISSION,
3456     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
3457     GADGET_ID_BD_INTERMISSION,          GADGET_ID_NONE,
3458     &level.bd_intermission,
3459     "Boulder Dash game engine settings:", NULL,
3460     "Intermission",                     "Level is an intermission level"
3461   },
3462   {
3463     ED_CHECKBUTTON_ID_BD_PAL_TIMING,
3464     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
3465     GADGET_ID_BD_PAL_TIMING,            GADGET_ID_NONE,
3466     &level.bd_pal_timing,
3467     NULL, NULL,
3468     "PAL timing",                       "Use slower timer (like PAL C64)"
3469   },
3470   {
3471     ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
3472     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(6),
3473     GADGET_ID_BD_LINE_SHIFTING_BORDERS, GADGET_ID_NONE,
3474     &level.bd_line_shifting_borders,
3475     "Compatibility settings:", NULL,
3476     "Line-shifting borders",            "Use line-shifting wrap-around"
3477   },
3478   {
3479     ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
3480     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(7),
3481     GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW, GADGET_ID_NONE,
3482     &level.bd_scan_first_and_last_row,
3483     NULL, NULL,
3484     "Scan first and last row",          "Also process top/bottom border rows"
3485   },
3486   {
3487     ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
3488     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(8),
3489     GADGET_ID_BD_SHORT_EXPLOSIONS,      GADGET_ID_NONE,
3490     &level.bd_short_explosions,
3491     NULL, NULL,
3492     "Short explosions",                 "Use four game cycles for explosions"
3493   },
3494   {
3495     ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
3496     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(9),
3497     GADGET_ID_BD_GRAVITY_AFFECTS_ALL,   GADGET_ID_NONE,
3498     &level.bd_gravity_affects_all,
3499     NULL, NULL,
3500     "Gravity change affects everything", "Gravity affects all falling objects"
3501   },
3502
3503   // ---------- element settings: configure (various elements) ----------------
3504
3505   {
3506     ED_CHECKBUTTON_ID_STICK_ELEMENT,
3507     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3508     GADGET_ID_STICK_ELEMENT,            GADGET_ID_NONE,
3509     &stick_element_properties_window,
3510     NULL, NULL,
3511     "Stick this screen to edit content","Stick this screen to edit content"
3512   },
3513   {
3514     ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
3515     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3516     GADGET_ID_EM_SLIPPERY_GEMS,         GADGET_ID_NONE,
3517     &level.em_slippery_gems,
3518     NULL, NULL,
3519     "Slip down from certain flat walls","Use EM/DC style slipping behaviour"
3520   },
3521   {
3522     ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
3523     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3524     GADGET_ID_EM_EXPLODES_BY_FIRE,      GADGET_ID_NONE,
3525     &level.em_explodes_by_fire,
3526     NULL, NULL,
3527     "Explodes with chain reaction",     "Use R'n'D style explosion behaviour"
3528   },
3529   {
3530     ED_CHECKBUTTON_ID_USE_SPRING_BUG,
3531     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3532     GADGET_ID_USE_SPRING_BUG,           GADGET_ID_NONE,
3533     &level.use_spring_bug,
3534     NULL, NULL,
3535     "Use spring pushing bug",           "Use odd spring pushing behaviour"
3536   },
3537   {
3538     ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
3539     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3540     GADGET_ID_USE_TIME_ORB_BUG,         GADGET_ID_NONE,
3541     &level.use_time_orb_bug,
3542     NULL, NULL,
3543     "Use time orb bug",                 "Use odd time orb behaviour"
3544   },
3545   {
3546     ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
3547     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3548     GADGET_ID_USE_LIFE_BUGS,            GADGET_ID_NONE,
3549     &level.use_life_bugs,
3550     NULL, NULL,
3551     "Use buggy element behaviour",      "Use odd (historic) element behaviour"
3552   },
3553   {
3554     ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
3555     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3556     GADGET_ID_RANDOM_BALL_CONTENT,      GADGET_ID_NONE,
3557     &level.ball_random,
3558     NULL, NULL,
3559     "Create single random element",     "Only create one element from content"
3560   },
3561   {
3562     ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
3563     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3564     GADGET_ID_INITIAL_BALL_ACTIVE,      GADGET_ID_NONE,
3565     &level.ball_active_initial,
3566     NULL, NULL,
3567     "Magic ball initially activated",   "Activate magic ball after level start"
3568   },
3569   {
3570     ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
3571     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3572     GADGET_ID_GROW_INTO_DIGGABLE,       GADGET_ID_NONE,
3573     &level.grow_into_diggable,
3574     NULL, NULL,
3575     "Can grow into anything diggable",  "Grow into more than just sand"
3576   },
3577   {
3578     ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
3579     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3580     GADGET_ID_SB_FIELDS_NEEDED,         GADGET_ID_NONE,
3581     &level.sb_fields_needed,
3582     NULL, NULL,
3583     "All fields need to be filled",     "Require all SB fields to be solved"
3584   },
3585   {
3586     ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
3587     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3588     GADGET_ID_SB_OBJECTS_NEEDED,        GADGET_ID_NONE,
3589     &level.sb_objects_needed,
3590     NULL, NULL,
3591     "All objects need to be placed",    "Require all SB objects to be solved"
3592   },
3593   {
3594     ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
3595     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3596     GADGET_ID_AUTO_EXIT_SOKOBAN,        GADGET_ID_NONE,
3597     &level.auto_exit_sokoban,
3598     NULL, NULL,
3599     "Exit level if all tasks solved",   "Automatically finish Sokoban levels"
3600   },
3601   {
3602     ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
3603     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
3604     GADGET_ID_SOLVED_BY_ONE_PLAYER,     GADGET_ID_NONE,
3605     &level.solved_by_one_player,
3606     NULL, NULL,
3607     "Only one player must enter exit",  "Level solved by first player in exit"
3608   },
3609   {
3610     ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
3611     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3612     GADGET_ID_FINISH_DIG_COLLECT,       GADGET_ID_NONE,
3613     &level.finish_dig_collect,
3614     NULL, NULL,
3615     "CE action on finished dig/collect", "Only finished dig/collect triggers CE"
3616   },
3617   {
3618     ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
3619     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3620     GADGET_ID_KEEP_WALKABLE_CE,         GADGET_ID_NONE,
3621     &level.keep_walkable_ce,
3622     NULL, NULL,
3623     "Keep walkable CE changed to player", "Keep CE changing to player if walkable"
3624   },
3625   {
3626     ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
3627     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3628     GADGET_ID_CONTINUOUS_SNAPPING,      GADGET_ID_NONE,
3629     &level.continuous_snapping,
3630     NULL, NULL,
3631     "Continuous snapping",              "Use snapping without releasing key"
3632   },
3633   {
3634     ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
3635     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
3636     GADGET_ID_BLOCK_SNAP_FIELD,         GADGET_ID_NONE,
3637     &level.block_snap_field,
3638     NULL, NULL,
3639     "Block snapped field when snapping", "Use snapping delay to show animation"
3640   },
3641   {
3642     ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
3643     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3644     GADGET_ID_BLOCK_LAST_FIELD,         GADGET_ID_NONE,
3645     &level.block_last_field,
3646     NULL, NULL,
3647     "Block last field when moving",     "Player blocks last field when moving"
3648   },
3649   {
3650     ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
3651     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3652     GADGET_ID_SP_BLOCK_LAST_FIELD,      GADGET_ID_NONE,
3653     &level.sp_block_last_field,
3654     NULL, NULL,
3655     "Block last field when moving",     "Player blocks last field when moving"
3656   },
3657   {
3658     ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
3659     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3660     GADGET_ID_INSTANT_RELOCATION,       GADGET_ID_NONE,
3661     &level.instant_relocation,
3662     NULL, NULL,
3663     "No scrolling when relocating",     "Player gets relocated without delay"
3664   },
3665   {
3666     ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
3667     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3668     GADGET_ID_SHIFTED_RELOCATION,       GADGET_ID_NONE,
3669     &level.shifted_relocation,
3670     NULL, NULL,
3671     "No centering when relocating",     "Level not centered after relocation"
3672   },
3673   {
3674     ED_CHECKBUTTON_ID_LAZY_RELOCATION,
3675     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3676     GADGET_ID_LAZY_RELOCATION,          GADGET_ID_NONE,
3677     &level.lazy_relocation,
3678     NULL, NULL,
3679     "Only redraw off-screen relocation","No redraw if relocation target visible"
3680   },
3681   {
3682     ED_CHECKBUTTON_ID_USE_START_ELEMENT,
3683     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
3684     GADGET_ID_USE_START_ELEMENT,        GADGET_ID_NONE,
3685     &level.use_start_element[0],
3686     NULL, NULL,
3687     "Use level start element:",        "Start level at this element's position"
3688   },
3689   {
3690     ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
3691     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
3692     GADGET_ID_USE_ARTWORK_ELEMENT,      GADGET_ID_NONE,
3693     &level.use_artwork_element[0],
3694     NULL, NULL,
3695     "Use artwork from element:",        "Use player artwork from other element"
3696   },
3697   {
3698     ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
3699     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
3700     GADGET_ID_USE_EXPLOSION_ELEMENT,    GADGET_ID_NONE,
3701     &level.use_explosion_element[0],
3702     NULL, NULL,
3703     "Use explosion from element:",      "Use explosion properties from element"
3704   },
3705   {
3706     ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
3707     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
3708     GADGET_ID_INITIAL_GRAVITY,          GADGET_ID_NONE,
3709     &level.initial_player_gravity[0],
3710     NULL, NULL,
3711     "Use initial gravity",              "Set initial player gravity"
3712   },
3713   {
3714     ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
3715     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3716     GADGET_ID_USE_INITIAL_INVENTORY,    GADGET_ID_NONE,
3717     &level.use_initial_inventory[0],
3718     NULL, NULL,
3719     "Use initial inventory:",           "Use collected elements on level start"
3720   },
3721   {
3722     ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
3723     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
3724     GADGET_ID_CAN_PASS_TO_WALKABLE,     GADGET_ID_NONE,
3725     &level.can_pass_to_walkable,
3726     NULL, NULL,
3727     "Can pass to walkable element",     "Player can pass to empty or walkable"
3728   },
3729   {
3730     ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
3731     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3732     GADGET_ID_CAN_FALL_INTO_ACID,       GADGET_ID_NONE,
3733     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3734     NULL, NULL,
3735     "Can fall into acid (with gravity)","Player can fall into acid pool"
3736   },
3737   {
3738     ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
3739     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3740     GADGET_ID_CAN_MOVE_INTO_ACID,       GADGET_ID_NONE,
3741     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3742     NULL, NULL,
3743     "Can move into acid",               "Element can move into acid pool"
3744   },
3745   {
3746     ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
3747     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3748     GADGET_ID_DONT_COLLIDE_WITH,        GADGET_ID_NONE,
3749     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3750     NULL, NULL,
3751     "Deadly when colliding with",       "Element is deadly when hitting player"
3752   },
3753   {
3754     ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
3755     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3756     GADGET_ID_BD_DIAGONAL_MOVEMENTS,    GADGET_ID_NONE,
3757     &level.bd_diagonal_movements,
3758     NULL, NULL,
3759     "Can move diagonally",              "Player can move diagonally"
3760   },
3761   {
3762     ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
3763     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3764     GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE, GADGET_ID_NONE,
3765     &level.bd_topmost_player_active,
3766     NULL, NULL,
3767     "Topmost player is active",         "Use first player found on playfield"
3768   },
3769   {
3770     ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
3771     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3772     GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET, GADGET_ID_NONE,
3773     &level.bd_push_mega_rock_with_sweet,
3774     NULL, NULL,
3775     "Mega rocks pushable with sweet",   "Push mega rocks after eating sweet"
3776   },
3777   {
3778     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
3779     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3780     GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING, GADGET_ID_NONE,
3781     &level.bd_magic_wall_wait_hatching,
3782     NULL, NULL,
3783     "Wait for player's birth",          "Timer start waits for player's birth"
3784   },
3785   {
3786     ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
3787     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3788     GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA, GADGET_ID_NONE,
3789     &level.bd_magic_wall_stops_amoeba,
3790     NULL, NULL,
3791     "Turn amoeba to diamonds",          "Activation changes amoeba to diamonds"
3792   },
3793   {
3794     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
3795     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3796     GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING, GADGET_ID_NONE,
3797     &level.bd_amoeba_wait_for_hatching,
3798     NULL, NULL,
3799     "Wait for player's birth",          "Timer start waits for player's birth"
3800   },
3801   {
3802     ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
3803     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3804     GADGET_ID_BD_AMOEBA_START_IMMEDIATELY, GADGET_ID_NONE,
3805     &level.bd_amoeba_start_immediately,
3806     NULL, NULL,
3807     "Start growing immediately",        "Start slow growth time immediately"
3808   },
3809   {
3810     ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
3811     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3812     GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA, GADGET_ID_NONE,
3813     &level.bd_amoeba_2_explode_by_amoeba,
3814     NULL, NULL,
3815     "Explodes if touched by amoeba",    "Amoeba 2 explodes if touched by amoeba"
3816   },
3817   {
3818     ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
3819     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3820     GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS, GADGET_ID_NONE,
3821     &level.bd_voodoo_collects_diamonds,
3822     NULL, NULL,
3823     "Can collect diamonds",             "Can collect diamonds for the player"
3824   },
3825   {
3826     ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
3827     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3828     GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER, GADGET_ID_NONE,
3829     &level.bd_voodoo_hurt_kills_player,
3830     NULL, NULL,
3831     "Player is killed if hurt",         "If hurt in any way, player is killed"
3832   },
3833   {
3834     ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
3835     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3836     GADGET_ID_BD_VOODOO_DIES_BY_ROCK,   GADGET_ID_NONE,
3837     &level.bd_voodoo_dies_by_rock,
3838     NULL, NULL,
3839     "Killed by falling rock",           "Can be killed by a falling rock"
3840   },
3841   {
3842     ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
3843     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3844     GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION, GADGET_ID_NONE,
3845     &level.bd_voodoo_vanish_by_explosion,
3846     NULL, NULL,
3847     "Disappears in explosions",         "Can be destroyed by explosions"
3848   },
3849   {
3850     ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
3851     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3852     GADGET_ID_BD_SLIME_IS_PREDICTABLE, GADGET_ID_NONE,
3853     &level.bd_slime_is_predictable,
3854     NULL, NULL,
3855     "Slime is predictable",             "Use predictable random numbers"
3856   },
3857   {
3858     ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
3859     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3860     GADGET_ID_BD_CHANGE_EXPANDING_WALL, GADGET_ID_NONE,
3861     &level.bd_change_expanding_wall,
3862     NULL, NULL,
3863     "Change direction",                 "Switch horizontal/vertical direction"
3864   },
3865   {
3866     ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
3867     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3868     GADGET_ID_BD_REPLICATORS_ACTIVE,    GADGET_ID_NONE,
3869     &level.bd_replicators_active,
3870     NULL, NULL,
3871     "Active at start",                  "Replicators start in active state"
3872   },
3873   {
3874     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
3875     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3876     GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE, GADGET_ID_NONE,
3877     &level.bd_conveyor_belts_active,
3878     NULL, NULL,
3879     "Active at start",                  "Conveyor belts start in active state"
3880   },
3881   {
3882     ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
3883     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3884     GADGET_ID_BD_CONVEYOR_BELTS_CHANGED, GADGET_ID_NONE,
3885     &level.bd_conveyor_belts_changed,
3886     NULL, NULL,
3887     "Change direction",                 "Switch conveyor belt direction"
3888   },
3889   {
3890     ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
3891     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3892     GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN, GADGET_ID_NONE,
3893     &level.bd_water_cannot_flow_down,
3894     NULL, NULL,
3895     "Does not flow downwards",          "Water can only flow up, left and right"
3896   },
3897   {
3898     ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
3899     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3900     GADGET_ID_BD_HAMMER_WALLS_REAPPEAR, GADGET_ID_NONE,
3901     &level.bd_hammer_walls_reappear,
3902     NULL, NULL,
3903     "Hammered walls reappear",          "Hammered walls reappear after delay"
3904   },
3905   {
3906     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
3907     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3908     GADGET_ID_ENVELOPE_AUTOWRAP,        GADGET_ID_NONE,
3909     &level.envelope[0].autowrap,
3910     NULL, NULL,
3911     "Auto-wrap",                        "Automatically wrap envelope text"
3912   },
3913   {
3914     ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
3915     -1,                                 ED_ELEMENT_SETTINGS_YPOS(1),
3916     GADGET_ID_ENVELOPE_CENTERED,        GADGET_ID_ENVELOPE_AUTOWRAP,
3917     &level.envelope[0].centered,
3918     NULL, " ",
3919     "Centered",                         "Automatically center envelope text"
3920   },
3921   {
3922     ED_CHECKBUTTON_ID_MM_LASER_RED,
3923     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3924     GADGET_ID_MM_LASER_RED,             GADGET_ID_NONE,
3925     &level.mm_laser_red,
3926     "Choose color components for laser:", NULL,
3927     "Red",                              "Use red color components in laser"
3928   },
3929   {
3930     ED_CHECKBUTTON_ID_MM_LASER_GREEN,
3931     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3932     GADGET_ID_MM_LASER_GREEN,           GADGET_ID_NONE,
3933     &level.mm_laser_green,
3934     NULL, NULL,
3935     "Green",                            "Use green color components in laser"
3936   },
3937   {
3938     ED_CHECKBUTTON_ID_MM_LASER_BLUE,
3939     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3940     GADGET_ID_MM_LASER_BLUE,            GADGET_ID_NONE,
3941     &level.mm_laser_blue,
3942     NULL, NULL,
3943     "Blue",                             "Use blue color components in laser"
3944   },
3945   {
3946     ED_CHECKBUTTON_ID_DF_LASER_RED,
3947     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3948     GADGET_ID_DF_LASER_RED,             GADGET_ID_NONE,
3949     &level.df_laser_red,
3950     "Choose color components for laser:", NULL,
3951     "Red",                              "Use red color components in laser"
3952   },
3953   {
3954     ED_CHECKBUTTON_ID_DF_LASER_GREEN,
3955     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3956     GADGET_ID_DF_LASER_GREEN,           GADGET_ID_NONE,
3957     &level.df_laser_green,
3958     NULL, NULL,
3959     "Green",                            "Use green color components in laser"
3960   },
3961   {
3962     ED_CHECKBUTTON_ID_DF_LASER_BLUE,
3963     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3964     GADGET_ID_DF_LASER_BLUE,            GADGET_ID_NONE,
3965     &level.df_laser_blue,
3966     NULL, NULL,
3967     "Blue",                             "Use blue color components in laser"
3968   },
3969   {
3970     ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
3971     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3972     GADGET_ID_ROTATE_MM_BALL_CONTENT,   GADGET_ID_NONE,
3973     &level.rotate_mm_ball_content,
3974     NULL, NULL,
3975     "Randomly rotate created content",  "Randomly rotate newly created content"
3976   },
3977   {
3978     ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
3979     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
3980     GADGET_ID_EXPLODE_MM_BALL,          GADGET_ID_NONE,
3981     &level.explode_mm_ball,
3982     NULL, NULL,
3983     "Explode ball instead of melting",  "Use explosion to release ball content"
3984   },
3985
3986   // ---------- element settings: configure 1 (custom elements) ---------------
3987
3988   {
3989     ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
3990     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3991     GADGET_ID_CUSTOM_USE_GRAPHIC,       GADGET_ID_NONE,
3992     &custom_element.use_gfx_element,
3993     NULL, NULL,
3994     "Use graphic of element:",          "Use existing element graphic"
3995   },
3996   {
3997     ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
3998     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
3999     GADGET_ID_CUSTOM_USE_TEMPLATE_1,    GADGET_ID_NONE,
4000     &level.use_custom_template,
4001     NULL, NULL,
4002     "Use template",                     "Use template for custom properties"
4003   },
4004   {
4005     ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
4006     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
4007     GADGET_ID_CUSTOM_ACCESSIBLE,        GADGET_ID_NONE,
4008     &custom_element_properties[EP_ACCESSIBLE],
4009     NULL, NULL,
4010     NULL,                               "Player can walk to or pass this field"
4011   },
4012   {
4013     ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
4014     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
4015     GADGET_ID_CUSTOM_GRAV_REACHABLE,    GADGET_ID_NONE,
4016     &custom_element_properties[EP_GRAVITY_REACHABLE],
4017     NULL, NULL,
4018     "Reachable despite gravity",        "Player can walk/dig despite gravity"
4019   },
4020   {
4021     ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
4022     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
4023     GADGET_ID_CUSTOM_USE_LAST_VALUE,    GADGET_ID_NONE,
4024     &custom_element.use_last_ce_value,
4025     NULL, NULL,
4026     "Use last CE value after change",   "Use last CE value after change"
4027   },
4028   {
4029     ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
4030     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
4031     GADGET_ID_CUSTOM_WALK_TO_OBJECT,    GADGET_ID_NONE,
4032     &custom_element_properties[EP_WALK_TO_OBJECT],
4033     NULL, NULL,
4034     NULL,                               "Player can dig/collect/push element"
4035   },
4036   {
4037     ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
4038     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
4039     GADGET_ID_CUSTOM_INDESTRUCTIBLE,    GADGET_ID_NONE,
4040     &custom_element_properties[EP_INDESTRUCTIBLE],
4041     NULL, NULL,
4042     "Indestructible",                   "Element is indestructible"
4043   },
4044
4045   // ---------- element settings: configure 2 (custom elements) ---------------
4046
4047   {
4048     ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
4049     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
4050     GADGET_ID_CUSTOM_CAN_MOVE,          GADGET_ID_NONE,
4051     &custom_element_properties[EP_CAN_MOVE],
4052     NULL, NULL,
4053     NULL,                               "Element can move with some pattern"
4054   },
4055   {
4056     ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
4057     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
4058     GADGET_ID_CUSTOM_CAN_FALL,          GADGET_ID_NONE,
4059     &custom_element_properties[EP_CAN_FALL],
4060     NULL, NULL,
4061     "Can fall",                         "Element can fall down"
4062   },
4063   {
4064     ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
4065     -1,                                 ED_ELEMENT_SETTINGS_YPOS(8),
4066     GADGET_ID_CUSTOM_CAN_SMASH,         GADGET_ID_CUSTOM_CAN_FALL,
4067     &custom_element_properties[EP_CAN_SMASH],
4068     NULL, " ",
4069     NULL,                               "Element can smash other elements"
4070   },
4071   {
4072     ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
4073     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
4074     GADGET_ID_CUSTOM_SLIPPERY,          GADGET_ID_NONE,
4075     &custom_element_properties[EP_SLIPPERY],
4076     NULL, NULL,
4077     NULL,                               "Other elements can fall down from it"
4078   },
4079   {
4080     ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
4081     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
4082     GADGET_ID_CUSTOM_DEADLY,            GADGET_ID_NONE,
4083     &custom_element_properties[EP_DEADLY],
4084     NULL, NULL,
4085     NULL,                               "Element can kill the player"
4086   },
4087   {
4088     ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
4089     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
4090     GADGET_ID_CUSTOM_CAN_EXPLODE,       GADGET_ID_NONE,
4091     &custom_element_properties[EP_CAN_EXPLODE],
4092     NULL, NULL,
4093     NULL,                               "Element can explode"
4094   },
4095   {
4096     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
4097     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(12),
4098     GADGET_ID_CUSTOM_EXPLODE_FIRE,      GADGET_ID_NONE,
4099     &custom_element_properties[EP_EXPLODES_BY_FIRE],
4100     NULL, NULL,
4101     "By fire",                          "Element can explode by fire/explosion"
4102   },
4103   {
4104     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
4105     -1,                                 ED_ELEMENT_SETTINGS_YPOS(12),
4106     GADGET_ID_CUSTOM_EXPLODE_SMASH,     GADGET_ID_CUSTOM_EXPLODE_FIRE,
4107     &custom_element_properties[EP_EXPLODES_SMASHED],
4108     NULL, " ",
4109     "Smashed",                          "Element can explode when smashed"
4110   },
4111   {
4112     ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
4113     -1,                                 ED_ELEMENT_SETTINGS_YPOS(12),
4114     GADGET_ID_CUSTOM_EXPLODE_IMPACT,    GADGET_ID_CUSTOM_EXPLODE_SMASH,
4115     &custom_element_properties[EP_EXPLODES_IMPACT],
4116     NULL, " ",
4117     "Impact",                           "Element can explode on impact"
4118   },
4119
4120   // ---------- element settings: advanced (custom elements) ------------------
4121
4122   {
4123     ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
4124     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
4125     GADGET_ID_CUSTOM_CAN_CHANGE,        GADGET_ID_NONE,
4126     &custom_element_change.can_change,
4127     NULL, NULL,
4128     "Element changes to:",              "Change element on specified condition"
4129   },
4130   {
4131     ED_CHECKBUTTON_ID_CHANGE_DELAY,
4132     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
4133     GADGET_ID_CHANGE_DELAY,             GADGET_ID_NONE,
4134     &custom_element_change_events[CE_DELAY],
4135     NULL, NULL,
4136     NULL,                               "Element changes after delay"
4137   },
4138   {
4139     ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
4140     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
4141     GADGET_ID_CHANGE_BY_DIRECT_ACT,     GADGET_ID_NONE,
4142     &custom_element_change_events[CE_BY_DIRECT_ACTION],
4143     NULL, NULL,
4144     NULL,                               "Element changes by direct action"
4145   },
4146   {
4147     ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
4148     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
4149     GADGET_ID_CHANGE_BY_OTHER_ACT,      GADGET_ID_NONE,
4150     &custom_element_change_events[CE_BY_OTHER_ACTION],
4151     NULL, NULL,
4152     NULL,                               "Element changes by other element"
4153   },
4154   {
4155     ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
4156     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
4157     GADGET_ID_CHANGE_USE_EXPLOSION,     GADGET_ID_NONE,
4158     &custom_element_change.explode,
4159     NULL, NULL,
4160     "Explode instead of change",        "Element explodes instead of change"
4161   },
4162   {
4163     ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
4164     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
4165     GADGET_ID_CHANGE_USE_CONTENT,       GADGET_ID_NONE,
4166     &custom_element_change.use_target_content,
4167     NULL, NULL,
4168     "Use extended change target:",      "Element changes to more elements"
4169   },
4170   {
4171     ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
4172     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(11),
4173     GADGET_ID_CHANGE_ONLY_COMPLETE,     GADGET_ID_NONE,
4174     &custom_element_change.only_if_complete,
4175     NULL, NULL,
4176     "Replace all or nothing",           "Only replace when all can be changed"
4177   },
4178   {
4179     ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
4180     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(12),
4181     GADGET_ID_CHANGE_USE_RANDOM,        GADGET_ID_NONE,
4182     &custom_element_change.use_random_replace,
4183     NULL, NULL,
4184     NULL,                               "Use percentage for random replace"
4185   },
4186   {
4187     ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
4188     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
4189     GADGET_ID_CHANGE_HAS_ACTION,        GADGET_ID_NONE,
4190     &custom_element_change.has_action,
4191     NULL, NULL,
4192     NULL,                               "Execute action on specified condition"
4193   },
4194 };
4195
4196 static struct
4197 {
4198   int gadget_type_id;
4199   int x, y;
4200   int xoffset, yoffset;
4201   int gadget_id;
4202   int gadget_id_align;
4203   int *value;
4204   int area_xsize, area_ysize;
4205   char *text_left, *text_right, *text_above, *text_below, *infotext;
4206 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
4207 {
4208   // ---------- level playfield content ---------------------------------------
4209
4210   {
4211     ED_DRAWING_ID_DRAWING_LEVEL,
4212     0,                                  0,
4213     0,                                  0,
4214     GADGET_ID_DRAWING_LEVEL,            GADGET_ID_NONE,
4215     NULL,
4216     -1, -1,     // these values are not constant, but can change at runtime
4217     NULL, NULL, NULL, NULL,             NULL
4218   },
4219
4220   // ---------- yam yam content -----------------------------------------------
4221
4222   {
4223     ED_DRAWING_ID_YAMYAM_CONTENT_0,
4224     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4225     ED_AREA_YAMYAM_CONTENT_XOFF(0),     ED_AREA_YAMYAM_CONTENT_YOFF(0),
4226     GADGET_ID_YAMYAM_CONTENT_0,         GADGET_ID_NONE,
4227     &level.yamyam_content[0].e[0][0],   3, 3,
4228     NULL, NULL, NULL, "1",              NULL
4229   },
4230   {
4231     ED_DRAWING_ID_YAMYAM_CONTENT_1,
4232     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4233     ED_AREA_YAMYAM_CONTENT_XOFF(1),     ED_AREA_YAMYAM_CONTENT_YOFF(1),
4234     GADGET_ID_YAMYAM_CONTENT_1,         GADGET_ID_NONE,
4235     &level.yamyam_content[1].e[0][0],   3, 3,
4236     NULL, NULL, NULL, "2",              NULL
4237   },
4238   {
4239     ED_DRAWING_ID_YAMYAM_CONTENT_2,
4240     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4241     ED_AREA_YAMYAM_CONTENT_XOFF(2),     ED_AREA_YAMYAM_CONTENT_YOFF(2),
4242     GADGET_ID_YAMYAM_CONTENT_2,         GADGET_ID_NONE,
4243     &level.yamyam_content[2].e[0][0],   3, 3,
4244     NULL, NULL, NULL, "3",              NULL
4245   },
4246   {
4247     ED_DRAWING_ID_YAMYAM_CONTENT_3,
4248     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4249     ED_AREA_YAMYAM_CONTENT_XOFF(3),     ED_AREA_YAMYAM_CONTENT_YOFF(3),
4250     GADGET_ID_YAMYAM_CONTENT_3,         GADGET_ID_NONE,
4251     &level.yamyam_content[3].e[0][0],   3, 3,
4252     NULL, NULL, NULL, "4",              NULL
4253   },
4254   {
4255     ED_DRAWING_ID_YAMYAM_CONTENT_4,
4256     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4257     ED_AREA_YAMYAM_CONTENT_XOFF(4),     ED_AREA_YAMYAM_CONTENT_YOFF(4),
4258     GADGET_ID_YAMYAM_CONTENT_4,         GADGET_ID_NONE,
4259     &level.yamyam_content[4].e[0][0],   3, 3,
4260     NULL, NULL, NULL, "5",              NULL
4261   },
4262   {
4263     ED_DRAWING_ID_YAMYAM_CONTENT_5,
4264     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4265     ED_AREA_YAMYAM_CONTENT_XOFF(5),     ED_AREA_YAMYAM_CONTENT_YOFF(5),
4266     GADGET_ID_YAMYAM_CONTENT_5,         GADGET_ID_NONE,
4267     &level.yamyam_content[5].e[0][0],   3, 3,
4268     NULL, NULL, NULL, "6",              NULL
4269   },
4270   {
4271     ED_DRAWING_ID_YAMYAM_CONTENT_6,
4272     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4273     ED_AREA_YAMYAM_CONTENT_XOFF(6),     ED_AREA_YAMYAM_CONTENT_YOFF(6),
4274     GADGET_ID_YAMYAM_CONTENT_6,         GADGET_ID_NONE,
4275     &level.yamyam_content[6].e[0][0],   3, 3,
4276     NULL, NULL, NULL, "7",              NULL
4277   },
4278   {
4279     ED_DRAWING_ID_YAMYAM_CONTENT_7,
4280     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
4281     ED_AREA_YAMYAM_CONTENT_XOFF(7),     ED_AREA_YAMYAM_CONTENT_YOFF(7),
4282     GADGET_ID_YAMYAM_CONTENT_7,         GADGET_ID_NONE,
4283     &level.yamyam_content[7].e[0][0],   3, 3,
4284     NULL, NULL, NULL, "8",              NULL
4285   },
4286
4287   // ---------- magic ball content --------------------------------------------
4288
4289   {
4290     ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
4291     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4292     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0), ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
4293     GADGET_ID_MAGIC_BALL_CONTENT_0,     GADGET_ID_NONE,
4294     &level.ball_content[0].e[0][0],     3, 3,
4295     NULL, NULL, NULL, "1",              NULL
4296   },
4297   {
4298     ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
4299     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4300     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1), ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
4301     GADGET_ID_MAGIC_BALL_CONTENT_1,     GADGET_ID_NONE,
4302     &level.ball_content[1].e[0][0],     3, 3,
4303     NULL, NULL, NULL, "2",              NULL
4304   },
4305   {
4306     ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
4307     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4308     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2), ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
4309     GADGET_ID_MAGIC_BALL_CONTENT_2,     GADGET_ID_NONE,
4310     &level.ball_content[2].e[0][0],     3, 3,
4311     NULL, NULL, NULL, "3",              NULL
4312   },
4313   {
4314     ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
4315     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4316     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3), ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
4317     GADGET_ID_MAGIC_BALL_CONTENT_3,     GADGET_ID_NONE,
4318     &level.ball_content[3].e[0][0],     3, 3,
4319     NULL, NULL, NULL, "4",              NULL
4320   },
4321   {
4322     ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
4323     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4324     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4), ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
4325     GADGET_ID_MAGIC_BALL_CONTENT_4,     GADGET_ID_NONE,
4326     &level.ball_content[4].e[0][0],     3, 3,
4327     NULL, NULL, NULL, "5",              NULL
4328   },
4329   {
4330     ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
4331     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4332     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5), ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
4333     GADGET_ID_MAGIC_BALL_CONTENT_5,     GADGET_ID_NONE,
4334     &level.ball_content[5].e[0][0],     3, 3,
4335     NULL, NULL, NULL, "6",              NULL
4336   },
4337   {
4338     ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
4339     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4340     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6), ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
4341     GADGET_ID_MAGIC_BALL_CONTENT_6,     GADGET_ID_NONE,
4342     &level.ball_content[6].e[0][0],     3, 3,
4343     NULL, NULL, NULL, "7",              NULL
4344   },
4345   {
4346     ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
4347     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
4348     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7), ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
4349     GADGET_ID_MAGIC_BALL_CONTENT_7,     GADGET_ID_NONE,
4350     &level.ball_content[7].e[0][0],     3, 3,
4351     NULL, NULL, NULL, "8",              NULL
4352   },
4353
4354   // ---------- android content -----------------------------------------------
4355
4356   {
4357     ED_DRAWING_ID_ANDROID_CONTENT,
4358     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(6),
4359     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4360     GADGET_ID_ANDROID_CONTENT,          GADGET_ID_NONE,
4361     &level.android_clone_element[0],    MAX_ANDROID_ELEMENTS, 1,
4362     NULL, NULL, "Elements:", NULL,      "Elements android can clone"
4363   },
4364
4365   // ---------- amoeba content ------------------------------------------------
4366
4367   {
4368     ED_DRAWING_ID_AMOEBA_CONTENT,
4369     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(3),
4370     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4371     GADGET_ID_AMOEBA_CONTENT,           GADGET_ID_NONE,
4372     &level.amoeba_content,              1, 1,
4373     "Content:", NULL, NULL, NULL,       "Amoeba content"
4374   },
4375
4376   // ---------- BD snap element -----------------------------------------------
4377
4378   {
4379     ED_DRAWING_ID_BD_SNAP_ELEMENT,
4380     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
4381     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4382     GADGET_ID_BD_SNAP_ELEMENT,          GADGET_ID_NONE,
4383     &level.bd_snap_element,             1, 1,
4384     "Snap element:", NULL, NULL, NULL,  "Element created when snapping"
4385   },
4386
4387   // ---------- BD magic wall elements ----------------------------------------
4388
4389   {
4390     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
4391     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(4),
4392     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4393     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO, GADGET_ID_NONE,
4394     &level.bd_magic_wall_diamond_to,    1, 1,
4395     "Changes diamonds to:", NULL, NULL, NULL,   "Element to turn diamonds to"
4396   },
4397   {
4398     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
4399     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
4400     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4401     GADGET_ID_BD_MAGIC_WALL_ROCK_TO, GADGET_ID_NONE,
4402     &level.bd_magic_wall_rock_to,       1, 1,
4403     "Changes rocks to:", NULL, NULL, NULL,      "Element to turn rocks to"
4404   },
4405   {
4406     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
4407     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(6),
4408     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4409     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO, GADGET_ID_NONE,
4410     &level.bd_magic_wall_mega_rock_to,  1, 1,
4411     "Changes mega rocks to:", NULL, NULL, NULL, "Element to turn mega rocks to"
4412   },
4413   {
4414     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
4415     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(7),
4416     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4417     GADGET_ID_BD_MAGIC_WALL_NUT_TO, GADGET_ID_NONE,
4418     &level.bd_magic_wall_nut_to,        1, 1,
4419     "Changes nuts to:", NULL, NULL, NULL,       "Element to turn nuts to"
4420   },
4421   {
4422     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
4423     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(8),
4424     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4425     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO, GADGET_ID_NONE,
4426     &level.bd_magic_wall_nitro_pack_to, 1, 1,
4427     "Changes nitro packs to:", NULL, NULL, NULL,        "Element to turn nitro packs to"
4428   },
4429   {
4430     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
4431     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(9),
4432     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4433     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO, GADGET_ID_NONE,
4434     &level.bd_magic_wall_flying_diamond_to, 1, 1,
4435     "Changes flying diamonds to:", NULL, NULL, NULL,    "Element to turn flying diamonds to"
4436   },
4437   {
4438     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
4439     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(10),
4440     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4441     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO, GADGET_ID_NONE,
4442     &level.bd_magic_wall_flying_rock_to, 1, 1,
4443     "Changes flying rocks to:", NULL, NULL, NULL,       "Element to turn flying rocks to"
4444   },
4445
4446   // ---------- BD amoeba content ---------------------------------------------
4447
4448   {
4449     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
4450     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(7),
4451     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4452     GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG, GADGET_ID_NONE,
4453     &level.bd_amoeba_content_too_big,   1, 1,
4454     "If too big, changes to:", NULL, NULL, NULL,        "BD amoeba content if too big"
4455   },
4456   {
4457     ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
4458     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(8),
4459     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4460     GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED, GADGET_ID_NONE,
4461     &level.bd_amoeba_content_enclosed,  1, 1,
4462     "If enclosed, changes to:", NULL, NULL, NULL,       "BD amoeba content if enclosed"
4463   },
4464
4465   // ---------- BD amoeba 2 content -------------------------------------------
4466
4467   {
4468     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
4469     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(7),
4470     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4471     GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG, GADGET_ID_NONE,
4472     &level.bd_amoeba_2_content_too_big, 1, 1,
4473     "If too big, changes to:", NULL, NULL, NULL,        "BD amoeba 2 content if too big"
4474   },
4475   {
4476     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
4477     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(8),
4478     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4479     GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED, GADGET_ID_NONE,
4480     &level.bd_amoeba_2_content_enclosed,        1, 1,
4481     "If enclosed, changes to:", NULL, NULL, NULL,       "BD amoeba 2 content if enclosed"
4482   },
4483   {
4484     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
4485     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(10),
4486     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4487     GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING, GADGET_ID_NONE,
4488     &level.bd_amoeba_2_content_exploding,       1, 1,
4489     "If exploding, changes to:", NULL, NULL, NULL,      "BD amoeba 2 content if exploding"
4490   },
4491   {
4492     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
4493     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(11),
4494     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4495     GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,   GADGET_ID_NONE,
4496     &level.bd_amoeba_2_content_looks_like,      1, 1,
4497     "Use graphic of element:", NULL, NULL, NULL,        "BD amoeba 2 looks like this element"
4498   },
4499   {
4500     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
4501     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
4502     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4503     GADGET_ID_BD_SLIME_EATS_ELEMENT_1,  GADGET_ID_NONE,
4504     &level.bd_slime_eats_element_1,     1, 1,
4505     "Can eat:", NULL, NULL, NULL,       "Element that can be eaten"
4506   },
4507   {
4508     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
4509     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
4510     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4511     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1, GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
4512     &level.bd_slime_converts_to_element_1,      1, 1,
4513     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4514   },
4515   {
4516     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
4517     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(6),
4518     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4519     GADGET_ID_BD_SLIME_EATS_ELEMENT_2,  GADGET_ID_NONE,
4520     &level.bd_slime_eats_element_2,     1, 1,
4521     "Can eat:", NULL, NULL, NULL,       "Element that can be eaten"
4522   },
4523   {
4524     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
4525     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(6),
4526     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4527     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2, GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
4528     &level.bd_slime_converts_to_element_2,      1, 1,
4529     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4530   },
4531   {
4532     ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
4533     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(7),
4534     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4535     GADGET_ID_BD_SLIME_EATS_ELEMENT_3,  GADGET_ID_NONE,
4536     &level.bd_slime_eats_element_3,     1, 1,
4537     "Can eat:", NULL, NULL, NULL,       "Element that can be eaten"
4538   },
4539   {
4540     ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
4541     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(7),
4542     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4543     GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3, GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
4544     &level.bd_slime_converts_to_element_3,      1, 1,
4545     " and convert to:", NULL, NULL, NULL,       "Eaten element is converted to"
4546   },
4547   {
4548     ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
4549     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(1),
4550     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4551     GADGET_ID_BD_ACID_EATS_ELEMENT,     GADGET_ID_NONE,
4552     &level.bd_acid_eats_element,        1, 1,
4553     "Can eat:", NULL, NULL, NULL,               "Eats this element when spreading"
4554   },
4555   {
4556     ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
4557     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(3),
4558     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4559     GADGET_ID_BD_ACID_TURNS_TO_ELEMENT, GADGET_ID_NONE,
4560     &level.bd_acid_turns_to_element,    1, 1,
4561     "Can leave behind:", NULL, NULL, NULL,      "Turns to this element after spreading"
4562   },
4563   {
4564     ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
4565     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
4566     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4567     GADGET_ID_BD_BITER_EATS_ELEMENT,    GADGET_ID_NONE,
4568     &level.bd_biter_eats_element,       1, 1,
4569     "Can eat:", NULL, NULL, NULL,       "Eats this element when moving"
4570   },
4571   {
4572     ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,
4573     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(1),
4574     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4575     GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT, GADGET_ID_NONE,
4576     &level.bd_bladder_converts_by_element,      1, 1,
4577     "Turns to clock by touching:", NULL, NULL, NULL,    "Turns to clock by touching element"
4578   },
4579   {
4580     ED_DRAWING_ID_BD_NUT_CONTENT,
4581     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(1),
4582     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4583     GADGET_ID_BD_NUT_CONTENT,           GADGET_ID_NONE,
4584     &level.bd_nut_content,              1, 1,
4585     "When breaking, changes to:", NULL, NULL, NULL,     "Element created when breaking nut"
4586   },
4587   {
4588     ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
4589     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(1),
4590     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4591     GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE, GADGET_ID_NONE,
4592     &level.bd_expanding_wall_looks_like,        1, 1,
4593     "Use graphic of element:", NULL, NULL, NULL,        "Expanding wall looks like this element"
4594   },
4595   {
4596     ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
4597     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(0),
4598     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4599     GADGET_ID_BD_SAND_LOOKS_LIKE, GADGET_ID_NONE,
4600     &level.bd_sand_looks_like,  1, 1,
4601     "Use graphic of element:", NULL, NULL, NULL,        "Sand looks like this element"
4602   },
4603
4604   // ---------- level start element -------------------------------------------
4605
4606   {
4607     ED_DRAWING_ID_START_ELEMENT,
4608     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(10),
4609     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4610     GADGET_ID_START_ELEMENT,            GADGET_ID_USE_START_ELEMENT,
4611     &level.start_element[0],            1, 1,
4612     NULL, NULL, NULL, NULL,             "Level start element"
4613   },
4614
4615   // ---------- player artwork element ----------------------------------------
4616
4617   {
4618     ED_DRAWING_ID_ARTWORK_ELEMENT,
4619     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(11),
4620     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4621     GADGET_ID_ARTWORK_ELEMENT,          GADGET_ID_USE_ARTWORK_ELEMENT,
4622     &level.artwork_element[0],          1, 1,
4623     NULL, NULL, NULL, NULL,             "Element for player artwork"
4624   },
4625
4626   // ---------- player explosion element --------------------------------------
4627
4628   {
4629     ED_DRAWING_ID_EXPLOSION_ELEMENT,
4630     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(12),
4631     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4632     GADGET_ID_EXPLOSION_ELEMENT,        GADGET_ID_USE_EXPLOSION_ELEMENT,
4633     &level.explosion_element[0],        1, 1,
4634     NULL, NULL, NULL, NULL,             "Element for player explosion"
4635   },
4636
4637   // ---------- player initial inventory --------------------------------------
4638
4639   {
4640     ED_DRAWING_ID_INVENTORY_CONTENT,
4641     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
4642     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4643     GADGET_ID_INVENTORY_CONTENT,        GADGET_ID_USE_INITIAL_INVENTORY,
4644     &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
4645     NULL, NULL, NULL, NULL,             "Content for initial inventory"
4646   },
4647
4648   // ---------- gray ball content -----------------------------------------
4649
4650   {
4651     ED_DRAWING_ID_MM_BALL_CONTENT,
4652     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
4653     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4654     GADGET_ID_MM_BALL_CONTENT,          GADGET_ID_NONE,
4655     &level.mm_ball_content[0],          MAX_MM_BALL_CONTENTS, 1,
4656     "Content:", NULL, NULL, NULL,       "Content for gray ball"
4657   },
4658
4659   // ---------- element settings: configure 1 (custom elements) ---------------
4660
4661   // ---------- custom graphic ------------------------------------------------
4662
4663   {
4664     ED_DRAWING_ID_CUSTOM_GRAPHIC,
4665     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
4666     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4667     GADGET_ID_CUSTOM_GRAPHIC,           GADGET_ID_CUSTOM_USE_GRAPHIC,
4668     &custom_element.gfx_element_initial, 1, 1,
4669     NULL, NULL, NULL, NULL,             "Custom graphic element"
4670   },
4671
4672   // ---------- element settings: configure 2 (custom elements) ---------------
4673
4674   // ---------- custom content (when exploding) -------------------------------
4675
4676   {
4677     ED_DRAWING_ID_CUSTOM_CONTENT,
4678     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(11),
4679     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
4680     GADGET_ID_CUSTOM_CONTENT,           GADGET_ID_NONE, // align three rows
4681     &custom_element.content.e[0][0],    3, 3,
4682     "Content:", NULL, NULL, NULL,       NULL
4683   },
4684
4685   // ---------- custom enter and leave element (when moving) ------------------
4686
4687   {
4688     ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
4689     ED_AREA_1X1_SETTINGS_XPOS(1),       ED_AREA_1X1_SETTINGS_YPOS(3),
4690     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4691     GADGET_ID_CUSTOM_MOVE_ENTER,        GADGET_ID_NONE,
4692     &custom_element.move_enter_element, 1, 1,
4693     "Can dig:", " ", NULL, NULL,        "Element that can be digged/collected"
4694   },
4695   {
4696     ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
4697     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(3),
4698     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4699     GADGET_ID_CUSTOM_MOVE_LEAVE,        GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
4700     &custom_element.move_leave_element, 1, 1,
4701     NULL, NULL, NULL, NULL,             "Element that will be left behind"
4702   },
4703
4704   // ---------- element settings: advanced (custom elements) ------------------
4705
4706   // ---------- custom change target ------------------------------------------
4707
4708   {
4709     ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
4710     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
4711     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4712     GADGET_ID_CUSTOM_CHANGE_TARGET,     GADGET_ID_CUSTOM_CAN_CHANGE,
4713     &custom_element_change.target_element, 1, 1,
4714     NULL, "after/when:", NULL, NULL,    "New target element after change"
4715   },
4716
4717   // ---------- custom change content (extended change target) ----------------
4718
4719   {
4720     ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
4721     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(9),
4722     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
4723     GADGET_ID_CUSTOM_CHANGE_CONTENT,    GADGET_ID_NONE, // align three rows
4724     &custom_element_change.target_content.e[0][0], 3, 3,
4725     NULL, NULL, NULL, NULL,             "New extended elements after change"
4726   },
4727
4728   // ---------- custom change trigger (element causing change) ----------------
4729
4730   {
4731     ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
4732     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(5),
4733     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4734     GADGET_ID_CUSTOM_CHANGE_TRIGGER,    GADGET_ID_CHANGE_OTHER_ACTION,
4735     &custom_element_change.initial_trigger_element, 1, 1,
4736     NULL, NULL, NULL, NULL,             "Other element triggering change"
4737   },
4738
4739   // ---------- custom change action (element used for action) ----------------
4740
4741   {
4742     ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
4743     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(13),
4744     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
4745     GADGET_ID_CUSTOM_CHANGE_ACTION,     GADGET_ID_ACTION_ARG,
4746     &custom_element_change.action_element, 1, 1,
4747     NULL, NULL, NULL, NULL,             "Element used as action parameter"
4748   },
4749
4750   // ---------- group element content -----------------------------------------
4751
4752   {
4753     ED_DRAWING_ID_GROUP_CONTENT,
4754     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
4755     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
4756     GADGET_ID_GROUP_CONTENT,            GADGET_ID_NONE,
4757     &group_element_info.element[0],     MAX_ELEMENTS_IN_GROUP, 1,
4758     "Content:", NULL, NULL, NULL,       NULL
4759   },
4760
4761   // ---------- random background (for random painting) -----------------------
4762
4763   {
4764     ED_DRAWING_ID_RANDOM_BACKGROUND,
4765     -1,                                 ED_AREA_1X1_LSETTINGS_YPOS(1),
4766     0,                                  ED_AREA_1X1_LSETTINGS_YOFF,
4767     GADGET_ID_RANDOM_BACKGROUND,        GADGET_ID_RANDOM_RESTRICTED,
4768     &random_placement_background_element, 1, 1,
4769     NULL, NULL, NULL, NULL,             "Random placement background"
4770   },
4771 };
4772
4773
4774 // ----------------------------------------------------------------------------
4775 // some internally used variables
4776 // ----------------------------------------------------------------------------
4777
4778 // maximal size of level editor drawing area
4779 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
4780
4781 // actual size of level editor drawing area
4782 static int ed_fieldx, ed_fieldy;
4783
4784 // actual position of level editor drawing area in level playfield
4785 static int level_xpos = -1, level_ypos = -1;
4786
4787 // actual tile size used to display playfield drawing area
4788 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
4789 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
4790
4791 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
4792
4793 // drawing elements on the three mouse buttons
4794 static int new_element1 = EL_WALL;
4795 static int new_element2 = EL_EMPTY;
4796 static int new_element3 = EL_SAND;
4797
4798 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
4799 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
4800                                 (button) == 2 ? new_element2 : \
4801                                 (button) == 3 ? new_element3 : EL_EMPTY)
4802
4803 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
4804
4805 static int use_permanent_palette = TRUE;
4806
4807 #define PX              (use_permanent_palette ? DX : SX)
4808 #define PY              (use_permanent_palette ? DY : SY)
4809 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
4810 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
4811
4812 // forward declaration for internal use
4813 static void CopyBrushToCursor(int, int);
4814 static void DeleteBrushFromCursor(void);
4815 static void ModifyEditorCounterValue(int, int);
4816 static void ModifyEditorCounterLimits(int, int, int);
4817 static void ModifyEditorSelectboxValue(int, int);
4818 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
4819 static void ModifyEditorDrawingArea(int, int, int);
4820 static void ModifyEditorElementList(void);
4821 static void AdjustElementListScrollbar(void);
4822 static void RedrawDrawingElements(void);
4823 static void DrawDrawingWindowExt(boolean);
4824 static void DrawDrawingWindow(void);
4825 static void DrawLevelConfigWindow(void);
4826 static void DrawPropertiesWindow(void);
4827 static void DrawPaletteWindow(void);
4828 static void UpdateCustomElementGraphicGadgets(void);
4829 static boolean checkPropertiesConfig(int);
4830 static void SetAutomaticNumberOfGemsNeeded(void);
4831 static void ClearEditorGadgetInfoText(void);
4832 static void CopyLevelToUndoBuffer(int);
4833 static void HandleDrawingAreas(struct GadgetInfo *);
4834 static void HandleCounterButtons(struct GadgetInfo *);
4835 static void HandleTextInputGadgets(struct GadgetInfo *);
4836 static void HandleTextAreaGadgets(struct GadgetInfo *);
4837 static void HandleSelectboxGadgets(struct GadgetInfo *);
4838 static void HandleTextbuttonGadgets(struct GadgetInfo *);
4839 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
4840 static void HandleRadiobuttons(struct GadgetInfo *);
4841 static void HandleCheckbuttons(struct GadgetInfo *);
4842 static void HandleControlButtons(struct GadgetInfo *);
4843 static void HandleDrawingAreaInfo(struct GadgetInfo *);
4844 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
4845 static boolean AskToCopyAndModifyLevelTemplate(void);
4846 static boolean getDrawModeHiRes(void);
4847 static int getTabulatorBarWidth(void);
4848 static int getTabulatorBarHeight(void);
4849 static Pixel getTabulatorBarColor(void);
4850 static void getEditorGraphicAndFrame(int, int *, int *, boolean);
4851 static int numHiresTiles(int);
4852
4853 static int num_editor_gadgets = 0;      // dynamically determined
4854
4855 static struct GadgetInfo **level_editor_gadget = NULL;
4856 static int *right_gadget_border = NULL;
4857
4858 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
4859 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
4860 static boolean draw_with_brush = FALSE;
4861 static int properties_element = 0;
4862
4863 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4864 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4865 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4866 static int undo_buffer_position = 0;
4867 static int undo_buffer_steps = 0;
4868 static int redo_buffer_steps = 0;
4869
4870 static int edit_mode;
4871 static int edit_mode_levelconfig;
4872 static int edit_mode_properties;
4873
4874 static int element_shift = 0;
4875
4876 static int editor_el_players[] =
4877 {
4878   EL_PLAYER_1,
4879   EL_PLAYER_2,
4880   EL_PLAYER_3,
4881   EL_PLAYER_4
4882 };
4883 static int *editor_el_players_ptr = editor_el_players;
4884 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
4885
4886 static int editor_hl_boulderdash[] =
4887 {
4888   EL_INTERNAL_CASCADE_BD_ACTIVE,
4889   EL_CHAR('B'),
4890   EL_CHAR('D'),
4891   EL_EMPTY,
4892 };
4893
4894 static int editor_el_boulderdash[] =
4895 {
4896   EL_EMPTY,
4897   EL_SAND,
4898   EL_BD_ROCK,
4899   EL_BD_DIAMOND,
4900
4901   EL_STEELWALL,
4902   EL_BD_WALL,
4903   EL_BD_EXPANDABLE_WALL,
4904   EL_BD_MAGIC_WALL,
4905
4906   EL_BD_AMOEBA,
4907   EL_BD_BUTTERFLY_UP,
4908   EL_BD_FIREFLY_UP,
4909   EL_EXIT_CLOSED,
4910
4911   EL_BD_BUTTERFLY_LEFT,
4912   EL_BD_FIREFLY_LEFT,
4913   EL_BD_BUTTERFLY_RIGHT,
4914   EL_BD_FIREFLY_RIGHT,
4915
4916   EL_EMPTY,
4917   EL_BD_BUTTERFLY_DOWN,
4918   EL_BD_FIREFLY_DOWN,
4919   EL_EXIT_OPEN,
4920 };
4921 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
4922 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
4923 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
4924 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
4925
4926 static int editor_hl_boulderdash_native[] =
4927 {
4928   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
4929   EL_CHAR('B'),
4930   EL_CHAR('D'),
4931   EL_EMPTY,
4932 };
4933
4934 static int editor_el_boulderdash_native[] =
4935 {
4936   EL_EMPTY,
4937   EL_BD_SAND,
4938   EL_BD_ROCK,
4939   EL_BD_DIAMOND,
4940
4941   EL_BD_STEELWALL,
4942   EL_BD_WALL,
4943   EL_BD_SAND_2,
4944   EL_BD_MAGIC_WALL,
4945
4946   EL_BD_AMOEBA,
4947   EL_BD_BUTTERFLY_UP,
4948   EL_BD_FIREFLY_UP,
4949   EL_BD_EXIT_CLOSED,
4950
4951   EL_BD_BUTTERFLY_LEFT,
4952   EL_BD_FIREFLY_LEFT,
4953   EL_BD_BUTTERFLY_RIGHT,
4954   EL_BD_FIREFLY_RIGHT,
4955
4956   EL_BD_INBOX,
4957   EL_BD_BUTTERFLY_DOWN,
4958   EL_BD_FIREFLY_DOWN,
4959   EL_BD_EXIT_OPEN,
4960
4961   EL_BD_AMOEBA_2,
4962   EL_BD_BUTTERFLY_2_UP,
4963   EL_BD_FIREFLY_2_UP,
4964   EL_BD_SLIME,
4965
4966   EL_BD_BUTTERFLY_2_LEFT,
4967   EL_BD_FIREFLY_2_LEFT,
4968   EL_BD_BUTTERFLY_2_RIGHT,
4969   EL_BD_FIREFLY_2_RIGHT,
4970
4971   EL_BD_BOMB,
4972   EL_BD_BUTTERFLY_2_DOWN,
4973   EL_BD_FIREFLY_2_DOWN,
4974   EL_BD_FLYING_DIAMOND,
4975
4976   EL_BD_NITRO_PACK,
4977   EL_BD_DRAGONFLY_UP,
4978   EL_BD_STONEFLY_UP,
4979   EL_BD_DIAMOND_GLUED,
4980
4981   EL_BD_DRAGONFLY_LEFT,
4982   EL_BD_STONEFLY_LEFT,
4983   EL_BD_DRAGONFLY_RIGHT,
4984   EL_BD_STONEFLY_RIGHT,
4985
4986   EL_BD_NUT,
4987   EL_BD_DRAGONFLY_DOWN,
4988   EL_BD_STONEFLY_DOWN,
4989   EL_EMPTY,
4990
4991   EL_BD_BITER_SWITCH_1,
4992   EL_BD_BITER_UP,
4993   EL_BD_COW_UP,
4994   EL_EMPTY,
4995
4996   EL_BD_BITER_LEFT,
4997   EL_BD_COW_LEFT,
4998   EL_BD_BITER_RIGHT,
4999   EL_BD_COW_RIGHT,
5000
5001   EL_BD_VOODOO_DOLL,
5002   EL_BD_BITER_DOWN,
5003   EL_BD_COW_DOWN,
5004   EL_BD_GHOST,
5005
5006   EL_BD_SAND_GLUED,
5007   EL_BD_SAND_BALL,
5008   EL_BD_SAND_LOOSE,
5009   EL_BD_WALL_NON_SLOPED,
5010
5011   EL_BD_SAND_SLOPED_UP_LEFT,
5012   EL_BD_SAND_SLOPED_UP_RIGHT,
5013   EL_BD_WALL_SLOPED_UP_LEFT,
5014   EL_BD_WALL_SLOPED_UP_RIGHT,
5015
5016   EL_BD_SAND_SLOPED_DOWN_LEFT,
5017   EL_BD_SAND_SLOPED_DOWN_RIGHT,
5018   EL_BD_WALL_SLOPED_DOWN_LEFT,
5019   EL_BD_WALL_SLOPED_DOWN_RIGHT,
5020
5021   EL_BD_FLYING_ROCK,
5022   EL_BD_ROCK_GLUED,
5023   EL_BD_STEELWALL_SLOPED_UP_LEFT,
5024   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
5025
5026   EL_BD_WAITING_ROCK,
5027   EL_BD_CHASING_ROCK,
5028   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
5029   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
5030
5031   EL_BD_MEGA_ROCK,
5032   EL_BD_SWEET,
5033   EL_BD_INVISIBLE_EXIT_CLOSED,
5034   EL_BD_INVISIBLE_EXIT_OPEN,
5035
5036   EL_BD_STEELWALL_EXPLODABLE,
5037   EL_BD_STEELWALL_DIGGABLE,
5038   EL_BD_WALL_DIGGABLE,
5039   EL_BD_FALLING_WALL,
5040
5041   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
5042   EL_BD_EXPANDABLE_WALL_VERTICAL,
5043   EL_BD_EXPANDABLE_WALL_ANY,
5044   EL_BD_EXPANDABLE_WALL_SWITCH_HORIZONTAL,
5045
5046   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
5047   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
5048   EL_BD_EXPANDABLE_STEELWALL_ANY,
5049   EL_BD_CREATURE_SWITCH,
5050
5051   EL_BD_BLADDER,
5052   EL_BD_BLADDER_SPENDER,
5053   EL_BD_REPLICATOR,
5054   EL_BD_REPLICATOR_SWITCH,
5055
5056   EL_BD_CONVEYOR_LEFT,
5057   EL_BD_CONVEYOR_RIGHT,
5058   EL_BD_CONVEYOR_SWITCH,
5059   EL_BD_CONVEYOR_DIR_SWITCH_NORMAL,
5060
5061   EL_BD_CLOCK,
5062   EL_BD_TIME_PENALTY,
5063   EL_BD_GRAVESTONE,
5064   EL_BD_SKELETON,
5065
5066   EL_BD_WATER,
5067   EL_BD_ACID,
5068   EL_BD_LAVA,
5069   EL_BD_BOX,
5070
5071   EL_BD_GATE_1,
5072   EL_BD_GATE_2,
5073   EL_BD_GATE_3,
5074   EL_BD_TRAPPED_DIAMOND,
5075
5076   EL_BD_KEY_1,
5077   EL_BD_KEY_2,
5078   EL_BD_KEY_3,
5079   EL_BD_DIAMOND_KEY,
5080
5081   EL_BD_WALL_KEY_1,
5082   EL_BD_WALL_KEY_2,
5083   EL_BD_WALL_KEY_3,
5084   EL_BD_WALL_DIAMOND,
5085
5086   EL_BD_POT,
5087   EL_BD_GRAVITY_SWITCH,
5088   EL_BD_PNEUMATIC_HAMMER,
5089   EL_BD_TELEPORTER,
5090
5091   EL_BD_PLAYER,
5092   EL_BD_PLAYER_WITH_BOMB,
5093   EL_BD_PLAYER_GLUED,
5094   EL_BD_PLAYER_STIRRING,
5095 };
5096 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
5097 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
5098 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
5099 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
5100
5101 static int editor_hl_boulderdash_effects[] =
5102 {
5103   EL_INTERNAL_CASCADE_BD_EFFECTS_ACTIVE,
5104   EL_CHAR('B'),
5105   EL_CHAR('D'),
5106   EL_CHAR('E'),
5107 };
5108
5109 static int editor_el_boulderdash_effects[] =
5110 {
5111   EL_BD_DIAMOND_FALLING,
5112   EL_BD_ROCK_FALLING,
5113   EL_BD_MEGA_ROCK_FALLING,
5114   EL_BD_FLYING_DIAMOND_FLYING,
5115
5116   EL_BD_FALLING_WALL_FALLING,
5117   EL_BD_NITRO_PACK_FALLING,
5118   EL_BD_NUT_FALLING,
5119   EL_BD_FLYING_ROCK_FLYING,
5120
5121   EL_BD_PLAYER_GROWING_1,
5122   EL_BD_PLAYER_GROWING_2,
5123   EL_BD_PLAYER_GROWING_3,
5124   EL_BD_PLAYER,
5125
5126   EL_BD_PLAYER_WITH_BOMB,
5127   EL_BD_PLAYER_STIRRING,
5128   EL_BD_EXIT_OPEN,
5129   EL_BD_INVISIBLE_EXIT_OPEN,
5130
5131   EL_BD_BLADDER_1,
5132   EL_BD_BLADDER_2,
5133   EL_BD_BLADDER_3,
5134   EL_BD_BLADDER_4,
5135
5136   EL_BD_BLADDER_5,
5137   EL_BD_BLADDER_6,
5138   EL_BD_BLADDER_7,
5139   EL_BD_BLADDER_8,
5140
5141   EL_BD_SAND_2,
5142   EL_BD_COW_ENCLOSED_1,
5143   EL_BD_COW_ENCLOSED_2,
5144   EL_BD_COW_ENCLOSED_3,
5145
5146   EL_BD_COW_ENCLOSED_4,
5147   EL_BD_COW_ENCLOSED_5,
5148   EL_BD_COW_ENCLOSED_6,
5149   EL_BD_COW_ENCLOSED_7,
5150
5151   EL_BD_WATER_1,
5152   EL_BD_WATER_2,
5153   EL_BD_WATER_3,
5154   EL_BD_WATER_4,
5155
5156   EL_BD_WATER_5,
5157   EL_BD_WATER_6,
5158   EL_BD_WATER_7,
5159   EL_BD_WATER_8,
5160
5161   EL_BD_WATER_9,
5162   EL_BD_WATER_10,
5163   EL_BD_WATER_11,
5164   EL_BD_WATER_12,
5165
5166   EL_BD_WATER_13,
5167   EL_BD_WATER_14,
5168   EL_BD_WATER_15,
5169   EL_BD_WATER_16,
5170
5171   EL_BD_BOMB_TICKING_1,
5172   EL_BD_BOMB_TICKING_2,
5173   EL_BD_BOMB_TICKING_3,
5174   EL_BD_BOMB_TICKING_4,
5175
5176   EL_BD_BOMB_TICKING_5,
5177   EL_BD_BOMB_TICKING_6,
5178   EL_BD_BOMB_TICKING_7,
5179   EL_EMPTY,
5180
5181   EL_BD_BOMB_EXPLODING_1,
5182   EL_BD_BOMB_EXPLODING_2,
5183   EL_BD_BOMB_EXPLODING_3,
5184   EL_BD_BOMB_EXPLODING_4,
5185
5186   EL_BD_NUT_BREAKING_1,
5187   EL_BD_NUT_BREAKING_2,
5188   EL_BD_NUT_BREAKING_3,
5189   EL_BD_NUT_BREAKING_4,
5190
5191   EL_BD_EXPLODING_1,
5192   EL_BD_EXPLODING_2,
5193   EL_BD_EXPLODING_3,
5194   EL_BD_EXPLODING_4,
5195
5196   EL_BD_EXPLODING_5,
5197   EL_BD_TIME_PENALTY,
5198   EL_BD_DIAMOND_GROWING_1,
5199   EL_BD_DIAMOND_GROWING_2,
5200
5201   EL_BD_DIAMOND_GROWING_3,
5202   EL_BD_DIAMOND_GROWING_4,
5203   EL_BD_DIAMOND_GROWING_5,
5204   EL_BD_NITRO_PACK_EXPLODING,
5205
5206   EL_BD_NITRO_PACK_EXPLODING_1,
5207   EL_BD_NITRO_PACK_EXPLODING_2,
5208   EL_BD_NITRO_PACK_EXPLODING_3,
5209   EL_BD_NITRO_PACK_EXPLODING_4,
5210
5211   EL_BD_ROCK_GROWING_1,
5212   EL_BD_ROCK_GROWING_2,
5213   EL_BD_ROCK_GROWING_3,
5214   EL_BD_ROCK_GROWING_4,
5215
5216   EL_BD_STEELWALL_GROWING_1,
5217   EL_BD_STEELWALL_GROWING_2,
5218   EL_BD_STEELWALL_GROWING_3,
5219   EL_BD_STEELWALL_GROWING_4,
5220
5221   EL_BD_CLOCK_GROWING_1,
5222   EL_BD_CLOCK_GROWING_2,
5223   EL_BD_CLOCK_GROWING_3,
5224   EL_BD_CLOCK_GROWING_4,
5225
5226   EL_BD_GHOST_EXPLODING_1,
5227   EL_BD_GHOST_EXPLODING_2,
5228   EL_BD_GHOST_EXPLODING_3,
5229   EL_BD_GHOST_EXPLODING_4,
5230 };
5231 static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
5232 static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
5233 static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
5234 static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
5235
5236 static int editor_hl_emerald_mine[] =
5237 {
5238   EL_INTERNAL_CASCADE_EM_ACTIVE,
5239   EL_CHAR('E'),
5240   EL_CHAR('M'),
5241   EL_EMPTY,
5242 };
5243
5244 static int editor_el_emerald_mine[] =
5245 {
5246   EL_SAND,
5247   EL_ROCK,
5248   EL_QUICKSAND_EMPTY,
5249   EL_QUICKSAND_FULL,
5250
5251   EL_STEELWALL,
5252   EL_WALL,
5253   EL_WALL_SLIPPERY,
5254   EL_MAGIC_WALL,
5255
5256   EL_EMERALD,
5257   EL_DIAMOND,
5258   EL_NUT,
5259   EL_BOMB,
5260
5261   EL_EM_DYNAMITE,
5262   EL_EM_DYNAMITE_ACTIVE,
5263   EL_EM_EXIT_CLOSED,
5264   EL_EM_EXIT_OPEN,
5265
5266   EL_YAMYAM_UP,
5267   EL_BUG_UP,
5268   EL_SPACESHIP_UP,
5269   EL_ROBOT,
5270
5271   EL_BUG_LEFT,
5272   EL_SPACESHIP_LEFT,
5273   EL_BUG_RIGHT,
5274   EL_SPACESHIP_RIGHT,
5275
5276   EL_ROBOT_WHEEL,
5277   EL_BUG_DOWN,
5278   EL_SPACESHIP_DOWN,
5279   EL_INVISIBLE_WALL,
5280
5281   EL_ACID_POOL_TOPLEFT,
5282   EL_ACID,
5283   EL_ACID_POOL_TOPRIGHT,
5284   EL_AMOEBA_DROP,
5285
5286   EL_ACID_POOL_BOTTOMLEFT,
5287   EL_ACID_POOL_BOTTOM,
5288   EL_ACID_POOL_BOTTOMRIGHT,
5289   EL_AMOEBA_WET,
5290
5291   EL_EM_KEY_1,
5292   EL_EM_KEY_2,
5293   EL_EM_KEY_3,
5294   EL_EM_KEY_4,
5295
5296   EL_EM_GATE_1,
5297   EL_EM_GATE_2,
5298   EL_EM_GATE_3,
5299   EL_EM_GATE_4,
5300
5301   EL_EM_GATE_1_GRAY,
5302   EL_EM_GATE_2_GRAY,
5303   EL_EM_GATE_3_GRAY,
5304   EL_EM_GATE_4_GRAY,
5305 };
5306 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
5307 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
5308 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
5309 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
5310
5311 static int editor_hl_emerald_mine_club[] =
5312 {
5313   EL_INTERNAL_CASCADE_EMC_ACTIVE,
5314   EL_CHAR('E'),
5315   EL_CHAR('M'),
5316   EL_CHAR('C'),
5317 };
5318
5319 static int editor_el_emerald_mine_club[] =
5320 {
5321   EL_EMC_KEY_5,
5322   EL_EMC_KEY_6,
5323   EL_EMC_KEY_7,
5324   EL_EMC_KEY_8,
5325
5326   EL_EMC_GATE_5,
5327   EL_EMC_GATE_6,
5328   EL_EMC_GATE_7,
5329   EL_EMC_GATE_8,
5330
5331   EL_EMC_GATE_5_GRAY,
5332   EL_EMC_GATE_6_GRAY,
5333   EL_EMC_GATE_7_GRAY,
5334   EL_EMC_GATE_8_GRAY,
5335
5336   EL_EMC_STEELWALL_1,
5337   EL_EMC_STEELWALL_2,
5338   EL_EMC_STEELWALL_3,
5339   EL_EMC_STEELWALL_4,
5340
5341   EL_EMC_WALL_13,
5342   EL_EMC_WALL_14,
5343   EL_EMC_WALL_15,
5344   EL_EMC_WALL_16,
5345
5346   EL_EMC_WALL_SLIPPERY_1,
5347   EL_EMC_WALL_SLIPPERY_2,
5348   EL_EMC_WALL_SLIPPERY_3,
5349   EL_EMC_WALL_SLIPPERY_4,
5350
5351   EL_EMC_WALL_1,
5352   EL_EMC_WALL_2,
5353   EL_EMC_WALL_3,
5354   EL_EMC_WALL_4,
5355
5356   EL_EMC_WALL_5,
5357   EL_EMC_WALL_6,
5358   EL_EMC_WALL_7,
5359   EL_EMC_WALL_8,
5360
5361   EL_EMC_WALL_9,
5362   EL_EMC_WALL_10,
5363   EL_EMC_WALL_11,
5364   EL_EMC_WALL_12,
5365
5366   EL_EMC_GRASS,
5367   EL_EMC_FAKE_GRASS,
5368   EL_EMC_PLANT,
5369   EL_EMC_DRIPPER,
5370
5371   EL_EMC_MAGIC_BALL,
5372   EL_EMC_MAGIC_BALL_SWITCH,
5373   EL_EMC_LENSES,
5374   EL_EMC_MAGNIFIER,
5375
5376   EL_SPRING_LEFT,
5377   EL_SPRING,
5378   EL_SPRING_RIGHT,
5379   EL_EMC_SPRING_BUMPER,
5380
5381   EL_BALLOON,
5382   EL_YAMYAM_UP,
5383   EL_BALLOON_SWITCH_UP,
5384   EL_BALLOON_SWITCH_ANY,
5385
5386   EL_YAMYAM_LEFT,
5387   EL_BALLOON_SWITCH_LEFT,
5388   EL_YAMYAM_RIGHT,
5389   EL_BALLOON_SWITCH_RIGHT,
5390
5391   EL_EMC_ANDROID,
5392   EL_YAMYAM_DOWN,
5393   EL_BALLOON_SWITCH_DOWN,
5394   EL_BALLOON_SWITCH_NONE,
5395 };
5396 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
5397 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
5398 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
5399 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
5400
5401 static int editor_hl_rnd[] =
5402 {
5403   EL_INTERNAL_CASCADE_RND_ACTIVE,
5404   EL_CHAR('R'),
5405   EL_CHAR('N'),
5406   EL_CHAR('D'),
5407 };
5408
5409 static int editor_el_rnd[] =
5410 {
5411   EL_DYNAMITE,                  // RND
5412   EL_DYNAMITE_ACTIVE,           // RND
5413   EL_EMPTY,
5414   EL_EMPTY,
5415
5416   EL_KEY_1,
5417   EL_KEY_2,
5418   EL_KEY_3,
5419   EL_KEY_4,
5420
5421   EL_GATE_1,
5422   EL_GATE_2,
5423   EL_GATE_3,
5424   EL_GATE_4,
5425
5426   EL_GATE_1_GRAY,
5427   EL_GATE_2_GRAY,
5428   EL_GATE_3_GRAY,
5429   EL_GATE_4_GRAY,
5430
5431   EL_ARROW_LEFT,
5432   EL_ARROW_RIGHT,
5433   EL_ARROW_UP,
5434   EL_ARROW_DOWN,
5435
5436   EL_AMOEBA_DEAD,
5437   EL_AMOEBA_DRY,
5438   EL_AMOEBA_FULL,
5439   EL_GAME_OF_LIFE,
5440
5441   EL_EMERALD_YELLOW,
5442   EL_EMERALD_RED,
5443   EL_EMERALD_PURPLE,
5444   EL_BIOMAZE,
5445
5446   EL_WALL_EMERALD_YELLOW,
5447   EL_WALL_EMERALD_RED,
5448   EL_WALL_EMERALD_PURPLE,
5449   EL_WALL_BD_DIAMOND,
5450
5451   EL_SPEED_PILL,
5452   EL_PACMAN_UP,
5453   EL_TIME_ORB_FULL,
5454   EL_TIME_ORB_EMPTY,
5455
5456   EL_PACMAN_LEFT,
5457   EL_DARK_YAMYAM,
5458   EL_PACMAN_RIGHT,
5459   EL_YAMYAM,                    // RND
5460
5461   EL_BLACK_ORB,
5462   EL_PACMAN_DOWN,
5463   EL_LAMP,
5464   EL_LAMP_ACTIVE,
5465
5466   EL_DYNABOMB_INCREASE_NUMBER,
5467   EL_DYNABOMB_INCREASE_SIZE,
5468   EL_DYNABOMB_INCREASE_POWER,
5469   EL_STONEBLOCK,
5470
5471   EL_MOLE,
5472   EL_PENGUIN,
5473   EL_PIG,
5474   EL_DRAGON,
5475
5476   EL_BUG,
5477   EL_MOLE_UP,
5478   EL_BD_BUTTERFLY,
5479   EL_BD_FIREFLY,
5480
5481   EL_MOLE_LEFT,
5482   EL_SATELLITE,
5483   EL_MOLE_RIGHT,
5484   EL_PACMAN,
5485
5486   EL_SPACESHIP,
5487   EL_MOLE_DOWN,
5488   EL_INVISIBLE_STEELWALL,
5489   EL_INVISIBLE_WALL,
5490
5491   EL_EXPANDABLE_WALL,
5492   EL_EXPANDABLE_WALL_HORIZONTAL,
5493   EL_EXPANDABLE_WALL_VERTICAL,
5494   EL_EXPANDABLE_WALL_ANY,
5495 };
5496 static int *editor_hl_rnd_ptr = editor_hl_rnd;
5497 static int *editor_el_rnd_ptr = editor_el_rnd;
5498 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
5499 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
5500
5501 static int editor_hl_sokoban[] =
5502 {
5503   EL_INTERNAL_CASCADE_SB_ACTIVE,
5504   EL_CHAR('S'),
5505   EL_CHAR('B'),
5506   EL_EMPTY,
5507 };
5508
5509 static int editor_el_sokoban[] =
5510 {
5511   EL_SOKOBAN_OBJECT,
5512   EL_SOKOBAN_FIELD_EMPTY,
5513   EL_SOKOBAN_FIELD_FULL,
5514   EL_SOKOBAN_FIELD_PLAYER,
5515 };
5516 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
5517 static int *editor_el_sokoban_ptr = editor_el_sokoban;
5518 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
5519 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
5520
5521 static int editor_hl_supaplex[] =
5522 {
5523   EL_INTERNAL_CASCADE_SP_ACTIVE,
5524   EL_CHAR('S'),
5525   EL_CHAR('P'),
5526   EL_EMPTY,
5527 };
5528
5529 static int editor_el_supaplex[] =
5530 {
5531   EL_SP_MURPHY,
5532   EL_EMPTY,
5533   EL_SP_BASE,
5534   EL_SP_BUGGY_BASE,
5535
5536   EL_SP_INFOTRON,
5537   EL_SP_ZONK,
5538   EL_SP_SNIKSNAK,
5539   EL_SP_ELECTRON,
5540
5541   EL_SP_DISK_RED,
5542   EL_SP_DISK_ORANGE,
5543   EL_SP_DISK_YELLOW,
5544   EL_SP_TERMINAL,
5545
5546   EL_SP_EXIT_CLOSED,
5547   EL_SP_PORT_HORIZONTAL,
5548   EL_SP_PORT_VERTICAL,
5549   EL_SP_PORT_ANY,
5550
5551   EL_SP_PORT_LEFT,
5552   EL_SP_PORT_RIGHT,
5553   EL_SP_PORT_UP,
5554   EL_SP_PORT_DOWN,
5555
5556   EL_SP_GRAVITY_PORT_LEFT,
5557   EL_SP_GRAVITY_PORT_RIGHT,
5558   EL_SP_GRAVITY_PORT_UP,
5559   EL_SP_GRAVITY_PORT_DOWN,
5560
5561   EL_SP_GRAVITY_ON_PORT_LEFT,
5562   EL_SP_GRAVITY_ON_PORT_RIGHT,
5563   EL_SP_GRAVITY_ON_PORT_UP,
5564   EL_SP_GRAVITY_ON_PORT_DOWN,
5565
5566   EL_SP_GRAVITY_OFF_PORT_LEFT,
5567   EL_SP_GRAVITY_OFF_PORT_RIGHT,
5568   EL_SP_GRAVITY_OFF_PORT_UP,
5569   EL_SP_GRAVITY_OFF_PORT_DOWN,
5570
5571   EL_SP_HARDWARE_GRAY,
5572   EL_SP_HARDWARE_GREEN,
5573   EL_SP_HARDWARE_BLUE,
5574   EL_SP_HARDWARE_RED,
5575
5576   EL_SP_HARDWARE_BASE_1,
5577   EL_SP_HARDWARE_BASE_2,
5578   EL_SP_HARDWARE_BASE_3,
5579   EL_SP_HARDWARE_BASE_4,
5580
5581   EL_SP_HARDWARE_BASE_5,
5582   EL_SP_HARDWARE_BASE_6,
5583   EL_SP_HARDWARE_YELLOW,
5584   EL_SP_CHIP_TOP,
5585
5586   EL_SP_CHIP_SINGLE,
5587   EL_SP_CHIP_LEFT,
5588   EL_SP_CHIP_RIGHT,
5589   EL_SP_CHIP_BOTTOM,
5590 };
5591 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
5592 static int *editor_el_supaplex_ptr = editor_el_supaplex;
5593 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
5594 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
5595
5596 static int editor_hl_diamond_caves[] =
5597 {
5598   EL_INTERNAL_CASCADE_DC_ACTIVE,
5599   EL_CHAR('D'),
5600   EL_CHAR('C'),
5601   EL_CHAR('2'),
5602 };
5603
5604 static int editor_el_diamond_caves[] =
5605 {
5606   EL_EM_STEEL_EXIT_CLOSED,      // DC2
5607   EL_EM_STEEL_EXIT_OPEN,        // DC2
5608   EL_WALL_EMERALD,              // DC2
5609   EL_WALL_DIAMOND,              // DC2
5610
5611   EL_PEARL,
5612   EL_CRYSTAL,
5613   EL_WALL_PEARL,
5614   EL_WALL_CRYSTAL,
5615
5616   EL_CONVEYOR_BELT_1_LEFT,
5617   EL_CONVEYOR_BELT_1_MIDDLE,
5618   EL_CONVEYOR_BELT_1_RIGHT,
5619   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
5620
5621   EL_CONVEYOR_BELT_2_LEFT,
5622   EL_CONVEYOR_BELT_2_MIDDLE,
5623   EL_CONVEYOR_BELT_2_RIGHT,
5624   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
5625
5626   EL_CONVEYOR_BELT_3_LEFT,
5627   EL_CONVEYOR_BELT_3_MIDDLE,
5628   EL_CONVEYOR_BELT_3_RIGHT,
5629   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
5630
5631   EL_CONVEYOR_BELT_4_LEFT,
5632   EL_CONVEYOR_BELT_4_MIDDLE,
5633   EL_CONVEYOR_BELT_4_RIGHT,
5634   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
5635
5636   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5637   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5638   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5639   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
5640
5641   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
5642   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
5643   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
5644   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
5645
5646   EL_TIMEGATE_CLOSED,
5647   EL_TIMEGATE_OPEN,
5648   EL_TIMEGATE_SWITCH,
5649   EL_DC_TIMEGATE_SWITCH,
5650
5651   EL_SWITCHGATE_CLOSED,
5652   EL_SWITCHGATE_OPEN,
5653   EL_SWITCHGATE_SWITCH_UP,
5654   EL_SWITCHGATE_SWITCH_DOWN,
5655
5656   EL_LIGHT_SWITCH,
5657   EL_LIGHT_SWITCH_ACTIVE,
5658   EL_DC_SWITCHGATE_SWITCH_UP,
5659   EL_DC_SWITCHGATE_SWITCH_DOWN,
5660
5661   EL_STEEL_EXIT_CLOSED,
5662   EL_STEEL_EXIT_OPEN,
5663   EL_STEELWALL_SLIPPERY,
5664   EL_INVISIBLE_SAND,
5665
5666   EL_QUICKSAND_FAST_EMPTY,
5667   EL_QUICKSAND_FAST_FULL,
5668   EL_LANDMINE,
5669   EL_DC_LANDMINE,
5670
5671   EL_SHIELD_NORMAL,
5672   EL_SHIELD_DEADLY,
5673   EL_EXTRA_TIME,
5674   EL_DC_MAGIC_WALL,
5675
5676   EL_ENVELOPE_1,
5677   EL_ENVELOPE_2,
5678   EL_ENVELOPE_3,
5679   EL_ENVELOPE_4,
5680
5681   EL_SIGN_RADIOACTIVITY,
5682   EL_SIGN_WHEELCHAIR,
5683   EL_SIGN_PARKING,
5684   EL_SIGN_NO_ENTRY,
5685
5686   EL_SIGN_GIVE_WAY,
5687   EL_SIGN_ENTRY_FORBIDDEN,
5688   EL_SIGN_EMERGENCY_EXIT,
5689   EL_SIGN_YIN_YANG,
5690
5691 #if 0
5692   EL_SIGN_SPERMS,
5693   EL_SIGN_BULLET,
5694   EL_SIGN_HEART,
5695   EL_SIGN_CROSS,
5696
5697   EL_SIGN_FRANKIE,
5698   EL_EMPTY,
5699   EL_EMPTY,
5700   EL_EMPTY,
5701
5702   EL_SPERMS,
5703   EL_BULLET,
5704   EL_HEART,
5705   EL_CROSS,
5706
5707   EL_FRANKIE,
5708   EL_EMPTY,
5709   EL_EMPTY,
5710   EL_EMPTY,
5711 #endif
5712
5713   EL_DC_STEELWALL_2_SINGLE,
5714   EL_DC_STEELWALL_2_TOP,
5715   EL_SIGN_EXCLAMATION,
5716   EL_SIGN_STOP,
5717
5718   EL_DC_STEELWALL_2_LEFT,
5719   EL_DC_STEELWALL_2_MIDDLE,
5720   EL_DC_STEELWALL_2_HORIZONTAL,
5721   EL_DC_STEELWALL_2_RIGHT,
5722
5723   EL_DC_STEELWALL_1_TOPLEFT,
5724   EL_DC_STEELWALL_2_VERTICAL,
5725   EL_DC_STEELWALL_1_TOPRIGHT,
5726   EL_DC_GATE_WHITE,
5727
5728   EL_DC_STEELWALL_1_VERTICAL,
5729   EL_DC_STEELWALL_2_BOTTOM,
5730   EL_DC_KEY_WHITE,
5731   EL_DC_GATE_WHITE_GRAY,
5732
5733   EL_DC_STEELWALL_1_BOTTOMLEFT,
5734   EL_DC_STEELWALL_1_HORIZONTAL,
5735   EL_DC_STEELWALL_1_BOTTOMRIGHT,
5736   EL_DC_GATE_FAKE_GRAY,
5737
5738   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
5739   EL_DC_STEELWALL_1_BOTTOM,
5740   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
5741   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
5742
5743   EL_DC_STEELWALL_1_RIGHT,
5744   EL_EMPTY,
5745   EL_DC_STEELWALL_1_LEFT,
5746   EL_EXPANDABLE_STEELWALL_VERTICAL,
5747
5748   EL_DC_STEELWALL_1_TOPRIGHT_2,
5749   EL_DC_STEELWALL_1_TOP,
5750   EL_DC_STEELWALL_1_TOPLEFT_2,
5751   EL_EXPANDABLE_STEELWALL_ANY,
5752 };
5753 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
5754 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
5755 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
5756 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
5757
5758 static int editor_hl_dx_boulderdash[] =
5759 {
5760   EL_INTERNAL_CASCADE_DX_ACTIVE,
5761   EL_CHAR('D'),
5762   EL_CHAR('X'),
5763   EL_EMPTY,
5764 };
5765
5766 static int editor_el_dx_boulderdash[] =
5767 {
5768   EL_EMPTY,
5769   EL_TUBE_RIGHT_DOWN,
5770   EL_TUBE_HORIZONTAL_DOWN,
5771   EL_TUBE_LEFT_DOWN,
5772
5773   EL_TUBE_HORIZONTAL,
5774   EL_TUBE_VERTICAL_RIGHT,
5775   EL_TUBE_ANY,
5776   EL_TUBE_VERTICAL_LEFT,
5777
5778   EL_TUBE_VERTICAL,
5779   EL_TUBE_RIGHT_UP,
5780   EL_TUBE_HORIZONTAL_UP,
5781   EL_TUBE_LEFT_UP,
5782
5783   EL_TRAP,
5784   EL_DX_SUPABOMB,
5785   EL_EMPTY,
5786   EL_EMPTY
5787 };
5788 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
5789 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
5790 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
5791 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
5792
5793 static int editor_hl_mirror_magic[] =
5794 {
5795   EL_INTERNAL_CASCADE_MM_ACTIVE,
5796   EL_CHAR('M'),
5797   EL_CHAR('M'),
5798   EL_EMPTY,
5799 };
5800
5801 static int editor_el_mirror_magic[] =
5802 {
5803   EL_MM_MCDUFFIN_RIGHT,
5804   EL_MM_MCDUFFIN_UP,
5805   EL_MM_MCDUFFIN_LEFT,
5806   EL_MM_MCDUFFIN_DOWN,
5807
5808   EL_MM_MIRROR_START,
5809   EL_MM_MIRROR_FIXED_START,
5810   EL_MM_POLARIZER_START,
5811   EL_MM_POLARIZER_CROSS_START,
5812
5813   EL_MM_TELEPORTER_RED_START,
5814   EL_MM_TELEPORTER_YELLOW_START,
5815   EL_MM_TELEPORTER_GREEN_START,
5816   EL_MM_TELEPORTER_BLUE_START,
5817
5818   EL_MM_PRISM,
5819   EL_MM_FUSE_ACTIVE,
5820   EL_MM_PACMAN_RIGHT,
5821   EL_MM_EXIT_CLOSED,
5822
5823   EL_MM_KETTLE,
5824   EL_MM_BOMB,
5825   EL_MM_KEY,
5826   EL_MM_FUEL_FULL,
5827
5828   EL_MM_LIGHTBULB,
5829   EL_MM_LIGHTBULB_ACTIVE,
5830   EL_MM_GRAY_BALL,
5831   EL_MM_LIGHTBALL,
5832
5833   EL_MM_STEEL_WALL,
5834   EL_MM_WOODEN_WALL,
5835   EL_MM_ICE_WALL,
5836   EL_MM_AMOEBA_WALL,
5837
5838   EL_MM_STEEL_LOCK,
5839   EL_MM_WOODEN_LOCK,
5840   EL_MM_STEEL_BLOCK,
5841   EL_MM_WOODEN_BLOCK,
5842
5843   EL_MM_STEEL_GRID_FIXED_1,
5844   EL_MM_STEEL_GRID_FIXED_2,
5845   EL_MM_STEEL_GRID_FIXED_3,
5846   EL_MM_STEEL_GRID_FIXED_4,
5847
5848   EL_MM_WOODEN_GRID_FIXED_1,
5849   EL_MM_WOODEN_GRID_FIXED_2,
5850   EL_MM_WOODEN_GRID_FIXED_3,
5851   EL_MM_WOODEN_GRID_FIXED_4,
5852
5853   EL_MM_ENVELOPE_1,
5854   EL_MM_ENVELOPE_2,
5855   EL_MM_ENVELOPE_3,
5856   EL_MM_ENVELOPE_4
5857 };
5858 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
5859 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
5860 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
5861 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
5862
5863 static int editor_hl_deflektor[] =
5864 {
5865   EL_INTERNAL_CASCADE_DF_ACTIVE,
5866   EL_CHAR('D'),
5867   EL_CHAR('F'),
5868   EL_EMPTY,
5869 };
5870
5871 static int editor_el_deflektor[] =
5872 {
5873   EL_DF_LASER_RIGHT,
5874   EL_DF_LASER_UP,
5875   EL_DF_LASER_LEFT,
5876   EL_DF_LASER_DOWN,
5877
5878   EL_DF_RECEIVER_RIGHT,
5879   EL_DF_RECEIVER_UP,
5880   EL_DF_RECEIVER_LEFT,
5881   EL_DF_RECEIVER_DOWN,
5882
5883   EL_DF_MIRROR_START,
5884   EL_DF_MIRROR_ROTATING_START,
5885   EL_DF_MIRROR_FIXED_START,
5886   EL_DF_CELL,
5887
5888   EL_DF_FIBRE_OPTIC_RED_1,
5889   EL_DF_FIBRE_OPTIC_YELLOW_1,
5890   EL_DF_FIBRE_OPTIC_GREEN_1,
5891   EL_DF_FIBRE_OPTIC_BLUE_1,
5892
5893   EL_DF_STEEL_GRID_FIXED_START,
5894   EL_DF_STEEL_GRID_ROTATING_START,
5895   EL_DF_WOODEN_GRID_FIXED_START,
5896   EL_DF_WOODEN_GRID_ROTATING_START,
5897
5898   EL_DF_STEEL_WALL,
5899   EL_DF_WOODEN_WALL,
5900   EL_DF_REFRACTOR,
5901   EL_DF_MINE,
5902
5903   EL_DF_SLOPE_1,
5904   EL_DF_SLOPE_2,
5905   EL_DF_SLOPE_3,
5906   EL_DF_SLOPE_4
5907 };
5908 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
5909 static int *editor_el_deflektor_ptr = editor_el_deflektor;
5910 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
5911 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
5912
5913 static int editor_hl_chars[] =
5914 {
5915   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
5916   EL_CHAR('T'),
5917   EL_CHAR('X'),
5918   EL_CHAR('T'),
5919 };
5920
5921 static int editor_el_chars[] =
5922 {
5923   EL_CHAR(' '),
5924   EL_CHAR('!'),
5925   EL_CHAR('"'),
5926   EL_CHAR('#'),
5927
5928   EL_CHAR('$'),
5929   EL_CHAR('%'),
5930   EL_CHAR('&'),
5931   EL_CHAR('\''),
5932
5933   EL_CHAR('('),
5934   EL_CHAR(')'),
5935   EL_CHAR('*'),
5936   EL_CHAR('+'),
5937
5938   EL_CHAR(','),
5939   EL_CHAR('-'),
5940   EL_CHAR('.'),
5941   EL_CHAR('/'),
5942
5943   EL_CHAR('0'),
5944   EL_CHAR('1'),
5945   EL_CHAR('2'),
5946   EL_CHAR('3'),
5947
5948   EL_CHAR('4'),
5949   EL_CHAR('5'),
5950   EL_CHAR('6'),
5951   EL_CHAR('7'),
5952
5953   EL_CHAR('8'),
5954   EL_CHAR('9'),
5955   EL_CHAR(':'),
5956   EL_CHAR(';'),
5957
5958   EL_CHAR('<'),
5959   EL_CHAR('='),
5960   EL_CHAR('>'),
5961   EL_CHAR('?'),
5962
5963   EL_CHAR('@'),
5964   EL_CHAR('A'),
5965   EL_CHAR('B'),
5966   EL_CHAR('C'),
5967
5968   EL_CHAR('D'),
5969   EL_CHAR('E'),
5970   EL_CHAR('F'),
5971   EL_CHAR('G'),
5972
5973   EL_CHAR('H'),
5974   EL_CHAR('I'),
5975   EL_CHAR('J'),
5976   EL_CHAR('K'),
5977
5978   EL_CHAR('L'),
5979   EL_CHAR('M'),
5980   EL_CHAR('N'),
5981   EL_CHAR('O'),
5982
5983   EL_CHAR('P'),
5984   EL_CHAR('Q'),
5985   EL_CHAR('R'),
5986   EL_CHAR('S'),
5987
5988   EL_CHAR('T'),
5989   EL_CHAR('U'),
5990   EL_CHAR('V'),
5991   EL_CHAR('W'),
5992
5993   EL_CHAR('X'),
5994   EL_CHAR('Y'),
5995   EL_CHAR('Z'),
5996   EL_CHAR('['),
5997
5998   EL_CHAR('\\'),
5999   EL_CHAR(']'),
6000   EL_CHAR('^'),
6001   EL_CHAR('_'),
6002
6003   EL_CHAR(CHAR_BYTE_COPYRIGHT),
6004   EL_CHAR(CHAR_BYTE_UMLAUT_A),
6005   EL_CHAR(CHAR_BYTE_UMLAUT_O),
6006   EL_CHAR(CHAR_BYTE_UMLAUT_U),
6007
6008   EL_CHAR(CHAR_BYTE_DEGREE),
6009   EL_CHAR(CHAR_BYTE_REGISTERED),
6010   EL_CHAR(FONT_ASCII_CURSOR),
6011   EL_CHAR(FONT_ASCII_BUTTON),
6012
6013   EL_CHAR(FONT_ASCII_UP),
6014   EL_CHAR(FONT_ASCII_DOWN),
6015   EL_CHAR(' '),
6016   EL_CHAR(' ')
6017 };
6018 static int *editor_hl_chars_ptr = editor_hl_chars;
6019 static int *editor_el_chars_ptr = editor_el_chars;
6020 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
6021 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
6022
6023 static int editor_hl_steel_chars[] =
6024 {
6025   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
6026   EL_STEEL_CHAR('T'),
6027   EL_STEEL_CHAR('X'),
6028   EL_STEEL_CHAR('T'),
6029 };
6030
6031 static int editor_el_steel_chars[] =
6032 {
6033   EL_STEEL_CHAR(' '),
6034   EL_STEEL_CHAR('!'),
6035   EL_STEEL_CHAR('"'),
6036   EL_STEEL_CHAR('#'),
6037
6038   EL_STEEL_CHAR('$'),
6039   EL_STEEL_CHAR('%'),
6040   EL_STEEL_CHAR('&'),
6041   EL_STEEL_CHAR('\''),
6042
6043   EL_STEEL_CHAR('('),
6044   EL_STEEL_CHAR(')'),
6045   EL_STEEL_CHAR('*'),
6046   EL_STEEL_CHAR('+'),
6047
6048   EL_STEEL_CHAR(','),
6049   EL_STEEL_CHAR('-'),
6050   EL_STEEL_CHAR('.'),
6051   EL_STEEL_CHAR('/'),
6052
6053   EL_STEEL_CHAR('0'),
6054   EL_STEEL_CHAR('1'),
6055   EL_STEEL_CHAR('2'),
6056   EL_STEEL_CHAR('3'),
6057
6058   EL_STEEL_CHAR('4'),
6059   EL_STEEL_CHAR('5'),
6060   EL_STEEL_CHAR('6'),
6061   EL_STEEL_CHAR('7'),
6062
6063   EL_STEEL_CHAR('8'),
6064   EL_STEEL_CHAR('9'),
6065   EL_STEEL_CHAR(':'),
6066   EL_STEEL_CHAR(';'),
6067
6068   EL_STEEL_CHAR('<'),
6069   EL_STEEL_CHAR('='),
6070   EL_STEEL_CHAR('>'),
6071   EL_STEEL_CHAR('?'),
6072
6073   EL_STEEL_CHAR('@'),
6074   EL_STEEL_CHAR('A'),
6075   EL_STEEL_CHAR('B'),
6076   EL_STEEL_CHAR('C'),
6077
6078   EL_STEEL_CHAR('D'),
6079   EL_STEEL_CHAR('E'),
6080   EL_STEEL_CHAR('F'),
6081   EL_STEEL_CHAR('G'),
6082
6083   EL_STEEL_CHAR('H'),
6084   EL_STEEL_CHAR('I'),
6085   EL_STEEL_CHAR('J'),
6086   EL_STEEL_CHAR('K'),
6087
6088   EL_STEEL_CHAR('L'),
6089   EL_STEEL_CHAR('M'),
6090   EL_STEEL_CHAR('N'),
6091   EL_STEEL_CHAR('O'),
6092
6093   EL_STEEL_CHAR('P'),
6094   EL_STEEL_CHAR('Q'),
6095   EL_STEEL_CHAR('R'),
6096   EL_STEEL_CHAR('S'),
6097
6098   EL_STEEL_CHAR('T'),
6099   EL_STEEL_CHAR('U'),
6100   EL_STEEL_CHAR('V'),
6101   EL_STEEL_CHAR('W'),
6102
6103   EL_STEEL_CHAR('X'),
6104   EL_STEEL_CHAR('Y'),
6105   EL_STEEL_CHAR('Z'),
6106   EL_STEEL_CHAR('['),
6107
6108   EL_STEEL_CHAR('\\'),
6109   EL_STEEL_CHAR(']'),
6110   EL_STEEL_CHAR('^'),
6111   EL_STEEL_CHAR('_'),
6112
6113   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
6114   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
6115   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
6116   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
6117
6118   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
6119   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
6120   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
6121   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
6122
6123   EL_STEEL_CHAR(FONT_ASCII_UP),
6124   EL_STEEL_CHAR(FONT_ASCII_DOWN),
6125   EL_STEEL_CHAR(' '),
6126   EL_STEEL_CHAR(' ')
6127 };
6128 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
6129 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
6130 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
6131 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
6132
6133 static int editor_hl_custom[] =
6134 {
6135   EL_INTERNAL_CASCADE_CE_ACTIVE,
6136   EL_CHAR('C'),
6137   EL_CHAR('E'),
6138   EL_EMPTY,
6139 };
6140
6141 static int editor_el_custom[] =
6142 {
6143   EL_CUSTOM_START + 0,
6144   EL_CUSTOM_START + 1,
6145   EL_CUSTOM_START + 2,
6146   EL_CUSTOM_START + 3,
6147
6148   EL_CUSTOM_START + 4,
6149   EL_CUSTOM_START + 5,
6150   EL_CUSTOM_START + 6,
6151   EL_CUSTOM_START + 7,
6152
6153   EL_CUSTOM_START + 8,
6154   EL_CUSTOM_START + 9,
6155   EL_CUSTOM_START + 10,
6156   EL_CUSTOM_START + 11,
6157
6158   EL_CUSTOM_START + 12,
6159   EL_CUSTOM_START + 13,
6160   EL_CUSTOM_START + 14,
6161   EL_CUSTOM_START + 15,
6162
6163   EL_CUSTOM_START + 16,
6164   EL_CUSTOM_START + 17,
6165   EL_CUSTOM_START + 18,
6166   EL_CUSTOM_START + 19,
6167
6168   EL_CUSTOM_START + 20,
6169   EL_CUSTOM_START + 21,
6170   EL_CUSTOM_START + 22,
6171   EL_CUSTOM_START + 23,
6172
6173   EL_CUSTOM_START + 24,
6174   EL_CUSTOM_START + 25,
6175   EL_CUSTOM_START + 26,
6176   EL_CUSTOM_START + 27,
6177
6178   EL_CUSTOM_START + 28,
6179   EL_CUSTOM_START + 29,
6180   EL_CUSTOM_START + 30,
6181   EL_CUSTOM_START + 31,
6182
6183   EL_CUSTOM_START + 32,
6184   EL_CUSTOM_START + 33,
6185   EL_CUSTOM_START + 34,
6186   EL_CUSTOM_START + 35,
6187
6188   EL_CUSTOM_START + 36,
6189   EL_CUSTOM_START + 37,
6190   EL_CUSTOM_START + 38,
6191   EL_CUSTOM_START + 39,
6192
6193   EL_CUSTOM_START + 40,
6194   EL_CUSTOM_START + 41,
6195   EL_CUSTOM_START + 42,
6196   EL_CUSTOM_START + 43,
6197
6198   EL_CUSTOM_START + 44,
6199   EL_CUSTOM_START + 45,
6200   EL_CUSTOM_START + 46,
6201   EL_CUSTOM_START + 47,
6202
6203   EL_CUSTOM_START + 48,
6204   EL_CUSTOM_START + 49,
6205   EL_CUSTOM_START + 50,
6206   EL_CUSTOM_START + 51,
6207
6208   EL_CUSTOM_START + 52,
6209   EL_CUSTOM_START + 53,
6210   EL_CUSTOM_START + 54,
6211   EL_CUSTOM_START + 55,
6212
6213   EL_CUSTOM_START + 56,
6214   EL_CUSTOM_START + 57,
6215   EL_CUSTOM_START + 58,
6216   EL_CUSTOM_START + 59,
6217
6218   EL_CUSTOM_START + 60,
6219   EL_CUSTOM_START + 61,
6220   EL_CUSTOM_START + 62,
6221   EL_CUSTOM_START + 63,
6222
6223   EL_CUSTOM_START + 64,
6224   EL_CUSTOM_START + 65,
6225   EL_CUSTOM_START + 66,
6226   EL_CUSTOM_START + 67,
6227
6228   EL_CUSTOM_START + 68,
6229   EL_CUSTOM_START + 69,
6230   EL_CUSTOM_START + 70,
6231   EL_CUSTOM_START + 71,
6232
6233   EL_CUSTOM_START + 72,
6234   EL_CUSTOM_START + 73,
6235   EL_CUSTOM_START + 74,
6236   EL_CUSTOM_START + 75,
6237
6238   EL_CUSTOM_START + 76,
6239   EL_CUSTOM_START + 77,
6240   EL_CUSTOM_START + 78,
6241   EL_CUSTOM_START + 79,
6242
6243   EL_CUSTOM_START + 80,
6244   EL_CUSTOM_START + 81,
6245   EL_CUSTOM_START + 82,
6246   EL_CUSTOM_START + 83,
6247
6248   EL_CUSTOM_START + 84,
6249   EL_CUSTOM_START + 85,
6250   EL_CUSTOM_START + 86,
6251   EL_CUSTOM_START + 87,
6252
6253   EL_CUSTOM_START + 88,
6254   EL_CUSTOM_START + 89,
6255   EL_CUSTOM_START + 90,
6256   EL_CUSTOM_START + 91,
6257
6258   EL_CUSTOM_START + 92,
6259   EL_CUSTOM_START + 93,
6260   EL_CUSTOM_START + 94,
6261   EL_CUSTOM_START + 95,
6262
6263   EL_CUSTOM_START + 96,
6264   EL_CUSTOM_START + 97,
6265   EL_CUSTOM_START + 98,
6266   EL_CUSTOM_START + 99,
6267
6268   EL_CUSTOM_START + 100,
6269   EL_CUSTOM_START + 101,
6270   EL_CUSTOM_START + 102,
6271   EL_CUSTOM_START + 103,
6272
6273   EL_CUSTOM_START + 104,
6274   EL_CUSTOM_START + 105,
6275   EL_CUSTOM_START + 106,
6276   EL_CUSTOM_START + 107,
6277
6278   EL_CUSTOM_START + 108,
6279   EL_CUSTOM_START + 109,
6280   EL_CUSTOM_START + 110,
6281   EL_CUSTOM_START + 111,
6282
6283   EL_CUSTOM_START + 112,
6284   EL_CUSTOM_START + 113,
6285   EL_CUSTOM_START + 114,
6286   EL_CUSTOM_START + 115,
6287
6288   EL_CUSTOM_START + 116,
6289   EL_CUSTOM_START + 117,
6290   EL_CUSTOM_START + 118,
6291   EL_CUSTOM_START + 119,
6292
6293   EL_CUSTOM_START + 120,
6294   EL_CUSTOM_START + 121,
6295   EL_CUSTOM_START + 122,
6296   EL_CUSTOM_START + 123,
6297
6298   EL_CUSTOM_START + 124,
6299   EL_CUSTOM_START + 125,
6300   EL_CUSTOM_START + 126,
6301   EL_CUSTOM_START + 127,
6302
6303   EL_CUSTOM_START + 128,
6304   EL_CUSTOM_START + 129,
6305   EL_CUSTOM_START + 130,
6306   EL_CUSTOM_START + 131,
6307
6308   EL_CUSTOM_START + 132,
6309   EL_CUSTOM_START + 133,
6310   EL_CUSTOM_START + 134,
6311   EL_CUSTOM_START + 135,
6312
6313   EL_CUSTOM_START + 136,
6314   EL_CUSTOM_START + 137,
6315   EL_CUSTOM_START + 138,
6316   EL_CUSTOM_START + 139,
6317
6318   EL_CUSTOM_START + 140,
6319   EL_CUSTOM_START + 141,
6320   EL_CUSTOM_START + 142,
6321   EL_CUSTOM_START + 143,
6322
6323   EL_CUSTOM_START + 144,
6324   EL_CUSTOM_START + 145,
6325   EL_CUSTOM_START + 146,
6326   EL_CUSTOM_START + 147,
6327
6328   EL_CUSTOM_START + 148,
6329   EL_CUSTOM_START + 149,
6330   EL_CUSTOM_START + 150,
6331   EL_CUSTOM_START + 151,
6332
6333   EL_CUSTOM_START + 152,
6334   EL_CUSTOM_START + 153,
6335   EL_CUSTOM_START + 154,
6336   EL_CUSTOM_START + 155,
6337
6338   EL_CUSTOM_START + 156,
6339   EL_CUSTOM_START + 157,
6340   EL_CUSTOM_START + 158,
6341   EL_CUSTOM_START + 159,
6342
6343   EL_CUSTOM_START + 160,
6344   EL_CUSTOM_START + 161,
6345   EL_CUSTOM_START + 162,
6346   EL_CUSTOM_START + 163,
6347
6348   EL_CUSTOM_START + 164,
6349   EL_CUSTOM_START + 165,
6350   EL_CUSTOM_START + 166,
6351   EL_CUSTOM_START + 167,
6352
6353   EL_CUSTOM_START + 168,
6354   EL_CUSTOM_START + 169,
6355   EL_CUSTOM_START + 170,
6356   EL_CUSTOM_START + 171,
6357
6358   EL_CUSTOM_START + 172,
6359   EL_CUSTOM_START + 173,
6360   EL_CUSTOM_START + 174,
6361   EL_CUSTOM_START + 175,
6362
6363   EL_CUSTOM_START + 176,
6364   EL_CUSTOM_START + 177,
6365   EL_CUSTOM_START + 178,
6366   EL_CUSTOM_START + 179,
6367
6368   EL_CUSTOM_START + 180,
6369   EL_CUSTOM_START + 181,
6370   EL_CUSTOM_START + 182,
6371   EL_CUSTOM_START + 183,
6372
6373   EL_CUSTOM_START + 184,
6374   EL_CUSTOM_START + 185,
6375   EL_CUSTOM_START + 186,
6376   EL_CUSTOM_START + 187,
6377
6378   EL_CUSTOM_START + 188,
6379   EL_CUSTOM_START + 189,
6380   EL_CUSTOM_START + 190,
6381   EL_CUSTOM_START + 191,
6382
6383   EL_CUSTOM_START + 192,
6384   EL_CUSTOM_START + 193,
6385   EL_CUSTOM_START + 194,
6386   EL_CUSTOM_START + 195,
6387
6388   EL_CUSTOM_START + 196,
6389   EL_CUSTOM_START + 197,
6390   EL_CUSTOM_START + 198,
6391   EL_CUSTOM_START + 199,
6392
6393   EL_CUSTOM_START + 200,
6394   EL_CUSTOM_START + 201,
6395   EL_CUSTOM_START + 202,
6396   EL_CUSTOM_START + 203,
6397
6398   EL_CUSTOM_START + 204,
6399   EL_CUSTOM_START + 205,
6400   EL_CUSTOM_START + 206,
6401   EL_CUSTOM_START + 207,
6402
6403   EL_CUSTOM_START + 208,
6404   EL_CUSTOM_START + 209,
6405   EL_CUSTOM_START + 210,
6406   EL_CUSTOM_START + 211,
6407
6408   EL_CUSTOM_START + 212,
6409   EL_CUSTOM_START + 213,
6410   EL_CUSTOM_START + 214,
6411   EL_CUSTOM_START + 215,
6412
6413   EL_CUSTOM_START + 216,
6414   EL_CUSTOM_START + 217,
6415   EL_CUSTOM_START + 218,
6416   EL_CUSTOM_START + 219,
6417
6418   EL_CUSTOM_START + 220,
6419   EL_CUSTOM_START + 221,
6420   EL_CUSTOM_START + 222,
6421   EL_CUSTOM_START + 223,
6422
6423   EL_CUSTOM_START + 224,
6424   EL_CUSTOM_START + 225,
6425   EL_CUSTOM_START + 226,
6426   EL_CUSTOM_START + 227,
6427
6428   EL_CUSTOM_START + 228,
6429   EL_CUSTOM_START + 229,
6430   EL_CUSTOM_START + 230,
6431   EL_CUSTOM_START + 231,
6432
6433   EL_CUSTOM_START + 232,
6434   EL_CUSTOM_START + 233,
6435   EL_CUSTOM_START + 234,
6436   EL_CUSTOM_START + 235,
6437
6438   EL_CUSTOM_START + 236,
6439   EL_CUSTOM_START + 237,
6440   EL_CUSTOM_START + 238,
6441   EL_CUSTOM_START + 239,
6442
6443   EL_CUSTOM_START + 240,
6444   EL_CUSTOM_START + 241,
6445   EL_CUSTOM_START + 242,
6446   EL_CUSTOM_START + 243,
6447
6448   EL_CUSTOM_START + 244,
6449   EL_CUSTOM_START + 245,
6450   EL_CUSTOM_START + 246,
6451   EL_CUSTOM_START + 247,
6452
6453   EL_CUSTOM_START + 248,
6454   EL_CUSTOM_START + 249,
6455   EL_CUSTOM_START + 250,
6456   EL_CUSTOM_START + 251,
6457
6458   EL_CUSTOM_START + 252,
6459   EL_CUSTOM_START + 253,
6460   EL_CUSTOM_START + 254,
6461   EL_CUSTOM_START + 255
6462 };
6463 static int *editor_hl_custom_ptr = editor_hl_custom;
6464 static int *editor_el_custom_ptr = editor_el_custom;
6465 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
6466 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
6467
6468 static int editor_hl_group[] =
6469 {
6470   EL_INTERNAL_CASCADE_GE_ACTIVE,
6471   EL_CHAR('G'),
6472   EL_CHAR('E'),
6473   EL_EMPTY,
6474 };
6475
6476 static int editor_el_group[] =
6477 {
6478   EL_GROUP_START + 0,
6479   EL_GROUP_START + 1,
6480   EL_GROUP_START + 2,
6481   EL_GROUP_START + 3,
6482
6483   EL_GROUP_START + 4,
6484   EL_GROUP_START + 5,
6485   EL_GROUP_START + 6,
6486   EL_GROUP_START + 7,
6487
6488   EL_GROUP_START + 8,
6489   EL_GROUP_START + 9,
6490   EL_GROUP_START + 10,
6491   EL_GROUP_START + 11,
6492
6493   EL_GROUP_START + 12,
6494   EL_GROUP_START + 13,
6495   EL_GROUP_START + 14,
6496   EL_GROUP_START + 15,
6497
6498   EL_GROUP_START + 16,
6499   EL_GROUP_START + 17,
6500   EL_GROUP_START + 18,
6501   EL_GROUP_START + 19,
6502
6503   EL_GROUP_START + 20,
6504   EL_GROUP_START + 21,
6505   EL_GROUP_START + 22,
6506   EL_GROUP_START + 23,
6507
6508   EL_GROUP_START + 24,
6509   EL_GROUP_START + 25,
6510   EL_GROUP_START + 26,
6511   EL_GROUP_START + 27,
6512
6513   EL_GROUP_START + 28,
6514   EL_GROUP_START + 29,
6515   EL_GROUP_START + 30,
6516   EL_GROUP_START + 31
6517 };
6518 static int *editor_hl_group_ptr = editor_hl_group;
6519 static int *editor_el_group_ptr = editor_el_group;
6520 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
6521 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
6522
6523 static int editor_hl_empty_space[] =
6524 {
6525   EL_INTERNAL_CASCADE_ES_ACTIVE,
6526   EL_CHAR('E'),
6527   EL_CHAR('S'),
6528   EL_EMPTY,
6529 };
6530
6531 static int editor_el_empty_space[] =
6532 {
6533   EL_EMPTY_SPACE_1,
6534   EL_EMPTY_SPACE_2,
6535   EL_EMPTY_SPACE_3,
6536   EL_EMPTY_SPACE_4,
6537
6538   EL_EMPTY_SPACE_5,
6539   EL_EMPTY_SPACE_6,
6540   EL_EMPTY_SPACE_7,
6541   EL_EMPTY_SPACE_8,
6542
6543   EL_EMPTY_SPACE_9,
6544   EL_EMPTY_SPACE_10,
6545   EL_EMPTY_SPACE_11,
6546   EL_EMPTY_SPACE_12,
6547
6548   EL_EMPTY_SPACE_13,
6549   EL_EMPTY_SPACE_14,
6550   EL_EMPTY_SPACE_15,
6551   EL_EMPTY_SPACE_16
6552 };
6553 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
6554 static int *editor_el_empty_space_ptr = editor_el_empty_space;
6555 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
6556 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
6557
6558 static int editor_hl_reference[] =
6559 {
6560   EL_INTERNAL_CASCADE_REF_ACTIVE,
6561   EL_CHAR('R'),
6562   EL_CHAR('E'),
6563   EL_CHAR('F')
6564 };
6565
6566 static int editor_el_reference[] =
6567 {
6568   EL_TRIGGER_PLAYER,
6569   EL_TRIGGER_ELEMENT,
6570   EL_TRIGGER_CE_VALUE,
6571   EL_TRIGGER_CE_SCORE,
6572
6573   EL_SELF,
6574   EL_ANY_ELEMENT,
6575   EL_CURRENT_CE_VALUE,
6576   EL_CURRENT_CE_SCORE,
6577
6578   EL_PREV_CE_8,
6579   EL_PREV_CE_7,
6580   EL_PREV_CE_6,
6581   EL_PREV_CE_5,
6582
6583   EL_PREV_CE_4,
6584   EL_PREV_CE_3,
6585   EL_PREV_CE_2,
6586   EL_PREV_CE_1,
6587
6588   EL_NEXT_CE_1,
6589   EL_NEXT_CE_2,
6590   EL_NEXT_CE_3,
6591   EL_NEXT_CE_4,
6592
6593   EL_NEXT_CE_5,
6594   EL_NEXT_CE_6,
6595   EL_NEXT_CE_7,
6596   EL_NEXT_CE_8,
6597 };
6598 static int *editor_hl_reference_ptr = editor_hl_reference;
6599 static int *editor_el_reference_ptr = editor_el_reference;
6600 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
6601 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
6602
6603 static int editor_hl_user_defined[] =
6604 {
6605   EL_INTERNAL_CASCADE_USER_ACTIVE,
6606   EL_CHAR('M'),
6607   EL_CHAR('Y'),
6608   EL_EMPTY,
6609 };
6610
6611 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
6612 static int *editor_el_user_defined_ptr = NULL;
6613 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
6614 static int num_editor_el_user_defined = 0;
6615
6616 static int editor_hl_dynamic[] =
6617 {
6618   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
6619   EL_CHAR('U'),
6620   EL_CHAR('S'),
6621   EL_CHAR('E'),
6622 };
6623
6624 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
6625 static int *editor_el_dynamic_ptr = NULL;
6626 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
6627 static int num_editor_el_dynamic = 0;
6628
6629 static int editor_hl_empty[] = { EL_EMPTY };
6630 static int *editor_el_empty = NULL;     // dynamically allocated
6631
6632 static int *editor_hl_empty_ptr = editor_hl_empty;
6633 static int *editor_el_empty_ptr = NULL;
6634 static int num_editor_hl_empty = 0;
6635 static int num_editor_el_empty = 0;     // dynamically determined, if needed
6636
6637 static boolean use_el_empty = FALSE;
6638
6639 static int *editor_elements = NULL;     // dynamically allocated
6640 static int num_editor_elements = 0;     // dynamically determined
6641
6642 static boolean setup_editor_cascade_never = FALSE;
6643
6644 static boolean setup_editor_el_players                  = TRUE;
6645 static boolean setup_editor_el_boulderdash              = TRUE;
6646 static boolean setup_editor_el_boulderdash_native       = TRUE;
6647 static boolean setup_editor_el_boulderdash_effects      = TRUE;
6648 static boolean setup_editor_el_emerald_mine             = TRUE;
6649 static boolean setup_editor_el_emerald_mine_club        = TRUE;
6650 static boolean setup_editor_el_more                     = TRUE;
6651 static boolean setup_editor_el_sokoban                  = TRUE;
6652 static boolean setup_editor_el_supaplex                 = TRUE;
6653 static boolean setup_editor_el_diamond_caves            = TRUE;
6654 static boolean setup_editor_el_dx_boulderdash           = TRUE;
6655 static boolean setup_editor_el_mirror_magic             = TRUE;
6656 static boolean setup_editor_el_deflektor                = TRUE;
6657 static boolean setup_editor_el_chars                    = TRUE;
6658 static boolean setup_editor_el_steel_chars              = TRUE;
6659 static boolean setup_editor_el_custom                   = TRUE;
6660 static boolean setup_editor_el_user_defined             = TRUE;
6661 static boolean setup_editor_el_dynamic                  = TRUE;
6662
6663 static int editor_hl_unused[] = { EL_EMPTY };
6664 static int *editor_hl_unused_ptr = editor_hl_unused;
6665 static int num_editor_hl_unused = 0;
6666
6667 static struct
6668 {
6669   boolean *setup_value;
6670   boolean *setup_cascade_value;
6671
6672   int **headline_list;
6673   int *headline_list_size;
6674
6675   int **element_list;
6676   int *element_list_size;
6677
6678   boolean last_setup_value;
6679 }
6680 editor_elements_info[] =
6681 {
6682   {
6683     &setup_editor_el_players,
6684     &setup_editor_cascade_never,
6685     &editor_hl_unused_ptr,              &num_editor_hl_unused,
6686     &editor_el_players_ptr,             &num_editor_el_players
6687   },
6688   {
6689     &setup_editor_el_boulderdash,
6690     &setup.editor_cascade.el_bd,
6691     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
6692     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
6693   },
6694   {
6695     &setup_editor_el_boulderdash_native,
6696     &setup.editor_cascade.el_bd_native,
6697     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
6698     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
6699   },
6700   {
6701     &setup_editor_el_boulderdash_effects,
6702     &setup.editor_cascade.el_bd_effects,
6703     &editor_hl_boulderdash_effects_ptr, &num_editor_hl_boulderdash_effects,
6704     &editor_el_boulderdash_effects_ptr, &num_editor_el_boulderdash_effects
6705   },
6706   {
6707     &setup_editor_el_emerald_mine,
6708     &setup.editor_cascade.el_em,
6709     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
6710     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
6711   },
6712   {
6713     &setup_editor_el_emerald_mine_club,
6714     &setup.editor_cascade.el_emc,
6715     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
6716     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
6717   },
6718   {
6719     &setup_editor_el_more,
6720     &setup.editor_cascade.el_rnd,
6721     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
6722     &editor_el_rnd_ptr,                 &num_editor_el_rnd
6723   },
6724   {
6725     &setup_editor_el_sokoban,
6726     &setup.editor_cascade.el_sb,
6727     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
6728     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
6729   },
6730   {
6731     &setup_editor_el_supaplex,
6732     &setup.editor_cascade.el_sp,
6733     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
6734     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
6735   },
6736   {
6737     &setup_editor_el_diamond_caves,
6738     &setup.editor_cascade.el_dc,
6739     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
6740     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
6741   },
6742   {
6743     &setup_editor_el_dx_boulderdash,
6744     &setup.editor_cascade.el_dx,
6745     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
6746     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
6747   },
6748   {
6749     &setup_editor_el_mirror_magic,
6750     &setup.editor_cascade.el_mm,
6751     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
6752     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
6753   },
6754   {
6755     &setup_editor_el_deflektor,
6756     &setup.editor_cascade.el_df,
6757     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
6758     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
6759   },
6760   {
6761     &setup_editor_el_chars,
6762     &setup.editor_cascade.el_chars,
6763     &editor_hl_chars_ptr,               &num_editor_hl_chars,
6764     &editor_el_chars_ptr,               &num_editor_el_chars
6765   },
6766   {
6767     &setup_editor_el_steel_chars,
6768     &setup.editor_cascade.el_steel_chars,
6769     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
6770     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
6771   },
6772   {
6773     &setup_editor_el_custom,
6774     &setup.editor_cascade.el_ce,
6775     &editor_hl_custom_ptr,              &num_editor_hl_custom,
6776     &editor_el_custom_ptr,              &num_editor_el_custom
6777   },
6778   {
6779     &setup_editor_el_custom,
6780     &setup.editor_cascade.el_ge,
6781     &editor_hl_group_ptr,               &num_editor_hl_group,
6782     &editor_el_group_ptr,               &num_editor_el_group
6783   },
6784   {
6785     &setup_editor_el_custom,
6786     &setup.editor_cascade.el_es,
6787     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
6788     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
6789   },
6790   {
6791     &setup_editor_el_custom,
6792     &setup.editor_cascade.el_ref,
6793     &editor_hl_reference_ptr,           &num_editor_hl_reference,
6794     &editor_el_reference_ptr,           &num_editor_el_reference
6795   },
6796   {
6797     &setup_editor_el_user_defined,
6798     &setup.editor_cascade.el_user,
6799     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
6800     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
6801   },
6802   {
6803     &setup_editor_el_dynamic,
6804     &setup.editor_cascade.el_dynamic,
6805     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
6806     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
6807   },
6808   {
6809     &use_el_empty,
6810     &use_el_empty,
6811     &editor_hl_empty_ptr,               &num_editor_hl_empty,
6812     &editor_el_empty_ptr,               &num_editor_el_empty,
6813   },
6814   {
6815     NULL,
6816     NULL,
6817     NULL,                               NULL,
6818     NULL,                               NULL
6819   }
6820 };
6821
6822 static struct XY xy_directions[] =
6823 {
6824   { -1,  0 },
6825   { +1,  0 },
6826   {  0, -1 },
6827   {  0, +1 }
6828 };
6829
6830
6831 // ----------------------------------------------------------------------------
6832 // functions
6833 // ----------------------------------------------------------------------------
6834
6835 static int getMaxInfoTextLength(void)
6836 {
6837   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
6838 }
6839
6840 static int getTextWidthForGadget(char *text)
6841 {
6842   if (text == NULL)
6843     return 0;
6844
6845   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
6846 }
6847
6848 static int getTextWidthForDrawingArea(char *text)
6849 {
6850   if (text == NULL)
6851     return 0;
6852
6853   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
6854 }
6855
6856 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
6857 {
6858   return (gi->x + gi->width + getTextWidthForGadget(text));
6859 }
6860
6861 static char *getElementInfoText(int element)
6862 {
6863   char *info_text = NULL;
6864
6865   if (element < MAX_NUM_ELEMENTS)
6866   {
6867     if (strlen(element_info[element].description) > 0)
6868       info_text = element_info[element].description;
6869     else if (element_info[element].custom_description != NULL)
6870       info_text = element_info[element].custom_description;
6871     else if (element_info[element].editor_description != NULL)
6872       info_text = element_info[element].editor_description;
6873   }
6874
6875   if (info_text == NULL)
6876     info_text = INFOTEXT_UNKNOWN_ELEMENT;
6877
6878   return info_text;
6879 }
6880
6881 static char *getElementDescriptionFilenameExt(char *basename)
6882 {
6883   char *elements_subdir = ELEMENTS_DIRECTORY;
6884   static char *elements_subdir2 = NULL;
6885   static char *filename = NULL;
6886
6887   if (elements_subdir2 == NULL)
6888     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
6889
6890   checked_free(filename);
6891
6892   // 1st try: look for element description in current level set directory
6893   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
6894   if (fileExists(filename))
6895     return filename;
6896
6897   free(filename);
6898
6899   // 2nd try: look for element description in the game's base directory
6900   filename = getPath3(options.docs_directory, elements_subdir, basename);
6901   if (fileExists(filename))
6902     return filename;
6903
6904   return NULL;
6905 }
6906
6907 static char *getElementDescriptionFilename(int element)
6908 {
6909   char basename[MAX_FILENAME_LEN];
6910   char *filename;
6911
6912   // 1st try: look for element description file for exactly this element
6913   sprintf(basename, "%s.txt", element_info[element].token_name);
6914   filename = getElementDescriptionFilenameExt(basename);
6915   if (filename != NULL)
6916     return filename;
6917
6918   // 2nd try: look for element description file for this element's class
6919   sprintf(basename, "%s.txt", element_info[element].class_name);
6920   filename = getElementDescriptionFilenameExt(basename);
6921   if (filename != NULL)
6922     return filename;
6923
6924   // 3rd try: look for generic fallback text file for any element
6925   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
6926   if (filename != NULL)
6927     return filename;
6928
6929   return NULL;
6930 }
6931
6932 static boolean suppressBorderElement(void)
6933 {
6934   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
6935           lev_fieldx <= MAX_ED_FIELDX &&
6936           lev_fieldy <= MAX_ED_FIELDY);
6937 }
6938
6939 static void InitDynamicEditorElementList(int **elements, int *num_elements)
6940 {
6941   boolean element_found[NUM_FILE_ELEMENTS];
6942   int i, x, y;
6943
6944   // initialize list of used elements to "not used"
6945   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6946     element_found[i] = FALSE;
6947
6948   // find all elements used in current level
6949   for (y = 0; y < lev_fieldy; y++)
6950   {
6951     for (x = 0; x < lev_fieldx; x++)
6952     {
6953       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
6954         continue;
6955
6956       if (IS_MM_WALL(Tile[x][y]))
6957         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
6958       else
6959         element_found[Tile[x][y]] = TRUE;
6960     }
6961   }
6962
6963   *num_elements = 0;
6964
6965   // count number of elements used in current level
6966   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6967     if (element_found[i])
6968       (*num_elements)++;
6969
6970   // add space for up to 3 more elements for padding that may be needed
6971   *num_elements += 3;
6972
6973   // free memory for old list of elements, if needed
6974   checked_free(*elements);
6975
6976   // allocate memory for new list of elements
6977   *elements = checked_malloc(*num_elements * sizeof(int));
6978
6979   *num_elements = 0;
6980
6981   // add all elements used in current level (non-custom/group/empty elements)
6982   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6983     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
6984                               IS_GROUP_ELEMENT(i) ||
6985                               IS_EMPTY_ELEMENT(i)))
6986       (*elements)[(*num_elements)++] = i;
6987
6988   // add all elements used in current level (custom/group/empty elements)
6989   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6990     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
6991                              IS_GROUP_ELEMENT(i) ||
6992                              IS_EMPTY_ELEMENT(i)))
6993       (*elements)[(*num_elements)++] = i;
6994
6995   while (*num_elements % 4)     // pad with empty elements, if needed
6996     (*elements)[(*num_elements)++] = EL_EMPTY;
6997 }
6998
6999 static void ReinitializeElementList_EnableSections(void)
7000 {
7001   // default: enable all element sections
7002
7003   setup_editor_el_players               = TRUE;
7004   setup_editor_el_boulderdash           = TRUE;
7005   setup_editor_el_boulderdash_native    = TRUE;
7006   setup_editor_el_boulderdash_effects   = TRUE;
7007   setup_editor_el_emerald_mine          = TRUE;
7008   setup_editor_el_emerald_mine_club     = TRUE;
7009   setup_editor_el_more                  = TRUE;
7010   setup_editor_el_sokoban               = TRUE;
7011   setup_editor_el_supaplex              = TRUE;
7012   setup_editor_el_diamond_caves         = TRUE;
7013   setup_editor_el_dx_boulderdash        = TRUE;
7014   setup_editor_el_mirror_magic          = TRUE;
7015   setup_editor_el_deflektor             = TRUE;
7016   setup_editor_el_chars                 = TRUE;
7017   setup_editor_el_steel_chars           = TRUE;
7018
7019   setup_editor_el_custom                = TRUE;
7020   setup_editor_el_user_defined          = TRUE;
7021   setup_editor_el_dynamic               = TRUE;
7022
7023   // now disable all element sections not to be displayed
7024
7025   if (!setup.editor.el_classic)
7026   {
7027     setup_editor_el_players             = FALSE;
7028     setup_editor_el_boulderdash         = FALSE;
7029     setup_editor_el_boulderdash_native  = FALSE;
7030     setup_editor_el_boulderdash_effects = FALSE;
7031     setup_editor_el_emerald_mine        = FALSE;
7032     setup_editor_el_emerald_mine_club   = FALSE;
7033     setup_editor_el_more                = FALSE;
7034     setup_editor_el_sokoban             = FALSE;
7035     setup_editor_el_supaplex            = FALSE;
7036     setup_editor_el_diamond_caves       = FALSE;
7037     setup_editor_el_dx_boulderdash      = FALSE;
7038     setup_editor_el_mirror_magic        = FALSE;
7039     setup_editor_el_deflektor           = FALSE;
7040     setup_editor_el_chars               = FALSE;
7041     setup_editor_el_steel_chars         = FALSE;
7042   }
7043
7044   if (!setup.editor.el_custom)
7045   {
7046     setup_editor_el_custom              = FALSE;
7047   }
7048
7049   if (!setup.editor.el_user_defined)
7050   {
7051     setup_editor_el_user_defined        = FALSE;
7052   }
7053
7054   if (!setup.editor.el_dynamic)
7055   {
7056     setup_editor_el_dynamic             = FALSE;
7057   }
7058
7059   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
7060   {
7061     setup_editor_el_boulderdash_native  = FALSE;
7062     setup_editor_el_boulderdash_effects = FALSE;
7063     setup_editor_el_mirror_magic        = FALSE;
7064     setup_editor_el_deflektor           = FALSE;
7065   }
7066   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
7067   {
7068     setup_editor_el_players             = FALSE;
7069     setup_editor_el_boulderdash         = FALSE;
7070     setup_editor_el_emerald_mine        = FALSE;
7071     setup_editor_el_emerald_mine_club   = FALSE;
7072     setup_editor_el_more                = FALSE;
7073     setup_editor_el_sokoban             = FALSE;
7074     setup_editor_el_supaplex            = FALSE;
7075     setup_editor_el_diamond_caves       = FALSE;
7076     setup_editor_el_dx_boulderdash      = FALSE;
7077     setup_editor_el_mirror_magic        = FALSE;
7078     setup_editor_el_deflektor           = FALSE;
7079     setup_editor_el_chars               = FALSE;
7080     setup_editor_el_steel_chars         = FALSE;
7081
7082     setup_editor_el_custom              = FALSE;
7083   }
7084   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7085   {
7086     setup_editor_el_boulderdash         = FALSE;
7087     setup_editor_el_boulderdash_native  = FALSE;
7088     setup_editor_el_boulderdash_effects = FALSE;
7089     setup_editor_el_more                = FALSE;
7090     setup_editor_el_sokoban             = FALSE;
7091     setup_editor_el_supaplex            = FALSE;
7092     setup_editor_el_diamond_caves       = FALSE;
7093     setup_editor_el_dx_boulderdash      = FALSE;
7094     setup_editor_el_mirror_magic        = FALSE;
7095     setup_editor_el_deflektor           = FALSE;
7096     setup_editor_el_steel_chars         = FALSE;
7097
7098     setup_editor_el_custom              = FALSE;
7099   }
7100   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7101   {
7102     setup_editor_el_players             = FALSE;
7103     setup_editor_el_boulderdash         = FALSE;
7104     setup_editor_el_boulderdash_native  = FALSE;
7105     setup_editor_el_boulderdash_effects = FALSE;
7106     setup_editor_el_emerald_mine        = FALSE;
7107     setup_editor_el_emerald_mine_club   = FALSE;
7108     setup_editor_el_more                = FALSE;
7109     setup_editor_el_sokoban             = FALSE;
7110     setup_editor_el_diamond_caves       = FALSE;
7111     setup_editor_el_dx_boulderdash      = FALSE;
7112     setup_editor_el_mirror_magic        = FALSE;
7113     setup_editor_el_deflektor           = FALSE;
7114     setup_editor_el_chars               = FALSE;
7115     setup_editor_el_steel_chars         = FALSE;
7116
7117     setup_editor_el_custom              = FALSE;
7118   }
7119   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
7120   {
7121     setup_editor_el_players             = FALSE;
7122     setup_editor_el_boulderdash         = FALSE;
7123     setup_editor_el_boulderdash_native  = FALSE;
7124     setup_editor_el_boulderdash_effects = FALSE;
7125     setup_editor_el_emerald_mine        = FALSE;
7126     setup_editor_el_emerald_mine_club   = FALSE;
7127     setup_editor_el_more                = FALSE;
7128     setup_editor_el_sokoban             = FALSE;
7129     setup_editor_el_supaplex            = FALSE;
7130     setup_editor_el_diamond_caves       = FALSE;
7131     setup_editor_el_dx_boulderdash      = FALSE;
7132     setup_editor_el_steel_chars         = FALSE;
7133
7134     setup_editor_el_custom              = FALSE;
7135   }
7136 }
7137
7138 static void ReinitializeElementList(void)
7139 {
7140   static boolean initialization_needed = TRUE;
7141   int pos = 0;
7142   int i, j;
7143
7144   ReinitializeElementList_EnableSections();
7145
7146   if (initialization_needed)
7147   {
7148     LoadSetup_EditorCascade();          // load last editor cascade state
7149
7150     // initialize editor cascade element from saved cascade state
7151     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7152     {
7153       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
7154       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
7155
7156       if (IS_EDITOR_CASCADE(*cascade_element))
7157         *cascade_element =
7158           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
7159            EL_CASCADE_INACTIVE(*cascade_element));
7160     }
7161
7162     initialization_needed = FALSE;
7163   }
7164
7165   checked_free(editor_elements);
7166
7167   // reload optional user defined element list for each invocation of editor
7168   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
7169                                    &num_editor_el_user_defined);
7170
7171   // initialize dynamic level element list for each invocation of editor
7172   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
7173                                &num_editor_el_dynamic);
7174
7175   // initialize list of empty elements (used for padding, if needed)
7176   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7177     editor_el_empty[i] = EL_EMPTY;
7178
7179   // do some sanity checks for each element from element list
7180   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7181   {
7182     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7183     {
7184       int element = (*editor_elements_info[i].element_list)[j];
7185
7186       if (element >= NUM_FILE_ELEMENTS)
7187         Warn("editor element %d is runtime element", element);
7188
7189       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
7190         Warn("no element description text for element %d", element);
7191     }
7192   }
7193
7194   num_editor_elements = 0;
7195   use_el_empty = FALSE;
7196
7197   // determine size of element list
7198   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7199   {
7200     if (*editor_elements_info[i].setup_value)
7201     {
7202       boolean found_inactive_cascade = FALSE;
7203
7204       if (setup.editor.el_headlines)
7205       {
7206         // required for correct padding of palette headline buttons
7207         if (*editor_elements_info[i].headline_list_size > 0)
7208           num_editor_elements += ED_ELEMENTLIST_COLS;
7209
7210         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7211         {
7212           int element = (*editor_elements_info[i].headline_list)[j];
7213
7214           if (IS_EDITOR_CASCADE_INACTIVE(element))
7215             found_inactive_cascade = TRUE;
7216         }
7217       }
7218
7219       if (found_inactive_cascade)
7220         continue;
7221
7222       // required for correct padding of palette element buttons
7223       int element_list_size = *editor_elements_info[i].element_list_size;
7224       int element_rows =
7225         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7226       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7227
7228       num_editor_elements += element_buttons;
7229     }
7230   }
7231
7232   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
7233   {
7234     // offer at least as many elements as element buttons exist
7235     use_el_empty = TRUE;
7236     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
7237
7238     num_editor_elements += num_editor_el_empty;
7239   }
7240   else
7241   {
7242     num_editor_el_empty = 0;
7243   }
7244
7245   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
7246
7247   // fill element list
7248   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7249   {
7250     boolean found_inactive_cascade = FALSE;
7251
7252     if (*editor_elements_info[i].setup_value)
7253     {
7254       if (setup.editor.el_headlines)
7255       {
7256         // required for correct padding of palette headline buttons
7257         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
7258                              ED_ELEMENTLIST_COLS : 0);
7259
7260         for (j = 0; j < headline_size; j++)
7261         {
7262           // use empty elements for padding of palette headline buttons
7263           int element = (j < *editor_elements_info[i].headline_list_size ?
7264                          (*editor_elements_info[i].headline_list)[j] :
7265                          editor_el_empty[0]);
7266
7267           editor_elements[pos++] = element;
7268
7269           if (IS_EDITOR_CASCADE_INACTIVE(element))
7270             found_inactive_cascade = TRUE;
7271         }
7272       }
7273
7274       if (found_inactive_cascade)
7275         continue;
7276
7277       // required for correct padding of palette element buttons
7278       int element_list_size = *editor_elements_info[i].element_list_size;
7279       int element_rows =
7280         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
7281       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
7282
7283       // copy all elements from element list
7284       for (j = 0; j < element_list_size; j++)
7285         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
7286
7287       // use empty elements for padding of palette element buttons
7288       for (j = 0; j < element_buttons - element_list_size; j++)
7289         editor_elements[pos++] = editor_el_empty[0];
7290     }
7291   }
7292
7293   // (this function is also called before editor gadgets are initialized!)
7294   AdjustElementListScrollbar();
7295 }
7296
7297 void PrintEditorElementList(void)
7298 {
7299   boolean *stop = &setup_editor_el_user_defined;
7300   int i, j;
7301
7302   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
7303   {
7304     int cascade_element = (*editor_elements_info[i].headline_list)[0];
7305
7306     if (IS_EDITOR_CASCADE(cascade_element))
7307     {
7308       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
7309       char *headline = element_info[cascade_element_show].editor_description;
7310
7311       PrintLineWithPrefix("# ", "-", 77);
7312       Print("# %s\n", headline);
7313       PrintLineWithPrefix("# ", "-", 77);
7314     }
7315
7316     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
7317     {
7318       int element = (*editor_elements_info[i].headline_list)[j];
7319
7320       if (IS_EDITOR_CASCADE(element))
7321         element = EL_CHAR_MINUS;
7322
7323       Print("# %s\n", element_info[element].token_name);
7324     }
7325
7326     if (j > 0)
7327       Print("#\n");
7328
7329     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
7330     {
7331       int element = (*editor_elements_info[i].element_list)[j];
7332
7333       Print("# %s\n", element_info[element].token_name);
7334     }
7335
7336     if (j > 0)
7337       Print("#\n");
7338   }
7339 }
7340
7341 static void ReinitializeElementListButtons(void)
7342 {
7343   static boolean last_setup_value_headlines = FALSE;
7344   static boolean initialization_needed = TRUE;
7345   int i;
7346
7347   if (!initialization_needed)   // check if editor element setup has changed
7348   {
7349     if (last_setup_value_headlines != setup.editor.el_headlines)
7350       initialization_needed = TRUE;
7351
7352     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7353       if (editor_elements_info[i].last_setup_value !=
7354           *editor_elements_info[i].setup_value)
7355         initialization_needed = TRUE;
7356   }
7357
7358   if (!initialization_needed)
7359     return;
7360
7361   FreeLevelEditorGadgets();
7362   CreateLevelEditorGadgets();
7363
7364   // store current setup values for next invocation of this function
7365   last_setup_value_headlines = setup.editor.el_headlines;
7366   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
7367     editor_elements_info[i].last_setup_value =
7368       *editor_elements_info[i].setup_value;
7369
7370   initialization_needed = FALSE;
7371 }
7372
7373 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
7374                               boolean input)
7375 {
7376   int border_graphic =
7377     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
7378   struct GraphicInfo *g = &graphic_info[border_graphic];
7379   Bitmap *src_bitmap = g->bitmap;
7380   int src_x = g->src_x;
7381   int src_y = g->src_y;
7382   int border_size = g->border_size;
7383   int border_xpos = g->width  - border_size;
7384   int border_ypos = g->height - border_size;
7385   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7386   int i;
7387
7388   BlitBitmap(src_bitmap, drawto, src_x, src_y,
7389              border_size, border_size,
7390              dest_x - border_size, dest_y - border_size);
7391   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
7392              border_size, border_size,
7393              dest_x + width, dest_y - border_size);
7394   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
7395              border_size, border_size,
7396              dest_x - border_size, dest_y + height);
7397   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
7398              border_size, border_size,
7399              dest_x + width, dest_y + height);
7400
7401   for (i = 0; i < width / tilesize; i++)
7402   {
7403     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
7404                tilesize, border_size,
7405                dest_x + i * tilesize, dest_y - border_size);
7406     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
7407                tilesize, border_size,
7408                dest_x + i * tilesize, dest_y + height);
7409   }
7410
7411   for (i = 0; i < height / tilesize; i++)
7412   {
7413     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
7414                border_size, tilesize,
7415                dest_x - border_size, dest_y + i * tilesize);
7416     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
7417                border_size, tilesize,
7418                dest_x + width, dest_y + i * tilesize);
7419   }
7420
7421   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
7422 }
7423
7424 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
7425 {
7426   int xsize_tile = MAX(ed_tilesize, xsize);
7427   int ysize_tile = MAX(ed_tilesize, ysize);
7428   int xsize_full = xsize + 1;
7429   int ysize_full = ysize + 1;
7430   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
7431   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
7432   Pixel line_color = getTabulatorBarColor();
7433
7434   if (line_color == BLACK_PIXEL)                // black => transparent
7435     return;
7436
7437   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
7438   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
7439   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
7440 }
7441
7442 static void DrawEditorLevelBorderLinesIfNeeded(void)
7443 {
7444   int xsize = lev_fieldx * ed_tilesize;
7445   int ysize = lev_fieldy * ed_tilesize;
7446   int line_size = getTabulatorBarHeight();
7447
7448   if (!suppressBorderElement())
7449     return;
7450
7451   // draw little border line around editable level playfield
7452
7453   if (xsize < SXSIZE)
7454     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
7455
7456   if (ysize < SYSIZE)
7457     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
7458
7459   if (xsize < SXSIZE && ysize < SYSIZE)
7460     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
7461 }
7462
7463 static void DrawEditorElement(int x, int y, int element)
7464 {
7465   DrawSizedElement(x, y, element, ed_tilesize);
7466 }
7467
7468 static void DrawEditorElementThruMask(int x, int y, int element)
7469 {
7470   DrawSizedElementThruMask(x, y, element, ed_tilesize);
7471 }
7472
7473 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
7474 {
7475   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
7476 }
7477
7478 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
7479 {
7480   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
7481   DrawEditorLevelBorderLinesIfNeeded();
7482 }
7483
7484 static void DrawDrawingArea(int id)
7485 {
7486   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7487   int x, y;
7488
7489   int *value = drawingarea_info[id].value;
7490   int area_xsize = drawingarea_info[id].area_xsize;
7491   int area_ysize = drawingarea_info[id].area_ysize;
7492   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
7493
7494   for (x = 0; x < area_xsize; x++)
7495   {
7496     for (y = 0; y < area_ysize; y++)
7497     {
7498       int element = value[x * area_ysize + y];
7499       int graphic;
7500       int frame;
7501
7502       getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7503
7504       DrawSizedGraphicExt(drawto,
7505                           gi->x + x * tilesize,
7506                           gi->y + y * tilesize,
7507                           graphic, frame, tilesize);
7508     }
7509   }
7510 }
7511
7512 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
7513 {
7514   int x, y;
7515   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
7516   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
7517
7518   BlitBitmap(drawto, drawto,
7519              SX + (dx == -1 ? ed_tilesize : 0),
7520              SY + (dy == -1 ? ed_tilesize : 0),
7521              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
7522              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
7523              SX + (dx == +1 ? ed_tilesize : 0),
7524              SY + (dy == +1 ? ed_tilesize : 0));
7525
7526   if (dx)
7527   {
7528     x = (dx == 1 ? 0 : ed_fieldx - 1);
7529     for (y = 0; y < ed_fieldy; y++)
7530       DrawEditorElementOrWall(x, y, from_x, from_y);
7531   }
7532   else if (dy)
7533   {
7534     y = (dy == 1 ? 0 : ed_fieldy - 1);
7535     for (x = 0; x < ed_fieldx; x++)
7536       DrawEditorElementOrWall(x, y, from_x, from_y);
7537   }
7538
7539   redraw_mask |= REDRAW_FIELD;
7540   BackToFront();
7541 }
7542
7543 static void getEditorGraphicAndFrame(int element, int *graphic, int *frame, boolean use_editor_gfx)
7544 {
7545   if (use_editor_gfx)
7546   {
7547     *graphic = el2edimg(element);
7548     *frame = 0;
7549   }
7550   else
7551   {
7552     *graphic = el2img(element);
7553     *frame = (ANIM_MODE(*graphic) == ANIM_CE_VALUE ?
7554               custom_element.ce_value_fixed_initial :
7555               ANIM_MODE(*graphic) == ANIM_CE_SCORE ?
7556               custom_element.collect_score_initial : FrameCounter);
7557   }
7558
7559   if (*graphic == IMG_UNKNOWN)
7560   {
7561     // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
7562     // (normal BD style elements have graphics, but runtime ("effects") elements do not)
7563     int element_bd = map_element_RND_to_BD_cave(element);
7564
7565     if (element_bd != O_UNKNOWN)
7566     {
7567       struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
7568
7569       *graphic = g_bd->graphic;
7570       *frame   = g_bd->frame;
7571     }
7572   }
7573 }
7574
7575 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
7576                                    int *x, int *y)
7577 {
7578   int graphic;
7579   int frame;
7580
7581   getEditorGraphicAndFrame(element, &graphic, &frame, TRUE);
7582
7583   getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
7584 }
7585
7586 static void CreateControlButtons(void)
7587 {
7588   struct GadgetInfo *gi;
7589   int i;
7590
7591   // create toolbox buttons
7592   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7593   {
7594     int type_id = controlbutton_info[i].gadget_id;      // same as gadget ID here
7595     int id = controlbutton_info[i].gadget_id;
7596     int type = controlbutton_info[i].gadget_type;
7597     int graphic = controlbutton_info[i].graphic;
7598     struct XYTileSize *pos = controlbutton_info[i].pos;
7599     struct GraphicInfo *gd = &graphic_info[graphic];
7600     Bitmap *deco_bitmap = NULL;
7601     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7602     int tile_size = 0, deco_shift = 0;
7603     boolean deco_masked = FALSE;
7604     int gd_x1 = gd->src_x;
7605     int gd_y1 = gd->src_y;
7606     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7607     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7608     int gd_x1a = gd->src_x + gd->active_xoffset;
7609     int gd_y1a = gd->src_y + gd->active_yoffset;
7610     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7611     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7612     int x = pos->x;
7613     int y = pos->y;
7614     unsigned int event_mask;
7615     int radio_button_nr = RADIO_NR_NONE;
7616     boolean checked = FALSE;
7617
7618     if (type_id != i)
7619       Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
7620
7621     if (type == GD_TYPE_RADIO_BUTTON)
7622     {
7623       event_mask = GD_EVENT_PRESSED;
7624       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
7625
7626       if (id == drawing_function)
7627         checked = TRUE;
7628     }
7629     else
7630     {
7631       if (id == GADGET_ID_WRAP_LEFT ||
7632           id == GADGET_ID_WRAP_RIGHT ||
7633           id == GADGET_ID_WRAP_UP ||
7634           id == GADGET_ID_WRAP_DOWN)
7635         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7636       else
7637         event_mask = GD_EVENT_RELEASED;
7638     }
7639
7640     if (id == GADGET_ID_PROPERTIES ||
7641         id == GADGET_ID_PALETTE)
7642     {
7643       x += DX;
7644       y += DY;
7645     }
7646     else if (id == GADGET_ID_ELEMENT_LEFT ||
7647              id == GADGET_ID_ELEMENT_MIDDLE ||
7648              id == GADGET_ID_ELEMENT_RIGHT)
7649     {
7650       x += DX;
7651       y += DY;
7652
7653       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
7654                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
7655                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
7656
7657       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
7658                                    editor.button.element_left.tile_size :
7659                                    id == GADGET_ID_ELEMENT_MIDDLE ?
7660                                    editor.button.element_middle.tile_size :
7661                                    id == GADGET_ID_ELEMENT_RIGHT ?
7662                                    editor.button.element_right.tile_size : 0);
7663
7664       // make sure that decoration does not overlap gadget border
7665       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
7666
7667       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
7668
7669       deco_xpos = (gd->width  - tile_size) / 2;
7670       deco_ypos = (gd->height - tile_size) / 2;
7671       deco_shift = 1;
7672       deco_masked = gd->draw_masked;
7673     }
7674     else
7675     {
7676       x += EX;
7677       y += EY;
7678     }
7679
7680     gi = CreateGadget(GDI_CUSTOM_ID, id,
7681                       GDI_CUSTOM_TYPE_ID, type_id,
7682                       GDI_IMAGE_ID, graphic,
7683                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
7684                       GDI_X, x,
7685                       GDI_Y, y,
7686                       GDI_WIDTH, gd->width,
7687                       GDI_HEIGHT, gd->height,
7688                       GDI_TYPE, type,
7689                       GDI_STATE, GD_BUTTON_UNPRESSED,
7690                       GDI_RADIO_NR, radio_button_nr,
7691                       GDI_CHECKED, checked,
7692                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7693                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7694                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7695                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7696                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7697                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7698                       GDI_DECORATION_SIZE, tile_size, tile_size,
7699                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
7700                       GDI_DECORATION_MASKED, deco_masked,
7701                       GDI_EVENT_MASK, event_mask,
7702                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7703                       GDI_CALLBACK_ACTION, HandleControlButtons,
7704                       GDI_END);
7705
7706     if (gi == NULL)
7707       Fail("cannot create gadget");
7708
7709     level_editor_gadget[id] = gi;
7710   }
7711
7712   // these values are not constant, but can change at runtime
7713   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
7714   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
7715   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
7716   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
7717   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
7718   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
7719   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
7720   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
7721   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
7722   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
7723   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
7724   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
7725
7726   // create buttons for scrolling of drawing area and element list
7727   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
7728   {
7729     int id = scrollbutton_info[i].gadget_id;
7730     int type_id = scrollbutton_info[i].gadget_type_id;
7731     int graphic = scrollbutton_info[i].graphic;
7732     struct GraphicInfo *gd = &graphic_info[graphic];
7733     Bitmap *gd_bitmap = gd->bitmap;
7734     int gd_x1 = gd->src_x;
7735     int gd_y1 = gd->src_y;
7736     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7737     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7738     int width  = gd->width;
7739     int height = gd->height;
7740     int x = scrollbutton_pos[i].x;
7741     int y = scrollbutton_pos[i].y;
7742     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7743
7744     if (type_id != i)
7745       Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
7746
7747     if (id == GADGET_ID_SCROLL_LIST_UP ||
7748         id == GADGET_ID_SCROLL_LIST_DOWN)
7749     {
7750       x += PX;
7751       y += PY;
7752     }
7753     else
7754     {
7755       x += SX;
7756       y += SY;
7757     }
7758
7759     gi = CreateGadget(GDI_CUSTOM_ID, id,
7760                       GDI_CUSTOM_TYPE_ID, type_id,
7761                       GDI_IMAGE_ID, graphic,
7762                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
7763                       GDI_X, x,
7764                       GDI_Y, y,
7765                       GDI_WIDTH, width,
7766                       GDI_HEIGHT, height,
7767                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7768                       GDI_STATE, GD_BUTTON_UNPRESSED,
7769                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7770                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7771                       GDI_EVENT_MASK, event_mask,
7772                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7773                       GDI_CALLBACK_ACTION, HandleControlButtons,
7774                       GDI_END);
7775
7776     if (gi == NULL)
7777       Fail("cannot create gadget");
7778
7779     level_editor_gadget[id] = gi;
7780   }
7781
7782   // create buttons for element list
7783   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7784   {
7785     int type_id = i;
7786     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
7787     int graphic = IMG_EDITOR_PALETTE_BUTTON;
7788     struct GraphicInfo *gd = &graphic_info[graphic];
7789     Bitmap *gd_bitmap = gd->bitmap;
7790     Bitmap *deco_bitmap;
7791     int deco_x, deco_y, deco_xpos, deco_ypos;
7792     int gd_x1 = gd->src_x;
7793     int gd_y1 = gd->src_y;
7794     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7795     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7796     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
7797     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
7798     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
7799     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
7800     int element = editor_elements[i];
7801     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
7802     unsigned int event_mask = GD_EVENT_RELEASED;
7803
7804     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
7805
7806     deco_xpos = (gd->width  - tile_size) / 2;
7807     deco_ypos = (gd->height - tile_size) / 2;
7808
7809     gi = CreateGadget(GDI_CUSTOM_ID, id,
7810                       GDI_CUSTOM_TYPE_ID, type_id,
7811                       GDI_IMAGE_ID, graphic,
7812                       GDI_INFO_TEXT, getElementInfoText(element),
7813                       GDI_X, x,
7814                       GDI_Y, y,
7815                       GDI_WIDTH, gd->width,
7816                       GDI_HEIGHT, gd->height,
7817                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7818                       GDI_STATE, GD_BUTTON_UNPRESSED,
7819                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
7820                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
7821                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7822                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7823                       GDI_DECORATION_SIZE, tile_size, tile_size,
7824                       GDI_DECORATION_SHIFTING, 1, 1,
7825                       GDI_EVENT_MASK, event_mask,
7826                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7827                       GDI_CALLBACK_ACTION, HandleControlButtons,
7828                       GDI_END);
7829
7830     if (gi == NULL)
7831       Fail("cannot create gadget");
7832
7833     level_editor_gadget[id] = gi;
7834   }
7835 }
7836
7837 static void CreateCounterButtons(void)
7838 {
7839   int max_infotext_len = getMaxInfoTextLength();
7840   int i;
7841
7842   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
7843   {
7844     int type_id = counterbutton_info[i].gadget_type_id;
7845     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
7846     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
7847     int j;
7848
7849     if (type_id != i)
7850       Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
7851
7852     // determine horizontal position to the right of specified gadget
7853     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
7854       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
7855            ED_GADGET_TEXT_DISTANCE);
7856
7857     // determine horizontal offset for leading text
7858     if (counterbutton_info[i].text_left != NULL)
7859       x += getTextWidthForGadget(counterbutton_info[i].text_left);
7860
7861     for (j = 0; j < 2; j++)
7862     {
7863       struct GadgetInfo *gi;
7864       int id = (j == 0 ?
7865                 counterbutton_info[i].gadget_id_down :
7866                 counterbutton_info[i].gadget_id_up);
7867       int graphic;
7868       struct GraphicInfo *gd;
7869       int gd_x1, gd_x2, gd_y1, gd_y2;
7870       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
7871       char infotext[max_infotext_len + 1];
7872
7873       if (i == ED_COUNTER_ID_SELECT_LEVEL)
7874       {
7875         graphic = (j == 0 ?
7876                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
7877                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
7878
7879         event_mask |= GD_EVENT_RELEASED;
7880
7881         if (j == 0)
7882         {
7883           x = DX + editor.button.prev_level.x;
7884           y = DY + editor.button.prev_level.y;
7885         }
7886         else
7887         {
7888           x = DX + editor.button.next_level.x;
7889           y = DY + editor.button.next_level.y;
7890         }
7891       }
7892       else
7893       {
7894         graphic = (j == 0 ?
7895                    IMG_EDITOR_COUNTER_DOWN :
7896                    IMG_EDITOR_COUNTER_UP);
7897       }
7898
7899       gd = &graphic_info[graphic];
7900
7901       gd_x1 = gd->src_x;
7902       gd_y1 = gd->src_y;
7903       gd_x2 = gd->src_x + gd->pressed_xoffset;
7904       gd_y2 = gd->src_y + gd->pressed_yoffset;
7905
7906       sprintf(infotext, "%s counter value by 1, 5 or 10",
7907               (j == 0 ? "Decrease" : "Increase"));
7908
7909       gi = CreateGadget(GDI_CUSTOM_ID, id,
7910                         GDI_CUSTOM_TYPE_ID, type_id,
7911                         GDI_IMAGE_ID, graphic,
7912                         GDI_INFO_TEXT, infotext,
7913                         GDI_X, x,
7914                         GDI_Y, y,
7915                         GDI_WIDTH, gd->width,
7916                         GDI_HEIGHT, gd->height,
7917                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7918                         GDI_STATE, GD_BUTTON_UNPRESSED,
7919                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7920                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7921                         GDI_EVENT_MASK, event_mask,
7922                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7923                         GDI_CALLBACK_ACTION, HandleCounterButtons,
7924                         GDI_END);
7925
7926       if (gi == NULL)
7927         Fail("cannot create gadget");
7928
7929       level_editor_gadget[id] = gi;
7930       right_gadget_border[id] =
7931         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
7932
7933       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
7934
7935       if (j == 0)
7936       {
7937         int font_type = FONT_INPUT_1;
7938         int font_type_active = FONT_INPUT_1_ACTIVE;
7939
7940         id = counterbutton_info[i].gadget_id_text;
7941
7942         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
7943
7944         if (i == ED_COUNTER_ID_SELECT_LEVEL)
7945         {
7946           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
7947
7948           font_type = FONT_LEVEL_NUMBER;
7949           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
7950
7951           x = DX + editor.input.level_number.x;
7952           y = DY + editor.input.level_number.y;
7953         }
7954         else
7955         {
7956           graphic = IMG_EDITOR_COUNTER_INPUT;
7957         }
7958
7959         gd = &graphic_info[graphic];
7960
7961         gd_x1 = gd->src_x;
7962         gd_y1 = gd->src_y;
7963         gd_x2 = gd->src_x + gd->active_xoffset;
7964         gd_y2 = gd->src_y + gd->active_yoffset;
7965
7966         gi = CreateGadget(GDI_CUSTOM_ID, id,
7967                           GDI_CUSTOM_TYPE_ID, type_id,
7968                           GDI_IMAGE_ID, graphic,
7969                           GDI_INFO_TEXT, "Enter counter value",
7970                           GDI_X, x,
7971                           GDI_Y, y,
7972                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
7973                           GDI_NUMBER_VALUE, 0,
7974                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
7975                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
7976                           GDI_TEXT_SIZE, 3,     // minimal counter text size
7977                           GDI_TEXT_FONT, font_type,
7978                           GDI_TEXT_FONT_ACTIVE, font_type_active,
7979                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7980                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7981                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
7982                           GDI_DESIGN_WIDTH, gd->width,
7983                           GDI_EVENT_MASK, event_mask,
7984                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7985                           GDI_CALLBACK_ACTION, HandleCounterButtons,
7986                           GDI_END);
7987
7988         if (gi == NULL)
7989           Fail("cannot create gadget");
7990
7991         level_editor_gadget[id] = gi;
7992         right_gadget_border[id] =
7993           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
7994
7995         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
7996       }
7997     }
7998   }
7999 }
8000
8001 static void CreateDrawingAreas(void)
8002 {
8003   int i;
8004
8005   // these values are not constant, but can change at runtime
8006   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
8007   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
8008
8009   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
8010   {
8011     struct GadgetInfo *gi;
8012     int id = drawingarea_info[i].gadget_id;
8013     int type_id = drawingarea_info[i].gadget_type_id;
8014     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
8015     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
8016     int area_xsize = drawingarea_info[i].area_xsize;
8017     int area_ysize = drawingarea_info[i].area_ysize;
8018     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
8019                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
8020     unsigned int event_mask =
8021       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
8022       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
8023
8024     if (type_id != i)
8025       Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
8026
8027     // determine horizontal position to the right of specified gadget
8028     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
8029       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
8030            ED_DRAWINGAREA_TEXT_DISTANCE);
8031
8032     // determine horizontal offset for leading text
8033     if (drawingarea_info[i].text_left != NULL)
8034       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
8035
8036     gi = CreateGadget(GDI_CUSTOM_ID, id,
8037                       GDI_CUSTOM_TYPE_ID, type_id,
8038                       GDI_X, x,
8039                       GDI_Y, y,
8040                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
8041                       GDI_AREA_SIZE, area_xsize, area_ysize,
8042                       GDI_ITEM_SIZE, item_size, item_size,
8043                       GDI_EVENT_MASK, event_mask,
8044                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
8045                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
8046                       GDI_END);
8047
8048     if (gi == NULL)
8049       Fail("cannot create gadget");
8050
8051     level_editor_gadget[id] = gi;
8052     right_gadget_border[id] =
8053       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
8054   }
8055 }
8056
8057 static void CreateTextInputGadgets(void)
8058 {
8059   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
8060   int max_infotext_len = getMaxInfoTextLength();
8061   int i;
8062
8063   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
8064   {
8065     int gd_x1 = gd->src_x;
8066     int gd_y1 = gd->src_y;
8067     int gd_x2 = gd->src_x + gd->active_xoffset;
8068     int gd_y2 = gd->src_y + gd->active_yoffset;
8069     struct GadgetInfo *gi;
8070     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8071     char infotext[MAX_OUTPUT_LINESIZE + 1];
8072     int id = textinput_info[i].gadget_id;
8073     int type_id = textinput_info[i].gadget_type_id;
8074     int x, y;
8075
8076     if (type_id != i)
8077       Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
8078
8079     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
8080     {
8081       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
8082       int border_size = gd->border_size;
8083       int font_nr = FONT_INPUT_1;
8084       int font_height = getFontHeight(font_nr);
8085       int xoffset = element_border + TILEX + element_border + 3 * border_size;
8086       int yoffset = element_border + (TILEY - font_height) / 2;
8087
8088       x = (editor.settings.element_name.x != -1 ?
8089            editor.settings.element_name.x :
8090            editor.settings.element_graphic.x + xoffset) - border_size;
8091       y = (editor.settings.element_name.y != -1 ?
8092            editor.settings.element_name.y :
8093            editor.settings.element_graphic.y + yoffset) - border_size;
8094     }
8095     else
8096     {
8097       x = ED_SETTINGS_X(textinput_info[i].x);
8098       y = ED_SETTINGS_Y(textinput_info[i].y);
8099     }
8100
8101     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
8102     infotext[max_infotext_len] = '\0';
8103
8104     gi = CreateGadget(GDI_CUSTOM_ID, id,
8105                       GDI_CUSTOM_TYPE_ID, type_id,
8106                       GDI_INFO_TEXT, infotext,
8107                       GDI_X, SX + x,
8108                       GDI_Y, SY + y,
8109                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
8110                       GDI_TEXT_VALUE, textinput_info[i].value,
8111                       GDI_TEXT_SIZE, textinput_info[i].size,
8112                       GDI_TEXT_FONT, FONT_INPUT_1,
8113                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8114                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8115                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8116                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8117                       GDI_DESIGN_WIDTH, gd->width,
8118                       GDI_EVENT_MASK, event_mask,
8119                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8120                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
8121                       GDI_END);
8122
8123     if (gi == NULL)
8124       Fail("cannot create gadget");
8125
8126     level_editor_gadget[id] = gi;
8127   }
8128 }
8129
8130 static void CreateTextAreaGadgets(void)
8131 {
8132   int max_infotext_len = getMaxInfoTextLength();
8133   int i;
8134
8135   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
8136   {
8137     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
8138     int gd_x1 = gd->src_x;
8139     int gd_y1 = gd->src_y;
8140     int gd_x2 = gd->src_x + gd->active_xoffset;
8141     int gd_y2 = gd->src_y + gd->active_yoffset;
8142     struct GadgetInfo *gi;
8143     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
8144     char infotext[MAX_OUTPUT_LINESIZE + 1];
8145     int id = textarea_info[i].gadget_id;
8146     int type_id = textarea_info[i].gadget_type_id;
8147     int area_xsize = textarea_info[i].xsize;
8148     int area_ysize = textarea_info[i].ysize;
8149
8150     if (type_id != i)
8151       Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
8152
8153     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
8154     infotext[max_infotext_len] = '\0';
8155
8156     gi = CreateGadget(GDI_CUSTOM_ID, id,
8157                       GDI_CUSTOM_TYPE_ID, type_id,
8158                       GDI_INFO_TEXT, infotext,
8159                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
8160                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
8161                       GDI_TYPE, GD_TYPE_TEXT_AREA,
8162                       GDI_AREA_SIZE, area_xsize, area_ysize,
8163                       GDI_TEXT_FONT, FONT_INPUT_1,
8164                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8165                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8166                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8167                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8168                       GDI_DESIGN_WIDTH, gd->width,
8169                       GDI_EVENT_MASK, event_mask,
8170                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8171                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
8172                       GDI_END);
8173
8174     if (gi == NULL)
8175       Fail("cannot create gadget");
8176
8177     level_editor_gadget[id] = gi;
8178   }
8179 }
8180
8181 static void CreateSelectboxGadgets(void)
8182 {
8183   int max_infotext_len = getMaxInfoTextLength();
8184
8185   int i, j;
8186
8187   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8188   {
8189     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
8190     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
8191     int gd_x1 = gd->src_x;
8192     int gd_y1 = gd->src_y;
8193     int gd_x2 = gd->src_x + gd->active_xoffset;
8194     int gd_y2 = gd->src_y + gd->active_yoffset;
8195     int selectbox_button_xsize = gd2->width;
8196     struct GadgetInfo *gi;
8197     char infotext[MAX_OUTPUT_LINESIZE + 1];
8198     int id = selectbox_info[i].gadget_id;
8199     int type_id = selectbox_info[i].gadget_type_id;
8200     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
8201     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
8202     unsigned int event_mask =
8203       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
8204
8205     if (type_id != i)
8206       Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
8207
8208     if (selectbox_info[i].size == -1)   // dynamically determine size
8209     {
8210       // (we cannot use -1 for uninitialized values if we directly compare
8211       // with results from strlen(), because the '<' and '>' operation will
8212       // implicitely cast -1 to an unsigned integer value!)
8213       selectbox_info[i].size = 0;
8214
8215       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
8216         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
8217           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
8218
8219       selectbox_info[i].size++;         // add one character empty space
8220     }
8221
8222     // determine horizontal position to the right of specified gadget
8223     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
8224       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
8225            ED_GADGET_TEXT_DISTANCE);
8226
8227     // determine horizontal offset for leading text
8228     if (selectbox_info[i].text_left != NULL)
8229       x += getTextWidthForGadget(selectbox_info[i].text_left);
8230
8231     sprintf(infotext, "%s", selectbox_info[i].infotext);
8232     infotext[max_infotext_len] = '\0';
8233
8234     gi = CreateGadget(GDI_CUSTOM_ID, id,
8235                       GDI_CUSTOM_TYPE_ID, type_id,
8236                       GDI_INFO_TEXT, infotext,
8237                       GDI_X, x,
8238                       GDI_Y, y,
8239                       GDI_TYPE, GD_TYPE_SELECTBOX,
8240                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
8241                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
8242                       GDI_TEXT_SIZE, selectbox_info[i].size,
8243                       GDI_TEXT_FONT, FONT_INPUT_1,
8244                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
8245                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
8246                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8247                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8248                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8249                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
8250                       GDI_DESIGN_WIDTH, gd->width,
8251                       GDI_EVENT_MASK, event_mask,
8252                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8253                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
8254                       GDI_END);
8255
8256     if (gi == NULL)
8257       Fail("cannot create gadget");
8258
8259     level_editor_gadget[id] = gi;
8260     right_gadget_border[id] =
8261       getRightGadgetBorder(gi, selectbox_info[i].text_right);
8262   }
8263 }
8264
8265 static void CreateTextbuttonGadgets(void)
8266 {
8267   int max_infotext_len = getMaxInfoTextLength();
8268   int i;
8269
8270   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
8271   {
8272     int id = textbutton_info[i].gadget_id;
8273     int type_id = textbutton_info[i].gadget_type_id;
8274     int is_tab_button =
8275       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
8276        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
8277     int graphic =
8278       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
8279     int gadget_distance =
8280       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
8281     struct GraphicInfo *gd = &graphic_info[graphic];
8282     int gd_x1 = gd->src_x;
8283     int gd_y1 = gd->src_y;
8284     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8285     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8286     int gd_x1a = gd->src_x + gd->active_xoffset;
8287     int gd_y1a = gd->src_y + gd->active_yoffset;
8288     int border_xsize = gd->border_size + gd->draw_xoffset;
8289     int border_ysize = gd->border_size;
8290     struct GadgetInfo *gi;
8291     unsigned int event_mask = GD_EVENT_RELEASED;
8292     char infotext[MAX_OUTPUT_LINESIZE + 1];
8293     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
8294     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
8295
8296     if (type_id != i)
8297       Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
8298
8299     if (textbutton_info[i].size == -1)  // dynamically determine size
8300       textbutton_info[i].size = strlen(textbutton_info[i].text);
8301
8302     sprintf(infotext, "%s", textbutton_info[i].infotext);
8303     infotext[max_infotext_len] = '\0';
8304
8305     // determine horizontal position to the right of specified gadget
8306     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8307     {
8308       int gadget_id_align = textbutton_info[i].gadget_id_align;
8309
8310       x = right_gadget_border[gadget_id_align] + gadget_distance;
8311
8312       if (textbutton_info[i].y == -1)
8313         y = level_editor_gadget[gadget_id_align]->y;
8314     }
8315
8316     // determine horizontal offset for leading text
8317     if (textbutton_info[i].text_left != NULL)
8318       x += getTextWidthForGadget(textbutton_info[i].text_left);
8319
8320     gi = CreateGadget(GDI_CUSTOM_ID, id,
8321                       GDI_CUSTOM_TYPE_ID, type_id,
8322                       GDI_IMAGE_ID, graphic,
8323                       GDI_INFO_TEXT, infotext,
8324                       GDI_X, x,
8325                       GDI_Y, y,
8326                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
8327                       GDI_TEXT_VALUE, textbutton_info[i].text,
8328                       GDI_TEXT_SIZE, textbutton_info[i].size,
8329                       GDI_TEXT_FONT, FONT_INPUT_2,
8330                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
8331                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8332                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8333                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8334                       GDI_BORDER_SIZE, border_xsize, border_ysize,
8335                       GDI_DESIGN_WIDTH, gd->width,
8336                       GDI_DECORATION_SHIFTING, 1, 1,
8337                       GDI_EVENT_MASK, event_mask,
8338                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8339                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
8340                       GDI_END);
8341
8342     if (gi == NULL)
8343       Fail("cannot create gadget");
8344
8345     level_editor_gadget[id] = gi;
8346     right_gadget_border[id] =
8347       getRightGadgetBorder(gi, textbutton_info[i].text_right);
8348   }
8349 }
8350
8351 static void CreateGraphicbuttonGadgets(void)
8352 {
8353   struct GadgetInfo *gi;
8354   int i;
8355
8356   // create buttons for scrolling of drawing area and element list
8357   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
8358   {
8359     int id = graphicbutton_info[i].gadget_id;
8360     int type_id = graphicbutton_info[i].gadget_type_id;
8361     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
8362     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
8363     int graphic = graphicbutton_info[i].graphic;
8364     struct GraphicInfo *gd = &graphic_info[graphic];
8365     int gd_x1 = gd->src_x;
8366     int gd_y1 = gd->src_y;
8367     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8368     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8369     unsigned int event_mask = GD_EVENT_RELEASED;
8370
8371     if (type_id != i)
8372       Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
8373
8374     // determine horizontal position to the right of specified gadget
8375     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8376       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
8377            ED_GADGET_TEXT_DISTANCE);
8378
8379     // determine horizontal offset for leading text
8380     if (graphicbutton_info[i].text_left != NULL)
8381       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
8382
8383     gi = CreateGadget(GDI_CUSTOM_ID, id,
8384                       GDI_CUSTOM_TYPE_ID, type_id,
8385                       GDI_IMAGE_ID, graphic,
8386                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
8387                       GDI_X, x,
8388                       GDI_Y, y,
8389                       GDI_WIDTH, gd->width,
8390                       GDI_HEIGHT, gd->height,
8391                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
8392                       GDI_STATE, GD_BUTTON_UNPRESSED,
8393                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8394                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8395                       GDI_EVENT_MASK, event_mask,
8396                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8397                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
8398                       GDI_END);
8399
8400     if (gi == NULL)
8401       Fail("cannot create gadget");
8402
8403     level_editor_gadget[id] = gi;
8404     right_gadget_border[id] =
8405       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
8406   }
8407 }
8408
8409 static void CreateScrollbarGadgets(void)
8410 {
8411   int i;
8412
8413   // these values are not constant, but can change at runtime
8414   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
8415     SX + ED_SCROLL_HORIZONTAL_XPOS;
8416   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
8417     SY + ED_SCROLL_HORIZONTAL_YPOS;
8418   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
8419     ED_SCROLL_HORIZONTAL_XSIZE;
8420   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
8421     ED_SCROLL_HORIZONTAL_YSIZE;
8422   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
8423   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
8424   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
8425   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
8426
8427   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
8428     SX + ED_SCROLL_VERTICAL_XPOS;
8429   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
8430     SY + ED_SCROLL_VERTICAL_YPOS;
8431   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
8432     ED_SCROLL_VERTICAL_XSIZE;
8433   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
8434     ED_SCROLL_VERTICAL_YSIZE;
8435   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
8436   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
8437   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
8438   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
8439
8440   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
8441     PX + ED_SCROLL2_VERTICAL_XPOS;
8442   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
8443     PY + ED_SCROLL2_VERTICAL_YPOS;
8444   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
8445     ED_SCROLL2_VERTICAL_XSIZE;
8446   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
8447     ED_SCROLL2_VERTICAL_YSIZE;
8448   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
8449   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
8450   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
8451   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
8452
8453   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
8454   {
8455     int id = scrollbar_info[i].gadget_id;
8456     int type_id = scrollbar_info[i].gadget_type_id;
8457     int graphic = scrollbar_info[i].graphic;
8458     struct GraphicInfo *gd = &graphic_info[graphic];
8459     int gd_x1 = gd->src_x;
8460     int gd_y1 = gd->src_y;
8461     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8462     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8463     struct GadgetInfo *gi;
8464     int items_max, items_visible, item_position;
8465     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
8466
8467     if (type_id != i)
8468       Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
8469
8470     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
8471     {
8472       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
8473       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
8474       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
8475     }
8476     else        // drawing area scrollbars
8477     {
8478       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
8479       {
8480         items_max = MAX(lev_fieldx + 2, ed_fieldx);
8481         items_visible = ed_fieldx;
8482         item_position = 0;
8483       }
8484       else
8485       {
8486         items_max = MAX(lev_fieldy + 2, ed_fieldy);
8487         items_visible = ed_fieldy;
8488         item_position = 0;
8489       }
8490     }
8491
8492     gi = CreateGadget(GDI_CUSTOM_ID, id,
8493                       GDI_CUSTOM_TYPE_ID, type_id,
8494                       GDI_IMAGE_ID, graphic,
8495                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
8496                       GDI_X, scrollbar_pos[i].x,
8497                       GDI_Y, scrollbar_pos[i].y,
8498                       GDI_WIDTH, scrollbar_pos[i].width,
8499                       GDI_HEIGHT, scrollbar_pos[i].height,
8500                       GDI_TYPE, scrollbar_info[i].type,
8501                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
8502                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
8503                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
8504                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
8505                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
8506                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
8507                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
8508                       GDI_STATE, GD_BUTTON_UNPRESSED,
8509                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8510                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8511                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
8512                       GDI_EVENT_MASK, event_mask,
8513                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8514                       GDI_CALLBACK_ACTION, HandleControlButtons,
8515                       GDI_END);
8516
8517     if (gi == NULL)
8518       Fail("cannot create gadget");
8519
8520     level_editor_gadget[id] = gi;
8521   }
8522 }
8523
8524 static void CreateCheckbuttonGadgets(void)
8525 {
8526   struct GadgetInfo *gi;
8527   int i;
8528
8529   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
8530   {
8531     int id = checkbutton_info[i].gadget_id;
8532     int type_id = checkbutton_info[i].gadget_type_id;
8533     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
8534                    IMG_EDITOR_CHECKBOX);
8535     struct GraphicInfo *gd = &graphic_info[graphic];
8536     int gd_x1 = gd->src_x;
8537     int gd_y1 = gd->src_y;
8538     int gd_x2 = gd->src_x + gd->pressed_xoffset;
8539     int gd_y2 = gd->src_y + gd->pressed_yoffset;
8540     int gd_x1a = gd->src_x + gd->active_xoffset;
8541     int gd_y1a = gd->src_y + gd->active_yoffset;
8542     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8543     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8544     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
8545     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
8546     unsigned int event_mask = GD_EVENT_PRESSED;
8547
8548     if (type_id != i)
8549       Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
8550
8551     // determine horizontal position to the right of specified gadget
8552     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
8553       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
8554            ED_GADGET_TEXT_DISTANCE);
8555
8556     // determine horizontal offset for leading text
8557     if (checkbutton_info[i].text_left != NULL)
8558       x += getTextWidthForGadget(checkbutton_info[i].text_left);
8559
8560     gi = CreateGadget(GDI_CUSTOM_ID, id,
8561                       GDI_CUSTOM_TYPE_ID, type_id,
8562                       GDI_IMAGE_ID, graphic,
8563                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
8564                       GDI_X, x,
8565                       GDI_Y, y,
8566                       GDI_WIDTH, gd->width,
8567                       GDI_HEIGHT, gd->height,
8568                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
8569                       GDI_CHECKED, *checkbutton_info[i].value,
8570                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8571                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8572                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8573                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8574                       GDI_EVENT_MASK, event_mask,
8575                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8576                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
8577                       GDI_END);
8578
8579     if (gi == NULL)
8580       Fail("cannot create gadget");
8581
8582     level_editor_gadget[id] = gi;
8583     right_gadget_border[id] =
8584       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
8585   }
8586 }
8587
8588 static void CreateRadiobuttonGadgets(void)
8589 {
8590   int graphic = IMG_EDITOR_RADIOBUTTON;
8591   struct GraphicInfo *gd = &graphic_info[graphic];
8592   int gd_x1 = gd->src_x;
8593   int gd_y1 = gd->src_y;
8594   int gd_x2 = gd->src_x + gd->pressed_xoffset;
8595   int gd_y2 = gd->src_y + gd->pressed_yoffset;
8596   int gd_x1a = gd->src_x + gd->active_xoffset;
8597   int gd_y1a = gd->src_y + gd->active_yoffset;
8598   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
8599   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
8600   struct GadgetInfo *gi;
8601   int i;
8602
8603   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
8604   {
8605     int id = radiobutton_info[i].gadget_id;
8606     int type_id = radiobutton_info[i].gadget_type_id;
8607     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
8608     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
8609     unsigned int event_mask = GD_EVENT_PRESSED;
8610
8611     if (type_id != i)
8612       Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
8613
8614     int checked =
8615       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
8616
8617     // determine horizontal position to the right of specified gadget
8618     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
8619       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
8620            ED_GADGET_TEXT_DISTANCE);
8621
8622     // determine horizontal offset for leading text
8623     if (radiobutton_info[i].text_left != NULL)
8624       x += getTextWidthForGadget(radiobutton_info[i].text_left);
8625
8626     gi = CreateGadget(GDI_CUSTOM_ID, id,
8627                       GDI_CUSTOM_TYPE_ID, type_id,
8628                       GDI_IMAGE_ID, graphic,
8629                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
8630                       GDI_X, x,
8631                       GDI_Y, y,
8632                       GDI_WIDTH, gd->width,
8633                       GDI_HEIGHT, gd->height,
8634                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
8635                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
8636                       GDI_CHECKED, checked,
8637                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
8638                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
8639                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
8640                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
8641                       GDI_EVENT_MASK, event_mask,
8642                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
8643                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
8644                       GDI_END);
8645
8646     if (gi == NULL)
8647       Fail("cannot create gadget");
8648
8649     level_editor_gadget[id] = gi;
8650     right_gadget_border[id] =
8651       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
8652   }
8653 }
8654
8655 void CreateLevelEditorGadgets(void)
8656 {
8657   // force EDITOR font inside level editor
8658   SetFontStatus(GAME_MODE_EDITOR);
8659
8660   // these values are not constant, but can change at runtime
8661   ed_fieldx = MAX_ED_FIELDX - 1;
8662   ed_fieldy = MAX_ED_FIELDY - 1;
8663
8664   num_editor_gadgets = NUM_EDITOR_GADGETS;
8665
8666   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
8667
8668   level_editor_gadget =
8669     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
8670   right_gadget_border =
8671     checked_calloc(num_editor_gadgets * sizeof(int));
8672
8673   // set number of empty (padding) element buttons to maximum number of buttons
8674   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
8675
8676   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
8677   editor_el_empty_ptr = editor_el_empty;
8678
8679   use_permanent_palette = !editor.palette.show_as_separate_screen;
8680
8681   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
8682
8683   ReinitializeElementList();
8684
8685   CreateControlButtons();
8686   CreateScrollbarGadgets();
8687
8688   // order of function calls is important because of cross-references
8689   CreateCheckbuttonGadgets();
8690   CreateCounterButtons();
8691   CreateRadiobuttonGadgets();
8692   CreateTextInputGadgets();
8693   CreateTextAreaGadgets();
8694   CreateSelectboxGadgets();
8695   CreateGraphicbuttonGadgets();
8696   CreateTextbuttonGadgets();
8697   CreateDrawingAreas();
8698
8699   ResetFontStatus();
8700 }
8701
8702 void FreeLevelEditorGadgets(void)
8703 {
8704   int i;
8705
8706   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
8707
8708   for (i = 0; i < num_editor_gadgets; i++)
8709   {
8710     FreeGadget(level_editor_gadget[i]);
8711
8712     level_editor_gadget[i] = NULL;
8713   }
8714
8715   checked_free(level_editor_gadget);
8716   checked_free(right_gadget_border);
8717
8718   checked_free(editor_el_empty);
8719 }
8720
8721 static void MapCounterButtons(int id)
8722 {
8723   int font_nr = FONT_TEXT_1;
8724   int font_height = getFontHeight(font_nr);
8725   int gadget_id_down = counterbutton_info[id].gadget_id_down;
8726   int gadget_id_text = counterbutton_info[id].gadget_id_text;
8727   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
8728   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
8729   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
8730   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
8731   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
8732   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8733   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8734   int yoffset = (gi_down->height - font_height) / 2;
8735   int x_left = gi_down->x - xoffset_left;
8736   int x_right;  // set after gadget position was modified
8737   int y_above = gi_down->y - yoffset_above;
8738   int x = gi_down->x;
8739   int y;        // set after gadget position was modified
8740
8741   // counter limits must be changed first to prevent value truncation
8742   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
8743                             counterbutton_info[id].max_value);
8744
8745   // right text position might have changed after setting position above
8746   x_right = gi_up->x + gi_up->width + xoffset_right;
8747
8748   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
8749
8750   // set position for counter gadgets with dynamically determined position
8751   if (id != ED_COUNTER_ID_SELECT_LEVEL)
8752   {
8753     ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8754     ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8755     ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
8756   }
8757
8758   // vertical position might have changed after setting position above
8759   y = gi_up->y + yoffset;
8760
8761   if (counterbutton_info[id].text_above)
8762     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
8763
8764   if (counterbutton_info[id].text_left)
8765     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
8766
8767   if (counterbutton_info[id].text_right)
8768     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
8769
8770   MapGadget(gi_down);
8771   MapGadget(gi_text);
8772   MapGadget(gi_up);
8773 }
8774
8775 static void MapControlButtons(void)
8776 {
8777   int counter_id;
8778   int i;
8779
8780   // map toolbox buttons (excluding special CE toolbox buttons)
8781   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
8782     MapGadget(level_editor_gadget[i]);
8783
8784   // map toolbox buttons (element properties buttons)
8785   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
8786     MapGadget(level_editor_gadget[i]);
8787
8788   if (use_permanent_palette)
8789   {
8790     // map buttons to select elements
8791     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
8792       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
8793     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
8794     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
8795     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
8796   }
8797
8798   // map buttons to select level
8799   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
8800   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
8801   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
8802   MapCounterButtons(counter_id);
8803 }
8804
8805 static void MapDrawingArea(int id)
8806 {
8807   int font_nr = FONT_TEXT_1;
8808   int font_height = getFontHeight(font_nr);
8809   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8810   int area_xsize = gi->drawing.area_xsize;
8811   int area_ysize = gi->drawing.area_ysize;
8812   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8813   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
8814   int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
8815   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
8816   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
8817   int x_below = gi->x + (gi->width - xoffset_below) / 2;
8818   int y_side  = gi->y + (gi->height - font_height) / 2;
8819   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
8820   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
8821
8822   if (drawingarea_info[id].text_left)
8823     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
8824
8825   if (drawingarea_info[id].text_right)
8826     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
8827
8828   if (drawingarea_info[id].text_above)
8829     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
8830
8831   if (drawingarea_info[id].text_below)
8832     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
8833
8834   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
8835   {
8836     DrawElementBorder(gi->x, gi->y,
8837                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
8838                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
8839
8840     DrawDrawingArea(id);
8841   }
8842
8843   MapGadget(gi);
8844 }
8845
8846 static void MapTextInputGadget(int id)
8847 {
8848   int font_nr = FONT_TEXT_1;
8849   int font_height = getFontHeight(font_nr);
8850   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
8851   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8852   int x_above = ED_SETTINGS_X(textinput_info[id].x);
8853   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
8854
8855   if (textinput_info[id].text_above)
8856     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
8857
8858   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
8859
8860   MapGadget(gi);
8861 }
8862
8863 static void MapTextAreaGadget(int id)
8864 {
8865   int font_nr = FONT_TEXT_1;
8866   int font_height = getFontHeight(font_nr);
8867   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
8868   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8869   int x_above = ED_SETTINGS_X(textarea_info[id].x);
8870   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
8871   char *text_above = textarea_info[id].text_above;
8872
8873   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
8874     text_above = textarea_info[id].text_above_cropped;
8875
8876   if (text_above)
8877     DrawTextS(x_above, y_above, font_nr, text_above);
8878
8879   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
8880
8881   MapGadget(gi);
8882 }
8883
8884 static void MapSelectboxGadget(int id)
8885 {
8886   int font_nr = FONT_TEXT_1;
8887   int font_height = getFontHeight(font_nr);
8888   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
8889   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
8890   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8891   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8892   int yoffset = (gi->height - font_height) / 2;
8893   int x_left = gi->x - xoffset_left;
8894   int x_right = gi->x + gi->width + xoffset_right;
8895   int y_above = gi->y - yoffset_above;
8896   int x = gi->x;
8897   int y = gi->y + yoffset;
8898
8899   if (selectbox_info[id].text_above)
8900     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
8901
8902   if (selectbox_info[id].text_left)
8903     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
8904
8905   if (selectbox_info[id].text_right)
8906     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
8907
8908   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
8909
8910   MapGadget(gi);
8911 }
8912
8913 static void MapTextbuttonGadget(int id)
8914 {
8915   int font_nr = FONT_TEXT_1;
8916   int font_height = getFontHeight(font_nr);
8917   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
8918   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
8919   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8920   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8921   int yoffset = (gi->height - font_height) / 2;
8922   int x_left = gi->x - xoffset_left;
8923   int x_right = gi->x + gi->width + xoffset_right;
8924   int y_above = gi->y - yoffset_above;
8925   int x = gi->x;
8926   int y = gi->y + yoffset;
8927
8928   // only show button to delete change pages when more than minimum pages
8929   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
8930       custom_element.num_change_pages == MIN_CHANGE_PAGES)
8931     return;
8932
8933   if (textbutton_info[id].text_above)
8934     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
8935
8936   if (textbutton_info[id].text_left)
8937     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
8938
8939   if (textbutton_info[id].text_right)
8940     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
8941
8942   MapGadget(gi);
8943 }
8944
8945 static void MapGraphicbuttonGadget(int id)
8946 {
8947   int font_nr = FONT_TEXT_1;
8948   int font_height = getFontHeight(font_nr);
8949   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
8950   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
8951   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8952   int yoffset = (gi->height - font_height) / 2;
8953   int x_left = gi->x - xoffset_left;
8954   int x_right = gi->x + gi->width + xoffset_right;
8955   int y = gi->y + yoffset;
8956
8957   if (graphicbutton_info[id].text_left)
8958     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
8959
8960   if (graphicbutton_info[id].text_right)
8961     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
8962
8963   MapGadget(gi);
8964 }
8965
8966 static void MapRadiobuttonGadget(int id)
8967 {
8968   int font_nr = FONT_TEXT_1;
8969   int font_height = getFontHeight(font_nr);
8970   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
8971   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
8972   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8973   int yoffset = (gi->height - font_height) / 2;
8974   int x_left = gi->x - xoffset_left;
8975   int x_right = gi->x + gi->width + xoffset_right;
8976   int y = gi->y + yoffset;
8977   boolean checked =
8978     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
8979
8980   if (radiobutton_info[id].text_left)
8981     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
8982
8983   if (radiobutton_info[id].text_right)
8984     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
8985
8986   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
8987
8988   MapGadget(gi);
8989 }
8990
8991 static void MapCheckbuttonGadget(int id)
8992 {
8993   int font_nr = FONT_TEXT_1;
8994   int font_height = getFontHeight(font_nr);
8995   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
8996   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
8997   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
8998   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
8999   int yoffset = (gi->height - font_height) / 2;
9000   int y_above = gi->y - yoffset_above;
9001   int x = gi->x;
9002   int x_left, x_right, y;       // set after gadget position was modified
9003
9004   // set position for gadgets with dynamically determined position
9005   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
9006     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
9007   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
9008
9009   x_left = gi->x - xoffset_left;
9010   x_right = gi->x + gi->width + xoffset_right;
9011   y = gi->y + yoffset;
9012
9013   if (checkbutton_info[id].text_above)
9014     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
9015
9016   if (checkbutton_info[id].text_left)
9017     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
9018
9019   if (checkbutton_info[id].text_right)
9020     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
9021
9022   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
9023
9024   MapGadget(gi);
9025 }
9026
9027 static void MapMainDrawingArea(void)
9028 {
9029   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
9030   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
9031   int i;
9032
9033   if (suppressBorderElement())
9034   {
9035     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
9036     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
9037   }
9038
9039   for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
9040   {
9041     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
9042           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
9043          no_horizontal_scrollbar) ||
9044         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
9045           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
9046          no_vertical_scrollbar))
9047       continue;
9048
9049     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
9050   }
9051
9052   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
9053   {
9054     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
9055         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
9056       continue;
9057
9058     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
9059   }
9060
9061   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
9062 }
9063
9064 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
9065 {
9066   int i;
9067
9068   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
9069   {
9070     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
9071         i == GADGET_ID_CUSTOM_COPY_TO ||
9072         i == GADGET_ID_CUSTOM_EXCHANGE ||
9073         i == GADGET_ID_CUSTOM_COPY ||
9074         i == GADGET_ID_CUSTOM_PASTE)
9075     {
9076       if (map)
9077         MapGadget(level_editor_gadget[i]);
9078       else
9079         UnmapGadget(level_editor_gadget[i]);
9080     }
9081   }
9082 }
9083
9084 static void MapLevelEditorToolboxCustomGadgets(void)
9085 {
9086   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
9087 }
9088
9089 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
9090 {
9091   if (IS_CUSTOM_ELEMENT(properties_element) ||
9092       IS_GROUP_ELEMENT(properties_element) ||
9093       IS_EMPTY_ELEMENT(properties_element))
9094     MapLevelEditorToolboxCustomGadgets();
9095 }
9096
9097 static void UnmapLevelEditorToolboxCustomGadgets(void)
9098 {
9099   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
9100 }
9101
9102 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
9103 {
9104   int i;
9105
9106   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
9107   {
9108     if (i != GADGET_ID_SINGLE_ITEMS &&
9109         i != GADGET_ID_PICK_ELEMENT)
9110     {
9111       struct GadgetInfo *gi = level_editor_gadget[i];
9112
9113       if (map)
9114       {
9115         MapGadget(gi);
9116       }
9117       else
9118       {
9119         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
9120         struct GraphicInfo *gd = &graphic_info[graphic];
9121
9122         UnmapGadget(gi);
9123
9124         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
9125                    gi->width, gi->height, gi->x, gi->y);
9126
9127         redraw_mask |= REDRAW_DOOR_3;
9128       }
9129     }
9130   }
9131 }
9132
9133 static void MapLevelEditorToolboxDrawingGadgets(void)
9134 {
9135   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
9136 }
9137
9138 static void UnmapLevelEditorToolboxDrawingGadgets(void)
9139 {
9140   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
9141 }
9142
9143 static void UnmapDrawingArea(int id)
9144 {
9145   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
9146 }
9147
9148 static void UnmapLevelEditorFieldGadgets(void)
9149 {
9150   int i;
9151
9152   for (i = 0; i < num_editor_gadgets; i++)
9153     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
9154                           level_editor_gadget[i]->y))
9155       UnmapGadget(level_editor_gadget[i]);
9156 }
9157
9158 void UnmapLevelEditorGadgets(void)
9159 {
9160   int i;
9161
9162   for (i = 0; i < num_editor_gadgets; i++)
9163     UnmapGadget(level_editor_gadget[i]);
9164 }
9165
9166 static void ResetUndoBuffer(void)
9167 {
9168   undo_buffer_position = -1;
9169   undo_buffer_steps = -1;
9170   redo_buffer_steps = 0;
9171
9172   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
9173
9174   level.changed = FALSE;
9175 }
9176
9177 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
9178 {
9179   if (remap_toolbox_gadgets)
9180   {
9181     ModifyEditorElementList();
9182     RedrawDrawingElements();
9183   }
9184
9185   if (edit_mode == ED_MODE_LEVELCONFIG)
9186     DrawLevelConfigWindow();
9187   else if (edit_mode == ED_MODE_PROPERTIES)
9188     DrawPropertiesWindow();
9189   else if (edit_mode == ED_MODE_PALETTE)
9190     DrawPaletteWindow();
9191   else  // edit_mode == ED_MODE_DRAWING
9192     DrawDrawingWindowExt(remap_toolbox_gadgets);
9193 }
9194
9195 static void DrawEditModeWindow(void)
9196 {
9197   DrawEditModeWindowExt(TRUE);
9198 }
9199
9200 static void DrawEditModeWindow_PlayfieldOnly(void)
9201 {
9202   DrawEditModeWindowExt(FALSE);
9203 }
9204
9205 static void ChangeEditModeWindow(int new_edit_mode)
9206 {
9207   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
9208
9209   DrawEditModeWindow();
9210 }
9211
9212 static boolean LevelChanged(void)
9213 {
9214   boolean field_changed = FALSE;
9215   int x, y;
9216
9217   for (y = 0; y < lev_fieldy; y++) 
9218     for (x = 0; x < lev_fieldx; x++)
9219       if (Tile[x][y] != level.field[x][y])
9220         field_changed = TRUE;
9221
9222   return (level.changed || field_changed);
9223 }
9224
9225 static boolean PrepareSavingIntoPersonalLevelSet(void)
9226 {
9227   static LevelDirTree *last_copied_leveldir = NULL;
9228   static LevelDirTree *last_written_leveldir = NULL;
9229   static int last_copied_level_nr = -1;
9230   static int last_written_level_nr = -1;
9231   LevelDirTree *leveldir_former = leveldir_current;
9232   int level_nr_former = level_nr;
9233   int new_level_nr;
9234
9235   // remember last mod/save so that for current session, we write
9236   // back to the same personal copy, asking only about overwrite.
9237   if (leveldir_current == last_copied_leveldir &&
9238       level_nr == last_copied_level_nr)
9239   {
9240     // "cd" to personal level set dir (as used when writing last copy)
9241     leveldir_current = last_written_leveldir;
9242     level_nr = last_written_level_nr;
9243
9244     return TRUE;
9245   }
9246
9247   if (!Request("This level is read-only! "
9248                "Save into personal level set?", REQ_ASK))
9249     return FALSE;
9250
9251   // "cd" to personal level set dir (for writing copy the first time)
9252   leveldir_current =
9253     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
9254
9255   // this may happen if "setup.internal.create_user_levelset" is FALSE
9256   // or if file "levelinfo.conf" is missing in personal user level set
9257   if (leveldir_current == NULL)
9258   {
9259     Request("Cannot find personal level set?!", REQ_CONFIRM);
9260
9261     leveldir_current = leveldir_former;
9262
9263     return FALSE;
9264   }
9265
9266   // find unused level number
9267   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
9268   {
9269     static char *level_filename = NULL;
9270
9271     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
9272
9273     if (!fileExists(level_filename))
9274       break;
9275   }
9276
9277   last_copied_leveldir = leveldir_former;
9278   last_copied_level_nr = level_nr_former;
9279
9280   last_written_leveldir = leveldir_current;
9281   last_written_level_nr = level_nr = new_level_nr;
9282
9283   return TRUE;
9284 }
9285
9286 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
9287 {
9288   static char *filename_levelinfo = NULL, *mod_name = NULL;
9289   FILE *file;
9290
9291   // annotate this copy-and-mod in personal levelinfo.conf
9292   setString(&filename_levelinfo,
9293             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
9294
9295   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
9296   {
9297     fprintf(file, "\n");
9298     fprintf(file, "# level %d was modified from:\n", level_nr);
9299     fprintf(file, "# - previous level set name:    %s\n",
9300             former_name);
9301     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
9302             level.file_info.nr, level.name);
9303     fprintf(file, "# - previous author:            %s\n",
9304             level.author);
9305     fprintf(file, "# - previous save date:         ");
9306
9307     if (level.creation_date.src == DATE_SRC_LEVELFILE)
9308     {
9309       fprintf(file, "%04d-%02d-%02d\n",
9310               level.creation_date.year,
9311               level.creation_date.month,
9312               level.creation_date.day);
9313     }
9314     else
9315     {
9316       fprintf(file, "not recorded\n");
9317     }
9318
9319     fclose(file);
9320   }
9321
9322   if (level_nr > leveldir_current->last_level)
9323     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
9324
9325   // else: allow the save even if annotation failed
9326
9327   // now... spray graffiti on the old level vital statistics
9328   // user can change these; just trying to set a good baseline
9329
9330   // don't truncate names for fear of making offensive or silly:
9331   // long-named original author only recorded in levelinfo.conf.
9332   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
9333   if (!strEqual(level.author, leveldir_current->author))
9334   {
9335     setString(&mod_name, getStringCat3(leveldir_current->author,
9336                                        " after ", level.author));
9337
9338     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9339       setString(&mod_name,
9340                 getStringCat2(leveldir_current->author, " (ed.)"));
9341
9342     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
9343       setString(&mod_name, leveldir_current->author);
9344
9345     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
9346
9347     // less worried about truncation here
9348     setString(&mod_name, getStringCat2("Mod: ", level.name));
9349     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
9350   }
9351 }
9352
9353 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
9354                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
9355 {
9356   int x, y;
9357
9358   for (x = 0; x < lev_fieldx; x++)
9359     for (y = 0; y < lev_fieldy; y++) 
9360       dst[x][y] = src[x][y];
9361 }
9362
9363 static int setSelectboxValue(int selectbox_id, int new_value)
9364 {
9365   int new_index_value = 0;
9366   int i;
9367
9368   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
9369     if (selectbox_info[selectbox_id].options[i].value == new_value)
9370       new_index_value = i;
9371
9372   *selectbox_info[selectbox_id].value =
9373     selectbox_info[selectbox_id].options[new_index_value].value;
9374
9375   return new_index_value;
9376 }
9377
9378 static void setSelectboxSpecialActionVariablesIfNeeded(void)
9379 {
9380   int i;
9381
9382   // change action mode and arg variables according to action type variable
9383   for (i = 0; action_arg_options[i].value != -1; i++)
9384   {
9385     if (action_arg_options[i].value == custom_element_change.action_type)
9386     {
9387       int mode = action_arg_options[i].mode;
9388
9389       // only change if corresponding selectbox has changed
9390       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
9391           action_arg_modes[mode])
9392         custom_element_change.action_mode = -1;
9393
9394       // only change if corresponding selectbox has changed
9395       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
9396           action_arg_options[i].options)
9397         custom_element_change.action_arg = -1;
9398
9399       break;
9400     }
9401   }
9402 }
9403
9404 static void setSelectboxSpecialActionOptions(void)
9405 {
9406   int i;
9407
9408   // change action mode and arg selectbox according to action type selectbox
9409   for (i = 0; action_arg_options[i].value != -1; i++)
9410   {
9411     if (action_arg_options[i].value == custom_element_change.action_type)
9412     {
9413       int mode = action_arg_options[i].mode;
9414
9415       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
9416                                    action_arg_modes[mode]);
9417       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
9418                                  custom_element_change.action_mode);
9419
9420       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
9421                                    action_arg_options[i].options);
9422       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
9423                                  custom_element_change.action_arg);
9424       break;
9425     }
9426   }
9427 }
9428
9429 static void copy_custom_element_settings(int element_from, int element_to)
9430 {
9431   struct ElementInfo *ei_from = &element_info[element_from];
9432   struct ElementInfo *ei_to = &element_info[element_to];
9433
9434   copyElementInfo(ei_from, ei_to);
9435 }
9436
9437 static void replace_custom_element_in_settings(int element_from,
9438                                                int element_to)
9439 {
9440   int i, j, x, y;
9441
9442   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9443   {
9444     struct ElementInfo *ei = &element_info[i];
9445
9446     for (y = 0; y < 3; y++)
9447       for (x = 0; x < 3; x++)
9448         if (ei->content.e[x][y] == element_from)
9449           ei->content.e[x][y] = element_to;
9450
9451     for (j = 0; j < ei->num_change_pages; j++)
9452     {
9453       struct ElementChangeInfo *change = &ei->change_page[j];
9454
9455       if (change->target_element == element_from)
9456         change->target_element = element_to;
9457
9458       if (change->initial_trigger_element == element_from)
9459         change->initial_trigger_element = element_to;
9460
9461       if (change->action_element == element_from)
9462         change->action_element = element_to;
9463
9464       for (y = 0; y < 3; y++)
9465         for (x = 0; x < 3; x++)
9466           if (change->target_content.e[x][y] == element_from)
9467             change->target_content.e[x][y] = element_to;
9468     }
9469
9470     if (ei->group != NULL)                              // group or internal
9471       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
9472         if (ei->group->element[j] == element_from)
9473           ei->group->element[j] = element_to;
9474   }
9475 }
9476
9477 static void replace_custom_element_in_playfield(int element_from,
9478                                                 int element_to)
9479 {
9480   int x, y;
9481
9482   for (x = 0; x < lev_fieldx; x++)
9483     for (y = 0; y < lev_fieldy; y++)
9484       if (Tile[x][y] == element_from)
9485         Tile[x][y] = element_to;
9486 }
9487
9488 static boolean CopyCustomElement(int element_old, int element_new,
9489                                  int copy_mode)
9490 {
9491   int copy_mode_orig = copy_mode;
9492
9493   if (copy_mode == GADGET_ID_CUSTOM_COPY)
9494   {
9495     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
9496                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9497     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9498   }
9499   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
9500   {
9501     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
9502                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
9503     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
9504
9505     level.changed = TRUE;
9506   }
9507   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
9508   {
9509     Request("Please choose custom element!", REQ_CONFIRM);
9510
9511     return FALSE;
9512   }
9513   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
9514   {
9515     Request("Please choose group element!", REQ_CONFIRM);
9516
9517     return FALSE;
9518   }
9519   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
9520   {
9521     Request("Please choose empty element!", REQ_CONFIRM);
9522
9523     return FALSE;
9524   }
9525   else
9526   {
9527     level.changed = TRUE;
9528   }
9529
9530   // when modifying custom/group element, ask for copying level template
9531   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
9532   {
9533     if (!AskToCopyAndModifyLevelTemplate())
9534       return FALSE;
9535   }
9536
9537   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
9538   {
9539     copy_custom_element_settings(element_new, element_old);
9540   }
9541   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
9542   {
9543     copy_custom_element_settings(element_old, element_new);
9544   }
9545   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
9546   {
9547     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
9548     copy_custom_element_settings(element_new, element_old);
9549     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
9550
9551     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
9552     replace_custom_element_in_settings(element_new, element_old);
9553     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
9554
9555     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
9556     replace_custom_element_in_playfield(element_new, element_old);
9557     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
9558   }
9559
9560   UpdateCustomElementGraphicGadgets();
9561   DrawPropertiesWindow();
9562
9563   return TRUE;
9564 }
9565
9566 static void CopyCustomElementPropertiesToEditor(int element)
9567 {
9568   int i;
9569   int current_change_page = element_info[element].current_change_page;
9570
9571   // dynamically (re)build selectbox for selecting change page
9572   for (i = 0; i < element_info[element].num_change_pages; i++)
9573   {
9574     sprintf(options_change_page_strings[i], "%d", i + 1);
9575
9576     options_change_page[i].value = i;
9577     options_change_page[i].text = options_change_page_strings[i];
9578   }
9579
9580   options_change_page[i].value = -1;
9581   options_change_page[i].text = NULL;
9582
9583   // needed here to initialize combined element properties
9584   InitElementPropertiesEngine(level.game_version);
9585
9586   element_info[element].change =
9587     &element_info[element].change_page[current_change_page];
9588
9589   custom_element = element_info[element];
9590   custom_element_change = *element_info[element].change;
9591
9592   // needed to initially set selectbox options for special action options
9593   setSelectboxSpecialActionOptions();
9594
9595   // needed to initially set selectbox value variables to reliable defaults
9596   for (i = 0; i < ED_NUM_SELECTBOX; i++)
9597     setSelectboxValue(i, *selectbox_info[i].value);
9598
9599   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9600     custom_element_properties[i] = HAS_PROPERTY(element, i);
9601
9602   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9603     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
9604
9605   // ---------- element settings: configure (custom elements) -----------------
9606
9607   // set accessible layer selectbox help value
9608   custom_element.access_type =
9609     (IS_WALKABLE(element) ? EP_WALKABLE :
9610      IS_PASSABLE(element) ? EP_PASSABLE :
9611      custom_element.access_type);
9612   custom_element.access_layer =
9613     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
9614      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
9615      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
9616      custom_element.access_layer);
9617   custom_element.access_protected =
9618     (IS_PROTECTED(element) ? 1 : 0);
9619   custom_element_properties[EP_ACCESSIBLE] =
9620     (IS_ACCESSIBLE_OVER(element) ||
9621      IS_ACCESSIBLE_INSIDE(element) ||
9622      IS_ACCESSIBLE_UNDER(element));
9623
9624   // set walk-to-object action selectbox help value
9625   custom_element.walk_to_action =
9626     (IS_DIGGABLE(element) ? EP_DIGGABLE :
9627      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
9628      IS_DROPPABLE(element) ? EP_DROPPABLE :
9629      IS_THROWABLE(element) ? EP_THROWABLE :
9630      IS_PUSHABLE(element) ? EP_PUSHABLE :
9631      custom_element.walk_to_action);
9632   custom_element_properties[EP_WALK_TO_OBJECT] =
9633     (IS_DIGGABLE(element) ||
9634      IS_COLLECTIBLE_ONLY(element) ||
9635      IS_DROPPABLE(element) ||
9636      IS_THROWABLE(element) ||
9637      IS_PUSHABLE(element));
9638
9639   // set smash targets selectbox help value
9640   custom_element.smash_targets =
9641     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
9642      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
9643      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
9644      custom_element.smash_targets);
9645   custom_element_properties[EP_CAN_SMASH] =
9646     (CAN_SMASH_EVERYTHING(element) ||
9647      CAN_SMASH_ENEMIES(element) ||
9648      CAN_SMASH_PLAYER(element));
9649
9650   // set deadliness selectbox help value
9651   custom_element.deadliness =
9652     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
9653      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
9654      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
9655      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
9656      custom_element.deadliness);
9657   custom_element_properties[EP_DEADLY] =
9658     (DONT_TOUCH(element) ||
9659      DONT_GET_HIT_BY(element) ||
9660      DONT_COLLIDE_WITH(element) ||
9661      DONT_RUN_INTO(element));
9662
9663   // ---------- element settings: advanced (custom elements) ------------------
9664
9665   // set "change by direct action" selectbox help value
9666   custom_element_change.direct_action =
9667     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
9668      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
9669      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
9670      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
9671      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
9672      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
9673      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
9674      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
9675      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
9676      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
9677      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
9678      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
9679      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
9680      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
9681      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
9682      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
9683      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
9684      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
9685      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
9686      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
9687      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
9688      custom_element_change.direct_action);
9689
9690   // set "change by other element action" selectbox help value
9691   custom_element_change.other_action =
9692     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
9693      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
9694      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
9695      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
9696      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
9697      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
9698      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
9699      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
9700      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
9701      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
9702      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
9703      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
9704      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
9705      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
9706      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
9707      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
9708      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
9709      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
9710      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
9711      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
9712      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
9713      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
9714      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
9715      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
9716      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
9717      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
9718      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
9719      custom_element_change.other_action);
9720 }
9721
9722 static void CopyGroupElementPropertiesToEditor(int element)
9723 {
9724   group_element_info = *element_info[element].group;
9725   custom_element = element_info[element];       // needed for description
9726 }
9727
9728 static void CopyEmptyElementPropertiesToEditor(int element)
9729 {
9730   custom_element = element_info[element];
9731 }
9732
9733 static void CopyClassicElementPropertiesToEditor(int element)
9734 {
9735   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9736     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
9737       getMoveIntoAcidProperty(&level, element);
9738
9739   if (MAYBE_DONT_COLLIDE_WITH(element))
9740     custom_element_properties[EP_DONT_COLLIDE_WITH] =
9741       getDontCollideWithProperty(&level, element);
9742 }
9743
9744 static void CopyElementPropertiesToEditor(int element)
9745 {
9746   if (IS_CUSTOM_ELEMENT(element))
9747     CopyCustomElementPropertiesToEditor(element);
9748   else if (IS_GROUP_ELEMENT(element))
9749     CopyGroupElementPropertiesToEditor(element);
9750   else if (IS_EMPTY_ELEMENT(element))
9751     CopyEmptyElementPropertiesToEditor(element);
9752   else
9753     CopyClassicElementPropertiesToEditor(element);
9754 }
9755
9756 static boolean AskToCopyAndModifyLevelTemplate(void)
9757 {
9758   if (Request("Copy and modify settings from level template?", REQ_ASK))
9759   {
9760     level.use_custom_template = FALSE;
9761
9762     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
9763                  GDI_CHECKED, FALSE, GDI_END);
9764     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
9765                  GDI_CHECKED, FALSE, GDI_END);
9766
9767     return TRUE;
9768   }
9769   else
9770   {
9771     LoadLevelTemplate(-1);      // this resets all element modifications ...
9772
9773     DrawEditModeWindow();       // ... and copies them to 'custom_element'
9774
9775     return FALSE;
9776   }
9777 }
9778
9779 static void CopyCustomElementPropertiesToGame(int element)
9780 {
9781   int i;
9782   int access_type_and_layer;
9783
9784   // mark that this custom element has been modified
9785   custom_element.modified_settings = TRUE;
9786   level.changed = TRUE;
9787
9788   if (level.use_custom_template)
9789     AskToCopyAndModifyLevelTemplate();
9790
9791   element_info[element] = custom_element;
9792   *element_info[element].change = custom_element_change;
9793
9794   // ---------- element settings: configure (custom elements) -----------------
9795
9796   // set accessible property from checkbox and selectbox
9797   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
9798   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
9799   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
9800   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
9801   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
9802   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
9803   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
9804                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
9805                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
9806   custom_element_properties[access_type_and_layer] =
9807     custom_element_properties[EP_ACCESSIBLE];
9808   custom_element_properties[EP_PROTECTED] =
9809     (custom_element.access_protected != 0 &&
9810      custom_element_properties[EP_ACCESSIBLE]);
9811
9812   // set walk-to-object property from checkbox and selectbox
9813   custom_element_properties[EP_DIGGABLE] = FALSE;
9814   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
9815   custom_element_properties[EP_DROPPABLE] = FALSE;
9816   custom_element_properties[EP_THROWABLE] = FALSE;
9817   custom_element_properties[EP_PUSHABLE] = FALSE;
9818   custom_element_properties[custom_element.walk_to_action] =
9819     custom_element_properties[EP_WALK_TO_OBJECT];
9820
9821   // set smash property from checkbox and selectbox
9822   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
9823   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
9824   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
9825   custom_element_properties[custom_element.smash_targets] =
9826     custom_element_properties[EP_CAN_SMASH];
9827
9828   // set deadliness property from checkbox and selectbox
9829   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
9830   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
9831   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
9832   custom_element_properties[EP_DONT_TOUCH] = FALSE;
9833   custom_element_properties[custom_element.deadliness] =
9834     custom_element_properties[EP_DEADLY];
9835
9836   // ---------- element settings: advanced (custom elements) ------------------
9837
9838   // set player change event from checkbox and selectbox
9839   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
9840   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
9841   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
9842   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
9843   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
9844   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
9845   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
9846   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
9847   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
9848   custom_element_change_events[CE_SWITCHED] = FALSE;
9849   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
9850   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
9851   custom_element_change_events[CE_BLOCKED] = FALSE;
9852   custom_element_change_events[CE_IMPACT] = FALSE;
9853   custom_element_change_events[CE_SMASHED] = FALSE;
9854   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
9855   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
9856   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
9857   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
9858   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
9859   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
9860   custom_element_change_events[custom_element_change.direct_action] =
9861     custom_element_change_events[CE_BY_DIRECT_ACTION];
9862
9863   // set other element action change event from checkbox and selectbox
9864   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
9865   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
9866   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
9867   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
9868   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
9869   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
9870   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
9871   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
9872   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
9873   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
9874   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
9875   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
9876   custom_element_change_events[CE_TOUCHING_X] = FALSE;
9877   custom_element_change_events[CE_HITTING_X] = FALSE;
9878   custom_element_change_events[CE_DIGGING_X] = FALSE;
9879   custom_element_change_events[CE_HIT_BY_X] = FALSE;
9880   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
9881   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
9882   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
9883   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
9884   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
9885   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
9886   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
9887   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
9888   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
9889   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
9890   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
9891   custom_element_change_events[custom_element_change.other_action] =
9892     custom_element_change_events[CE_BY_OTHER_ACTION];
9893
9894   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
9895     SET_PROPERTY(element, i, custom_element_properties[i]);
9896
9897   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
9898     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
9899
9900   // copy change events also to special level editor variable
9901   custom_element = element_info[element];
9902   custom_element_change = *element_info[element].change;
9903
9904   // needed here to restore runtime value "element_info[element].gfx_element"
9905   InitElementPropertiesGfxElement();
9906 }
9907
9908 static void CopyGroupElementPropertiesToGame(int element)
9909 {
9910   // mark that this group element has been modified
9911   custom_element.modified_settings = TRUE;
9912   level.changed = TRUE;
9913
9914   if (level.use_custom_template)
9915     AskToCopyAndModifyLevelTemplate();
9916
9917   element_info[element] = custom_element;
9918   *element_info[element].group = group_element_info;
9919
9920   // needed here to restore runtime value "element_info[element].gfx_element"
9921   InitElementPropertiesGfxElement();
9922 }
9923
9924 static void CopyEmptyElementPropertiesToGame(int element)
9925 {
9926   // mark that this empty element has been modified
9927   custom_element.modified_settings = TRUE;
9928   level.changed = TRUE;
9929
9930   if (level.use_custom_template)
9931     AskToCopyAndModifyLevelTemplate();
9932
9933   element_info[element] = custom_element;
9934
9935   // needed here to restore runtime value "element_info[element].gfx_element"
9936   InitElementPropertiesGfxElement();
9937 }
9938
9939 static void CopyClassicElementPropertiesToGame(int element)
9940 {
9941   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
9942     setMoveIntoAcidProperty(&level, element,
9943                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
9944
9945   if (MAYBE_DONT_COLLIDE_WITH(element))
9946     setDontCollideWithProperty(&level, element,
9947                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
9948 }
9949
9950 static void CopyElementPropertiesToGame(int element)
9951 {
9952   if (IS_CUSTOM_ELEMENT(element))
9953     CopyCustomElementPropertiesToGame(element);
9954   else if (IS_GROUP_ELEMENT(element))
9955     CopyGroupElementPropertiesToGame(element);
9956   else if (IS_EMPTY_ELEMENT(element))
9957     CopyEmptyElementPropertiesToGame(element);
9958   else
9959     CopyClassicElementPropertiesToGame(element);
9960 }
9961
9962 #if DEBUG
9963 static void CheckElementDescriptions(void)
9964 {
9965   int i;
9966
9967   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9968     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
9969       Warn("no element description file for element '%s'", EL_NAME(i));
9970 }
9971 #endif
9972
9973 static int getMaxEdFieldX(boolean has_scrollbar)
9974 {
9975   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
9976   int sxsize = SXSIZE - scrollbar_width;
9977   int max_ed_fieldx = sxsize / ed_tilesize;
9978
9979   return max_ed_fieldx;
9980 }
9981
9982 static int getMaxEdFieldY(boolean has_scrollbar)
9983 {
9984   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
9985                          INFOTEXT_YSIZE_FULL : 0);
9986   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
9987   int sysize = SYSIZE - scrollbar_height - infotext_height;
9988   int max_ed_fieldy = sysize / ed_tilesize;
9989
9990   return max_ed_fieldy;
9991 }
9992
9993 static void InitZoomLevelSettings(int zoom_tilesize)
9994 {
9995   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
9996
9997   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
9998   {
9999     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
10000     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
10001
10002     // make sure that tile size is always a power of 2
10003     ed_tilesize = (1 << log_2(ed_tilesize));
10004
10005     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10006     {
10007       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
10008       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
10009     }
10010   }
10011
10012   last_game_engine_type = level.game_engine_type;
10013
10014   // limit zoom tilesize by upper and lower bound
10015   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
10016
10017   // store zoom tilesize in auto setup file only if it was manually changed
10018   if (zoom_tilesize != -1)
10019     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
10020
10021   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
10022   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
10023 }
10024
10025 static void InitDrawingElements(void)
10026 {
10027   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
10028
10029   if (level.game_engine_type == game_engine_type_last)
10030     return;
10031
10032   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10033   {
10034     new_element1 = EL_BD_WALL;
10035     new_element2 = EL_EMPTY;
10036     new_element3 = EL_BD_SAND;
10037   }
10038   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
10039   {
10040     new_element1 = EL_SP_CHIP_SINGLE;
10041     new_element2 = EL_EMPTY;
10042     new_element3 = EL_SP_BASE;
10043   }
10044   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
10045   {
10046     new_element1 = EL_MM_MIRROR_START;
10047     new_element2 = EL_EMPTY;
10048     new_element3 = EL_MM_WOODEN_WALL;
10049   }
10050   else
10051   {
10052     new_element1 = EL_WALL;
10053     new_element2 = EL_EMPTY;
10054     new_element3 = EL_SAND;
10055   }
10056
10057   game_engine_type_last = level.game_engine_type;
10058 }
10059
10060 static void InitLevelSetInfo(void)
10061 {
10062   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
10063            "%s", leveldir_current->name);
10064   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
10065            "%s", leveldir_current->author);
10066
10067   levelset_num_levels = leveldir_current->levels;
10068
10069   levelset_use_levelset_artwork = FALSE;
10070   levelset_copy_level_template = FALSE;
10071
10072   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
10073 }
10074
10075 static void ChangeEditorToLevelSet(char *levelset_subdir)
10076 {
10077   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
10078
10079   // the previous level set might have used custom artwork
10080   ReloadCustomArtwork(0);
10081
10082   LoadLevelSetup_SeriesInfo();
10083
10084   SaveLevelSetup_LastSeries();
10085   SaveLevelSetup_SeriesInfo();
10086
10087   TapeErase();
10088
10089   LoadLevel(level_nr);
10090   LoadScore(level_nr);
10091
10092   DrawLevelEd();
10093 }
10094
10095 static boolean useEditorDoorAnimation(void)
10096 {
10097   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
10098   boolean door_1_viewport_unchanged =
10099     (vp_door_1->x      == DX     &&
10100      vp_door_1->y      == DY     &&
10101      vp_door_1->width  == DXSIZE &&
10102      vp_door_1->height == DYSIZE);
10103   boolean door_1_contains_toolbox =
10104     (EX >= DX &&
10105      EY >= DY &&
10106      EX + EXSIZE <= DX + DXSIZE &&
10107      EY + EYSIZE <= DY + DYSIZE);
10108
10109   return (door_1_viewport_unchanged && door_1_contains_toolbox);
10110 }
10111
10112 static void DrawEditorDoorBackground(int graphic, int x, int y,
10113                                      int width, int height)
10114 {
10115   struct GraphicInfo *g = &graphic_info[graphic];
10116
10117   if (g->bitmap != NULL)
10118     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
10119                MIN(width, g->width), MIN(height, g->height), x, y);
10120   else
10121     ClearRectangle(drawto, x, y, width, height);
10122 }
10123
10124 static void DrawEditorDoorContent(void)
10125 {
10126   // needed for gadgets drawn on background (like palette scrollbar)
10127   SetDoorBackgroundImage(IMG_UNDEFINED);
10128
10129   // copy default editor door content to main double buffer
10130   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
10131
10132   // draw bigger door
10133   DrawSpecialEditorDoor();
10134
10135   // draw new control window
10136   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
10137
10138   // draw all toolbox gadgets to editor doors
10139   MapControlButtons();
10140
10141   // when returning from test game to properties page, redraw toolbox gadgets
10142   if (edit_mode == ED_MODE_PROPERTIES)
10143   {
10144     UnmapLevelEditorToolboxDrawingGadgets();
10145     UnmapLevelEditorToolboxCustomGadgets();
10146
10147     MapLevelEditorToolboxCustomGadgetsIfNeeded();
10148   }
10149
10150   // draw all palette gadgets to editor doors
10151   ModifyEditorElementList();
10152   RedrawDrawingElements();
10153
10154   // copy actual editor door content to door double buffer for OpenDoor()
10155   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
10156 }
10157
10158 void DrawLevelEd(void)
10159 {
10160   int fade_mask = REDRAW_FIELD;
10161
10162   FadeSoundsAndMusic();
10163
10164   if (CheckFadeAll())
10165     fade_mask = REDRAW_ALL;
10166
10167   FadeOut(fade_mask);
10168
10169   // needed if different viewport properties defined for editor
10170   ChangeViewportPropertiesIfNeeded();
10171
10172   ClearField();
10173
10174   InitZoomLevelSettings(-1);
10175   InitDrawingElements();
10176   InitLevelSetInfo();
10177
10178 #if DEBUG
10179   CheckElementDescriptions();
10180 #endif
10181
10182   if (level_editor_test_game)
10183   {
10184     CopyPlayfield(level.field, Tile);
10185     CopyPlayfield(TileBackup, level.field);
10186
10187     level_editor_test_game = FALSE;
10188   }
10189   else
10190   {
10191     edit_mode = ED_MODE_DRAWING;
10192     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
10193     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
10194
10195     ResetUndoBuffer();
10196
10197     level_xpos = -1;
10198     level_ypos = -1;
10199   }
10200
10201   // redraw_mask |= REDRAW_ALL;
10202
10203   FreeLevelEditorGadgets();
10204   CreateLevelEditorGadgets();
10205
10206   ReinitializeElementList();            // update dynamic level element list
10207   ReinitializeElementListButtons();     // custom element may look different
10208
10209   InitElementPropertiesGfxElement();
10210
10211   UnmapAllGadgets();
10212
10213   DrawEditModeWindow_PlayfieldOnly();
10214
10215   DrawMaskedBorder(fade_mask);
10216
10217   // use door animation if door 1 viewport is unchanged and contains toolbox
10218   if (useEditorDoorAnimation())
10219   {
10220     FadeIn(fade_mask);
10221
10222     DrawEditorDoorContent();
10223
10224     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
10225   }
10226   else
10227   {
10228     DrawEditorDoorContent();
10229
10230     FadeIn(fade_mask);
10231   }
10232
10233   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
10234 }
10235
10236 static void AdjustDrawingAreaGadgets(void)
10237 {
10238   int ed_xsize = lev_fieldx + 2;
10239   int ed_ysize = lev_fieldy + 2;
10240   int max_ed_fieldx = MAX_ED_FIELDX;
10241   int max_ed_fieldy = MAX_ED_FIELDY;
10242   boolean horizontal_scrollbar_needed;
10243   boolean vertical_scrollbar_needed;
10244   int x, y, width, height;
10245
10246   if (suppressBorderElement())
10247   {
10248     ed_xsize = lev_fieldx;
10249     ed_ysize = lev_fieldy;
10250   }
10251
10252   // check if we need any scrollbars
10253   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10254   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10255
10256   // check if we have a smaller editor field because of scrollbars
10257   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10258   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10259
10260   // check again if we now need more scrollbars because of less space
10261   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
10262   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
10263
10264   // check if editor field gets even smaller after adding new scrollbars
10265   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
10266   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
10267
10268   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
10269   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
10270
10271   x = SX + ed_fieldx * ed_tilesize;
10272   y = SY + ed_fieldy * ed_tilesize;
10273
10274   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
10275   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
10276
10277   // adjust drawing area gadget
10278   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
10279                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
10280                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
10281                GDI_END);
10282
10283   // adjust horizontal scrollbar gadgets
10284   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
10285                GDI_Y, y,
10286                GDI_END);
10287   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
10288                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
10289                GDI_Y, y,
10290                GDI_END);
10291   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
10292                GDI_Y, y,
10293                GDI_WIDTH, width,
10294                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
10295                GDI_END);
10296
10297   // adjust vertical scrollbar gadgets
10298   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
10299                GDI_X, x,
10300                GDI_END);
10301   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
10302                GDI_X, x,
10303                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
10304                GDI_END);
10305   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
10306                GDI_X, x,
10307                GDI_HEIGHT, height,
10308                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
10309                GDI_END);
10310 }
10311
10312 static void AdjustLevelScrollPosition(void)
10313 {
10314   if (level_xpos < -1)
10315     level_xpos = -1;
10316   if (level_xpos > lev_fieldx - ed_fieldx + 1)
10317     level_xpos = lev_fieldx - ed_fieldx + 1;
10318   if (lev_fieldx < ed_fieldx - 2)
10319     level_xpos = -1;
10320
10321   if (level_ypos < -1)
10322     level_ypos = -1;
10323   if (level_ypos > lev_fieldy - ed_fieldy + 1)
10324     level_ypos = lev_fieldy - ed_fieldy + 1;
10325   if (lev_fieldy < ed_fieldy - 2)
10326     level_ypos = -1;
10327
10328   if (suppressBorderElement())
10329   {
10330     level_xpos = 0;
10331     level_ypos = 0;
10332   }
10333 }
10334
10335 static void AdjustEditorScrollbar(int id)
10336 {
10337   struct GadgetInfo *gi = level_editor_gadget[id];
10338   int items_max, items_visible, item_position;
10339
10340   if (id == GADGET_ID_SCROLL_HORIZONTAL)
10341   {
10342     items_max = MAX(lev_fieldx + 2, ed_fieldx);
10343     items_visible = ed_fieldx;
10344     item_position = level_xpos + 1;
10345   }
10346   else
10347   {
10348     items_max = MAX(lev_fieldy + 2, ed_fieldy);
10349     items_visible = ed_fieldy;
10350     item_position = level_ypos + 1;
10351   }
10352
10353   if (item_position > items_max - items_visible)
10354     item_position = items_max - items_visible;
10355
10356   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10357                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10358 }
10359
10360 static void AdjustElementListScrollbar(void)
10361 {
10362   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
10363   int items_max, items_visible, item_position;
10364
10365   // correct position of element list scrollbar
10366   if (element_shift < 0)
10367     element_shift = 0;
10368   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
10369     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
10370
10371   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
10372   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
10373   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
10374
10375   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
10376                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
10377                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
10378 }
10379
10380 static void ModifyEditorCounterValue(int counter_id, int new_value)
10381 {
10382   int *counter_value = counterbutton_info[counter_id].value;
10383   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10384   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10385
10386   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
10387
10388   if (counter_value != NULL)
10389     *counter_value = gi->textinput.number_value;
10390 }
10391
10392 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
10393 {
10394   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
10395   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10396
10397   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
10398
10399   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
10400       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
10401   {
10402     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
10403     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
10404
10405     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
10406     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
10407                  GDI_END);
10408   }
10409 }
10410
10411 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
10412 {
10413   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10414   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10415   int new_index_value = setSelectboxValue(selectbox_id, new_value);
10416
10417   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
10418 }
10419
10420 static void ModifyEditorSelectboxOptions(int selectbox_id,
10421                                          struct ValueTextInfo *options)
10422 {
10423   int gadget_id = selectbox_info[selectbox_id].gadget_id;
10424   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10425
10426   selectbox_info[selectbox_id].options = options;
10427
10428   // set index to zero -- list may be shorter now (correct later, if needed)
10429   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
10430                GDI_SELECTBOX_OPTIONS, options, GDI_END);
10431 }
10432
10433 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
10434 {
10435   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
10436   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10437
10438   drawingarea_info[drawingarea_id].area_xsize = xsize;
10439   drawingarea_info[drawingarea_id].area_ysize = ysize;
10440
10441   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
10442 }
10443
10444 static void ModifyEditorElementList(void)
10445 {
10446   int i;
10447
10448   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
10449     return;
10450
10451   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10452   {
10453     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
10454     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10455     struct GadgetDesign *gd = &gi->deco.design;
10456     int element = editor_elements[element_shift + i];
10457     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
10458
10459     UnmapGadget(gi);
10460
10461     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
10462
10463     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
10464
10465     MapGadget(gi);
10466   }
10467 }
10468
10469 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
10470 {
10471   int graphic = el2edimg(element);
10472   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
10473
10474   if (pos->x == -1 &&
10475       pos->y == -1)
10476     return;
10477
10478   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
10479 }
10480
10481 static void ModifyDrawingElementButton(int element, int id)
10482 {
10483   struct GadgetInfo *gi = level_editor_gadget[id];
10484   Bitmap *deco_bitmap;
10485   int deco_x, deco_y;
10486   int tile_size = gi->deco.width;
10487
10488   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
10489
10490   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
10491 }
10492
10493 static void PickDrawingElement(int button, int element)
10494 {
10495   struct
10496   {
10497     int *new_element;
10498     struct XYTileSize *pos;
10499     int id;
10500   } de, drawing_elements[] =
10501   {
10502     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
10503     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
10504     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
10505   };
10506
10507   if (button < 1 || button > 3)
10508     return;
10509
10510   if (IS_MM_WALL(element))
10511     element = map_mm_wall_element(element);
10512
10513   de = drawing_elements[button - 1];
10514
10515   *de.new_element = element;    // update global drawing element variable
10516
10517   DrawDrawingElementGraphic(element, de.pos);
10518   ModifyDrawingElementButton(element, de.id);
10519
10520   redraw_mask |= REDRAW_DOOR_1;
10521 }
10522
10523 static void RedrawDrawingElements(void)
10524 {
10525   PickDrawingElement(1, new_element1);
10526   PickDrawingElement(2, new_element2);
10527   PickDrawingElement(3, new_element3);
10528 }
10529
10530 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
10531 {
10532   stick_element_properties_window = FALSE;
10533
10534   SetMainBackgroundImage(IMG_UNDEFINED);
10535   ClearField();
10536
10537   UnmapLevelEditorFieldGadgets();
10538
10539   AdjustDrawingAreaGadgets();
10540   AdjustLevelScrollPosition();
10541   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
10542   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
10543
10544   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10545
10546   MapMainDrawingArea();
10547
10548   if (remap_toolbox_gadgets)
10549   {
10550     UnmapLevelEditorToolboxCustomGadgets();
10551     MapLevelEditorToolboxDrawingGadgets();
10552   }
10553 }
10554
10555 static void DrawDrawingWindow(void)
10556 {
10557   DrawDrawingWindowExt(TRUE);
10558 }
10559
10560 static int getTabulatorBarWidth(void)
10561 {
10562   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10563   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
10564
10565   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
10566 }
10567
10568 static int getTabulatorBarHeight(void)
10569 {
10570   return ED_TAB_BAR_HEIGHT;
10571 }
10572
10573 static Pixel getTabulatorBarColor(void)
10574 {
10575   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10576   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10577   int gd_x = gd->x + gd_gi1->border.width / 2;
10578   int gd_y = gd->y + gd_gi1->height - 1;
10579
10580   return GetPixel(gd->bitmap, gd_x, gd_y);
10581 }
10582
10583 static void DrawLevelConfigTabulatorGadgets(void)
10584 {
10585   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
10586   Pixel tab_color = getTabulatorBarColor();
10587   int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
10588   int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
10589   int i;
10590
10591   // draw additional "engine" tabulator when using native BD engine
10592   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
10593     id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
10594
10595   for (i = id_first; i <= id_last; i++)
10596   {
10597     int gadget_id = textbutton_info[i].gadget_id;
10598     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10599     boolean active = (i != edit_mode_levelconfig);
10600
10601     // draw background line below tabulator button
10602     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10603
10604     // draw solid line below inactive tabulator buttons
10605     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10606       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10607                     ED_GADGET_TINY_DISTANCE, tab_color);
10608
10609     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10610     MapTextbuttonGadget(i);
10611   }
10612
10613   // draw little border line below tabulator buttons
10614   if (tab_color != BLACK_PIXEL)                 // black => transparent
10615     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10616                   ED_GADGET_TINY_DISTANCE,
10617                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10618 }
10619
10620 static void DrawPropertiesTabulatorGadgets(void)
10621 {
10622   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10623   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10624   int gd_x = gd->x + gd_gi1->border.width / 2;
10625   int gd_y = gd->y + gd_gi1->height - 1;
10626   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10627   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
10628   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
10629   int i;
10630
10631   // draw two config tabulators for player elements
10632   if (IS_PLAYER_ELEMENT(properties_element))
10633     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
10634
10635   // draw two config and one "change" tabulator for custom elements
10636   if (IS_CUSTOM_ELEMENT(properties_element))
10637     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
10638
10639   for (i = id_first; i <= id_last; i++)
10640   {
10641     int gadget_id = textbutton_info[i].gadget_id;
10642     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
10643     boolean active = (i != edit_mode_properties);
10644
10645     // use "config 1" and "config 2" instead of "config" for players and CEs
10646     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
10647         (IS_PLAYER_ELEMENT(properties_element) ||
10648          IS_CUSTOM_ELEMENT(properties_element)))
10649       continue;
10650
10651     // draw background line below tabulator button
10652     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
10653
10654     // draw solid line below inactive tabulator buttons
10655     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
10656       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
10657                     ED_GADGET_TINY_DISTANCE, tab_color);
10658
10659     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
10660     MapTextbuttonGadget(i);
10661   }
10662
10663   // draw little border line below tabulator buttons
10664   if (tab_color != BLACK_PIXEL)                 // black => transparent
10665     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
10666                   ED_GADGET_TINY_DISTANCE,
10667                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10668 }
10669
10670 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
10671 {
10672   DrawText(SX + xpos, SY + ypos, text, font_nr);
10673 }
10674
10675 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
10676                                            int xpos, int ypos)
10677 {
10678   int font_width = getFontWidth(font_nr);
10679   int font_height = getFontHeight(font_nr);
10680   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
10681   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
10682
10683   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
10684                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
10685                       TRUE, FALSE, FALSE);
10686 }
10687
10688 static void DrawLevelConfigLevel(void)
10689 {
10690   int i;
10691
10692   // draw counter gadgets
10693   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
10694     MapCounterButtons(i);
10695
10696   // draw checkbutton gadgets
10697   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
10698     MapCheckbuttonGadget(i);
10699
10700   // draw selectbox gadgets
10701   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
10702     MapSelectboxGadget(i);
10703
10704   // draw text input gadgets
10705   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
10706     MapTextInputGadget(i);
10707 }
10708
10709 static char *getLevelSubdirFromSaveMode(int save_mode)
10710 {
10711   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
10712     return getNewUserLevelSubdir();
10713
10714   return leveldir_current->subdir;
10715 }
10716
10717 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
10718 {
10719   char *directory_text = "Level set directory:";
10720   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
10721   int font1_nr = FONT_TEXT_1;
10722   int font2_nr = FONT_TEXT_2;
10723   int font1_height = getFontHeight(font1_nr);
10724   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
10725   int x = ED_LEVEL_SETTINGS_X(0);
10726   int y = ED_LEVEL_SETTINGS_Y(6);
10727
10728   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
10729   PrintInfoText(directory_name, font2_nr, x, y);
10730 }
10731
10732 static void DrawLevelConfigLevelSet(void)
10733 {
10734   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
10735   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
10736   int i;
10737
10738   // draw counter gadgets
10739   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
10740     MapCounterButtons(i);
10741
10742   // draw checkbutton gadgets
10743   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
10744   {
10745     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
10746         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
10747         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
10748       continue;
10749
10750     MapCheckbuttonGadget(i);
10751   }
10752
10753   // draw selectbox gadgets
10754   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
10755     MapSelectboxGadget(i);
10756
10757   // draw text input gadgets
10758   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
10759     MapTextInputGadget(i);
10760
10761   // draw textbutton gadgets
10762   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
10763
10764   // draw info text
10765   DrawLevelConfigLevelSet_DirectoryInfo();
10766 }
10767
10768 static void DrawLevelConfigEditor(void)
10769 {
10770   int i;
10771
10772   // draw counter gadgets
10773   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
10774     MapCounterButtons(i);
10775
10776   // draw checkbutton gadgets
10777   for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
10778     MapCheckbuttonGadget(i);
10779
10780   // draw radiobutton gadgets
10781   for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
10782     MapRadiobuttonGadget(i);
10783
10784   // draw drawing area
10785   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
10786
10787   // draw textbutton gadgets
10788   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
10789 }
10790
10791 static void DrawLevelConfigEngine(void)
10792 {
10793   int i;
10794
10795   // draw counter gadgets
10796   if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
10797   {
10798     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
10799     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
10800   }
10801   else
10802   {
10803     MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
10804     MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
10805   }
10806
10807   // draw checkbutton gadgets
10808   for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
10809     MapCheckbuttonGadget(i);
10810
10811   // draw selectbox gadgets
10812   for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
10813     MapSelectboxGadget(i);
10814 }
10815
10816 static void DrawLevelConfigWindow(void)
10817 {
10818   char *text = "Global Settings";
10819   int font_nr = FONT_TITLE_1;
10820   struct MenuPosInfo *pos = &editor.settings.headline;
10821   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
10822   int sy = SY + pos->y;
10823
10824   stick_element_properties_window = FALSE;
10825
10826   SetAutomaticNumberOfGemsNeeded();
10827
10828   UnmapLevelEditorFieldGadgets();
10829
10830   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
10831   ClearField();
10832
10833   DrawText(sx, sy, text, font_nr);
10834
10835   DrawLevelConfigTabulatorGadgets();
10836
10837   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
10838     DrawLevelConfigLevel();
10839   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
10840     DrawLevelConfigLevelSet();
10841   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
10842     DrawLevelConfigEditor();
10843   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
10844     DrawLevelConfigEngine();
10845 }
10846
10847 static void DrawCustomContentArea(void)
10848 {
10849   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
10850   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
10851   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
10852   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
10853   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
10854   int xoffset = ED_GADGET_SPACE_DISTANCE;
10855
10856   // add distance for potential left text (without drawing area border)
10857   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
10858
10859   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
10860
10861   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
10862 }
10863
10864 static void DrawCustomChangeContentArea(void)
10865 {
10866   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
10867   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
10868   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
10869   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
10870   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
10871   int xoffset = ED_GADGET_SPACE_DISTANCE;
10872
10873   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
10874
10875   MapDrawingArea(id);
10876 }
10877
10878 static void RemoveElementContentArea(int id, int font_height)
10879 {
10880   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
10881
10882   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
10883                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
10884                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
10885                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
10886                  ED_GADGET_TEXT_DISTANCE + font_height);
10887 }
10888
10889 static void DrawYamYamContentAreas(void)
10890 {
10891   int font_nr = FONT_TEXT_1;
10892   int font_height = getFontHeight(font_nr);
10893   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
10894   int yoffset = (tilesize - font_height) / 2;
10895   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
10896   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
10897   int i;
10898
10899   // display counter to choose number of element content areas
10900   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
10901
10902   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
10903   {
10904     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
10905
10906     if (i < level.num_yamyam_contents)
10907     {
10908       MapDrawingArea(id);
10909     }
10910     else
10911     {
10912       UnmapDrawingArea(id);
10913
10914       // delete content areas in case of reducing number of them
10915       RemoveElementContentArea(id, font_height);
10916     }
10917   }
10918
10919   DrawText(x, y + 0 * tilesize, "content", font_nr);
10920   DrawText(x, y + 1 * tilesize, "when",    font_nr);
10921   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
10922 }
10923
10924 static void DrawMagicBallContentAreas(void)
10925 {
10926   int font_nr = FONT_TEXT_1;
10927   int font_height = getFontHeight(font_nr);
10928   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
10929   int yoffset = (tilesize - font_height) / 2;
10930   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
10931   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
10932   int i;
10933
10934   // display counter to choose number of element content areas
10935   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
10936
10937   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
10938   {
10939     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
10940
10941     if (i < level.num_ball_contents)
10942     {
10943       MapDrawingArea(id);
10944     }
10945     else
10946     {
10947       UnmapDrawingArea(id);
10948
10949       // delete content areas in case of reducing number of them
10950       RemoveElementContentArea(id, font_height);
10951     }
10952   }
10953
10954   DrawText(x, y + 0 * tilesize, "generated", font_nr);
10955   DrawText(x, y + 1 * tilesize, "when",      font_nr);
10956   DrawText(x, y + 2 * tilesize, "active",    font_nr);
10957 }
10958
10959 static void DrawAndroidElementArea(void)
10960 {
10961   int id = ED_DRAWING_ID_ANDROID_CONTENT;
10962   int num_elements = level.num_android_clone_elements;
10963   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
10964   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
10965   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
10966   int xsize = MAX_ANDROID_ELEMENTS;
10967   int ysize = 1;
10968
10969   // display counter to choose number of element areas
10970   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
10971
10972   if (drawingarea_info[id].text_left != NULL)
10973     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
10974
10975   UnmapDrawingArea(id);
10976
10977   ModifyEditorDrawingArea(id, num_elements, 1);
10978
10979   // delete content areas in case of reducing number of them
10980   DrawBackground(sx, sy,
10981                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
10982                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
10983
10984   MapDrawingArea(id);
10985 }
10986
10987 static void DrawGroupElementArea(void)
10988 {
10989   int id = ED_DRAWING_ID_GROUP_CONTENT;
10990   int num_elements = group_element_info.num_elements;
10991   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
10992   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
10993   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
10994   int xsize = MAX_ELEMENTS_IN_GROUP;
10995   int ysize = 1;
10996
10997   if (drawingarea_info[id].text_left != NULL)
10998     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
10999
11000   UnmapDrawingArea(id);
11001
11002   ModifyEditorDrawingArea(id, num_elements, 1);
11003
11004   // delete content areas in case of reducing number of them
11005   DrawBackground(sx, sy,
11006                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11007                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11008
11009   MapDrawingArea(id);
11010 }
11011
11012 static void DrawPlayerInitialInventoryArea(int element)
11013 {
11014   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
11015   int player_nr = GET_PLAYER_NR(element);
11016   int num_elements = level.initial_inventory_size[player_nr];
11017   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11018   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11019   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11020   int xsize = MAX_INITIAL_INVENTORY_SIZE;
11021   int ysize = 1;
11022
11023   // determine horizontal position to the right of specified gadget
11024   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
11025     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
11026           ED_DRAWINGAREA_TEXT_DISTANCE);
11027
11028   // determine horizontal offset for leading text
11029   if (drawingarea_info[id].text_left != NULL)
11030     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11031
11032   UnmapDrawingArea(id);
11033
11034   ModifyEditorDrawingArea(id, num_elements, 1);
11035
11036   // delete content areas in case of reducing number of them
11037   DrawBackground(sx, sy,
11038                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11039                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11040
11041   MapDrawingArea(id);
11042 }
11043
11044 static void DrawMMBallContentArea(void)
11045 {
11046   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
11047   int num_elements = level.num_mm_ball_contents;
11048   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
11049   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
11050   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
11051   int xsize = MAX_MM_BALL_CONTENTS;
11052   int ysize = 1;
11053
11054   if (drawingarea_info[id].text_left != NULL)
11055     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
11056
11057   UnmapDrawingArea(id);
11058
11059   ModifyEditorDrawingArea(id, num_elements, 1);
11060
11061   // delete content areas in case of reducing number of them
11062   DrawBackground(sx, sy,
11063                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
11064                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
11065
11066   MapDrawingArea(id);
11067 }
11068
11069 static void DrawEnvelopeTextArea(int envelope_nr)
11070 {
11071   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
11072   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
11073
11074   UnmapGadget(gi);
11075
11076   DrawBackground(gi->x, gi->y,
11077                  gi->textarea.crop_width, gi->textarea.crop_height);
11078
11079   if (envelope_nr != -1)
11080     textarea_info[id].value = level.envelope[envelope_nr].text;
11081
11082   ModifyGadget(gi, GDI_AREA_SIZE,
11083                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
11084                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
11085                GDI_END);
11086
11087   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
11088 }
11089
11090 static void DrawPropertiesInfo(void)
11091 {
11092   static struct
11093   {
11094     int value;
11095     char *text;
11096   }
11097   properties[] =
11098   {
11099     // configurable properties
11100
11101     { EP_WALKABLE_OVER,         "- player can walk over it"             },
11102     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
11103     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
11104     { EP_PASSABLE_OVER,         "- player can pass over it"             },
11105     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
11106     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
11107     { EP_PROTECTED,             "- player is protected by it"           },
11108
11109     { EP_DIGGABLE,              "- can be digged away"                  },
11110     { EP_COLLECTIBLE,           "- can be collected"                    },
11111     { EP_DROPPABLE,             "- can be dropped after collecting"     },
11112     { EP_THROWABLE,             "- can be thrown after collecting"      },
11113     { EP_PUSHABLE,              "- can be pushed"                       },
11114
11115     { EP_CAN_FALL,              "- can fall"                            },
11116     { EP_CAN_MOVE,              "- can move"                            },
11117
11118     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
11119 #if 0
11120     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
11121 #endif
11122     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
11123
11124     { EP_SLIPPERY,              "- slippery for falling elements"       },
11125     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
11126
11127     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
11128     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
11129     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
11130     { EP_DONT_TOUCH,            "- deadly when touching"                },
11131
11132     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
11133
11134     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
11135     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
11136     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
11137
11138     { EP_CAN_CHANGE,            "- can change to other element"         },
11139
11140     // pre-defined properties
11141     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
11142     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
11143     { EP_SWITCHABLE,            "- can be switched"                     },
11144 #if 0
11145     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
11146 #endif
11147
11148     { -1,                       NULL                                    }
11149   };
11150   char *filename = getElementDescriptionFilename(properties_element);
11151   char *num_elements_text = "In this level: ";
11152   char *num_similar_text = "Similar tiles: ";
11153   char *properties_text = "Standard properties: ";
11154   char *description_text = "Description:";
11155   char *no_description_text = "No description available.";
11156   char *none_text = "None";
11157   float percentage;
11158   int num_elements_in_level = 0;
11159   int num_similar_in_level = 0;
11160   int num_hires_tiles_in_level = 0;
11161   int num_standard_properties = 0;
11162   int font1_nr = FONT_TEXT_1;
11163   int font2_nr = FONT_TEXT_2;
11164   int font1_width = getFontWidth(font1_nr);
11165   int font1_height = getFontHeight(font1_nr);
11166   int font2_height = getFontHeight(font2_nr);
11167   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
11168   int font2_yoffset = (font1_height - font2_height) / 2;
11169   int num_elements_text_len = strlen(num_elements_text) * font1_width;
11170   int num_similar_text_len = strlen(num_similar_text) * font1_width;
11171   int properties_text_len = strlen(properties_text) * font1_width;
11172   int xpos = ED_ELEMENT_SETTINGS_X(0);
11173   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11174   int i, x, y;
11175
11176   if (setup.editor.show_element_token)
11177   {
11178     int font3_nr = FONT_TEXT_3;
11179     int font3_height = getFontHeight(font3_nr);
11180
11181     DrawTextF(xpos, ypos, font3_nr,
11182               "[%s]", element_info[properties_element].token_name);
11183
11184     ypos += 2 * font3_height;
11185   }
11186
11187   // ----- print number of elements / percentage of this element in level
11188
11189   for (y = 0; y < lev_fieldy; y++)
11190   {
11191     for (x = 0; x < lev_fieldx; x++)
11192     {
11193       if (Tile[x][y] == properties_element)
11194       {
11195         num_elements_in_level++;
11196       }
11197       else if (IS_MM_WALL(Tile[x][y]) &&
11198                map_mm_wall_element(Tile[x][y]) == properties_element)
11199       {
11200         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
11201       }
11202     }
11203   }
11204
11205   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11206
11207   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
11208
11209   if (num_hires_tiles_in_level > 0)
11210     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11211               "%d wall tiles", num_hires_tiles_in_level);
11212   else if (num_elements_in_level > 0)
11213     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11214               "%d (%.2f %%)", num_elements_in_level, percentage);
11215   else
11216     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
11217               none_text);
11218
11219   // ----- print number of similar elements / percentage of them in level
11220
11221   for (y = 0; y < lev_fieldy; y++)
11222   {
11223     for (x = 0; x < lev_fieldx; x++)
11224     {
11225       if (strEqual(element_info[Tile[x][y]].class_name,
11226                    element_info[properties_element].class_name))
11227       {
11228         num_similar_in_level++;
11229       }
11230     }
11231   }
11232
11233   if (num_similar_in_level != num_elements_in_level)
11234   {
11235     ypos += 1 * MAX(font1_height, font2_height);
11236
11237     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
11238
11239     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
11240
11241     if (num_similar_in_level > 0)
11242       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11243                 "%d (%.2f %%)", num_similar_in_level, percentage);
11244     else
11245       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
11246                 none_text);
11247   }
11248
11249   ypos += 2 * MAX(font1_height, font2_height);
11250
11251   // ----- print standard properties of this element
11252
11253   DrawTextS(xpos, ypos, font1_nr, properties_text);
11254
11255   ypos += line1_height;
11256
11257   for (i = 0; properties[i].value != -1; i++)
11258   {
11259     if (!HAS_PROPERTY(properties_element, properties[i].value))
11260       continue;
11261
11262     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
11263
11264     ypos += font2_height;
11265
11266     num_standard_properties++;
11267   }
11268
11269   if (num_standard_properties == 0)
11270   {
11271     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
11272               font2_nr, none_text);
11273
11274     ypos -= (line1_height - font1_height);
11275   }
11276
11277   ypos += MAX(font1_height, font2_height);
11278
11279   // ----- print special description of this element
11280
11281   PrintInfoText(description_text, font1_nr, xpos, ypos);
11282
11283   ypos += line1_height;
11284
11285   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
11286     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
11287 }
11288
11289 #define TEXT_COLLECTING                 "Score for collecting"
11290 #define TEXT_COLLECTING_EXTRA           "Score for extra diamonds"
11291 #define TEXT_SMASHING                   "Score for smashing"
11292 #define TEXT_SLURPING                   "Score for slurping robot"
11293 #define TEXT_CRACKING                   "Score for cracking"
11294 #define TEXT_AMOEBA_SPEED               "Speed of amoeba growth"
11295 #define TEXT_AMOEBA_THRESHOED           "Size for turning to rocks"
11296 #define TEXT_AMOEBA_SLOW_TIME           "Slow growth time (seconds)"
11297 #define TEXT_AMOEBA_SLOW_RATE           "Slow growth rate (percent)"
11298 #define TEXT_AMOEBA_FAST_RATE           "Fast growth rate (percent)"
11299 #define TEXT_DURATION                   "Duration when activated"
11300 #define TEXT_DELAY_ON                   "Delay before activating"
11301 #define TEXT_DELAY_OFF                  "Delay before deactivating"
11302 #define TEXT_DELAY_CHANGING             "Delay before changing"
11303 #define TEXT_DELAY_EXPLODING            "Delay before exploding"
11304 #define TEXT_DELAY_MOVING               "Delay before moving"
11305 #define TEXT_BALL_DELAY                 "Element generation delay"
11306 #define TEXT_MOVE_SPEED                 "Speed of android moving"
11307 #define TEXT_CLONE_SPEED                "Speed of android cloning"
11308 #define TEXT_GAME_OF_LIFE_1             "Min neighbours to survive"
11309 #define TEXT_GAME_OF_LIFE_2             "Max neighbours to survive"
11310 #define TEXT_GAME_OF_LIFE_3             "Min neighbours to create"
11311 #define TEXT_GAME_OF_LIFE_4             "Max neighbours to create"
11312 #define TEXT_TIME_BONUS                 "Extra time to solve level"
11313 #define TEXT_TIME_PENALTY               "Time penalty if destroyed"
11314 #define TEXT_PERMEABILITY_RATE          "slime permeability rate"
11315 #define TEXT_PERMEABILITY_BITS          "slime permeability bits"
11316 #define TEXT_RANDOM_SEED                "slime random number seed"
11317 #define TEXT_ACID_SPREAD_RATE           "Spread rate (percent)"
11318 #define TEXT_BITER_MOVE_DELAY           "Move delay (BD frames)"
11319 #define TEXT_REPLICATION_DELAY          "Create delay (BD frames)"
11320 #define TEXT_HAMMER_BREAK_DELAY         "Delay for breaking walls"
11321 #define TEXT_HAMMER_REAPPEAR_DELAY      "Delay for reappearing walls"
11322 #define TEXT_SKELETONS_NEEDED           "Skeletons needed to use pot"
11323 #define TEXT_SKELETONS_WORTH            "Counts as this many diamonds"
11324
11325 static struct
11326 {
11327   int element;
11328   int *value;
11329   char *text;
11330   int min_value;
11331   int max_value;
11332 } elements_with_counter[] =
11333 {
11334   { EL_EMERALD,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11335   { EL_BD_DIAMOND,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11336   { EL_BD_DIAMOND,              &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
11337   { EL_EMERALD_YELLOW,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11338   { EL_EMERALD_RED,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11339   { EL_EMERALD_PURPLE,          &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11340   { EL_SP_INFOTRON,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11341   { EL_DIAMOND,                 &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
11342   { EL_CRYSTAL,                 &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
11343   { EL_PEARL,                   &level.score[SC_PEARL],                 TEXT_COLLECTING         },
11344   { EL_BUG,                     &level.score[SC_BUG],                   TEXT_SMASHING           },
11345   { EL_BUG_RIGHT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
11346   { EL_BUG_UP,                  &level.score[SC_BUG],                   TEXT_SMASHING           },
11347   { EL_BUG_LEFT,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11348   { EL_BUG_DOWN,                &level.score[SC_BUG],                   TEXT_SMASHING           },
11349   { EL_BD_BUTTERFLY,            &level.score[SC_BUG],                   TEXT_SMASHING           },
11350   { EL_BD_BUTTERFLY_RIGHT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
11351   { EL_BD_BUTTERFLY_UP,         &level.score[SC_BUG],                   TEXT_SMASHING           },
11352   { EL_BD_BUTTERFLY_LEFT,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11353   { EL_BD_BUTTERFLY_DOWN,       &level.score[SC_BUG],                   TEXT_SMASHING           },
11354   { EL_SP_ELECTRON,             &level.score[SC_BUG],                   TEXT_SMASHING           },
11355   { EL_SPACESHIP,               &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11356   { EL_SPACESHIP_RIGHT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11357   { EL_SPACESHIP_UP,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11358   { EL_SPACESHIP_LEFT,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11359   { EL_SPACESHIP_DOWN,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11360   { EL_BD_FIREFLY,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11361   { EL_BD_FIREFLY_RIGHT,        &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11362   { EL_BD_FIREFLY_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11363   { EL_BD_FIREFLY_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11364   { EL_BD_FIREFLY_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11365   { EL_SP_SNIKSNAK,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
11366   { EL_YAMYAM,                  &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11367   { EL_YAMYAM_LEFT,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11368   { EL_YAMYAM_RIGHT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11369   { EL_YAMYAM_UP,               &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11370   { EL_YAMYAM_DOWN,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11371   { EL_DARK_YAMYAM,             &level.score[SC_YAMYAM],                TEXT_SMASHING           },
11372   { EL_ROBOT,                   &level.score[SC_ROBOT],                 TEXT_SMASHING           },
11373   { EL_PACMAN,                  &level.score[SC_PACMAN],                TEXT_SMASHING           },
11374   { EL_PACMAN_RIGHT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11375   { EL_PACMAN_UP,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11376   { EL_PACMAN_LEFT,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11377   { EL_PACMAN_DOWN,             &level.score[SC_PACMAN],                TEXT_SMASHING           },
11378   { EL_NUT,                     &level.score[SC_NUT],                   TEXT_CRACKING           },
11379   { EL_DYNAMITE,                &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11380   { EL_EM_DYNAMITE,             &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11381   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11382   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11383   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
11384   { EL_SHIELD_NORMAL,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11385   { EL_SHIELD_DEADLY,           &level.score[SC_SHIELD],                TEXT_COLLECTING         },
11386   { EL_EXTRA_TIME,              &level.extra_time_score,                TEXT_COLLECTING         },
11387   { EL_KEY_1,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11388   { EL_KEY_2,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11389   { EL_KEY_3,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11390   { EL_KEY_4,                   &level.score[SC_KEY],                   TEXT_COLLECTING         },
11391   { EL_EM_KEY_1,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11392   { EL_EM_KEY_2,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11393   { EL_EM_KEY_3,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11394   { EL_EM_KEY_4,                &level.score[SC_KEY],                   TEXT_COLLECTING         },
11395   { EL_EMC_KEY_5,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11396   { EL_EMC_KEY_6,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11397   { EL_EMC_KEY_7,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11398   { EL_EMC_KEY_8,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
11399   { EL_DC_KEY_WHITE,            &level.score[SC_KEY],                   TEXT_COLLECTING         },
11400   { EL_MM_KETTLE,               &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11401   { EL_DF_CELL,                 &level.score[SC_EMERALD],               TEXT_COLLECTING         },
11402   { EL_MM_KEY,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
11403   { EL_MM_LIGHTBALL,            &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
11404   { EL_MM_PACMAN,               &level.score[SC_PACMAN],                TEXT_SMASHING           },
11405   { EL_MM_PACMAN_RIGHT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
11406   { EL_MM_PACMAN_UP,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
11407   { EL_MM_PACMAN_LEFT,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11408   { EL_MM_PACMAN_DOWN,          &level.score[SC_PACMAN],                TEXT_SMASHING           },
11409   { EL_AMOEBA_WET,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11410   { EL_AMOEBA_DRY,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11411   { EL_AMOEBA_FULL,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11412   { EL_BD_AMOEBA,               &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11413   { EL_EMC_DRIPPER,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
11414   { EL_BD_AMOEBA,               &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
11415   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
11416   { EL_BD_AMOEBA,               &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
11417                                 0, 100                                                          },
11418   { EL_BD_AMOEBA,               &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
11419                                 0, 100                                                          },
11420   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
11421   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
11422   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
11423                                 0, 100                                                          },
11424   { EL_BD_AMOEBA_2,             &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
11425                                 0, 100                                                          },
11426   { EL_MAGIC_WALL,              &level.time_magic_wall,                 TEXT_DURATION           },
11427   { EL_BD_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11428   { EL_DC_MAGIC_WALL,           &level.time_magic_wall,                 TEXT_DURATION           },
11429   { EL_ROBOT_WHEEL,             &level.time_wheel,                      TEXT_DURATION           },
11430   { EL_TIMEGATE_SWITCH,         &level.time_timegate,                   TEXT_DURATION           },
11431   { EL_DC_TIMEGATE_SWITCH,      &level.time_timegate,                   TEXT_DURATION           },
11432   { EL_LIGHT_SWITCH,            &level.time_light,                      TEXT_DURATION           },
11433   { EL_LIGHT_SWITCH_ACTIVE,     &level.time_light,                      TEXT_DURATION           },
11434   { EL_SHIELD_NORMAL,           &level.shield_normal_time,              TEXT_DURATION           },
11435   { EL_SHIELD_DEADLY,           &level.shield_deadly_time,              TEXT_DURATION           },
11436   { EL_BD_CLOCK,                &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
11437                                 -100, 100                                                       },
11438   { EL_BD_VOODOO_DOLL,          &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
11439                                 0, 100                                                          },
11440   { EL_BD_SLIME,                &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
11441                                 0, 100                                                          },
11442   { EL_BD_SLIME,                &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
11443                                 0, 255                                                          },
11444   { EL_BD_SLIME,                &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
11445                                 -1, 65535                                                       },
11446   { EL_BD_ACID,                 &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
11447                                 0, 100                                                          },
11448   { EL_BD_BITER,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11449                                 0, 3                                                            },
11450   { EL_BD_BITER_RIGHT,          &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11451                                 0, 3                                                            },
11452   { EL_BD_BITER_UP,             &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11453                                 0, 3                                                            },
11454   { EL_BD_BITER_LEFT,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11455                                 0, 3                                                            },
11456   { EL_BD_BITER_DOWN,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
11457                                 0, 3                                                            },
11458   { EL_BD_REPLICATOR,           &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
11459                                 0, 100                                                          },
11460   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
11461                                 1, 100                                                          },
11462   { EL_BD_PNEUMATIC_HAMMER,     &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
11463                                 1, 200                                                          },
11464   { EL_BD_POT,                  &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11465                                 0, 50                                                           },
11466   { EL_BD_SKELETON,             &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
11467                                 0, 50                                                           },
11468   { EL_BD_SKELETON,             &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
11469                                 0, 10                                                           },
11470   { EL_EXTRA_TIME,              &level.extra_time,                      TEXT_TIME_BONUS         },
11471   { EL_TIME_ORB_FULL,           &level.time_orb_time,                   TEXT_TIME_BONUS         },
11472   { EL_GAME_OF_LIFE,            &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
11473   { EL_GAME_OF_LIFE,            &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
11474   { EL_GAME_OF_LIFE,            &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
11475   { EL_GAME_OF_LIFE,            &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
11476   { EL_BIOMAZE,                 &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
11477   { EL_BIOMAZE,                 &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
11478   { EL_BIOMAZE,                 &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
11479   { EL_BIOMAZE,                 &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
11480   { EL_EMC_ANDROID,             &level.android_move_time,               TEXT_MOVE_SPEED         },
11481   { EL_EMC_ANDROID,             &level.android_clone_time,              TEXT_CLONE_SPEED        },
11482   { EL_EMC_MAGIC_BALL,          &level.ball_time,                       TEXT_BALL_DELAY         },
11483   { EL_EMC_LENSES,              &level.lenses_score,                    TEXT_COLLECTING         },
11484   { EL_EMC_MAGNIFIER,           &level.magnify_score,                   TEXT_COLLECTING         },
11485   { EL_SPRING,                  &level.slurp_score,                     TEXT_SLURPING           },
11486   { EL_SPRING_LEFT,             &level.slurp_score,                     TEXT_SLURPING           },
11487   { EL_SPRING_RIGHT,            &level.slurp_score,                     TEXT_SLURPING           },
11488   { EL_EMC_LENSES,              &level.lenses_time,                     TEXT_DURATION           },
11489   { EL_EMC_MAGNIFIER,           &level.magnify_time,                    TEXT_DURATION           },
11490   { EL_MM_FUSE_ACTIVE,          &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
11491   { EL_MM_BOMB,                 &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
11492   { EL_MM_GRAY_BALL,            &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
11493   { EL_MM_STEEL_BLOCK,          &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11494   { EL_MM_WOODEN_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
11495
11496   { -1,                         NULL,                                   NULL                    }
11497 };
11498
11499 static boolean checkPropertiesConfig(int element)
11500 {
11501   int i;
11502
11503   // special case: empty space customization only available in R'n'D game engine
11504   if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
11505     return FALSE;
11506
11507   // special case: BD style rock customization only available in BD game engine
11508   if (element == EL_BD_ROCK && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11509     return FALSE;
11510
11511   if (IS_GEM(element) ||
11512       IS_CUSTOM_ELEMENT(element) ||
11513       IS_GROUP_ELEMENT(element) ||
11514       IS_EMPTY_ELEMENT(element) ||
11515       IS_BALLOON_ELEMENT(element) ||
11516       IS_ENVELOPE(element) ||
11517       IS_MM_ENVELOPE(element) ||
11518       IS_MM_MCDUFFIN(element) ||
11519       IS_DF_LASER(element) ||
11520       IS_PLAYER_ELEMENT(element) ||
11521       IS_BD_PLAYER_ELEMENT(element) ||
11522       IS_BD_EXPANDABLE_WALL(properties_element) ||
11523       IS_BD_EXPANDABLE_STEELWALL(properties_element) ||
11524       IS_BD_CONVEYOR_BELT(properties_element) ||
11525       IS_BD_CONVEYOR_BELT_SWITCH(properties_element) ||
11526       IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
11527       HAS_EDITOR_CONTENT(element) ||
11528       CAN_GROW(element) ||
11529       COULD_MOVE_INTO_ACID(element) ||
11530       MAYBE_DONT_COLLIDE_WITH(element) ||
11531       element == EL_BD_SAND ||
11532       element == EL_BD_ROCK ||
11533       element == EL_BD_MEGA_ROCK ||
11534       element == EL_BD_SWEET ||
11535       element == EL_BD_VOODOO_DOLL ||
11536       element == EL_BD_WATER)
11537   {
11538     return TRUE;
11539   }
11540   else
11541   {
11542     for (i = 0; elements_with_counter[i].element != -1; i++)
11543       if (elements_with_counter[i].element == element)
11544         return TRUE;
11545   }
11546
11547   return FALSE;
11548 }
11549
11550 static void SetAutomaticNumberOfGemsNeeded(void)
11551 {
11552   int x, y;
11553
11554   if (!level.auto_count_gems)
11555     return;
11556
11557   level.gems_needed = 0;
11558
11559   for (x = 0; x < lev_fieldx; x++)
11560   {
11561     for (y = 0; y < lev_fieldy; y++)
11562     {
11563       int element = Tile[x][y];
11564
11565       switch (element)
11566       {
11567         case EL_EMERALD:
11568         case EL_EMERALD_YELLOW:
11569         case EL_EMERALD_RED:
11570         case EL_EMERALD_PURPLE:
11571         case EL_BD_DIAMOND:
11572         case EL_WALL_EMERALD:
11573         case EL_WALL_EMERALD_YELLOW:
11574         case EL_WALL_EMERALD_RED:
11575         case EL_WALL_EMERALD_PURPLE:
11576         case EL_WALL_BD_DIAMOND:
11577         case EL_NUT:
11578         case EL_SP_INFOTRON:
11579         case EL_MM_KETTLE:
11580         case EL_DF_CELL:
11581           level.gems_needed++;
11582           break;
11583
11584         case EL_DIAMOND:
11585         case EL_WALL_DIAMOND:
11586           level.gems_needed += 3;
11587           break;
11588
11589         case EL_PEARL:
11590         case EL_WALL_PEARL:
11591           level.gems_needed += 5;
11592           break;
11593
11594         case EL_CRYSTAL:
11595         case EL_WALL_CRYSTAL:
11596           level.gems_needed += 8;
11597           break;
11598
11599         default:
11600           break;
11601       }
11602     }
11603   }
11604
11605   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
11606 }
11607
11608 static void DrawPropertiesConfig(void)
11609 {
11610   boolean draw_footer_line = FALSE;
11611   int max_num_element_counters = 4;
11612   int num_element_counters = 0;
11613   int i;
11614
11615   if (!checkPropertiesConfig(properties_element))
11616   {
11617     int xpos = ED_ELEMENT_SETTINGS_X(0);
11618     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
11619
11620     PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
11621
11622     return;
11623   }
11624
11625   // check if there are elements where a value can be chosen for
11626   for (i = 0; elements_with_counter[i].element != -1; i++)
11627   {
11628     if (elements_with_counter[i].element != properties_element)
11629       continue;
11630
11631     // special case: score for extra diamonds only available in BD game engine
11632     if (elements_with_counter[i].element == EL_BD_DIAMOND &&
11633         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
11634         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11635       continue;
11636
11637     // special case: some amoeba counters only available in BD game engine
11638     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11639         elements_with_counter[i].value != &level.amoeba_speed &&
11640         level.game_engine_type != GAME_ENGINE_TYPE_BD)
11641       continue;
11642
11643     // special case: some amoeba counters only available in R'n'D game engine
11644     if (elements_with_counter[i].element == EL_BD_AMOEBA &&
11645         elements_with_counter[i].value == &level.amoeba_speed &&
11646         level.game_engine_type == GAME_ENGINE_TYPE_BD)
11647       continue;
11648
11649     int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
11650
11651     counterbutton_info[counter_id].y =
11652       ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
11653                                (CAN_GROW(properties_element)                ? 1 : 0) +
11654                                (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
11655                                (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
11656                                (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
11657                                (properties_element == EL_BD_SLIME           ? 1 : 0) +
11658                                (properties_element == EL_BD_ACID            ? 1 : 0) +
11659                                (properties_element == EL_BD_REPLICATOR      ? 1 : 0) +
11660                                (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
11661                                num_element_counters);
11662
11663     // special case: set magic wall counter for BD game engine separately
11664     if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11665       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(1);
11666
11667     // special case: set amoeba counters for BD game engine separately
11668     if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
11669         (properties_element == EL_BD_AMOEBA_2))
11670       counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
11671
11672     // special case: set position for delay counter for reappearing hammered walls
11673     if (properties_element == EL_BD_PNEUMATIC_HAMMER && num_element_counters > 0)
11674       counterbutton_info[counter_id].y += 1;
11675
11676     counterbutton_info[counter_id].value      = elements_with_counter[i].value;
11677     counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
11678     counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
11679     counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
11680
11681     // default: counter values between 0 and 999
11682     if (counterbutton_info[counter_id].max_value == 0)
11683       counterbutton_info[counter_id].max_value = 999;
11684
11685     MapCounterButtons(counter_id);
11686
11687     num_element_counters++;
11688     if (num_element_counters >= max_num_element_counters)
11689       break;
11690   }
11691
11692   if (properties_element == EL_BD_MAGIC_WALL && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11693   {
11694     // draw stickybutton gadget
11695     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11696
11697     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
11698     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
11699
11700     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
11701     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
11702     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
11703     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
11704     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
11705     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
11706     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
11707   }
11708
11709   if (HAS_EDITOR_CONTENT(properties_element))
11710   {
11711     // draw stickybutton gadget
11712     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
11713
11714     if (properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11715     {
11716       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11717       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11718
11719       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG);
11720       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED);
11721     }
11722     else if (properties_element == EL_BD_AMOEBA_2)
11723     {
11724       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
11725       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
11726       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
11727
11728       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
11729       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
11730       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
11731       MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
11732     }
11733     else if (IS_AMOEBOID(properties_element))
11734       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
11735     else if (properties_element == EL_BD_ACID)
11736     {
11737       MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
11738       MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
11739     }
11740     else if (IS_BD_BITER(properties_element))
11741     {
11742       MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
11743     }
11744     else if (properties_element == EL_BD_BLADDER)
11745     {
11746       MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
11747     }
11748     else if (properties_element == EL_YAMYAM ||
11749              properties_element == EL_YAMYAM_LEFT ||
11750              properties_element == EL_YAMYAM_RIGHT ||
11751              properties_element == EL_YAMYAM_UP ||
11752              properties_element == EL_YAMYAM_DOWN)
11753       DrawYamYamContentAreas();
11754     else if (properties_element == EL_EMC_MAGIC_BALL)
11755     {
11756       DrawMagicBallContentAreas();
11757
11758       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
11759       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
11760     }
11761     else if (properties_element == EL_EMC_ANDROID)
11762       DrawAndroidElementArea();
11763     else if (properties_element == EL_MM_GRAY_BALL)
11764     {
11765       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
11766       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
11767       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
11768       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
11769
11770       DrawMMBallContentArea();
11771     }
11772   }
11773
11774   if (IS_PLAYER_ELEMENT(properties_element))
11775   {
11776     int player_nr = GET_PLAYER_NR(properties_element);
11777
11778     // these properties can be set for every player individually
11779
11780     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
11781     {
11782       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
11783         &level.start_element[player_nr];
11784       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
11785         &level.artwork_element[player_nr];
11786       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
11787         &level.explosion_element[player_nr];
11788
11789       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
11790         &level.use_start_element[player_nr];
11791       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
11792         &level.use_artwork_element[player_nr];
11793       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
11794         &level.use_explosion_element[player_nr];
11795       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
11796         &level.initial_player_gravity[player_nr];
11797
11798       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
11799         &level.initial_player_stepsize[player_nr];
11800
11801       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
11802       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
11803                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
11804                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
11805       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
11806       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
11807       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
11808       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
11809       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
11810       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
11811       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
11812       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
11813       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
11814       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
11815       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
11816
11817       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
11818       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
11819       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
11820
11821       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
11822     }
11823     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
11824     {
11825       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
11826         &level.initial_inventory_content[player_nr][0];
11827
11828       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
11829         &level.initial_inventory_size[player_nr];
11830
11831       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
11832         &level.use_initial_inventory[player_nr];
11833
11834       // draw checkbutton gadgets
11835       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
11836       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
11837       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
11838
11839       // draw counter gadgets
11840       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
11841
11842       // draw drawing area gadgets
11843       DrawPlayerInitialInventoryArea(properties_element);
11844     }
11845   }
11846
11847   if (IS_BD_PLAYER_ELEMENT(properties_element))
11848   {
11849     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
11850       ED_ELEMENT_SETTINGS_YPOS(2);
11851     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11852       ED_ELEMENT_SETTINGS_YPOS(3);
11853     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
11854       ED_ELEMENT_SETTINGS_YPOS(4);
11855
11856     // draw checkbutton gadgets
11857     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
11858     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
11859     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
11860
11861     // draw counter gadgets
11862     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
11863     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
11864
11865     // draw drawing area gadgets
11866     MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
11867   }
11868
11869   if (properties_element == EL_BD_SAND)
11870   {
11871     MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
11872   }
11873
11874   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
11875   {
11876     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
11877       ED_ELEMENT_SETTINGS_YPOS(0);
11878     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11879       ED_ELEMENT_SETTINGS_YPOS(1);
11880
11881     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
11882     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
11883   }
11884
11885   if (properties_element == EL_BD_MEGA_ROCK ||
11886       properties_element == EL_BD_SWEET)
11887   {
11888     counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
11889       ED_ELEMENT_SETTINGS_YPOS(0);
11890     checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
11891       ED_ELEMENT_SETTINGS_YPOS(1);
11892
11893     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
11894     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
11895   }
11896
11897   if (properties_element == EL_BD_VOODOO_DOLL)
11898   {
11899     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
11900     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
11901     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
11902     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
11903   }
11904
11905   if (properties_element == EL_BD_SLIME)
11906   {
11907     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
11908
11909     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
11910     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
11911     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
11912     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
11913     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
11914     MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
11915   }
11916
11917   if (IS_BD_EXPANDABLE_WALL(properties_element) ||
11918       IS_BD_EXPANDABLE_STEELWALL(properties_element))
11919   {
11920     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
11921
11922     if (IS_BD_EXPANDABLE_WALL(properties_element))
11923       MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
11924   }
11925
11926   if (properties_element == EL_BD_REPLICATOR)
11927   {
11928     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
11929   }
11930
11931   if (IS_BD_CONVEYOR_BELT(properties_element) ||
11932       IS_BD_CONVEYOR_BELT_SWITCH(properties_element))
11933   {
11934     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
11935     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
11936   }
11937
11938   if (properties_element == EL_BD_WATER)
11939   {
11940     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
11941   }
11942
11943   if (properties_element == EL_BD_PNEUMATIC_HAMMER)
11944   {
11945     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
11946   }
11947
11948   if (properties_element == EL_BD_NUT)
11949   {
11950     MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
11951   }
11952
11953   // special case: slippery walls option for gems only available in R'n'D game engine
11954   if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
11955     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
11956
11957   if (properties_element == EL_EM_DYNAMITE)
11958     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
11959
11960   if (COULD_MOVE_INTO_ACID(properties_element) &&
11961       !IS_PLAYER_ELEMENT(properties_element) &&
11962       (!IS_CUSTOM_ELEMENT(properties_element) ||
11963        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
11964   {
11965     // set position for checkbutton for "can move into acid"
11966     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
11967       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
11968     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
11969       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
11970                                IS_BALLOON_ELEMENT(properties_element) ||
11971                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
11972
11973     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
11974   }
11975
11976   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
11977     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
11978
11979   if (properties_element == EL_SPRING ||
11980       properties_element == EL_SPRING_LEFT ||
11981       properties_element == EL_SPRING_RIGHT)
11982     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
11983
11984   if (properties_element == EL_TIME_ORB_FULL)
11985     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
11986
11987   if (properties_element == EL_GAME_OF_LIFE ||
11988       properties_element == EL_BIOMAZE)
11989     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
11990
11991   if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
11992   {
11993     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
11994       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
11995
11996     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
11997   }
11998
11999   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
12000     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
12001
12002   if (properties_element == EL_SOKOBAN_OBJECT)
12003     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
12004
12005   if (properties_element == EL_SOKOBAN_OBJECT ||
12006       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
12007       properties_element == EL_SOKOBAN_FIELD_FULL)
12008   {
12009     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
12010       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
12011                                0 : 1);
12012
12013     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
12014   }
12015
12016   if (IS_BALLOON_ELEMENT(properties_element))
12017     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
12018
12019   if (IS_ENVELOPE(properties_element) ||
12020       IS_MM_ENVELOPE(properties_element))
12021   {
12022     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
12023     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
12024     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
12025     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
12026     int envelope_nr = ENVELOPE_NR(properties_element);
12027
12028     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
12029     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
12030
12031     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
12032     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
12033
12034     // display counter to choose size of envelope text area
12035     MapCounterButtons(counter1_id);
12036     MapCounterButtons(counter2_id);
12037
12038     // display checkbuttons to choose auto-wrap and alignment properties
12039     MapCheckbuttonGadget(button1_id);
12040     MapCheckbuttonGadget(button2_id);
12041
12042     DrawEnvelopeTextArea(envelope_nr);
12043   }
12044
12045   if (IS_MM_MCDUFFIN(properties_element))
12046   {
12047     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
12048     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
12049     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
12050   }
12051
12052   if (IS_DF_LASER(properties_element))
12053   {
12054     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
12055     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
12056     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
12057   }
12058
12059   if (IS_CUSTOM_ELEMENT(properties_element))
12060   {
12061     // draw stickybutton gadget
12062     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12063
12064     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
12065     {
12066       // draw checkbutton gadgets
12067       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
12068            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
12069         MapCheckbuttonGadget(i);
12070
12071       // draw counter gadgets
12072       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
12073            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
12074         MapCounterButtons(i);
12075
12076       // draw selectbox gadgets
12077       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
12078            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
12079         MapSelectboxGadget(i);
12080
12081       // draw textbutton gadgets
12082       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12083
12084       // draw text input gadgets
12085       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12086
12087       // draw drawing area gadgets
12088       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12089
12090       draw_footer_line = TRUE;
12091     }
12092     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
12093     {
12094       // draw checkbutton gadgets
12095       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
12096            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
12097         MapCheckbuttonGadget(i);
12098
12099       // draw counter gadgets
12100       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
12101            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
12102         MapCounterButtons(i);
12103
12104       // draw selectbox gadgets
12105       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
12106            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
12107         MapSelectboxGadget(i);
12108
12109       // draw drawing area gadgets
12110       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
12111       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
12112       DrawCustomContentArea();
12113     }
12114   }
12115   else if (IS_GROUP_ELEMENT(properties_element))
12116   {
12117     // draw stickybutton gadget
12118     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12119
12120     // draw checkbutton gadgets
12121     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12122     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12123
12124     // draw counter gadgets
12125     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
12126
12127     // draw selectbox gadgets
12128     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
12129
12130     // draw textbutton gadgets
12131     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12132
12133     // draw drawing area gadgets
12134     DrawGroupElementArea();
12135
12136     // draw text input gadgets
12137     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
12138
12139     // draw drawing area gadgets
12140     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12141
12142     draw_footer_line = TRUE;
12143   }
12144   else if (IS_EMPTY_ELEMENT(properties_element))
12145   {
12146     // draw stickybutton gadget
12147     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12148
12149     // draw checkbutton gadgets
12150     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
12151     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
12152
12153     // draw textbutton gadgets
12154     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
12155
12156     // draw drawing area gadgets
12157     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
12158
12159     draw_footer_line = TRUE;
12160   }
12161
12162   // draw little footer border line above CE/GE use/save template gadgets
12163   if (draw_footer_line)
12164   {
12165     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
12166     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
12167     int gd_x = gd->x + gd_gi1->border.width / 2;
12168     int gd_y = gd->y + gd_gi1->height - 1;
12169     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
12170
12171     if (tab_color != BLACK_PIXEL)               // black => transparent
12172       FillRectangle(drawto,
12173                     SX + ED_ELEMENT_SETTINGS_X(0),
12174                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
12175                     ED_TAB_BAR_HEIGHT,
12176                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
12177   }
12178 }
12179
12180 static void DrawPropertiesChangeDrawingAreas(void)
12181 {
12182   if (IS_CUSTOM_ELEMENT(properties_element))
12183   {
12184     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
12185     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
12186     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
12187
12188     DrawCustomChangeContentArea();
12189   }
12190
12191   redraw_mask |= REDRAW_FIELD;
12192 }
12193
12194 static void DrawPropertiesChange(void)
12195 {
12196   int i;
12197
12198   // needed to initially set selectbox options for special action options
12199   setSelectboxSpecialActionOptions();
12200
12201   // draw stickybutton gadget
12202   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
12203
12204   // draw checkbutton gadgets
12205   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
12206        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
12207     MapCheckbuttonGadget(i);
12208
12209   // draw counter gadgets
12210   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
12211        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
12212     MapCounterButtons(i);
12213
12214   // draw selectbox gadgets
12215   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
12216        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
12217     MapSelectboxGadget(i);
12218
12219   // draw textbutton gadgets
12220   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
12221        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
12222     MapTextbuttonGadget(i);
12223
12224   // draw graphicbutton gadgets
12225   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
12226        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
12227     MapGraphicbuttonGadget(i);
12228
12229   // draw drawing area gadgets
12230   DrawPropertiesChangeDrawingAreas();
12231 }
12232
12233 static void DrawEditorElementAnimation(int x, int y)
12234 {
12235   int graphic;
12236   int frame;
12237
12238   getEditorGraphicAndFrame(properties_element, &graphic, &frame, FALSE);
12239
12240   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
12241 }
12242
12243 static void DrawEditorElementName(int x, int y, int font_nr)
12244 {
12245   char *element_name = getElementInfoText(properties_element);
12246   int font_width = getFontWidth(font_nr);
12247   int font_height = getFontHeight(font_nr);
12248   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
12249   int max_chars_per_line = max_text_width / font_width;
12250
12251   if (strlen(element_name) <= max_chars_per_line)
12252     DrawTextS(x, y, font_nr, element_name);
12253   else
12254   {
12255     char buffer[max_chars_per_line + 1];
12256     int next_pos = max_chars_per_line;
12257
12258     strncpy(buffer, element_name, max_chars_per_line);
12259     buffer[max_chars_per_line] = '\0';
12260
12261     if (element_name[max_chars_per_line] == ' ')
12262       next_pos++;
12263     else
12264     {
12265       int i;
12266
12267       for (i = max_chars_per_line - 1; i >= 0; i--)
12268         if (buffer[i] == ' ')
12269           break;
12270
12271       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
12272       {
12273         buffer[i] = '\0';
12274         next_pos = i + 1;
12275       }
12276     }
12277
12278     DrawTextS(x, y - font_height / 2, font_nr, buffer);
12279
12280     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
12281     buffer[max_chars_per_line] = '\0';
12282
12283     DrawTextS(x, y + font_height / 2, font_nr, buffer);
12284   }
12285 }
12286
12287 static void DrawPropertiesWindow(void)
12288 {
12289   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
12290   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12291   int border_size = gd->border_size;
12292   int font_nr = FONT_TEXT_1;
12293   int font_height = getFontHeight(font_nr);
12294   int xoffset = TILEX + element_border + 3 * border_size;
12295   int yoffset = (TILEY - font_height) / 2;
12296   int x1 = editor.settings.element_graphic.x + element_border;
12297   int y1 = editor.settings.element_graphic.y + element_border;
12298   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
12299             editor.settings.element_name.x);
12300   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
12301             editor.settings.element_name.y);
12302   char *text = "Element Settings";
12303   int font2_nr = FONT_TITLE_1;
12304   struct MenuPosInfo *pos = &editor.settings.headline;
12305   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
12306   int sy = SY + pos->y;
12307
12308   stick_element_properties_window = FALSE;
12309
12310   // make sure that previous properties edit mode exists for this element
12311   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
12312       !IS_CUSTOM_ELEMENT(properties_element))
12313     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
12314
12315   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
12316       !IS_PLAYER_ELEMENT(properties_element) &&
12317       !IS_CUSTOM_ELEMENT(properties_element))
12318     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
12319
12320   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
12321       (IS_PLAYER_ELEMENT(properties_element) ||
12322        IS_CUSTOM_ELEMENT(properties_element)))
12323     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
12324
12325   CopyElementPropertiesToEditor(properties_element);
12326
12327   UnmapLevelEditorFieldGadgets();
12328   UnmapLevelEditorToolboxDrawingGadgets();
12329   UnmapLevelEditorToolboxCustomGadgets();
12330
12331   MapLevelEditorToolboxCustomGadgetsIfNeeded();
12332
12333   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12334   ClearField();
12335
12336   DrawText(sx, sy, text, font2_nr);
12337
12338   FrameCounter = 0;     // restart animation frame counter
12339
12340   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
12341   DrawEditorElementAnimation(SX + x1, SY + y1);
12342   DrawEditorElementName(x2, y2, font_nr);
12343
12344   DrawPropertiesTabulatorGadgets();
12345
12346   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
12347     DrawPropertiesInfo();
12348   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
12349     DrawPropertiesChange();
12350   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
12351     DrawPropertiesConfig();
12352 }
12353
12354 static void DrawPaletteWindow(void)
12355 {
12356   int i;
12357
12358   UnmapLevelEditorFieldGadgets();
12359
12360   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
12361   ClearField();
12362
12363   // map buttons to select elements
12364   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
12365     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
12366   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
12367   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
12368   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
12369 }
12370
12371 static void UpdateCustomElementGraphicGadgets(void)
12372 {
12373   int i;
12374
12375   InitElementPropertiesGfxElement();
12376
12377   ModifyEditorElementList();
12378   RedrawDrawingElements();
12379
12380   // force redraw of all mapped drawing area gadgets
12381   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
12382   {
12383     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
12384
12385     if (gi->mapped)
12386       MapDrawingArea(i);
12387   }
12388 }
12389
12390 static int getOpenDirectionFromTube(int element)
12391 {
12392   switch (element)
12393   {
12394     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
12395     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
12396     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
12397     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
12398     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
12399     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
12400     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
12401     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
12402     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
12403     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
12404     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
12405   }
12406
12407   return MV_NONE;
12408 }
12409
12410 static int getTubeFromOpenDirection(int direction)
12411 {
12412   switch (direction)
12413   {
12414     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
12415     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
12416     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
12417     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
12418     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
12419     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
12420     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
12421     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
12422     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
12423     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
12424     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
12425
12426     // if only one direction, fall back to simple tube with that direction
12427     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
12428     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
12429     case (MV_UP):                       return EL_TUBE_VERTICAL;
12430     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
12431   }
12432
12433   return EL_EMPTY;
12434 }
12435
12436 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
12437 {
12438   int element_new = getTubeFromOpenDirection(direction);
12439
12440   return (element_new != EL_EMPTY ? element_new : element_old);
12441 }
12442
12443 static int getOpenDirectionFromBelt(int element)
12444 {
12445   int belt_dir = getBeltDirFromBeltElement(element);
12446
12447   return (belt_dir == MV_LEFT ? MV_RIGHT :
12448           belt_dir == MV_RIGHT ? MV_LEFT :
12449           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
12450 }
12451
12452 static int getBeltFromNrAndOpenDirection(int nr, int direction)
12453 {
12454   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
12455                   direction == MV_RIGHT ? MV_LEFT :
12456                   direction == MV_HORIZONTAL ? MV_NONE : direction);
12457
12458   if (direction == MV_NONE)
12459     return EL_EMPTY;
12460
12461   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
12462 }
12463
12464 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
12465                                                  int element_old)
12466 {
12467   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
12468
12469   return (element_new != EL_EMPTY ? element_new : element_old);
12470 }
12471
12472 static int getOpenDirectionFromPool(int element)
12473 {
12474   switch (element)
12475   {
12476     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
12477     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
12478     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
12479     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
12480     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
12481     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
12482   }
12483
12484   return MV_NONE;
12485 }
12486
12487 static int getPoolFromOpenDirection(int direction)
12488 {
12489   switch (direction)
12490   {
12491     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
12492     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
12493     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
12494     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
12495     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
12496     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
12497   }
12498
12499   return EL_EMPTY;
12500 }
12501
12502 static int getPoolFromOpenDirectionExt(int direction, int help_element)
12503 {
12504   int element = getPoolFromOpenDirection(direction);
12505   int help_direction = getOpenDirectionFromPool(help_element);
12506
12507   if (element == EL_EMPTY)
12508   {
12509     int help_direction_vertical = help_direction & MV_VERTICAL;
12510
12511     element = getPoolFromOpenDirection(direction | help_direction_vertical);
12512   }
12513
12514   if (element == EL_EMPTY)
12515   {
12516     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
12517
12518     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
12519   }
12520
12521   return element;
12522 }
12523
12524 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
12525 {
12526   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
12527
12528   return (element_new != EL_EMPTY ? element_new : element_old);
12529 }
12530
12531 static int getOpenDirectionFromPillar(int element)
12532 {
12533   switch (element)
12534   {
12535     case EL_EMC_WALL_1:                 return (MV_DOWN);
12536     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
12537     case EL_EMC_WALL_3:                 return (MV_UP);
12538   }
12539
12540   return MV_NONE;
12541 }
12542
12543 static int getPillarFromOpenDirection(int direction)
12544 {
12545   switch (direction)
12546   {
12547     case (MV_DOWN):                     return EL_EMC_WALL_1;
12548     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
12549     case (MV_UP):                       return EL_EMC_WALL_3;
12550   }
12551
12552   return EL_EMPTY;
12553 }
12554
12555 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
12556 {
12557   int element_new = getPillarFromOpenDirection(direction);
12558
12559   return (element_new != EL_EMPTY ? element_new : element_old);
12560 }
12561
12562 static int getOpenDirectionFromSteel2(int element)
12563 {
12564   switch (element)
12565   {
12566     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
12567     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
12568     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
12569     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
12570     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
12571     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
12572     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
12573     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
12574   }
12575
12576   return MV_NONE;
12577 }
12578
12579 static int getSteel2FromOpenDirection(int direction)
12580 {
12581   switch (direction)
12582   {
12583     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
12584     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
12585     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
12586     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
12587     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
12588     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
12589     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
12590     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
12591   }
12592
12593   return EL_EMPTY;
12594 }
12595
12596 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
12597 {
12598   int element_new = getSteel2FromOpenDirection(direction);
12599
12600   return (element_new != EL_EMPTY ? element_new : element_old);
12601 }
12602
12603 static int getOpenDirectionFromChip(int element)
12604 {
12605   switch (element)
12606   {
12607     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
12608     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
12609     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
12610     case EL_SP_CHIP_TOP:                return (MV_DOWN);
12611     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
12612   }
12613
12614   return MV_NONE;
12615 }
12616
12617 static int getChipFromOpenDirection(int direction)
12618 {
12619   switch (direction)
12620   {
12621     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
12622     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
12623     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
12624     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
12625     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
12626   }
12627
12628   return EL_EMPTY;
12629 }
12630
12631 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
12632 {
12633   int element_new = getChipFromOpenDirection(direction);
12634
12635   return (element_new != EL_EMPTY ? element_new : element_old);
12636 }
12637
12638 static int getClosedTube(int x, int y)
12639 {
12640   struct XY *xy = xy_directions;
12641   int element_old = IntelliDrawBuffer[x][y];
12642   int direction_old = getOpenDirectionFromTube(element_old);
12643   int direction_new = MV_NONE;
12644   int i;
12645
12646   for (i = 0; i < NUM_DIRECTIONS; i++)
12647   {
12648     int xx = x + xy[i].x;
12649     int yy = y + xy[i].y;
12650     int dir = MV_DIR_FROM_BIT(i);
12651     int dir_opposite = MV_DIR_OPPOSITE(dir);
12652
12653     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
12654         (direction_old & dir) &&
12655         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12656       direction_new |= dir;
12657   }
12658
12659   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
12660 }
12661
12662 static int getClosedBelt(int x, int y)
12663 {
12664   struct XY *xy = xy_directions;
12665   int element_old = IntelliDrawBuffer[x][y];
12666   int nr = getBeltNrFromBeltElement(element_old);
12667   int direction_old = getOpenDirectionFromBelt(element_old);
12668   int direction_new = MV_NONE;
12669   int i;
12670
12671   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12672   {
12673     int xx = x + xy[i].x;
12674     int yy = y + xy[i].y;
12675     int dir = MV_DIR_FROM_BIT(i);
12676     int dir_opposite = MV_DIR_OPPOSITE(dir);
12677
12678     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
12679         (direction_old & dir) &&
12680         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12681       direction_new |= dir;
12682   }
12683
12684   return getBeltFromNrAndOpenDirection(nr, direction_new);
12685 }
12686
12687 static int getClosedPool(int x, int y)
12688 {
12689   struct XY *xy = xy_directions;
12690   int element_old = IntelliDrawBuffer[x][y];
12691   int direction_old = getOpenDirectionFromPool(element_old);
12692   int direction_new = MV_NONE;
12693   int i;
12694
12695   for (i = 0; i < NUM_DIRECTIONS; i++)
12696   {
12697     int xx = x + xy[i].x;
12698     int yy = y + xy[i].y;
12699     int dir = MV_DIR_FROM_BIT(i);
12700     int dir_opposite = MV_DIR_OPPOSITE(dir);
12701
12702     if (IN_LEV_FIELD(xx, yy) &&
12703         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
12704         (direction_old & dir) &&
12705         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12706       direction_new |= dir;
12707   }
12708
12709   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
12710 }
12711
12712 static int getClosedPillar(int x, int y)
12713 {
12714   struct XY *xy = xy_directions;
12715   int element_old = IntelliDrawBuffer[x][y];
12716   int direction_old = getOpenDirectionFromPillar(element_old);
12717   int direction_new = MV_NONE;
12718   int i;
12719
12720   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
12721   {
12722     int xx = x + xy[i].x;
12723     int yy = y + xy[i].y;
12724     int dir = MV_DIR_FROM_BIT(i);
12725     int dir_opposite = MV_DIR_OPPOSITE(dir);
12726
12727     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
12728         (direction_old & dir) &&
12729         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12730       direction_new |= dir;
12731   }
12732
12733   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
12734 }
12735
12736 static int getClosedSteel2(int x, int y)
12737 {
12738   struct XY *xy = xy_directions;
12739   int element_old = IntelliDrawBuffer[x][y];
12740   int direction_old = getOpenDirectionFromSteel2(element_old);
12741   int direction_new = MV_NONE;
12742   int i;
12743
12744   for (i = 0; i < NUM_DIRECTIONS; i++)
12745   {
12746     int xx = x + xy[i].x;
12747     int yy = y + xy[i].y;
12748     int dir = MV_DIR_FROM_BIT(i);
12749     int dir_opposite = MV_DIR_OPPOSITE(dir);
12750
12751     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
12752         (direction_old & dir) &&
12753         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12754       direction_new |= dir;
12755   }
12756
12757   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
12758 }
12759
12760 static int getClosedChip(int x, int y)
12761 {
12762   struct XY *xy = xy_directions;
12763   int element_old = IntelliDrawBuffer[x][y];
12764   int direction_old = getOpenDirectionFromChip(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_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
12776         (direction_old & dir) &&
12777         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
12778       direction_new |= dir;
12779   }
12780
12781   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
12782 }
12783
12784 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
12785                                 boolean change_level)
12786 {
12787   int sx = x - level_xpos;
12788   int sy = y - level_ypos;
12789   int old_element = Tile[x][y];
12790   int new_element = element;
12791   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
12792   boolean draw_masked = FALSE;
12793
12794   if (IS_MM_WALL_EDITOR(element))
12795   {
12796     element = map_mm_wall_element_editor(element) | new_bitmask;
12797
12798     if (IS_MM_WALL(old_element))
12799       element |= MM_WALL_BITS(old_element);
12800
12801     if (!change_level)
12802       draw_masked = TRUE;
12803   }
12804   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
12805   {
12806     int element_changed = old_element & ~new_bitmask;
12807
12808     if (MM_WALL_BITS(element_changed) != 0)
12809       element = element_changed;
12810   }
12811
12812   IntelliDrawBuffer[x][y] = element;
12813
12814   if (change_level)
12815     Tile[x][y] = element;
12816
12817   if (IN_ED_FIELD(sx, sy))
12818   {
12819     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
12820       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
12821     else if (draw_masked)
12822       DrawEditorElementThruMask(sx, sy, element);
12823     else
12824       DrawEditorElement(sx, sy, element);
12825   }
12826 }
12827
12828 static void SetElementSimple(int x, int y, int element, boolean change_level)
12829 {
12830   SetElementSimpleExt(x, y, 0, 0, element, change_level);
12831 }
12832
12833 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
12834                                            int x2, int y2, int *element2,
12835                                            int (*close_function)(int, int),
12836                                            boolean change_level)
12837 {
12838   // set neighbour elements to newly determined connections
12839   SetElementSimple(x1, y1, *element1, change_level);
12840   SetElementSimple(x2, y2, *element2, change_level);
12841
12842   // remove all open connections of neighbour elements
12843   *element1 = close_function(x1, y1);
12844   *element2 = close_function(x2, y2);
12845
12846   // set neighbour elements to new, minimized connections
12847   SetElementSimple(x1, y1, *element1, change_level);
12848   SetElementSimple(x2, y2, *element2, change_level);
12849 }
12850
12851 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
12852                                   boolean change_level, int button)
12853 {
12854   struct XY *xy = xy_directions;
12855   static int last_x = -1;
12856   static int last_y = -1;
12857
12858   if (new_element == EL_UNDEFINED)
12859   {
12860     last_x = -1;
12861     last_y = -1;
12862
12863     return;
12864   }
12865
12866   int old_element = IntelliDrawBuffer[x][y];
12867
12868   if (IS_TUBE(new_element))
12869   {
12870     int last_element_new = EL_UNDEFINED;
12871     int direction = MV_NONE;
12872     int i;
12873
12874     // if old element is of same kind, keep all existing directions
12875     if (IS_TUBE(old_element))
12876       direction |= getOpenDirectionFromTube(old_element);
12877
12878     for (i = 0; i < NUM_DIRECTIONS; i++)
12879     {
12880       int xx = x + xy[i].x;
12881       int yy = y + xy[i].y;
12882
12883       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
12884           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
12885       {
12886         int dir = MV_DIR_FROM_BIT(i);
12887         int dir_opposite = MV_DIR_OPPOSITE(dir);
12888         int last_element_old = IntelliDrawBuffer[last_x][last_y];
12889         int last_direction_old = getOpenDirectionFromTube(last_element_old);
12890         int last_direction_new = last_direction_old | dir_opposite;
12891
12892         last_element_new = getTubeFromOpenDirection(last_direction_new);
12893
12894         direction |= dir;
12895       }
12896     }
12897
12898     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
12899
12900     if (last_element_new != EL_UNDEFINED)
12901       MergeAndCloseNeighbourElements(x, y, &new_element,
12902                                      last_x, last_y, &last_element_new,
12903                                      getClosedTube, change_level);
12904   }
12905   else if (IS_BELT(new_element))
12906   {
12907     int belt_nr = getBeltNrFromBeltElement(new_element);
12908     int last_element_new = EL_UNDEFINED;
12909     int direction = MV_NONE;
12910     int i;
12911
12912     // if old element is of same kind, keep all existing directions
12913     if (IS_BELT(old_element))
12914       direction |= getOpenDirectionFromBelt(old_element);
12915
12916     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
12917     {
12918       int xx = x + xy[i].x;
12919       int yy = y + xy[i].y;
12920
12921       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
12922           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
12923       {
12924         int dir = MV_DIR_FROM_BIT(i);
12925         int dir_opposite = MV_DIR_OPPOSITE(dir);
12926         int last_element_old = IntelliDrawBuffer[last_x][last_y];
12927         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
12928         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
12929         int last_direction_new = last_direction_old | dir_opposite;
12930
12931         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
12932                                                          last_direction_new);
12933         direction |= dir;
12934       }
12935     }
12936
12937     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
12938                                                         new_element);
12939     if (last_element_new != EL_UNDEFINED)
12940       MergeAndCloseNeighbourElements(x, y, &new_element,
12941                                      last_x, last_y, &last_element_new,
12942                                      getClosedBelt, change_level);
12943   }
12944   else if (IS_ACID_POOL_OR_ACID(new_element))
12945   {
12946     int last_element_new = EL_UNDEFINED;
12947     int direction = MV_NONE;
12948     int i;
12949
12950     // if old element is of same kind, keep all existing directions
12951     if (IS_ACID_POOL_OR_ACID(old_element))
12952       direction |= getOpenDirectionFromPool(old_element);
12953
12954     for (i = 0; i < NUM_DIRECTIONS; i++)
12955     {
12956       int xx = x + xy[i].x;
12957       int yy = y + xy[i].y;
12958
12959       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
12960           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
12961       {
12962         int dir = MV_DIR_FROM_BIT(i);
12963         int dir_opposite = MV_DIR_OPPOSITE(dir);
12964         int last_element_old = IntelliDrawBuffer[last_x][last_y];
12965         int last_direction_old = getOpenDirectionFromPool(last_element_old);
12966         int last_direction_new = last_direction_old | dir_opposite;
12967
12968         last_element_new = getPoolFromOpenDirection(last_direction_new);
12969
12970         direction |= dir;
12971       }
12972     }
12973
12974     // special corrections needed for intuitively correct acid pool drawing
12975     if (last_element_new == EL_EMPTY)
12976       last_element_new = new_element;
12977     else if (last_element_new != EL_UNDEFINED)
12978       new_element = last_element_new;
12979
12980     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
12981
12982     if (last_element_new != EL_UNDEFINED)
12983       MergeAndCloseNeighbourElements(x, y, &new_element,
12984                                      last_x, last_y, &last_element_new,
12985                                      getClosedPool, change_level);
12986   }
12987   else if (IS_EMC_PILLAR(new_element))
12988   {
12989     int last_element_new = EL_UNDEFINED;
12990     int direction = MV_NONE;
12991     int i;
12992
12993     // if old element is of same kind, keep all existing directions
12994     if (IS_EMC_PILLAR(old_element))
12995       direction |= getOpenDirectionFromPillar(old_element);
12996
12997     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
12998     {
12999       int xx = x + xy[i].x;
13000       int yy = y + xy[i].y;
13001
13002       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13003           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
13004       {
13005         int dir = MV_DIR_FROM_BIT(i);
13006         int dir_opposite = MV_DIR_OPPOSITE(dir);
13007         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13008         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
13009         int last_direction_new = last_direction_old | dir_opposite;
13010
13011         last_element_new = getPillarFromOpenDirection(last_direction_new);
13012
13013         direction |= dir;
13014       }
13015     }
13016
13017     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
13018
13019     if (last_element_new != EL_UNDEFINED)
13020       MergeAndCloseNeighbourElements(x, y, &new_element,
13021                                      last_x, last_y, &last_element_new,
13022                                      getClosedPillar, change_level);
13023   }
13024   else if (IS_DC_STEELWALL_2(new_element))
13025   {
13026     int last_element_new = EL_UNDEFINED;
13027     int direction = MV_NONE;
13028     int i;
13029
13030     // if old element is of same kind, keep all existing directions
13031     if (IS_DC_STEELWALL_2(old_element))
13032       direction |= getOpenDirectionFromSteel2(old_element);
13033
13034     for (i = 0; i < NUM_DIRECTIONS; i++)
13035     {
13036       int xx = x + xy[i].x;
13037       int yy = y + xy[i].y;
13038
13039       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13040           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
13041       {
13042         int dir = MV_DIR_FROM_BIT(i);
13043         int dir_opposite = MV_DIR_OPPOSITE(dir);
13044         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13045         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
13046         int last_direction_new = last_direction_old | dir_opposite;
13047
13048         last_element_new = getSteel2FromOpenDirection(last_direction_new);
13049
13050         direction |= dir;
13051       }
13052     }
13053
13054     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
13055
13056     if (last_element_new != EL_UNDEFINED)
13057       MergeAndCloseNeighbourElements(x, y, &new_element,
13058                                      last_x, last_y, &last_element_new,
13059                                      getClosedSteel2, change_level);
13060   }
13061   else if (IS_SP_CHIP(new_element))
13062   {
13063     int last_element_new = EL_UNDEFINED;
13064     int direction = MV_NONE;
13065     int i;
13066
13067     // (do not keep existing directions, regardless of kind of old element)
13068
13069     for (i = 0; i < NUM_DIRECTIONS; i++)
13070     {
13071       int xx = x + xy[i].x;
13072       int yy = y + xy[i].y;
13073
13074       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13075           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
13076       {
13077         int dir = MV_DIR_FROM_BIT(i);
13078         int dir_opposite = MV_DIR_OPPOSITE(dir);
13079         int last_element_old = IntelliDrawBuffer[last_x][last_y];
13080         int last_direction_old = getOpenDirectionFromChip(last_element_old);
13081         int last_direction_new = last_direction_old | dir_opposite;
13082
13083         if (last_direction_old == MV_NONE)
13084         {
13085           last_element_new = getChipFromOpenDirection(last_direction_new);
13086           direction |= dir;
13087         }
13088         else if (last_direction_old & (dir | dir_opposite))
13089         {
13090           direction |= MV_DIR_OPPOSITE(last_direction_old);
13091         }
13092         else
13093         {
13094           direction |= MV_DIR_OPPOSITE(dir);
13095         }
13096       }
13097     }
13098
13099     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
13100
13101     if (last_element_new != EL_UNDEFINED)
13102       MergeAndCloseNeighbourElements(x, y, &new_element,
13103                                      last_x, last_y, &last_element_new,
13104                                      getClosedChip, change_level);
13105   }
13106   else if (IS_SP_HARDWARE_BASE(new_element))
13107   {
13108     int nr = GetSimpleRandom(6);
13109
13110     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
13111                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
13112                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
13113                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
13114                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
13115   }
13116   else if (new_element == EL_SP_HARDWARE_GREEN ||
13117            new_element == EL_SP_HARDWARE_BLUE ||
13118            new_element == EL_SP_HARDWARE_RED)
13119   {
13120     int nr = GetSimpleRandom(3);
13121
13122     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
13123                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
13124   }
13125   else if (IS_GROUP_ELEMENT(new_element))
13126   {
13127     boolean connected_drawing = FALSE;
13128     int i;
13129
13130     for (i = 0; i < NUM_DIRECTIONS; i++)
13131     {
13132       int xx = x + xy[i].x;
13133       int yy = y + xy[i].y;
13134
13135       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
13136           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
13137         connected_drawing = TRUE;
13138     }
13139
13140     if (!connected_drawing)
13141       ResolveGroupElement(new_element);
13142
13143     new_element = GetElementFromGroupElement(new_element);
13144   }
13145   else if (IS_BELT_SWITCH(old_element))
13146   {
13147     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
13148     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
13149
13150     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
13151                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
13152
13153     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
13154   }
13155   else
13156   {
13157     static int swappable_elements[][2] =
13158     {
13159       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
13160       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
13161       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
13162       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
13163       { EL_EMERALD,                     EL_WALL_EMERALD                 },
13164       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
13165       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
13166       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
13167       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
13168       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
13169       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
13170       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
13171       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
13172       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
13173       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
13174       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
13175       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
13176       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
13177       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
13178       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
13179       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
13180       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
13181       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
13182       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
13183       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
13184       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
13185       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
13186       { EL_PEARL,                       EL_WALL_PEARL                   },
13187       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
13188       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
13189       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
13190       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
13191       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
13192       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
13193       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
13194       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
13195       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
13196       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
13197       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
13198       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
13199       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
13200       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
13201       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
13202       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
13203
13204       { -1,                             -1                              },
13205     };
13206     static int rotatable_elements_4[][4] =
13207     {
13208       {
13209         EL_BUG_UP,
13210         EL_BUG_RIGHT,
13211         EL_BUG_DOWN,
13212         EL_BUG_LEFT
13213       },
13214       {
13215         EL_SPACESHIP_UP,
13216         EL_SPACESHIP_RIGHT,
13217         EL_SPACESHIP_DOWN,
13218         EL_SPACESHIP_LEFT
13219       },
13220       {
13221         EL_BD_BUTTERFLY_UP,
13222         EL_BD_BUTTERFLY_RIGHT,
13223         EL_BD_BUTTERFLY_DOWN,
13224         EL_BD_BUTTERFLY_LEFT
13225       },
13226       {
13227         EL_BD_FIREFLY_UP,
13228         EL_BD_FIREFLY_RIGHT,
13229         EL_BD_FIREFLY_DOWN,
13230         EL_BD_FIREFLY_LEFT
13231       },
13232       {
13233         EL_PACMAN_UP,
13234         EL_PACMAN_RIGHT,
13235         EL_PACMAN_DOWN,
13236         EL_PACMAN_LEFT
13237       },
13238       {
13239         EL_YAMYAM_UP,
13240         EL_YAMYAM_RIGHT,
13241         EL_YAMYAM_DOWN,
13242         EL_YAMYAM_LEFT
13243       },
13244       {
13245         EL_ARROW_UP,
13246         EL_ARROW_RIGHT,
13247         EL_ARROW_DOWN,
13248         EL_ARROW_LEFT
13249       },
13250       {
13251         EL_SP_PORT_UP,
13252         EL_SP_PORT_RIGHT,
13253         EL_SP_PORT_DOWN,
13254         EL_SP_PORT_LEFT
13255       },
13256       {
13257         EL_SP_GRAVITY_PORT_UP,
13258         EL_SP_GRAVITY_PORT_RIGHT,
13259         EL_SP_GRAVITY_PORT_DOWN,
13260         EL_SP_GRAVITY_PORT_LEFT
13261       },
13262       {
13263         EL_SP_GRAVITY_ON_PORT_UP,
13264         EL_SP_GRAVITY_ON_PORT_RIGHT,
13265         EL_SP_GRAVITY_ON_PORT_DOWN,
13266         EL_SP_GRAVITY_ON_PORT_LEFT
13267       },
13268       {
13269         EL_SP_GRAVITY_OFF_PORT_UP,
13270         EL_SP_GRAVITY_OFF_PORT_RIGHT,
13271         EL_SP_GRAVITY_OFF_PORT_DOWN,
13272         EL_SP_GRAVITY_OFF_PORT_LEFT
13273       },
13274       {
13275         EL_MOLE_UP,
13276         EL_MOLE_RIGHT,
13277         EL_MOLE_DOWN,
13278         EL_MOLE_LEFT
13279       },
13280       {
13281         EL_BALLOON_SWITCH_UP,
13282         EL_BALLOON_SWITCH_RIGHT,
13283         EL_BALLOON_SWITCH_DOWN,
13284         EL_BALLOON_SWITCH_LEFT
13285       },
13286       {
13287         EL_MM_MCDUFFIN_UP,
13288         EL_MM_MCDUFFIN_RIGHT,
13289         EL_MM_MCDUFFIN_DOWN,
13290         EL_MM_MCDUFFIN_LEFT
13291       },
13292       {
13293         EL_MM_MIRROR_FIXED_1,
13294         EL_MM_MIRROR_FIXED_4,
13295         EL_MM_MIRROR_FIXED_3,
13296         EL_MM_MIRROR_FIXED_2
13297       },
13298       {
13299         EL_MM_STEEL_GRID_FIXED_1,
13300         EL_MM_STEEL_GRID_FIXED_4,
13301         EL_MM_STEEL_GRID_FIXED_2,
13302         EL_MM_STEEL_GRID_FIXED_3
13303       },
13304       {
13305         EL_MM_WOODEN_GRID_FIXED_1,
13306         EL_MM_WOODEN_GRID_FIXED_4,
13307         EL_MM_WOODEN_GRID_FIXED_2,
13308         EL_MM_WOODEN_GRID_FIXED_3
13309       },
13310       {
13311         EL_MM_POLARIZER_CROSS_1,
13312         EL_MM_POLARIZER_CROSS_4,
13313         EL_MM_POLARIZER_CROSS_3,
13314         EL_MM_POLARIZER_CROSS_2
13315       },
13316       {
13317         EL_MM_PACMAN_UP,
13318         EL_MM_PACMAN_RIGHT,
13319         EL_MM_PACMAN_DOWN,
13320         EL_MM_PACMAN_LEFT
13321       },
13322       {
13323         EL_DF_LASER_UP,
13324         EL_DF_LASER_RIGHT,
13325         EL_DF_LASER_DOWN,
13326         EL_DF_LASER_LEFT
13327       },
13328       {
13329         EL_DF_RECEIVER_UP,
13330         EL_DF_RECEIVER_RIGHT,
13331         EL_DF_RECEIVER_DOWN,
13332         EL_DF_RECEIVER_LEFT
13333       },
13334       {
13335         EL_DF_SLOPE_1,
13336         EL_DF_SLOPE_4,
13337         EL_DF_SLOPE_3,
13338         EL_DF_SLOPE_2
13339       },
13340
13341       {
13342         -1,
13343       },
13344     };
13345     static int rotatable_elements_8[][8] =
13346     {
13347       {
13348         EL_DF_STEEL_GRID_FIXED_1,
13349         EL_DF_STEEL_GRID_FIXED_8,
13350         EL_DF_STEEL_GRID_FIXED_7,
13351         EL_DF_STEEL_GRID_FIXED_6,
13352         EL_DF_STEEL_GRID_FIXED_5,
13353         EL_DF_STEEL_GRID_FIXED_4,
13354         EL_DF_STEEL_GRID_FIXED_3,
13355         EL_DF_STEEL_GRID_FIXED_2
13356       },
13357       {
13358         EL_DF_WOODEN_GRID_FIXED_1,
13359         EL_DF_WOODEN_GRID_FIXED_8,
13360         EL_DF_WOODEN_GRID_FIXED_7,
13361         EL_DF_WOODEN_GRID_FIXED_6,
13362         EL_DF_WOODEN_GRID_FIXED_5,
13363         EL_DF_WOODEN_GRID_FIXED_4,
13364         EL_DF_WOODEN_GRID_FIXED_3,
13365         EL_DF_WOODEN_GRID_FIXED_2
13366       },
13367       {
13368         EL_DF_STEEL_GRID_ROTATING_1,
13369         EL_DF_STEEL_GRID_ROTATING_8,
13370         EL_DF_STEEL_GRID_ROTATING_7,
13371         EL_DF_STEEL_GRID_ROTATING_6,
13372         EL_DF_STEEL_GRID_ROTATING_5,
13373         EL_DF_STEEL_GRID_ROTATING_4,
13374         EL_DF_STEEL_GRID_ROTATING_3,
13375         EL_DF_STEEL_GRID_ROTATING_2
13376       },
13377       {
13378         EL_DF_WOODEN_GRID_ROTATING_1,
13379         EL_DF_WOODEN_GRID_ROTATING_8,
13380         EL_DF_WOODEN_GRID_ROTATING_7,
13381         EL_DF_WOODEN_GRID_ROTATING_6,
13382         EL_DF_WOODEN_GRID_ROTATING_5,
13383         EL_DF_WOODEN_GRID_ROTATING_4,
13384         EL_DF_WOODEN_GRID_ROTATING_3,
13385         EL_DF_WOODEN_GRID_ROTATING_2
13386       },
13387
13388       {
13389         -1,
13390       },
13391     };
13392     static int rotatable_elements_16[][16] =
13393     {
13394       {
13395         EL_MM_MIRROR_1,
13396         EL_MM_MIRROR_16,
13397         EL_MM_MIRROR_15,
13398         EL_MM_MIRROR_14,
13399         EL_MM_MIRROR_13,
13400         EL_MM_MIRROR_12,
13401         EL_MM_MIRROR_11,
13402         EL_MM_MIRROR_10,
13403         EL_MM_MIRROR_9,
13404         EL_MM_MIRROR_8,
13405         EL_MM_MIRROR_7,
13406         EL_MM_MIRROR_6,
13407         EL_MM_MIRROR_5,
13408         EL_MM_MIRROR_4,
13409         EL_MM_MIRROR_3,
13410         EL_MM_MIRROR_2
13411       },
13412       {
13413         EL_MM_TELEPORTER_5,
13414         EL_MM_TELEPORTER_4,
13415         EL_MM_TELEPORTER_3,
13416         EL_MM_TELEPORTER_2,
13417         EL_MM_TELEPORTER_1,
13418         EL_MM_TELEPORTER_16,
13419         EL_MM_TELEPORTER_15,
13420         EL_MM_TELEPORTER_14,
13421         EL_MM_TELEPORTER_13,
13422         EL_MM_TELEPORTER_12,
13423         EL_MM_TELEPORTER_11,
13424         EL_MM_TELEPORTER_10,
13425         EL_MM_TELEPORTER_9,
13426         EL_MM_TELEPORTER_8,
13427         EL_MM_TELEPORTER_7,
13428         EL_MM_TELEPORTER_6
13429       },
13430       {
13431         EL_MM_TELEPORTER_RED_5,
13432         EL_MM_TELEPORTER_RED_4,
13433         EL_MM_TELEPORTER_RED_3,
13434         EL_MM_TELEPORTER_RED_2,
13435         EL_MM_TELEPORTER_RED_1,
13436         EL_MM_TELEPORTER_RED_16,
13437         EL_MM_TELEPORTER_RED_15,
13438         EL_MM_TELEPORTER_RED_14,
13439         EL_MM_TELEPORTER_RED_13,
13440         EL_MM_TELEPORTER_RED_12,
13441         EL_MM_TELEPORTER_RED_11,
13442         EL_MM_TELEPORTER_RED_10,
13443         EL_MM_TELEPORTER_RED_9,
13444         EL_MM_TELEPORTER_RED_8,
13445         EL_MM_TELEPORTER_RED_7,
13446         EL_MM_TELEPORTER_RED_6
13447       },
13448       {
13449         EL_MM_TELEPORTER_YELLOW_5,
13450         EL_MM_TELEPORTER_YELLOW_4,
13451         EL_MM_TELEPORTER_YELLOW_3,
13452         EL_MM_TELEPORTER_YELLOW_2,
13453         EL_MM_TELEPORTER_YELLOW_1,
13454         EL_MM_TELEPORTER_YELLOW_16,
13455         EL_MM_TELEPORTER_YELLOW_15,
13456         EL_MM_TELEPORTER_YELLOW_14,
13457         EL_MM_TELEPORTER_YELLOW_13,
13458         EL_MM_TELEPORTER_YELLOW_12,
13459         EL_MM_TELEPORTER_YELLOW_11,
13460         EL_MM_TELEPORTER_YELLOW_10,
13461         EL_MM_TELEPORTER_YELLOW_9,
13462         EL_MM_TELEPORTER_YELLOW_8,
13463         EL_MM_TELEPORTER_YELLOW_7,
13464         EL_MM_TELEPORTER_YELLOW_6
13465       },
13466       {
13467         EL_MM_TELEPORTER_GREEN_5,
13468         EL_MM_TELEPORTER_GREEN_4,
13469         EL_MM_TELEPORTER_GREEN_3,
13470         EL_MM_TELEPORTER_GREEN_2,
13471         EL_MM_TELEPORTER_GREEN_1,
13472         EL_MM_TELEPORTER_GREEN_16,
13473         EL_MM_TELEPORTER_GREEN_15,
13474         EL_MM_TELEPORTER_GREEN_14,
13475         EL_MM_TELEPORTER_GREEN_13,
13476         EL_MM_TELEPORTER_GREEN_12,
13477         EL_MM_TELEPORTER_GREEN_11,
13478         EL_MM_TELEPORTER_GREEN_10,
13479         EL_MM_TELEPORTER_GREEN_9,
13480         EL_MM_TELEPORTER_GREEN_8,
13481         EL_MM_TELEPORTER_GREEN_7,
13482         EL_MM_TELEPORTER_GREEN_6
13483       },
13484       {
13485         EL_MM_TELEPORTER_BLUE_5,
13486         EL_MM_TELEPORTER_BLUE_4,
13487         EL_MM_TELEPORTER_BLUE_3,
13488         EL_MM_TELEPORTER_BLUE_2,
13489         EL_MM_TELEPORTER_BLUE_1,
13490         EL_MM_TELEPORTER_BLUE_16,
13491         EL_MM_TELEPORTER_BLUE_15,
13492         EL_MM_TELEPORTER_BLUE_14,
13493         EL_MM_TELEPORTER_BLUE_13,
13494         EL_MM_TELEPORTER_BLUE_12,
13495         EL_MM_TELEPORTER_BLUE_11,
13496         EL_MM_TELEPORTER_BLUE_10,
13497         EL_MM_TELEPORTER_BLUE_9,
13498         EL_MM_TELEPORTER_BLUE_8,
13499         EL_MM_TELEPORTER_BLUE_7,
13500         EL_MM_TELEPORTER_BLUE_6
13501       },
13502       {
13503         EL_MM_POLARIZER_1,
13504         EL_MM_POLARIZER_16,
13505         EL_MM_POLARIZER_15,
13506         EL_MM_POLARIZER_14,
13507         EL_MM_POLARIZER_13,
13508         EL_MM_POLARIZER_12,
13509         EL_MM_POLARIZER_11,
13510         EL_MM_POLARIZER_10,
13511         EL_MM_POLARIZER_9,
13512         EL_MM_POLARIZER_8,
13513         EL_MM_POLARIZER_7,
13514         EL_MM_POLARIZER_6,
13515         EL_MM_POLARIZER_5,
13516         EL_MM_POLARIZER_4,
13517         EL_MM_POLARIZER_3,
13518         EL_MM_POLARIZER_2
13519       },
13520       {
13521         EL_DF_MIRROR_1,
13522         EL_DF_MIRROR_16,
13523         EL_DF_MIRROR_15,
13524         EL_DF_MIRROR_14,
13525         EL_DF_MIRROR_13,
13526         EL_DF_MIRROR_12,
13527         EL_DF_MIRROR_11,
13528         EL_DF_MIRROR_10,
13529         EL_DF_MIRROR_9,
13530         EL_DF_MIRROR_8,
13531         EL_DF_MIRROR_7,
13532         EL_DF_MIRROR_6,
13533         EL_DF_MIRROR_5,
13534         EL_DF_MIRROR_4,
13535         EL_DF_MIRROR_3,
13536         EL_DF_MIRROR_2
13537       },
13538       {
13539         EL_DF_MIRROR_ROTATING_1,
13540         EL_DF_MIRROR_ROTATING_16,
13541         EL_DF_MIRROR_ROTATING_15,
13542         EL_DF_MIRROR_ROTATING_14,
13543         EL_DF_MIRROR_ROTATING_13,
13544         EL_DF_MIRROR_ROTATING_12,
13545         EL_DF_MIRROR_ROTATING_11,
13546         EL_DF_MIRROR_ROTATING_10,
13547         EL_DF_MIRROR_ROTATING_9,
13548         EL_DF_MIRROR_ROTATING_8,
13549         EL_DF_MIRROR_ROTATING_7,
13550         EL_DF_MIRROR_ROTATING_6,
13551         EL_DF_MIRROR_ROTATING_5,
13552         EL_DF_MIRROR_ROTATING_4,
13553         EL_DF_MIRROR_ROTATING_3,
13554         EL_DF_MIRROR_ROTATING_2
13555       },
13556       {
13557         EL_DF_MIRROR_FIXED_1,
13558         EL_DF_MIRROR_FIXED_16,
13559         EL_DF_MIRROR_FIXED_15,
13560         EL_DF_MIRROR_FIXED_14,
13561         EL_DF_MIRROR_FIXED_13,
13562         EL_DF_MIRROR_FIXED_12,
13563         EL_DF_MIRROR_FIXED_11,
13564         EL_DF_MIRROR_FIXED_10,
13565         EL_DF_MIRROR_FIXED_9,
13566         EL_DF_MIRROR_FIXED_8,
13567         EL_DF_MIRROR_FIXED_7,
13568         EL_DF_MIRROR_FIXED_6,
13569         EL_DF_MIRROR_FIXED_5,
13570         EL_DF_MIRROR_FIXED_4,
13571         EL_DF_MIRROR_FIXED_3,
13572         EL_DF_MIRROR_FIXED_2
13573       },
13574
13575       {
13576         -1,
13577       },
13578     };
13579     int i, j;
13580
13581     for (i = 0; swappable_elements[i][0] != -1; i++)
13582     {
13583       int element1 = swappable_elements[i][0];
13584       int element2 = swappable_elements[i][1];
13585
13586       if (old_element == element1 || old_element == element2)
13587         new_element = (old_element == element1 ? element2 : element1);
13588     }
13589
13590     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
13591     {
13592       for (j = 0; j < 4; j++)
13593       {
13594         int element = rotatable_elements_4[i][j];
13595
13596         if (old_element == element)
13597           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
13598                          button == 2 ? rotatable_elements_4[i][0]           :
13599                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
13600                          old_element);
13601       }
13602     }
13603
13604     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
13605     {
13606       for (j = 0; j < 8; j++)
13607       {
13608         int element = rotatable_elements_8[i][j];
13609
13610         if (old_element == element)
13611           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
13612                          button == 2 ? rotatable_elements_8[i][0]           :
13613                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
13614                          old_element);
13615       }
13616     }
13617
13618     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
13619     {
13620       for (j = 0; j < 16; j++)
13621       {
13622         int element = rotatable_elements_16[i][j];
13623
13624         if (old_element == element)
13625           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
13626                          button == 2 ? rotatable_elements_16[i][0]             :
13627                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
13628                          old_element);
13629       }
13630     }
13631
13632     if (old_element != new_element)
13633     {
13634       int max_infotext_len = getMaxInfoTextLength();
13635       char infotext[MAX_OUTPUT_LINESIZE + 1];
13636
13637       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
13638       infotext[max_infotext_len] = '\0';
13639
13640       ClearEditorGadgetInfoText();
13641
13642       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
13643                 infotext);
13644     }
13645   }
13646
13647   if (IS_MM_WALL_EDITOR(new_element))
13648     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
13649   else
13650     SetElementSimple(x, y, new_element, change_level);
13651
13652   last_x = x;
13653   last_y = y;
13654 }
13655
13656 static void ResetIntelliDraw(void)
13657 {
13658   int x, y;
13659
13660   for (x = 0; x < lev_fieldx; x++)
13661     for (y = 0; y < lev_fieldy; y++)
13662       IntelliDrawBuffer[x][y] = Tile[x][y];
13663
13664   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
13665 }
13666
13667 static boolean draw_mode_hires = FALSE;
13668
13669 static boolean isHiresTileElement(int element)
13670 {
13671   return (IS_MM_WALL(element)        || element == EL_EMPTY);
13672 }
13673
13674 static boolean isHiresDrawElement(int element)
13675 {
13676   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
13677 }
13678
13679 static int numHiresTiles(int element)
13680 {
13681   if (IS_MM_WALL(element))
13682     return get_number_of_bits(MM_WALL_BITS(element));
13683
13684   return 1;
13685 }
13686
13687 static void SetDrawModeHiRes(int element)
13688 {
13689   draw_mode_hires =
13690     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13691      isHiresDrawElement(element));
13692 }
13693
13694 static boolean getDrawModeHiRes(void)
13695 {
13696   return draw_mode_hires;
13697 }
13698
13699 static int getLoResScreenPos(int pos)
13700 {
13701   return (getDrawModeHiRes() ? pos / 2 : pos);
13702 }
13703
13704 static int getLoResScreenMod(int pos)
13705 {
13706   return (getDrawModeHiRes() ? pos % 2 : 0);
13707 }
13708
13709 static void SetElementExt(int x, int y, int dx, int dy, int element,
13710                           boolean change_level, int button)
13711 {
13712   if (element < 0)
13713     SetElementSimple(x, y, Tile[x][y], change_level);
13714   else if (GetKeyModState() & KMOD_Shift)
13715     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
13716   else
13717     SetElementSimpleExt(x, y, dx, dy, element, change_level);
13718 }
13719
13720 static void SetElement(int x, int y, int element)
13721 {
13722   SetElementExt(x, y, 0, 0, element, TRUE, -1);
13723 }
13724
13725 static void SetElementButton(int x, int y, int dx, int dy, int element,
13726                              int button)
13727 {
13728   SetElementExt(x, y, dx, dy, element, TRUE, button);
13729 }
13730
13731 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
13732 {
13733   int lx = getLoResScreenPos(sx2) + level_xpos;
13734   int ly = getLoResScreenPos(sy2) + level_ypos;
13735   int dx = getLoResScreenMod(sx2);
13736   int dy = getLoResScreenMod(sy2);
13737
13738   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
13739 }
13740
13741 static void SetLevelElementHiRes(int lx2, int ly2, int element)
13742 {
13743   int lx = lx2 / 2;
13744   int ly = ly2 / 2;
13745   int dx = lx2 % 2;
13746   int dy = ly2 % 2;
13747
13748   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
13749 }
13750
13751 static int getLevelElementHiRes(int lx2, int ly2)
13752 {
13753   int lx = lx2 / 2;
13754   int ly = ly2 / 2;
13755   int dx = lx2 % 2;
13756   int dy = ly2 % 2;
13757   int element = Tile[lx][ly];
13758   unsigned int bitmask = (dx + 1) << (dy * 2);
13759
13760   if (IS_MM_WALL(element))
13761   {
13762     if (element & bitmask)
13763       return map_mm_wall_element(element);
13764     else
13765       return EL_EMPTY;
13766   }
13767
13768   return element;
13769 }
13770
13771 static void DrawLineElement(int x, int y, int element, boolean change_level)
13772 {
13773   SetElementHiRes(x, y, element, change_level);
13774 }
13775
13776 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
13777                      int element, boolean change_level)
13778 {
13779   int xsize = ABS(to_x - from_x);
13780   int ysize = ABS(to_y - from_y);
13781   int dx = (to_x < from_x ? -1 : +1);
13782   int dy = (to_y < from_y ? -1 : +1);
13783   int i;
13784
13785   if (from_y == to_y)                   // horizontal line
13786   {
13787     for (i = 0; i <= xsize; i++)
13788       DrawLineElement(from_x + i * dx, from_y, element, change_level);
13789   }
13790   else if (from_x == to_x)              // vertical line
13791   {
13792     for (i = 0; i <= ysize; i++)
13793       DrawLineElement(from_x, from_y + i * dy, element, change_level);
13794   }
13795   else                                  // diagonal line
13796   {
13797     if (ysize < xsize)                  // a < 1
13798     {
13799       float a = (float)ysize / (float)xsize;
13800
13801       for (i = 0; i <= xsize; i++)
13802       {
13803         int x = dx * i;
13804         int y = dy * (int)(a * i + 0.5);
13805
13806         DrawLineElement(from_x + x, from_y + y, element, change_level);
13807       }
13808     }
13809     else                                // a >= 1
13810     {
13811       float a = (float)xsize / (float)ysize;
13812
13813       for (i = 0; i <= ysize; i++)
13814       {
13815         int x = dx * (int)(a * i + 0.5);
13816         int y = dy * i;
13817
13818         DrawLineElement(from_x + x, from_y + y, element, change_level);
13819       }
13820     }
13821   }
13822 }
13823
13824 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
13825                     int element, boolean change_level)
13826 {
13827   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
13828   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
13829   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
13830   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
13831 }
13832
13833 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
13834                           int element, boolean change_level)
13835 {
13836   int y;
13837
13838   if (from_y > to_y)
13839     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
13840
13841   for (y = from_y; y <= to_y; y++)
13842     DrawLine(from_x, y, to_x, y, element, change_level);
13843 }
13844
13845 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
13846                        int element, boolean change_level)
13847 {
13848   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
13849   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
13850   int len_x = ABS(to_x - from_x);
13851   int len_y = ABS(to_y - from_y);
13852   int radius, x, y;
13853
13854   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
13855
13856   // not optimal (some points get drawn twice) but simple,
13857   // and fast enough for the few points we are drawing
13858
13859   for (x = 0; x <= radius; x++)
13860   {
13861     int sx, sy, sx2, sy2, lx, ly;
13862
13863     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
13864
13865     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
13866     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
13867     sx = getLoResScreenPos(sx2);
13868     sy = getLoResScreenPos(sy2);
13869     lx = sx + level_xpos;
13870     ly = sy + level_ypos;
13871
13872     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
13873       DrawLineElement(sx2, sy2, element, change_level);
13874   }
13875
13876   for (y = 0; y <= radius; y++)
13877   {
13878     int sx, sy, sx2, sy2, lx, ly;
13879
13880     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
13881
13882     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
13883     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
13884     sx = getLoResScreenPos(sx2);
13885     sy = getLoResScreenPos(sy2);
13886     lx = sx + level_xpos;
13887     ly = sy + level_ypos;
13888
13889     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
13890       DrawLineElement(sx2, sy2, element, change_level);
13891   }
13892 }
13893
13894 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
13895                     int element, boolean change_level)
13896 {
13897   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
13898   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
13899
13900   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
13901 }
13902
13903 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
13904
13905 #if DRAW_CIRCLES_BUTTON_AVAILABLE
13906 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
13907                        int element, boolean change_level)
13908 {
13909   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
13910   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
13911   int mirror_to_x2 = from_x - (to_x2 - from_x);
13912   int mirror_to_y2 = from_y - (to_y2 - from_y);
13913
13914   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
13915   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
13916   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
13917   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
13918 }
13919 #endif
13920
13921 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
13922 {
13923   int from_sx, from_sy;
13924   int to_sx, to_sy;
13925
13926   if (from_x > to_x)
13927     swap_numbers(&from_x, &to_x);
13928
13929   if (from_y > to_y)
13930     swap_numbers(&from_y, &to_y);
13931
13932   from_sx = SX + from_x * ed_tilesize;
13933   from_sy = SY + from_y * ed_tilesize;
13934   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
13935   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
13936
13937   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
13938   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
13939   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
13940   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
13941
13942   if (from_x == to_x && from_y == to_y)
13943     MarkTileDirty(from_x/2, from_y/2);
13944   else
13945     redraw_mask |= REDRAW_FIELD;
13946 }
13947
13948 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
13949                         int element, boolean change_level)
13950 {
13951   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
13952 }
13953
13954 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
13955                        int element, boolean change_level)
13956 {
13957   if (element == -1 || change_level)
13958     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
13959   else
13960     DrawAreaBorder(from_x, from_y, to_x, to_y);
13961 }
13962
13963 // values for CopyBrushExt()
13964 #define CB_AREA_TO_BRUSH                0
13965 #define CB_BRUSH_TO_CURSOR              1
13966 #define CB_BRUSH_TO_LEVEL               2
13967 #define CB_DELETE_OLD_CURSOR            3
13968 #define CB_DUMP_BRUSH                   4
13969 #define CB_DUMP_BRUSH_SMALL             5
13970 #define CB_CLIPBOARD_TO_BRUSH           6
13971 #define CB_BRUSH_TO_CLIPBOARD           7
13972 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
13973 #define CB_UPDATE_BRUSH_POSITION        9
13974 #define CB_FLIP_BRUSH_X                 10
13975 #define CB_FLIP_BRUSH_Y                 11
13976 #define CB_FLIP_BRUSH_XY                12
13977
13978 #define MAX_CB_PART_SIZE        10
13979 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
13980 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
13981 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
13982                                  MAX_CB_NUM_LINES *     \
13983                                  MAX_CB_PART_SIZE)
13984
13985 static int getFlippedTileExt(int map[], int element)
13986 {
13987   int i;
13988
13989   for (i = 0; map[i] != -1; i++)
13990     if (map[i] == element)
13991       return map[i ^ 1];        // get flipped element by flipping LSB of index
13992
13993   return element;
13994 }
13995
13996 static int getFlippedTileX(int element)
13997 {
13998   int map[] =
13999   {
14000     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
14001     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
14002     EL_BUG_LEFT,                        EL_BUG_RIGHT,
14003     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
14004     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
14005     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
14006     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
14007     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
14008     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
14009     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
14010     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
14011     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
14012     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
14013     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
14014     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
14015     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
14016     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
14017     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
14018     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
14019     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
14020     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
14021     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
14022     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
14023     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
14024     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
14025     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
14026     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14027     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
14028     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
14029     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
14030
14031     -1
14032   };
14033
14034   return getFlippedTileExt(map, element);
14035 }
14036
14037 static int getFlippedTileY(int element)
14038 {
14039   int map[] =
14040   {
14041     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
14042     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
14043     EL_BUG_UP,                          EL_BUG_DOWN,
14044     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
14045     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
14046     EL_ARROW_UP,                        EL_ARROW_DOWN,
14047     EL_MOLE_UP,                         EL_MOLE_DOWN,
14048     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
14049     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
14050     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
14051     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
14052     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
14053     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
14054     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
14055     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
14056     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
14057     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
14058     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
14059     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
14060     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
14061     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14062     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
14063     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
14064     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
14065
14066     -1
14067   };
14068
14069   return getFlippedTileExt(map, element);
14070 }
14071
14072 static int getFlippedTileXY(int element)
14073 {
14074   int map[] =
14075   {
14076     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
14077     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
14078     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
14079     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
14080     EL_BUG_LEFT,                        EL_BUG_UP,
14081     EL_BUG_RIGHT,                       EL_BUG_DOWN,
14082     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
14083     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
14084     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
14085     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
14086     EL_ARROW_LEFT,                      EL_ARROW_UP,
14087     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
14088     EL_MOLE_LEFT,                       EL_MOLE_UP,
14089     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
14090     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
14091     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
14092     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
14093     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
14094     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
14095     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
14096     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
14097     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
14098     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
14099     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
14100     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
14101     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
14102     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
14103     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
14104     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
14105     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
14106     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
14107     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
14108     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
14109     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
14110     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
14111     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
14112     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
14113     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
14114     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
14115     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
14116     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
14117     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
14118
14119     -1
14120   };
14121
14122   return getFlippedTileExt(map, element);
14123 }
14124
14125 static int getFlippedTile(int element, int mode)
14126 {
14127   if (IS_MM_ELEMENT(element))
14128   {
14129     // get MM game element
14130     element = map_element_RND_to_MM(element);
14131
14132     // get flipped game element
14133     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
14134                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
14135                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
14136                element);
14137
14138     // get RND game element again
14139     element = map_element_MM_to_RND(element);
14140   }
14141   else
14142   {
14143     // get flipped game element
14144     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
14145                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
14146                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
14147                element);
14148   }
14149
14150   return element;
14151 }
14152
14153 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
14154 {
14155   // flip tiles
14156   short tile1_flipped = getFlippedTile(*tile1, mode);
14157   short tile2_flipped = getFlippedTile(*tile2, mode);
14158
14159   // swap tiles
14160   *tile1 = tile2_flipped;
14161   *tile2 = tile1_flipped;
14162 }
14163
14164 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
14165 {
14166   DrawLineElement(sx, sy, element, change_level);
14167 }
14168
14169 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
14170                          int button, int mode)
14171 {
14172   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14173   static int brush_width, brush_height;
14174   static int last_cursor_x = -1, last_cursor_y = -1;
14175   static boolean delete_old_brush = FALSE;
14176   int new_element = BUTTON_ELEMENT(button);
14177   int x, y;
14178
14179   if (mode == CB_DUMP_BRUSH ||
14180       mode == CB_DUMP_BRUSH_SMALL ||
14181       mode == CB_BRUSH_TO_CLIPBOARD ||
14182       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14183   {
14184     if (edit_mode != ED_MODE_DRAWING)
14185       return;
14186
14187     char part[MAX_CB_PART_SIZE + 1] = "";
14188     char text[MAX_CB_TEXT_SIZE + 1] = "";
14189     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
14190     int height = (draw_with_brush ? brush_height : lev_fieldy);
14191     char *format = "%s%03d";
14192
14193     for (y = 0; y < height; y++)
14194       for (x = 0; x < width; x++)
14195         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
14196           format = "%s%04d";
14197
14198     for (y = 0; y < height; y++)
14199     {
14200       for (x = 0; x < width; x++)
14201       {
14202         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
14203         char *prefix = (mode == CB_DUMP_BRUSH ||
14204                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
14205
14206         if (element >= NUM_FILE_ELEMENTS)
14207           element = EL_UNKNOWN;
14208
14209         // copy brush to level sketch text buffer for the R'n'D forum:
14210         // - large tiles: `xxx or `xxxx (0x60 ASCII)
14211         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
14212         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
14213         strcat(text, part);
14214       }
14215
14216       strcat(text, "\n");
14217     }
14218
14219     if (mode == CB_BRUSH_TO_CLIPBOARD ||
14220         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
14221       SDL_SetClipboardText(text);
14222     else
14223       Print("%s", text);        // print brush data to console and log file
14224
14225     return;
14226   }
14227
14228   if (mode == CB_CLIPBOARD_TO_BRUSH)
14229   {
14230     if (edit_mode != ED_MODE_DRAWING)
14231       return;
14232
14233     if (!SDL_HasClipboardText())
14234     {
14235       Request("Clipboard is empty!", REQ_CONFIRM);
14236
14237       return;
14238     }
14239
14240     boolean copy_to_brush = (draw_with_brush ||
14241                              drawing_function == GADGET_ID_GRAB_BRUSH);
14242
14243     // this will delete the old brush, if already drawing with a brush
14244     if (copy_to_brush)
14245       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
14246
14247     // initialization is required for "odd" (incomplete) clipboard content
14248     for (x = 0; x < MAX_LEV_FIELDX; x++)
14249       for (y = 0; y < MAX_LEV_FIELDY; y++)
14250         brush_buffer[x][y] = EL_EMPTY;
14251
14252     brush_width  = 0;
14253     brush_height = 0;
14254     x = 0;
14255     y = 0;
14256
14257     char *clipboard_text = SDL_GetClipboardText();
14258     char *ptr = clipboard_text;
14259     boolean allow_new_row = FALSE;
14260     boolean stop = FALSE;
14261
14262     while (*ptr && !stop)
14263     {
14264       boolean prefix_found = FALSE;
14265       boolean start_new_row = FALSE;
14266
14267       // level sketch element number prefixes (may be multi-byte characters)
14268       char *prefix_list[] = { "`", "¸" };
14269       int i;
14270
14271       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
14272       {
14273         char *prefix = prefix_list[i];
14274
14275         // check if string is large enough for prefix
14276         if (strlen(ptr) < strlen(prefix))
14277         {
14278           stop = TRUE;
14279
14280           break;
14281         }
14282
14283         // check if string starts with prefix
14284         if (strPrefix(ptr, prefix))
14285         {
14286           ptr += strlen(prefix);
14287
14288           prefix_found = TRUE;
14289
14290           break;
14291         }
14292       }
14293
14294       // check if prefix found and followed by (at least) three digits
14295       if (prefix_found &&
14296           strlen(ptr) >= 3 &&
14297           ptr[0] >= '0' && ptr[0] <= '9' &&
14298           ptr[1] >= '0' && ptr[1] <= '9' &&
14299           ptr[2] >= '0' && ptr[2] <= '9')
14300       {
14301         int element = ((ptr[0] - '0') * 100 +
14302                        (ptr[1] - '0') * 10 +
14303                        (ptr[2] - '0'));
14304
14305         ptr += 3;
14306
14307         // level sketch element number might consist of four digits
14308         if (ptr[0] >= '0' && ptr[0] <= '9')
14309         {
14310           element = element * 10 + (ptr[0] - '0');
14311           ptr++;
14312         }
14313
14314         // remap some (historic, now obsolete) elements
14315         element = getMappedElement(element);
14316
14317         if (element >= NUM_FILE_ELEMENTS)
14318           element = EL_UNKNOWN;
14319
14320         brush_buffer[x][y] = element;
14321
14322         brush_width  = MAX(x + 1, brush_width);
14323         brush_height = MAX(y + 1, brush_height);
14324
14325         x++;
14326
14327         if (x >= MAX_LEV_FIELDX)
14328           start_new_row = TRUE;
14329
14330         allow_new_row = TRUE;
14331       }
14332       else
14333       {
14334         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
14335           start_new_row = TRUE;
14336
14337         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
14338       }
14339
14340       if (start_new_row)
14341       {
14342         x = 0;
14343         y++;
14344
14345         if (y >= MAX_LEV_FIELDY)
14346           stop = TRUE;
14347
14348         allow_new_row = FALSE;
14349       }
14350     }
14351
14352     SDL_free(clipboard_text);
14353
14354     if (brush_width == 0 || brush_height == 0)
14355     {
14356       Request("No level sketch found in clipboard!", REQ_CONFIRM);
14357
14358       return;
14359     }
14360
14361     if (copy_to_brush)
14362     {
14363       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
14364       int mx, my;
14365
14366       SDL_GetMouseState(&mx, &my);
14367
14368       // if inside drawing area, activate and draw brush at last mouse position
14369       if (mx >= gi->x && mx < gi->x + gi->width &&
14370           my >= gi->y && my < gi->y + gi->height)
14371         CopyBrushToCursor(last_cursor_x, last_cursor_y);
14372
14373       draw_with_brush = TRUE;
14374     }
14375     else
14376     {
14377       char request[100];
14378
14379       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
14380               brush_width, brush_height);
14381
14382       if (!Request(request, REQ_ASK))
14383         return;
14384
14385       for (x = 0; x < MAX_LEV_FIELDX; x++)
14386         for (y = 0; y < MAX_LEV_FIELDY; y++)
14387           Tile[x][y] = brush_buffer[x][y];
14388
14389       lev_fieldx = level.fieldx = brush_width;
14390       lev_fieldy = level.fieldy = brush_height;
14391
14392       boolean use_bd_engine = TRUE;
14393       boolean use_em_engine = TRUE;
14394       boolean use_sp_engine = TRUE;
14395       boolean use_mm_engine = TRUE;
14396
14397       for (x = 0; x < MAX_LEV_FIELDX; x++)
14398       {
14399         for (y = 0; y < MAX_LEV_FIELDY; y++)
14400         {
14401           int element = Tile[x][y];
14402
14403           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14404             use_bd_engine = FALSE;
14405
14406           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
14407             use_em_engine = FALSE;
14408
14409           if (!IS_SP_ELEMENT(element))
14410             use_sp_engine = FALSE;
14411
14412           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
14413             use_mm_engine = FALSE;
14414         }
14415       }
14416
14417       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
14418                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
14419                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
14420                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
14421                                 GAME_ENGINE_TYPE_RND);
14422
14423       // update element selection list
14424       ReinitializeElementList();
14425       ModifyEditorElementList();
14426
14427       SetBorderElement();
14428
14429       DrawEditModeWindow();
14430       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14431     }
14432
14433     return;
14434   }
14435
14436   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
14437     return;
14438
14439   if (mode == CB_AREA_TO_BRUSH)
14440   {
14441     int from_lx, from_ly;
14442
14443     if (from_x > to_x)
14444       swap_numbers(&from_x, &to_x);
14445
14446     if (from_y > to_y)
14447       swap_numbers(&from_y, &to_y);
14448
14449     brush_width = to_x - from_x + 1;
14450     brush_height = to_y - from_y + 1;
14451
14452     from_lx = from_x + level_xpos;
14453     from_ly = from_y + level_ypos;
14454
14455     for (y = 0; y < brush_height; y++)
14456     {
14457       for (x = 0; x < brush_width; x++)
14458       {
14459         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
14460
14461         if (button != 1)
14462           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
14463       }
14464     }
14465
14466     if (button != 1)
14467       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14468
14469     delete_old_brush = FALSE;
14470   }
14471   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
14472            mode == CB_BRUSH_TO_LEVEL)
14473   {
14474     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
14475     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
14476     int cursor_from_x = cursor_x - brush_width / 2;
14477     int cursor_from_y = cursor_y - brush_height / 2;
14478     int border_from_x = cursor_x, border_from_y = cursor_y;
14479     int border_to_x = cursor_x, border_to_y = cursor_y;
14480
14481     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
14482       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14483
14484     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
14485         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
14486     {
14487       delete_old_brush = FALSE;
14488
14489       return;
14490     }
14491
14492     for (y = 0; y < brush_height; y++)
14493     {
14494       for (x = 0; x < brush_width; x++)
14495       {
14496         int sx = cursor_from_x + x;
14497         int sy = cursor_from_y + y;
14498         int lx = sx + level_xpos;
14499         int ly = sy + level_ypos;
14500         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
14501         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
14502                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
14503                        brush_buffer[x][y] : new_element);
14504
14505         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
14506         {
14507           if (sx < border_from_x)
14508             border_from_x = sx;
14509           else if (sx > border_to_x)
14510             border_to_x = sx;
14511           if (sy < border_from_y)
14512             border_from_y = sy;
14513           else if (sy > border_to_y)
14514             border_to_y = sy;
14515
14516           DrawBrushElement(sx, sy, element, change_level);
14517         }
14518       }
14519     }
14520
14521     if (mode != CB_DELETE_OLD_CURSOR)
14522       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
14523
14524     last_cursor_x = cursor_x;
14525     last_cursor_y = cursor_y;
14526
14527     delete_old_brush = TRUE;
14528   }
14529   else if (mode == CB_FLIP_BRUSH_X)
14530   {
14531     for (y = 0; y < brush_height; y++)
14532       for (x = 0; x < (brush_width + 1) / 2; x++)
14533         SwapFlippedTiles(&brush_buffer[x][y],
14534                          &brush_buffer[brush_width - x - 1][y], mode);
14535
14536     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14537   }
14538   else if (mode == CB_FLIP_BRUSH_Y)
14539   {
14540     for (y = 0; y < (brush_height + 1) / 2; y++)
14541       for (x = 0; x < brush_width; x++)
14542         SwapFlippedTiles(&brush_buffer[x][y],
14543                          &brush_buffer[x][brush_height - y - 1], mode);
14544
14545     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14546   }
14547   else if (mode == CB_FLIP_BRUSH_XY)
14548   {
14549     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14550
14551     for (y = 0; y < MAX(brush_width, brush_height); y++)
14552       for (x = 0; x <= y; x++)
14553         SwapFlippedTiles(&brush_buffer[x][y],
14554                          &brush_buffer[y][x], mode);
14555
14556     swap_numbers(&brush_width, &brush_height);
14557
14558     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14559   }
14560
14561   if (mode == CB_UPDATE_BRUSH_POSITION)
14562   {
14563     last_cursor_x = from_x;
14564     last_cursor_y = from_y;
14565   }
14566 }
14567
14568 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
14569                             int button)
14570 {
14571   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
14572 }
14573
14574 static void CopyBrushToLevel(int x, int y, int button)
14575 {
14576   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
14577 }
14578
14579 static void CopyBrushToCursor(int x, int y)
14580 {
14581   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
14582 }
14583
14584 static void UpdateBrushPosition(int x, int y)
14585 {
14586   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
14587 }
14588
14589 static void DeleteBrushFromCursor(void)
14590 {
14591   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
14592 }
14593
14594 static void FlipBrushX(void)
14595 {
14596   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14597 }
14598
14599 static void FlipBrushY(void)
14600 {
14601   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
14602 }
14603
14604 static void RotateBrush(void)
14605 {
14606   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
14607   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
14608 }
14609
14610 void DumpBrush(void)
14611 {
14612   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
14613 }
14614
14615 void DumpBrush_Small(void)
14616 {
14617   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
14618 }
14619
14620 void CopyClipboardToBrush(void)
14621 {
14622   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
14623 }
14624
14625 void CopyBrushToClipboard(void)
14626 {
14627   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
14628 }
14629
14630 void CopyBrushToClipboard_Small(void)
14631 {
14632   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
14633 }
14634
14635 void UndoLevelEditorOperation(void)
14636 {
14637   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
14638 }
14639
14640 void RedoLevelEditorOperation(void)
14641 {
14642   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
14643 }
14644
14645 static void FloodFill(int from_x, int from_y, int fill_element)
14646 {
14647   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
14648 }
14649
14650 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
14651 {
14652   int from_x = from_sx2 + 2 * level_xpos;
14653   int from_y = from_sy2 + 2 * level_ypos;
14654   int max_fillx = lev_fieldx * 2;
14655   int max_filly = lev_fieldy * 2;
14656   short Fill[max_fillx][max_filly];
14657   int x, y;
14658
14659   for (x = 0; x < max_fillx; x++)
14660     for (y = 0; y < max_filly; y++)
14661       Fill[x][y] = getLevelElementHiRes(x, y);
14662
14663   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
14664                     Fill, max_fillx, max_filly);
14665
14666   for (x = 0; x < max_fillx; x++)
14667     for (y = 0; y < max_filly; y++)
14668       if (Fill[x][y] == fill_element)
14669         SetLevelElementHiRes(x, y, Fill[x][y]);
14670 }
14671
14672 // values for DrawLevelText() modes
14673 #define TEXT_INIT               0
14674 #define TEXT_SETCURSOR          1
14675 #define TEXT_WRITECHAR          2
14676 #define TEXT_BACKSPACE          3
14677 #define TEXT_NEWLINE            4
14678 #define TEXT_END                5
14679 #define TEXT_QUERY_TYPING       6
14680
14681 static int DrawLevelText(int sx, int sy, char letter, int mode)
14682 {
14683   static short delete_buffer[MAX_LEV_FIELDX];
14684   static int start_sx;
14685   static int last_sx, last_sy;
14686   static boolean typing = FALSE;
14687   int letter_element;
14688   int lx = 0, ly = 0;
14689
14690   // map lower case letters to upper case and convert special characters
14691   if (letter >= 'a' && letter <= 'z')
14692     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
14693   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
14694     letter_element = EL_CHAR_AUMLAUT;
14695   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
14696     letter_element = EL_CHAR_OUMLAUT;
14697   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
14698     letter_element = EL_CHAR_UUMLAUT;
14699   else if (letter == '^')
14700     letter_element = EL_CHAR_COPYRIGHT;
14701   else
14702     letter_element = EL_CHAR_ASCII0 + letter;
14703
14704   if (mode != TEXT_INIT)
14705   {
14706     if (!typing)
14707       return FALSE;
14708
14709     if (mode != TEXT_SETCURSOR)
14710     {
14711       sx = last_sx;
14712       sy = last_sy;
14713     }
14714
14715     lx = last_sx + level_xpos;
14716     ly = last_sy + level_ypos;
14717   }
14718
14719   switch (mode)
14720   {
14721     case TEXT_INIT:
14722       if (typing)
14723         DrawLevelText(0, 0, 0, TEXT_END);
14724
14725       typing = TRUE;
14726       start_sx = sx;
14727       last_sx = sx;
14728       last_sy = sy;
14729       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
14730       break;
14731
14732     case TEXT_SETCURSOR:
14733       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
14734       DrawAreaBorder(sx, sy, sx, sy);
14735       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
14736                      ed_tilesize, ed_tilesize);
14737       last_sx = sx;
14738       last_sy = sy;
14739       break;
14740
14741     case TEXT_WRITECHAR:
14742       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
14743       {
14744         if (new_element1 >= EL_STEEL_CHAR_START &&
14745             new_element1 <= EL_STEEL_CHAR_END)
14746           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
14747
14748         delete_buffer[sx - start_sx] = Tile[lx][ly];
14749         Tile[lx][ly] = letter_element;
14750
14751         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
14752           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
14753         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
14754           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
14755         else
14756           DrawLevelText(0, 0, 0, TEXT_END);
14757
14758         level.changed = TRUE;
14759       }
14760       break;
14761
14762     case TEXT_BACKSPACE:
14763       if (sx > start_sx)
14764       {
14765         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
14766         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
14767         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
14768       }
14769       break;
14770
14771     case TEXT_NEWLINE:
14772       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
14773         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
14774       else
14775         DrawLevelText(0, 0, 0, TEXT_END);
14776       break;
14777
14778     case TEXT_END:
14779       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14780       DrawEditorElement(sx, sy, Tile[lx][ly]);
14781       StopTextInput();
14782       typing = FALSE;
14783       break;
14784
14785     case TEXT_QUERY_TYPING:
14786       break;
14787
14788     default:
14789       break;
14790   }
14791
14792   return typing;
14793 }
14794
14795 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
14796                           int element, boolean change_level)
14797 {
14798   int lx = sx + level_xpos;
14799   int ly = sy + level_ypos;
14800
14801   if (element == -1)
14802     DrawEditorElement(sx, sy, Tile[lx][ly]);
14803   else
14804     DrawAreaBorder(sx, sy, sx, sy);
14805 }
14806
14807 static void CheckLevelBorderElement(boolean redraw_playfield)
14808 {
14809   int last_border_element = BorderElement;
14810
14811   SetBorderElement();
14812
14813   if (redraw_playfield && BorderElement != last_border_element)
14814     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14815 }
14816
14817 static void CopyLevelToUndoBuffer(int mode)
14818 {
14819   static boolean accumulated_undo = FALSE;
14820   boolean new_undo_buffer_position = TRUE;
14821   int x, y;
14822
14823   if (undo_buffer_steps == 0)
14824     accumulated_undo = FALSE;
14825
14826   switch (mode)
14827   {
14828     case UNDO_IMMEDIATE:
14829       accumulated_undo = FALSE;
14830       break;
14831
14832     case UNDO_ACCUMULATE:
14833       if (accumulated_undo)
14834         new_undo_buffer_position = FALSE;
14835       accumulated_undo = TRUE;
14836       break;
14837
14838     default:
14839       break;
14840   }
14841
14842   if (new_undo_buffer_position)
14843   {
14844     // advance position in undo buffer ring
14845     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
14846
14847     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
14848       undo_buffer_steps++;
14849   }
14850
14851   // always reset redo buffer when storing level change into undo buffer
14852   redo_buffer_steps = 0;
14853
14854   for (x = 0; x < lev_fieldx; x++)
14855     for (y = 0; y < lev_fieldy; y++)
14856       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
14857
14858   // check if drawing operation forces change of border style
14859   CheckLevelBorderElement(TRUE);
14860
14861   level.changed = TRUE;
14862 }
14863
14864 static void RandomPlacement(int new_element)
14865 {
14866   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
14867   int num_free_positions = 0;
14868   int num_percentage, num_elements;
14869   int x, y;
14870
14871   ResetIntelliDraw();
14872
14873   // determine number of free positions for randomly placing the new element
14874   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
14875   {
14876     free_position[x][y] =
14877       (random_placement_background_restricted ?
14878        Tile[x][y] == random_placement_background_element :
14879        Tile[x][y] != new_element);
14880
14881     if (free_position[x][y])
14882       num_free_positions++;
14883   }
14884
14885   // determine number of new elements to place there
14886   num_percentage = num_free_positions * random_placement_value / 100;
14887   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
14888                   num_percentage : random_placement_value);
14889
14890   // if less free positions than elements to place, fill all these positions
14891   if (num_free_positions < num_elements)
14892   {
14893     for (x = 0; x < lev_fieldx; x++)
14894       for (y = 0; y < lev_fieldy; y++)
14895         if (free_position[x][y])
14896           SetElement(x, y, new_element);
14897   }
14898   else
14899   {
14900     while (num_elements > 0)
14901     {
14902       x = GetSimpleRandom(lev_fieldx);
14903       y = GetSimpleRandom(lev_fieldy);
14904
14905       // don't place element at the same position twice
14906       if (free_position[x][y])
14907       {
14908         free_position[x][y] = FALSE;
14909         SetElement(x, y, new_element);
14910         num_elements--;
14911       }
14912     }
14913   }
14914
14915   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14916   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
14917 }
14918
14919 static void WrapLevel(int dx, int dy)
14920 {
14921   int wrap_dx = lev_fieldx - dx;
14922   int wrap_dy = lev_fieldy - dy;
14923   int x, y;
14924
14925   for (x = 0; x < lev_fieldx; x++)
14926     for (y = 0; y < lev_fieldy; y++)
14927       TileBackup[x][y] = Tile[x][y];
14928
14929   for (x = 0; x < lev_fieldx; x++)
14930     for (y = 0; y < lev_fieldy; y++)
14931       Tile[x][y] =
14932         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
14933
14934   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14935   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
14936 }
14937
14938 static void DrawAreaElementHighlight(boolean highlighted,
14939                                      boolean highlighted_similar)
14940 {
14941   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14942
14943   if (!highlighted)
14944     return;
14945
14946   int x, y;
14947
14948   for (x = 0; x < ed_fieldx; x++)
14949   {
14950     for (y = 0; y < ed_fieldy; y++)
14951     {
14952       boolean highlight = FALSE;
14953       int lx = x + level_xpos;
14954       int ly = y + level_ypos;
14955
14956       if (!IN_LEV_FIELD(lx, ly))
14957         continue;
14958
14959       // check if element is the same
14960       if (Tile[lx][ly] == new_element1)
14961         highlight = TRUE;
14962
14963       // check if element is similar
14964       if (highlighted_similar &&
14965           strEqual(element_info[Tile[lx][ly]].class_name,
14966                    element_info[new_element1].class_name))
14967         highlight = TRUE;
14968
14969       // check if element is matching MM style wall
14970       if (IS_MM_WALL(Tile[lx][ly]) &&
14971           map_mm_wall_element(Tile[lx][ly]) == new_element1)
14972         highlight = TRUE;
14973
14974       if (!highlight)
14975         continue;
14976
14977       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
14978       {
14979         int i;
14980
14981         for (i = 0; i < 4; i++)
14982         {
14983           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
14984             continue;
14985
14986           int xx = x * 2 + (i % 2);
14987           int yy = y * 2 + (i / 2);
14988           int sx = SX + xx * ed_tilesize / 2;
14989           int sy = SY + yy * ed_tilesize / 2;
14990           int from_sx = sx;
14991           int from_sy = sy;
14992           int to_sx = sx + ed_tilesize / 2 - 1;
14993           int to_sy = sy + ed_tilesize / 2 - 1;
14994
14995           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
14996           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
14997           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
14998           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
14999         }
15000       }
15001       else
15002       {
15003         int sx = SX + x * ed_tilesize;
15004         int sy = SY + y * ed_tilesize;
15005         int from_sx = sx;
15006         int from_sy = sy;
15007         int to_sx = sx + ed_tilesize - 1;
15008         int to_sy = sy + ed_tilesize - 1;
15009
15010         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
15011         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
15012         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
15013         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
15014       }
15015     }
15016   }
15017 }
15018
15019 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
15020 {
15021   char *template_filename_old = getLocalLevelTemplateFilename();
15022   char *template_filename_new =
15023     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
15024
15025   if (copyFile(template_filename_old, template_filename_new) != 0)
15026     Request("Cannot copy level template!", REQ_CONFIRM);
15027
15028   free(template_filename_new);
15029 }
15030
15031 static void HandleDrawingAreas(struct GadgetInfo *gi)
15032 {
15033   static boolean started_inside_drawing_area = FALSE;
15034   static int last_sx = -1;
15035   static int last_sy = -1;
15036   static int last_sx2 = -1;
15037   static int last_sy2 = -1;
15038   int id = gi->custom_id;
15039   int type_id = gi->custom_type_id;
15040   boolean button_press_event;
15041   boolean button_release_event;
15042   boolean inside_drawing_area = !gi->event.off_borders;
15043   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
15044   int actual_drawing_function;
15045   int button = gi->event.button;
15046   int new_element = BUTTON_ELEMENT(button);
15047   int sx = gi->event.x, sy = gi->event.y;
15048   int min_sx = 0, min_sy = 0;
15049   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
15050   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
15051   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
15052   int sx2 = gi->event.mx / mini_item_xsize;
15053   int sy2 = gi->event.my / mini_item_ysize;
15054   int dx = sx2 % 2;
15055   int dy = sy2 % 2;
15056   int lx = 0, ly = 0;
15057   int x, y;
15058
15059   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
15060   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
15061
15062   // make sure to stay inside drawing area boundaries
15063   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15064   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15065
15066   if (draw_level)
15067   {
15068     int min_lx = 0, min_ly = 0;
15069     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15070
15071     // get positions inside level field
15072     lx = sx + level_xpos;
15073     ly = sy + level_ypos;
15074
15075     if (!IN_LEV_FIELD(lx, ly))
15076       inside_drawing_area = FALSE;
15077
15078     // make sure to stay inside level field boundaries
15079     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15080     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15081
15082     // correct drawing area positions accordingly
15083     sx = lx - level_xpos;
15084     sy = ly - level_ypos;
15085   }
15086
15087   // also correct MM wall-sized (double) drawing area positions accordingly
15088   if (sx2 / 2 < sx || sx2 / 2 > sx)
15089   {
15090     dx = (sx2 / 2 < sx ? 0 : 1);
15091     sx2 = sx * 2 + dx;
15092   }
15093   if (sy2 / 2 < sy || sy2 / 2 > sy)
15094   {
15095     dy = (sy2 / 2 < sy ? 0 : 1);
15096     sy2 = sy * 2 + dy;
15097   }
15098
15099   if (!button_press_event && !button_release_event)
15100   {
15101     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
15102     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
15103                              isHiresTileElement(old_element) &&
15104                              isHiresDrawElement(new_element));
15105
15106     // prevent handling events for every pixel position when moving mouse
15107     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
15108         (sx2 == last_sx2 && sy2 == last_sy2))
15109       return;
15110   }
15111
15112   last_sx = sx;
15113   last_sy = sy;
15114   last_sx2 = sx2;
15115   last_sy2 = sy2;
15116
15117   if (button_press_event)
15118     started_inside_drawing_area = inside_drawing_area;
15119
15120   if (!started_inside_drawing_area)
15121     return;
15122
15123   if (!IS_VALID_BUTTON(button))
15124     return;
15125
15126   // handle info callback for each invocation of action callback
15127   gi->callback_info(gi);
15128
15129   // automatically switch to 'single item' drawing mode, if needed
15130   actual_drawing_function =
15131     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
15132      drawing_function : GADGET_ID_SINGLE_ITEMS);
15133
15134   // clicking into drawing area with pressed Control key picks element
15135   if (GetKeyModState() & KMOD_Control)
15136   {
15137     last_drawing_function = drawing_function;
15138     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15139   }
15140
15141   if (GetKeyModState() & KMOD_Shift)
15142   {
15143     if (button_press_event || button_release_event)
15144       ResetIntelliDraw();
15145   }
15146
15147   SetDrawModeHiRes(-1);         // reset to normal draw mode
15148
15149   switch (actual_drawing_function)
15150   {
15151     case GADGET_ID_SINGLE_ITEMS:
15152       if (draw_level)
15153       {
15154         if (button_release_event)
15155         {
15156           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15157
15158           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
15159               !inside_drawing_area)
15160             DeleteBrushFromCursor();
15161
15162           break;
15163         }
15164
15165         if (draw_with_brush)
15166         {
15167           CopyBrushToLevel(sx, sy, button);
15168         }
15169         else
15170         {
15171           SetDrawModeHiRes(new_element);
15172
15173           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
15174           {
15175             // remove player at old position
15176             for (y = 0; y < lev_fieldy; y++)
15177             {
15178               for (x = 0; x < lev_fieldx; x++)
15179               {
15180                 int old_element = Tile[x][y];
15181
15182                 if (IS_PLAYER_ELEMENT(old_element) &&
15183                     IS_PLAYER_ELEMENT(new_element))
15184                 {
15185                   int replaced_with_element =
15186                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
15187                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
15188
15189                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
15190                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
15191
15192                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
15193                      old_element == EL_PLAYER_1 ? EL_EMPTY :
15194
15195                      new_element >= EL_PLAYER_1 &&
15196                      new_element <= EL_PLAYER_4 &&
15197                      new_element == old_element ? EL_EMPTY :
15198
15199                      old_element);
15200
15201                   SetElement(x, y, replaced_with_element);
15202                 }
15203                 else if (IS_MM_MCDUFFIN(old_element) &&
15204                          IS_MM_MCDUFFIN(new_element))
15205                 {
15206                   // remove McDuffin at old position
15207                   SetElement(x, y, EL_EMPTY);
15208                 }
15209               }
15210             }
15211           }
15212
15213           SetElementButton(lx, ly, dx, dy, new_element, button);
15214         }
15215       }
15216       else if (!button_release_event)
15217       {
15218         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15219
15220         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
15221           DrawMiniGraphicExt(drawto,
15222                              gi->x + sx * MINI_TILEX,
15223                              gi->y + sy * MINI_TILEY,
15224                              el2edimg(new_element));
15225         else
15226           DrawFixedGraphicExt(drawto,
15227                               gi->x + sx * TILEX,
15228                               gi->y + sy * TILEY,
15229                               el2edimg(new_element), 0);
15230
15231         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15232           new_element = GFX_ELEMENT(new_element);
15233
15234         drawingarea_info[type_id].value[pos] = new_element;
15235
15236         CopyElementPropertiesToGame(properties_element);
15237
15238         if (id == GADGET_ID_CUSTOM_GRAPHIC)
15239         {
15240           UpdateCustomElementGraphicGadgets();
15241
15242           FrameCounter = 0;     // restart animation frame counter
15243         }
15244       }
15245       break;
15246
15247     case GADGET_ID_CONNECTED_ITEMS:
15248       {
15249         static int last_sx = -1;
15250         static int last_sy = -1;
15251
15252         if (button_release_event)
15253           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15254
15255         SetDrawModeHiRes(new_element);
15256
15257         if (getDrawModeHiRes())
15258         {
15259           sx = sx2;
15260           sy = sy2;
15261         }
15262
15263         if (!button_press_event)
15264           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
15265
15266         last_sx = sx;
15267         last_sy = sy;
15268       }
15269       break;
15270
15271     case GADGET_ID_LINE:
15272     case GADGET_ID_ARC:
15273     case GADGET_ID_RECTANGLE:
15274     case GADGET_ID_FILLED_BOX:
15275       SetDrawModeHiRes(new_element);
15276
15277       if (getDrawModeHiRes())
15278       {
15279         sx = sx2;
15280         sy = sy2;
15281       }
15282       // FALLTHROUGH
15283     case GADGET_ID_GRAB_BRUSH:
15284     case GADGET_ID_TEXT:
15285       {
15286         static int last_sx = -1;
15287         static int last_sy = -1;
15288         static int start_sx = -1;
15289         static int start_sy = -1;
15290         void (*draw_func)(int, int, int, int, int, boolean);
15291
15292         if (drawing_function == GADGET_ID_LINE)
15293           draw_func = DrawLine;
15294         else if (drawing_function == GADGET_ID_ARC)
15295           draw_func = DrawArc;
15296         else if (drawing_function == GADGET_ID_RECTANGLE)
15297           draw_func = DrawBox;
15298         else if (drawing_function == GADGET_ID_FILLED_BOX)
15299           draw_func = DrawFilledBox;
15300         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
15301           draw_func = SelectArea;
15302         else // (drawing_function == GADGET_ID_TEXT)
15303           draw_func = SetTextCursor;
15304
15305         if (button_press_event)
15306         {
15307           draw_func(sx, sy, sx, sy, new_element, FALSE);
15308           start_sx = last_sx = sx;
15309           start_sy = last_sy = sy;
15310
15311           if (drawing_function == GADGET_ID_TEXT)
15312             DrawLevelText(0, 0, 0, TEXT_END);
15313         }
15314         else if (button_release_event)
15315         {
15316           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
15317           if (drawing_function == GADGET_ID_GRAB_BRUSH)
15318           {
15319             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
15320             CopyBrushToCursor(sx, sy);
15321             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
15322                           MB_LEFTBUTTON);
15323             draw_with_brush = TRUE;
15324           }
15325           else if (drawing_function == GADGET_ID_TEXT)
15326             DrawLevelText(sx, sy, 0, TEXT_INIT);
15327           else
15328             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15329         }
15330         else if (last_sx != sx || last_sy != sy)
15331         {
15332           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
15333           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
15334             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
15335           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
15336           last_sx = sx;
15337           last_sy = sy;
15338         }
15339       }
15340       break;
15341
15342     case GADGET_ID_FLOOD_FILL:
15343       if (button_press_event && Tile[lx][ly] != new_element)
15344       {
15345         if (IS_MM_WALL_EDITOR(new_element))
15346           FloodFillWall_MM(sx2, sy2, new_element);
15347         else
15348           FloodFill(lx, ly, new_element);
15349
15350         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15351         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
15352       }
15353       break;
15354
15355     case GADGET_ID_PICK_ELEMENT:
15356       if (button_release_event)
15357         ClickOnGadget(level_editor_gadget[last_drawing_function],
15358                       MB_LEFTBUTTON);
15359       else if (draw_level)
15360         PickDrawingElement(button, Tile[lx][ly]);
15361       else
15362       {
15363         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15364
15365         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
15366       }
15367
15368     default:
15369       break;
15370   }
15371
15372   // do not mark level as modified for certain non-level-changing gadgets
15373   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
15374        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
15375       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
15376       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15377     return;
15378
15379   level.changed = TRUE;
15380 }
15381
15382 static void HandleCounterButtons(struct GadgetInfo *gi)
15383 {
15384   int gadget_id = gi->custom_id;
15385   int counter_id = gi->custom_type_id;
15386   int button = gi->event.button;
15387   int *counter_value = counterbutton_info[counter_id].value;
15388   int step = BUTTON_STEPSIZE(button) *
15389     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
15390
15391   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15392   {
15393     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
15394     boolean released = (gi->event.type == GD_EVENT_RELEASED);
15395     boolean level_changed = LevelChanged();
15396
15397     if ((level_changed && pressed) || (!level_changed && released))
15398       return;
15399
15400     if (level_changed && !Request("Level has changed! Discard changes?",
15401                                   REQ_ASK))
15402     {
15403       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15404         ModifyEditorCounterValue(counter_id, *counter_value);
15405
15406       return;
15407     }
15408   }
15409
15410   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
15411     *counter_value = gi->textinput.number_value;
15412   else
15413     ModifyEditorCounterValue(counter_id, *counter_value + step);
15414
15415   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
15416   {
15417     int last_game_engine_type = level.game_engine_type;
15418
15419     LoadLevel(level_nr);
15420     LoadScore(level_nr);
15421
15422     SaveLevelSetup_SeriesInfo();
15423
15424     TapeErase();
15425
15426     ResetUndoBuffer();
15427     DrawEditModeWindow();
15428
15429     if (level.game_engine_type != last_game_engine_type)
15430     {
15431       // update element selection list
15432       ReinitializeElementList();
15433       ModifyEditorElementList();
15434     }
15435
15436     return;
15437   }
15438
15439   switch (counter_id)
15440   {
15441     case ED_COUNTER_ID_YAMYAM_CONTENT:
15442       DrawYamYamContentAreas();
15443       break;
15444
15445     case ED_COUNTER_ID_BALL_CONTENT:
15446       DrawMagicBallContentAreas();
15447       break;
15448
15449     case ED_COUNTER_ID_ANDROID_CONTENT:
15450       DrawAndroidElementArea();
15451       break;
15452
15453     case ED_COUNTER_ID_GROUP_CONTENT:
15454       DrawGroupElementArea();
15455       CopyGroupElementPropertiesToGame(properties_element);
15456       break;
15457
15458     case ED_COUNTER_ID_INVENTORY_SIZE:
15459       DrawPlayerInitialInventoryArea(properties_element);
15460       break;
15461
15462     case ED_COUNTER_ID_MM_BALL_CONTENT:
15463       DrawMMBallContentArea();
15464       break;
15465
15466     case ED_COUNTER_ID_ENVELOPE_XSIZE:
15467     case ED_COUNTER_ID_ENVELOPE_YSIZE:
15468       DrawEnvelopeTextArea(-1);
15469       break;
15470
15471     case ED_COUNTER_ID_LEVEL_XSIZE:
15472     case ED_COUNTER_ID_LEVEL_YSIZE:
15473       lev_fieldx = level.fieldx;
15474       lev_fieldy = level.fieldy;
15475
15476       // check if resizing of level results in change of border border
15477       SetBorderElement();
15478
15479       break;
15480
15481     default:
15482       break;
15483   }
15484
15485   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
15486        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
15487       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
15488        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
15489     CopyElementPropertiesToGame(properties_element);
15490
15491   // do not mark level as modified for certain non-level-changing gadgets
15492   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
15493        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
15494       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
15495        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
15496     return;
15497
15498   level.changed = TRUE;
15499 }
15500
15501 static void HandleTextInputGadgets(struct GadgetInfo *gi)
15502 {
15503   int type_id = gi->custom_type_id;
15504
15505   strcpy(textinput_info[type_id].value, gi->textinput.value);
15506
15507   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
15508   {
15509     CopyElementPropertiesToGame(properties_element);
15510
15511     ModifyEditorElementList();  // update changed button info text
15512   }
15513
15514   // do not mark level as modified for certain non-level-changing gadgets
15515   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
15516       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
15517     return;
15518
15519   level.changed = TRUE;
15520 }
15521
15522 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
15523 {
15524   int type_id = gi->custom_type_id;
15525
15526   strncpy(textarea_info[type_id].value, gi->textarea.value,
15527           MAX_ENVELOPE_TEXT_LEN);
15528   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
15529
15530   level.changed = TRUE;
15531 }
15532
15533 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
15534 {
15535   int type_id = gi->custom_type_id;
15536   int value_old = *selectbox_info[type_id].value;
15537   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
15538
15539   *selectbox_info[type_id].value = value_new;
15540
15541   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
15542   {
15543     DrawLevelConfigWindow();
15544   }
15545   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15546   {
15547     element_info[properties_element].current_change_page = gi->selectbox.index;
15548
15549     DrawPropertiesWindow();
15550   }
15551   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
15552             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
15553            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
15554             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
15555            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
15556   {
15557     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
15558     {
15559       // when changing action type, also check action mode and action arg
15560       if (value_old != value_new)
15561         setSelectboxSpecialActionVariablesIfNeeded();
15562
15563       DrawPropertiesChange();
15564     }
15565
15566     CopyElementPropertiesToGame(properties_element);
15567   }
15568   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
15569   {
15570     // show or hide "engine" tabulator depending on game engine type
15571     DrawLevelConfigWindow();
15572
15573     // update element selection list depending on game engine type
15574     ReinitializeElementList();
15575     ModifyEditorElementList();
15576   }
15577   else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
15578   {
15579     // update BD cycle delay counter gadgets depending on BD scheduling type
15580     DrawLevelConfigWindow();
15581   }
15582
15583   // do not mark level as modified for certain non-level-changing gadgets
15584   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
15585       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
15586     return;
15587
15588   level.changed = TRUE;
15589 }
15590
15591 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
15592 {
15593   int type_id = gi->custom_type_id;
15594   int i;
15595
15596   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
15597       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
15598   {
15599     edit_mode_levelconfig = gi->custom_type_id;
15600
15601     DrawLevelConfigWindow();
15602   }
15603   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
15604            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
15605   {
15606     edit_mode_properties = gi->custom_type_id;
15607
15608     DrawPropertiesWindow();
15609   }
15610   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
15611            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
15612   {
15613     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
15614
15615     // backup original "level.field" (needed to track playfield changes)
15616     CopyPlayfield(level.field, TileBackup);
15617
15618     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
15619     CopyPlayfield(Tile, level.field);
15620
15621     if (new_template ||
15622         Request("Save this template and kill the old?", REQ_ASK))
15623       SaveLevelTemplate();
15624
15625     if (new_template)
15626       Request("Template saved!", REQ_CONFIRM);
15627
15628     // restore original "level.field" (needed to track playfield changes)
15629     CopyPlayfield(TileBackup, level.field);
15630   }
15631   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
15632   {
15633     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
15634
15635     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
15636         leveldir_current->readonly)
15637     {
15638       Request("This level set is read-only!", REQ_CONFIRM);
15639
15640       return;
15641     }
15642
15643     if (strEqual(levelset_name, ""))
15644     {
15645       Request("Please enter level set title!", REQ_CONFIRM);
15646
15647       return;
15648     }
15649
15650     if (strEqual(levelset_author, ""))
15651     {
15652       Request("Please enter level set author!", REQ_CONFIRM);
15653
15654       return;
15655     }
15656
15657     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
15658     {
15659       if (UpdateUserLevelSet(levelset_subdir,
15660                              levelset_name,
15661                              levelset_author,
15662                              levelset_num_levels))
15663       {
15664         Request("Level set updated!", REQ_CONFIRM);
15665       }
15666       else
15667       {
15668         Request("Updating level set failed!", REQ_CONFIRM);
15669       }
15670     }
15671     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
15672     {
15673       if (level.changed && !Request("Level has changed! Discard changes?",
15674                                      REQ_ASK))
15675         return;
15676
15677       if (CreateUserLevelSet(levelset_subdir,
15678                              levelset_name,
15679                              levelset_author,
15680                              levelset_num_levels,
15681                              levelset_use_levelset_artwork))
15682       {
15683         if (levelset_copy_level_template)
15684           CopyLevelTemplateToUserLevelSet(levelset_subdir);
15685
15686         Request("New level set created!", REQ_CONFIRM);
15687
15688         AddUserLevelSetToLevelInfo(levelset_subdir);
15689         ChangeEditorToLevelSet(levelset_subdir);
15690       }
15691       else
15692       {
15693         Request("Creating new level set failed!", REQ_CONFIRM);
15694       }
15695     }
15696   }
15697   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
15698            custom_element.num_change_pages < MAX_CHANGE_PAGES)
15699   {
15700     struct ElementInfo *ei = &element_info[properties_element];
15701
15702     // when modifying custom element, ask for copying level template
15703     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15704       return;
15705
15706     setElementChangePages(ei, ei->num_change_pages + 1);
15707
15708     // set new change page to be new current change page
15709     ei->current_change_page = ei->num_change_pages - 1;
15710     ei->change = &ei->change_page[ei->current_change_page];
15711
15712     setElementChangeInfoToDefaults(ei->change);
15713
15714     DrawPropertiesWindow();
15715
15716     level.changed = TRUE;
15717   }
15718   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
15719            custom_element.num_change_pages > MIN_CHANGE_PAGES)
15720   {
15721     struct ElementInfo *ei = &element_info[properties_element];
15722
15723     // when modifying custom element, ask for copying level template
15724     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15725       return;
15726
15727     // copy all change pages after change page to be deleted
15728     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
15729       ei->change_page[i] = ei->change_page[i + 1];
15730
15731     setElementChangePages(ei, ei->num_change_pages - 1);
15732
15733     DrawPropertiesWindow();
15734
15735     level.changed = TRUE;
15736   }
15737 }
15738
15739 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
15740 {
15741   int type_id = gi->custom_type_id;
15742
15743   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
15744       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
15745   {
15746     struct ElementInfo *ei = &element_info[properties_element];
15747     int step = BUTTON_STEPSIZE(gi->event.button);
15748
15749     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
15750     ei->current_change_page += step;
15751
15752     if (ei->current_change_page < 0)
15753       ei->current_change_page = 0;
15754     else if (ei->current_change_page >= ei->num_change_pages)
15755       ei->current_change_page = ei->num_change_pages - 1;
15756
15757     DrawPropertiesWindow();
15758   }
15759   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
15760            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
15761   {
15762     struct ElementInfo *ei = &element_info[properties_element];
15763     int current_change_page = ei->current_change_page;
15764
15765     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
15766     {
15767       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
15768         ei->change_page[current_change_page];
15769     }
15770     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
15771     {
15772       // when modifying custom element, ask for copying level template
15773       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
15774         return;
15775
15776       ei->change_page[current_change_page] =
15777         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
15778
15779       level.changed = TRUE;
15780     }
15781
15782     DrawPropertiesWindow();
15783   }
15784 }
15785
15786 static void HandleRadiobuttons(struct GadgetInfo *gi)
15787 {
15788   int type_id = gi->custom_type_id;
15789
15790   *radiobutton_info[type_id].value =
15791     radiobutton_info[type_id].checked_value;
15792
15793   // do not mark level as modified for certain non-level-changing gadgets
15794   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
15795       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
15796     return;
15797
15798   level.changed = TRUE;
15799 }
15800
15801 static void HandleCheckbuttons(struct GadgetInfo *gi)
15802 {
15803   int type_id = gi->custom_type_id;
15804
15805   *checkbutton_info[type_id].value ^= TRUE;
15806
15807   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
15808       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
15809       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
15810       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
15811          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
15812         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
15813          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
15814        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
15815   {
15816     CopyElementPropertiesToGame(properties_element);
15817   }
15818
15819   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
15820   {
15821     UpdateCustomElementGraphicGadgets();
15822   }
15823   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
15824            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
15825   {
15826     boolean template_related_changes_found = FALSE;
15827     int i;
15828
15829     // check if any custom, group or empty elements have been changed
15830     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
15831       if ((IS_CUSTOM_ELEMENT(i) ||
15832            IS_GROUP_ELEMENT(i) ||
15833            IS_EMPTY_ELEMENT(i)) &&
15834           element_info[i].modified_settings)
15835         template_related_changes_found = TRUE;
15836
15837     if (level.use_custom_template &&
15838         !fileExists(getGlobalLevelTemplateFilename()))
15839     {
15840       Request("No level template found!", REQ_CONFIRM);
15841
15842       level.use_custom_template = FALSE;
15843
15844       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
15845
15846       return;
15847     }
15848
15849     if (level.use_custom_template &&
15850         template_related_changes_found &&
15851         !Request("Discard changes and use level template?", REQ_ASK))
15852     {
15853       level.use_custom_template = FALSE;
15854
15855       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
15856
15857       return;
15858     }
15859
15860     if (!level.use_custom_template &&
15861         Request("Copy settings from level template?", REQ_ASK))
15862     {
15863       return;
15864     }
15865
15866     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
15867
15868     DrawEditModeWindow();
15869   }
15870   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
15871   {
15872     if (setup.editor.use_template_for_new_levels &&
15873         !fileExists(getGlobalLevelTemplateFilename()))
15874     {
15875       Request("No level template found!", REQ_CONFIRM);
15876
15877       return;
15878     }
15879
15880     if (setup.editor.use_template_for_new_levels &&
15881         level.changed &&
15882         !Request("Discard level and load template?", REQ_ASK))
15883     {
15884       return;
15885     }
15886
15887     if (!setup.editor.use_template_for_new_levels &&
15888         level.changed &&
15889         !Request("Discard level and use empty level?", REQ_ASK))
15890     {
15891       return;
15892     }
15893
15894     LoadLevel(level_nr);
15895     LoadScore(level_nr);
15896
15897     TapeErase();
15898
15899     ResetUndoBuffer();
15900     DrawEditModeWindow();
15901   }
15902   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
15903   {
15904     SetAutomaticNumberOfGemsNeeded();
15905   }
15906
15907   // do not mark level as modified for certain non-level-changing gadgets
15908   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
15909        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
15910       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
15911        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
15912        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
15913       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
15914     return;
15915
15916   level.changed = TRUE;
15917 }
15918
15919 static void HandleControlButtons(struct GadgetInfo *gi)
15920 {
15921   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
15922   static int last_edit_mode = ED_MODE_DRAWING;
15923   static int last_custom_copy_mode = -1;
15924   static int last_button = 0;
15925   int id = gi->custom_id;
15926   int button = gi->event.button;
15927   int step = BUTTON_STEPSIZE(button);
15928   int new_element = BUTTON_ELEMENT(button);
15929   int last_properties_element = properties_element;
15930   int x, y;
15931
15932   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
15933     DrawLevelText(0, 0, 0, TEXT_END);
15934
15935   if (id < ED_NUM_CTRL1_BUTTONS &&
15936       id != GADGET_ID_SINGLE_ITEMS &&
15937       id != GADGET_ID_PICK_ELEMENT &&
15938       edit_mode != ED_MODE_DRAWING &&
15939       drawing_function != GADGET_ID_PICK_ELEMENT &&
15940       !(GetKeyModState() & KMOD_Control))
15941     ChangeEditModeWindow(ED_MODE_DRAWING);
15942
15943   // element copy mode active, but no element button pressed => deactivate
15944   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
15945     last_custom_copy_mode = -1;
15946
15947   // when showing palette on element buttons, change element of button used
15948   if (editor.palette.show_on_element_buttons &&
15949       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
15950   {
15951     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
15952
15953     id = GADGET_ID_PALETTE;
15954   }
15955
15956   switch (id)
15957   {
15958     case GADGET_ID_SCROLL_LEFT:
15959       if (level_xpos >= 0)
15960       {
15961         if (lev_fieldx < ed_fieldx - 2)
15962           break;
15963
15964         level_xpos -= step;
15965         if (level_xpos < -1)
15966           level_xpos = -1;
15967         if (button == 1)
15968           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
15969         else
15970           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15971
15972         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
15973                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
15974       }
15975       break;
15976
15977     case GADGET_ID_SCROLL_RIGHT:
15978       if (level_xpos <= lev_fieldx - ed_fieldx)
15979       {
15980         if (lev_fieldx < ed_fieldx - 2)
15981           break;
15982
15983         level_xpos += step;
15984         if (level_xpos > lev_fieldx - ed_fieldx + 1)
15985           level_xpos = lev_fieldx - ed_fieldx + 1;
15986         if (button == 1)
15987           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
15988         else
15989           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
15990
15991         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
15992                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
15993       }
15994       break;
15995
15996     case GADGET_ID_SCROLL_UP:
15997       if (level_ypos >= 0)
15998       {
15999         if (lev_fieldy < ed_fieldy - 2)
16000           break;
16001
16002         level_ypos -= step;
16003         if (level_ypos < -1)
16004           level_ypos = -1;
16005         if (button == 1)
16006           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
16007         else
16008           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16009
16010         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16011                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16012       }
16013       break;
16014
16015     case GADGET_ID_SCROLL_DOWN:
16016       if (level_ypos <= lev_fieldy - ed_fieldy)
16017       {
16018         if (lev_fieldy < ed_fieldy - 2)
16019           break;
16020
16021         level_ypos += step;
16022         if (level_ypos > lev_fieldy - ed_fieldy + 1)
16023           level_ypos = lev_fieldy - ed_fieldy + 1;
16024         if (button == 1)
16025           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
16026         else
16027           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16028
16029         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
16030                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
16031       }
16032       break;
16033
16034     case GADGET_ID_SCROLL_HORIZONTAL:
16035       level_xpos = gi->event.item_position - 1;
16036
16037       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16038       BackToFront();
16039
16040       break;
16041
16042     case GADGET_ID_SCROLL_VERTICAL:
16043       level_ypos = gi->event.item_position - 1;
16044
16045       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16046       BackToFront();
16047
16048       break;
16049
16050     case GADGET_ID_SCROLL_LIST_UP:
16051     case GADGET_ID_SCROLL_LIST_DOWN:
16052     case GADGET_ID_SCROLL_LIST_VERTICAL:
16053       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
16054         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
16055       else
16056       {
16057         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
16058         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16059
16060         if (element_shift < 0)
16061           element_shift = 0;
16062         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16063           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16064
16065         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16066                      GDI_SCROLLBAR_ITEM_POSITION,
16067                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16068       }
16069
16070       ModifyEditorElementList();
16071
16072       break;
16073
16074     case GADGET_ID_PROPERTIES:
16075       // always switch off element properties when they are already displayed
16076       last_properties_element = new_element;
16077     case GADGET_ID_ELEMENT_LEFT:
16078     case GADGET_ID_ELEMENT_MIDDLE:
16079     case GADGET_ID_ELEMENT_RIGHT:
16080       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
16081                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
16082                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
16083                             new_element);
16084
16085       if (edit_mode != ED_MODE_PROPERTIES)
16086       {
16087         last_edit_mode = edit_mode;
16088
16089         ChangeEditModeWindow(ED_MODE_PROPERTIES);
16090
16091         last_level_drawing_function = drawing_function;
16092         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
16093                       MB_LEFTBUTTON);
16094       }
16095       else if (properties_element != last_properties_element)
16096       {
16097         DrawEditModeWindow();
16098       }
16099       else
16100       {
16101         ChangeEditModeWindow(ED_MODE_DRAWING);
16102
16103         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
16104                       MB_LEFTBUTTON);
16105       }
16106       break;
16107
16108     case GADGET_ID_PALETTE:
16109       if (edit_mode != ED_MODE_PALETTE)
16110       {
16111         last_edit_mode = edit_mode;
16112
16113         ChangeEditModeWindow(ED_MODE_PALETTE);
16114       }
16115       else
16116       {
16117         ChangeEditModeWindow(last_edit_mode);
16118       }
16119       break;
16120
16121     case GADGET_ID_WRAP_LEFT:
16122       WrapLevel(-step, 0);
16123       break;
16124
16125     case GADGET_ID_WRAP_RIGHT:
16126       WrapLevel(step, 0);
16127       break;
16128
16129     case GADGET_ID_WRAP_UP:
16130       WrapLevel(0, -step);
16131       break;
16132
16133     case GADGET_ID_WRAP_DOWN:
16134       WrapLevel(0, step);
16135       break;
16136
16137     case GADGET_ID_SINGLE_ITEMS:
16138     case GADGET_ID_CONNECTED_ITEMS:
16139     case GADGET_ID_LINE:
16140     case GADGET_ID_ARC:
16141     case GADGET_ID_TEXT:
16142     case GADGET_ID_RECTANGLE:
16143     case GADGET_ID_FILLED_BOX:
16144     case GADGET_ID_FLOOD_FILL:
16145     case GADGET_ID_GRAB_BRUSH:
16146     case GADGET_ID_PICK_ELEMENT:
16147       if (drawing_function != GADGET_ID_PICK_ELEMENT)
16148         last_drawing_function = drawing_function;
16149       drawing_function = id;
16150       draw_with_brush = FALSE;
16151       break;
16152
16153     case GADGET_ID_RANDOM_PLACEMENT:
16154       RandomPlacement(new_element);
16155       break;
16156
16157     case GADGET_ID_ZOOM:
16158       // zoom level editor tile size in or out (or reset to default size)
16159       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
16160                      button == 2 ? ed_tilesize_default :
16161                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
16162
16163       // when using touch device, cycle through all zoom tilesizes
16164       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
16165         ed_tilesize = MICRO_TILESIZE;
16166
16167       // limit zoom level by upper and lower bound
16168       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
16169
16170       InitZoomLevelSettings(ed_tilesize);
16171
16172       if (edit_mode == ED_MODE_DRAWING)
16173       {
16174         DrawDrawingWindow();
16175
16176         // redraw zoom gadget info text
16177         PrintEditorGadgetInfoText(level_editor_gadget[id]);
16178       }
16179
16180       // save current editor zoom tilesize
16181       SaveSetup_AutoSetup();
16182
16183       break;
16184
16185     case GADGET_ID_CUSTOM_COPY_FROM:
16186     case GADGET_ID_CUSTOM_COPY_TO:
16187     case GADGET_ID_CUSTOM_EXCHANGE:
16188       last_custom_copy_mode = id;
16189       last_drawing_function = drawing_function;
16190       break;
16191
16192     case GADGET_ID_CUSTOM_COPY:
16193       CopyCustomElement(properties_element, -1, id);
16194       break;
16195
16196     case GADGET_ID_CUSTOM_PASTE:
16197       CopyCustomElement(-1, properties_element, id);
16198       break;
16199
16200     case GADGET_ID_UNDO:
16201       if (button < 0)   // keep button value (even if modifier keys are pressed)
16202         button = -button;
16203       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
16204         button = 3;
16205
16206       if (button == 1 && undo_buffer_steps == 0)
16207       {
16208         Request("Undo buffer empty!", REQ_CONFIRM);
16209
16210         break;
16211       }
16212       else if (button == 2)
16213       {
16214         break;
16215       }
16216       else if (button == 3 && redo_buffer_steps == 0)
16217       {
16218         Request("Redo buffer empty!", REQ_CONFIRM);
16219
16220         break;
16221       }
16222
16223       if (edit_mode != ED_MODE_DRAWING)
16224         ChangeEditModeWindow(ED_MODE_DRAWING);
16225
16226       if (button == 1)
16227       {
16228         // undo
16229
16230         undo_buffer_position =
16231           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
16232
16233         undo_buffer_steps--;
16234         redo_buffer_steps++;
16235       }
16236       else
16237       {
16238         // redo
16239
16240         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
16241
16242         undo_buffer_steps++;
16243         redo_buffer_steps--;
16244       }
16245
16246       for (x = 0; x < lev_fieldx; x++)
16247         for (y = 0; y < lev_fieldy; y++)
16248           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
16249
16250       // check if undo operation forces change of border style
16251       CheckLevelBorderElement(FALSE);
16252
16253       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16254
16255       break;
16256
16257     case GADGET_ID_CONF:
16258       if (edit_mode != ED_MODE_LEVELCONFIG)
16259       {
16260         last_edit_mode = edit_mode;
16261
16262         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
16263       }
16264       else
16265       {
16266         ChangeEditModeWindow(ED_MODE_DRAWING);
16267       }
16268       break;
16269
16270     case GADGET_ID_CLEAR:
16271       if (edit_mode != ED_MODE_DRAWING)
16272         ChangeEditModeWindow(ED_MODE_DRAWING);
16273
16274       for (x = 0; x < MAX_LEV_FIELDX; x++)
16275         for (y = 0; y < MAX_LEV_FIELDY; y++)
16276           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
16277
16278       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
16279
16280       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
16281       break;
16282
16283     case GADGET_ID_SAVE:
16284     {
16285       // saving read-only levels into personal level set modifies global vars
16286       // "leveldir_current" and "level_nr"; restore them after saving level
16287       LevelDirTree *leveldir_former = leveldir_current;
16288       int level_nr_former = level_nr;
16289       char *level_filename;
16290       boolean new_level;
16291
16292       if (leveldir_current->readonly &&
16293           !PrepareSavingIntoPersonalLevelSet())
16294         break;
16295
16296       level_filename = getDefaultLevelFilename(level_nr);
16297       new_level = !fileExists(level_filename);
16298
16299       if (new_level ||
16300           Request("Save this level and kill the old?", REQ_ASK))
16301       {
16302         if (leveldir_former->readonly)
16303           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
16304
16305         SetAutomaticNumberOfGemsNeeded();
16306
16307         CopyPlayfield(Tile, level.field);
16308         SaveLevel(level_nr);
16309
16310         level.changed = FALSE;
16311
16312         if (new_level)
16313         {
16314           char level_saved_msg[64];
16315
16316           if (leveldir_former->readonly)
16317             sprintf(level_saved_msg,
16318                     "Level saved as level %d into personal level set!",
16319                     level_nr);
16320           else
16321             strcpy(level_saved_msg, "Level saved!");
16322
16323           Request(level_saved_msg, REQ_CONFIRM);
16324         }
16325       }
16326
16327       // "cd" back to copied-from levelset (in case of saved read-only level)
16328       leveldir_current = leveldir_former;
16329       level_nr = level_nr_former;
16330
16331       break;
16332     }
16333
16334     case GADGET_ID_TEST:
16335       if (LevelChanged())
16336         level.game_version = GAME_VERSION_ACTUAL;
16337
16338       CopyPlayfield(level.field, TileBackup);
16339       CopyPlayfield(Tile, level.field);
16340
16341       CopyNativeLevel_RND_to_Native(&level);
16342
16343       UnmapLevelEditorGadgets();
16344       UndrawSpecialEditorDoor();
16345
16346       CloseDoor(DOOR_CLOSE_ALL);
16347
16348       // needed before playing if editor playfield area has different size
16349       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
16350
16351       // redraw_mask = REDRAW_ALL;
16352
16353       level_editor_test_game = TRUE;
16354
16355       StartGameActions(FALSE, setup.autorecord, level.random_seed);
16356
16357       break;
16358
16359     case GADGET_ID_EXIT:
16360       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
16361       break;
16362
16363     default:
16364       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
16365           id <= GADGET_ID_ELEMENTLIST_LAST)
16366       {
16367         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
16368
16369         new_element = editor_elements[element_position + element_shift];
16370
16371         if (IS_EDITOR_CASCADE(new_element))
16372         {
16373           int i;
16374
16375           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
16376           {
16377             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
16378             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
16379
16380             if (*cascade_element == new_element)
16381             {
16382               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
16383               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
16384
16385               // update element selection list
16386               ReinitializeElementList();
16387               ModifyEditorElementList();
16388
16389               // update cascading gadget info text
16390               PrintEditorGadgetInfoText(level_editor_gadget[id]);
16391
16392               // save current editor cascading state
16393               SaveSetup_EditorCascade();
16394
16395               break;
16396             }
16397           }
16398
16399           break;
16400         }
16401
16402         if (last_custom_copy_mode != -1)
16403         {
16404           if (CopyCustomElement(properties_element, new_element,
16405                                 last_custom_copy_mode))
16406           {
16407             ClickOnGadget(level_editor_gadget[last_drawing_function],
16408                           MB_LEFTBUTTON);
16409
16410             last_custom_copy_mode = -1;
16411           }
16412
16413           break;
16414         }
16415
16416         // change element of button used to show palette
16417         if (editor.palette.show_on_element_buttons)
16418           button = last_button;
16419
16420         PickDrawingElement(button, new_element);
16421
16422         if (!stick_element_properties_window &&
16423             drawing_function != GADGET_ID_PICK_ELEMENT &&
16424             !(GetKeyModState() & KMOD_Control))
16425         {
16426           properties_element = new_element;
16427           if (edit_mode == ED_MODE_PROPERTIES)
16428             DrawPropertiesWindow();
16429         }
16430
16431         if (drawing_function == GADGET_ID_PICK_ELEMENT)
16432           ClickOnGadget(level_editor_gadget[last_drawing_function],
16433                         MB_LEFTBUTTON);
16434
16435         if (!use_permanent_palette)
16436           ChangeEditModeWindow(last_edit_mode);
16437       }
16438 #ifdef DEBUG
16439       else if (gi->event.type == GD_EVENT_PRESSED)
16440         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
16441       else if (gi->event.type == GD_EVENT_RELEASED)
16442         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
16443       else if (gi->event.type == GD_EVENT_MOVING)
16444         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
16445       else
16446         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
16447 #endif
16448       break;
16449   }
16450 }
16451
16452 void HandleLevelEditorKeyInput(Key key)
16453 {
16454   char letter = getCharFromKey(key);
16455
16456   if (drawing_function == GADGET_ID_TEXT &&
16457       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
16458   {
16459     if (letter)
16460       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
16461     else if (key == KSYM_Delete || key == KSYM_BackSpace)
16462       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
16463     else if (key == KSYM_Return)
16464       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
16465     else if (key == KSYM_Escape)
16466       DrawLevelText(0, 0, 0, TEXT_END);
16467
16468     return;
16469   }
16470
16471   int id = GADGET_ID_NONE;
16472   int new_element_shift = element_shift;
16473   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
16474   int button = MB_LEFTBUTTON;
16475   int i;
16476
16477   switch (key)
16478   {
16479     case KSYM_Left:
16480       id = GADGET_ID_SCROLL_LEFT;
16481       break;
16482     case KSYM_Right:
16483       id = GADGET_ID_SCROLL_RIGHT;
16484       break;
16485     case KSYM_Up:
16486       id = GADGET_ID_SCROLL_UP;
16487       break;
16488     case KSYM_Down:
16489       id = GADGET_ID_SCROLL_DOWN;
16490       break;
16491
16492     case KSYM_Page_Up:
16493     case KSYM_Page_Down:
16494       step *= (key == KSYM_Page_Up ? -1 : +1);
16495       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
16496
16497       if (element_shift < 0)
16498         element_shift = 0;
16499       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16500         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16501
16502       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16503                    GDI_SCROLLBAR_ITEM_POSITION,
16504                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16505
16506       ModifyEditorElementList();
16507
16508       break;
16509
16510     case KSYM_Home:
16511     case KSYM_End:
16512       element_shift = (key == KSYM_Home ? 0 :
16513                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
16514
16515       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16516                    GDI_SCROLLBAR_ITEM_POSITION,
16517                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16518
16519       ModifyEditorElementList();
16520
16521       break;
16522
16523     case KSYM_Insert:
16524     case KSYM_Delete:
16525
16526       // this is needed to prevent interference with running "True X-Mouse"
16527       if (GetKeyModStateFromEvents() & KMOD_Control)
16528         break;
16529
16530       // check for last or next editor cascade block in element list
16531       for (i = 0; i < num_editor_elements; i++)
16532       {
16533         if ((key == KSYM_Insert && i == element_shift) ||
16534             (key == KSYM_Delete && new_element_shift > element_shift))
16535           break;
16536
16537         // jump to next cascade block (or to start of element list)
16538         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
16539           new_element_shift = i;
16540       }
16541
16542       if (i < num_editor_elements)
16543         element_shift = new_element_shift;
16544
16545       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
16546         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
16547
16548       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
16549                    GDI_SCROLLBAR_ITEM_POSITION,
16550                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
16551
16552       ModifyEditorElementList();
16553
16554       break;
16555
16556     case KSYM_Escape:
16557       if (edit_mode == ED_MODE_DRAWING)
16558         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
16559       else if (edit_mode == ED_MODE_LEVELCONFIG)
16560         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
16561       else if (edit_mode == ED_MODE_PROPERTIES)
16562         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
16563       else if (edit_mode == ED_MODE_PALETTE)
16564         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
16565       else              // should never happen
16566         ChangeEditModeWindow(ED_MODE_DRAWING);
16567
16568       break;
16569
16570     default:
16571       break;
16572   }
16573
16574   if (id != GADGET_ID_NONE)
16575     ClickOnGadget(level_editor_gadget[id], button);
16576   else if (letter == '1' || letter == '?')
16577     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
16578   else if (letter == '2')
16579     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
16580   else if (letter == '3')
16581     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
16582   else if (letter == '.')
16583     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
16584   else if (letter == 'U')
16585     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
16586   else if (letter == '-' || key == KSYM_KP_Subtract)
16587     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
16588   else if (letter == '0' || key == KSYM_KP_0)
16589     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
16590   else if (letter == '+' || key == KSYM_KP_Add ||
16591            letter == '=')       // ("Shift-=" is "+" on US keyboards)
16592     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
16593   else if (key == KSYM_Return ||
16594            key == KSYM_space ||
16595            key == setup.shortcut.toggle_pause)
16596     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
16597   else
16598     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
16599       if (letter && letter == controlbutton_info[i].shortcut)
16600         if (!anyTextGadgetActive())
16601           ClickOnGadget(level_editor_gadget[i], button);
16602
16603   if (draw_with_brush)
16604   {
16605     if (letter == 'x')
16606       FlipBrushX();
16607     else if (letter == 'y')
16608       FlipBrushY();
16609     else if (letter == 'z')
16610       RotateBrush();
16611   }
16612 }
16613
16614 static void HandleLevelEditorIdle_Properties(void)
16615 {
16616   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
16617   int x = editor.settings.element_graphic.x + element_border;
16618   int y = editor.settings.element_graphic.y + element_border;
16619   static DelayCounter action_delay = { 0 };
16620   int i;
16621
16622   action_delay.value = GameFrameDelay;
16623
16624   if (!DelayReached(&action_delay))
16625     return;
16626
16627   for (i = 0; i < ED_NUM_SELECTBOX; i++)
16628   {
16629     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
16630
16631     if (gi->mapped && gi->active && gi->selectbox.open)
16632       return;
16633   }
16634
16635   DrawEditorElementAnimation(SX + x, SY + y);
16636
16637   redraw_mask |= REDRAW_FIELD;
16638
16639   FrameCounter++;       // increase animation frame counter
16640 }
16641
16642 static void HandleLevelEditorIdle_Drawing(void)
16643 {
16644   static boolean last_highlighted = FALSE;
16645   static boolean last_highlighted_similar = FALSE;
16646   boolean highlighted = (GetKeyModState() & KMOD_Alt);
16647   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
16648
16649   if (highlighted != last_highlighted ||
16650       (highlighted && highlighted_similar != last_highlighted_similar))
16651   {
16652     DrawAreaElementHighlight(highlighted, highlighted_similar);
16653
16654     redraw_mask |= REDRAW_FIELD;
16655   }
16656
16657   last_highlighted = highlighted;
16658   last_highlighted_similar = highlighted_similar;
16659 }
16660
16661 void HandleLevelEditorIdle(void)
16662 {
16663   if (edit_mode == ED_MODE_PROPERTIES)
16664     HandleLevelEditorIdle_Properties();
16665   else if (edit_mode == ED_MODE_DRAWING)
16666     HandleLevelEditorIdle_Drawing();
16667 }
16668
16669 static void ClearEditorGadgetInfoText(void)
16670 {
16671   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
16672 }
16673
16674 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
16675 {
16676   char infotext[MAX_OUTPUT_LINESIZE + 1];
16677   int max_infotext_len = getMaxInfoTextLength();
16678
16679   if (gi == NULL || strlen(gi->info_text) == 0)
16680     return;
16681
16682   strncpy(infotext, gi->info_text, max_infotext_len);
16683   infotext[max_infotext_len] = '\0';
16684
16685   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
16686   {
16687     int key = controlbutton_info[gi->custom_id].shortcut;
16688
16689     if (key)
16690     {
16691       char shortcut[MAX_OUTPUT_LINESIZE + 1];
16692
16693       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
16694         sprintf(shortcut, " ('.' or '%c')", key);
16695       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
16696         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
16697       else if (gi->custom_id == GADGET_ID_TEST)
16698         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
16699       else if (gi->custom_id == GADGET_ID_UNDO)
16700         sprintf(shortcut, " ('%c/Shift-U')", key);
16701       else if (gi->custom_id == GADGET_ID_ZOOM)
16702         sprintf(shortcut, " ('%c', '0', '-')", key);
16703       else
16704         sprintf(shortcut, " ('%s%c')",
16705                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
16706
16707       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
16708         strcat(infotext, shortcut);
16709     }
16710   }
16711
16712   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
16713 }
16714
16715 void HandleEditorGadgetInfoText(void *ptr)
16716 {
16717   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
16718
16719   if (game_status != GAME_MODE_EDITOR)
16720     return;
16721
16722   ClearEditorGadgetInfoText();
16723
16724   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
16725     return;
16726
16727   // misuse this function to delete brush cursor, if needed
16728   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
16729     DeleteBrushFromCursor();
16730
16731   PrintEditorGadgetInfoText(gi);
16732 }
16733
16734 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
16735 {
16736   int id = gi->custom_id;
16737   int type_id = gi->custom_type_id;
16738   int sx = gi->event.x;
16739   int sy = gi->event.y;
16740   int lx = sx + level_xpos;
16741   int ly = sy + level_ypos;
16742   int min_sx = 0, min_sy = 0;
16743   int max_sx = gi->drawing.area_xsize - 1;
16744   int max_sy = gi->drawing.area_ysize - 1;
16745   int actual_drawing_function = drawing_function;
16746   int max_infotext_len = getMaxInfoTextLength();
16747   char infotext[MAX_OUTPUT_LINESIZE + 1];
16748
16749   infotext[0] = '\0';           // start with empty info text
16750
16751   // pressed Control key: simulate picking element
16752   if (GetKeyModState() & KMOD_Control)
16753     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
16754
16755   ClearEditorGadgetInfoText();
16756
16757   if (gi->event.type == GD_EVENT_INFO_LEAVING)
16758     return;
16759
16760   // make sure to stay inside drawing area boundaries
16761   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
16762   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
16763
16764   if (id == GADGET_ID_DRAWING_LEVEL)
16765   {
16766     if (button_status)
16767     {
16768       int min_lx = 0, min_ly = 0;
16769       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
16770
16771       // get positions inside level field
16772       lx = sx + level_xpos;
16773       ly = sy + level_ypos;
16774
16775       // make sure to stay inside level field boundaries
16776       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
16777       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
16778
16779       // correct drawing area positions accordingly
16780       sx = lx - level_xpos;
16781       sy = ly - level_ypos;
16782     }
16783
16784     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
16785     {
16786       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
16787       {
16788         static int start_lx = 0;
16789         static int start_ly = 0;
16790         char *text;
16791
16792         if (gi->event.type == GD_EVENT_PRESSED)
16793         {
16794           start_lx = lx;
16795           start_ly = ly;
16796         }
16797
16798         switch (actual_drawing_function)
16799         {
16800           case GADGET_ID_SINGLE_ITEMS:
16801             text = "Drawing single items";
16802             break;
16803           case GADGET_ID_CONNECTED_ITEMS:
16804             text = "Drawing connected items";
16805             break;
16806           case GADGET_ID_LINE:
16807             text = "Drawing line";
16808             break;
16809           case GADGET_ID_ARC:
16810             text = "Drawing arc";
16811             break;
16812           case GADGET_ID_TEXT:
16813             text = "Setting text cursor";
16814             break;
16815           case GADGET_ID_RECTANGLE:
16816             text = "Drawing rectangle";
16817             break;
16818           case GADGET_ID_FILLED_BOX:
16819             text = "Drawing filled box";
16820             break;
16821           case GADGET_ID_FLOOD_FILL:
16822             text = "Flood fill";
16823             break;
16824           case GADGET_ID_GRAB_BRUSH:
16825             text = "Grabbing brush";
16826             break;
16827           case GADGET_ID_PICK_ELEMENT:
16828             text = "Picking element";
16829             break;
16830
16831           default:
16832             text = "Drawing position";
16833             break;
16834         }
16835
16836         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16837           sprintf(infotext, "%s: %d, %d", text, lx, ly);
16838         else
16839           sprintf(infotext, "%s: %d, %d", text,
16840                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
16841       }
16842       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16843         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
16844       else
16845         sprintf(infotext, "Level position: %d, %d", lx, ly);
16846     }
16847
16848     // misuse this function to draw brush cursor, if needed
16849     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
16850     {
16851       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
16852         CopyBrushToCursor(sx, sy);
16853       else
16854         DeleteBrushFromCursor();
16855     }
16856
16857     if (!draw_with_brush)
16858       UpdateBrushPosition(sx, sy);
16859   }
16860   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
16861   {
16862     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
16863     int element = drawingarea_info[type_id].value[pos];
16864
16865     strncpy(infotext, getElementInfoText(element), max_infotext_len);
16866   }
16867   else
16868   {
16869     if (id == GADGET_ID_CUSTOM_CONTENT)
16870       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
16871     else if (id == GADGET_ID_GROUP_CONTENT)
16872       sprintf(infotext, "group element position: %d", sx + 1);
16873     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
16874              id <= GADGET_ID_YAMYAM_CONTENT_7)
16875       sprintf(infotext, "content area %d position: %d, %d",
16876               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
16877     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
16878              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
16879       sprintf(infotext, "content area %d position: %d, %d",
16880               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
16881     else if (id == GADGET_ID_ANDROID_CONTENT)
16882       sprintf(infotext, "android element position: %d", sx + 1);
16883     else if (drawingarea_info[type_id].infotext != NULL)
16884       strcpy(infotext, drawingarea_info[type_id].infotext);
16885   }
16886
16887   infotext[max_infotext_len] = '\0';
16888
16889   if (strlen(infotext) > 0)
16890     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
16891 }
16892
16893 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
16894                             boolean quick_quit)
16895 {
16896   if (!ask_if_level_has_changed ||
16897       !LevelChanged() ||
16898       Request("Level has changed! Exit without saving?",
16899               REQ_ASK | REQ_STAY_OPEN))
16900   {
16901     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
16902     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
16903
16904     // draw normal door
16905     UndrawSpecialEditorDoor();
16906
16907     // use door animation if door 1 viewport is unchanged and contains toolbox
16908     if (useEditorDoorAnimation())
16909       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
16910
16911     // close editor doors if viewport definition is the same as in main menu
16912     if (vp_door_1->x      == DX     &&
16913         vp_door_1->y      == DY     &&
16914         vp_door_1->width  == DXSIZE &&
16915         vp_door_1->height == DYSIZE &&
16916         vp_door_2->x      == VX     &&
16917         vp_door_2->y      == VY     &&
16918         vp_door_2->width  == VXSIZE &&
16919         vp_door_2->height == VYSIZE)
16920       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
16921     else
16922       SetDoorState(DOOR_CLOSE_ALL);
16923
16924     BackToFront();
16925
16926     if (quick_quit)
16927       FadeSkipNextFadeIn();
16928
16929     SetGameStatus(GAME_MODE_MAIN);
16930
16931     DrawMainMenu();
16932   }
16933   else
16934   {
16935     if (!global.use_envelope_request)
16936     {
16937       CloseDoor(DOOR_CLOSE_1);
16938       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
16939     }
16940   }
16941 }