added support for diagonal player movement in BD engine to level editor
[rocksndiamonds.git] / src / editor.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // editor.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "game.h"
21 #include "init.h"
22 #include "tape.h"
23
24
25 #define INFOTEXT_UNKNOWN_ELEMENT        "unknown"
26
27
28 // ----------------------------------------------------------------------------
29 // screen and artwork graphic pixel position definitions
30 // ----------------------------------------------------------------------------
31
32 // values for the control window
33 #define ED_CTRL1_BUTTONS_HORIZ          4       // toolbox
34 #define ED_CTRL1_BUTTONS_VERT           4
35 #define ED_CTRL2_BUTTONS_HORIZ          3       // level
36 #define ED_CTRL2_BUTTONS_VERT           2
37 #define ED_CTRL3_BUTTONS_HORIZ          3       // CE and GE
38 #define ED_CTRL3_BUTTONS_VERT           1
39 #define ED_CTRL4_BUTTONS_HORIZ          2       // CE and GE
40 #define ED_CTRL4_BUTTONS_VERT           1
41 #define ED_CTRL5_BUTTONS_HORIZ          1       // properties
42 #define ED_CTRL5_BUTTONS_VERT           1
43 #define ED_CTRL6_BUTTONS_HORIZ          3       // properties
44 #define ED_CTRL6_BUTTONS_VERT           1
45 #define ED_CTRL7_BUTTONS_HORIZ          1       // palette
46 #define ED_CTRL7_BUTTONS_VERT           1
47
48 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
49 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
50 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
51 #define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
52 #define ED_NUM_CTRL5_BUTTONS   (ED_CTRL5_BUTTONS_HORIZ * ED_CTRL5_BUTTONS_VERT)
53 #define ED_NUM_CTRL6_BUTTONS   (ED_CTRL6_BUTTONS_HORIZ * ED_CTRL6_BUTTONS_VERT)
54 #define ED_NUM_CTRL7_BUTTONS   (ED_CTRL7_BUTTONS_HORIZ * ED_CTRL7_BUTTONS_VERT)
55 #define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
56 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
57 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
58 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
59 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
60 #define ED_NUM_CTRL1_7_BUTTONS (ED_NUM_CTRL1_6_BUTTONS + ED_NUM_CTRL7_BUTTONS)
61 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_7_BUTTONS
62
63 // values for the element list
64 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
65 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
66 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
67 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
68 #define ED_ELEMENTLIST_COLS             MAX(1, editor.palette.cols)
69 #define ED_ELEMENTLIST_ROWS             MAX(1, editor.palette.rows)
70 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (ED_ELEMENTLIST_COLS)
71 #define ED_ELEMENTLIST_BUTTONS_VERT     (ED_ELEMENTLIST_ROWS)
72 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
73                                          ED_ELEMENTLIST_BUTTONS_VERT)
74
75 // standard distances
76 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
77 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
78 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
79 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
80 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
81 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
82 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
83                                          ED_DRAWINGAREA_BORDER_SIZE)
84 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
85
86 // values for drawingarea gadgets
87 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
88 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
89 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
90 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
91 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
92
93 // values for checkbutton gadgets
94 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
95 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
96
97 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
98 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
99
100 #define ED_SETTINGS_LEVEL_TABS_X        (editor.settings.tabs.x)
101 #define ED_SETTINGS_LEVEL_TABS_Y        (editor.settings.tabs.y)
102 #define ED_SETTINGS_ELEMENT_TABS_X      (editor.settings.tabs.x)
103 #define ED_SETTINGS_ELEMENT_TABS_Y      (editor.settings.tabs.y +       \
104                                          editor.settings.tabs.yoffset2)
105
106 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
107 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
108
109 #define ED_LEVEL_TABS_XSTART            (ED_SETTINGS_LEVEL_TABS_X)
110 #define ED_LEVEL_TABS_YSTART            (ED_SETTINGS_LEVEL_TABS_Y)
111 #define ED_LEVEL_SETTINGS_XSTART        (ED_SETTINGS_LEVEL_TABS_X +     \
112                                          ED_SETTINGS_TABS_XOFFSET)
113 #define ED_LEVEL_SETTINGS_YSTART        (ED_SETTINGS_LEVEL_TABS_Y +     \
114                                          ED_TABBUTTON_YSIZE +           \
115                                          ED_GADGET_TINY_DISTANCE +      \
116                                          ED_TAB_BAR_HEIGHT +            \
117                                          ED_SETTINGS_TABS_YOFFSET +     \
118                                          getFontHeight(FONT_TEXT_1) +   \
119                                          ED_GADGET_TEXT_DISTANCE)
120 #define ED_ELEMENT_TABS_XSTART          (ED_SETTINGS_ELEMENT_TABS_X)
121 #define ED_ELEMENT_TABS_YSTART          (ED_SETTINGS_ELEMENT_TABS_Y)
122 #define ED_ELEMENT_SETTINGS_XSTART      (ED_SETTINGS_ELEMENT_TABS_X +   \
123                                          ED_SETTINGS_TABS_XOFFSET)
124 #define ED_ELEMENT_SETTINGS_YSTART      (ED_SETTINGS_ELEMENT_TABS_Y +   \
125                                          ED_TABBUTTON_YSIZE +           \
126                                          ED_GADGET_TINY_DISTANCE +      \
127                                          ED_TAB_BAR_HEIGHT +            \
128                                          ED_SETTINGS_TABS_YOFFSET)
129
130 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
131                                          ED_GADGET_TEXT_DISTANCE)
132 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
133                                          ED_GADGET_LINE_DISTANCE)
134
135 #define ED_POS_RANGE                    (10000)
136 #define ED_POS_LEVEL_TABS_FIRST         (1 * ED_POS_RANGE)
137 #define ED_POS_LEVEL_TABS_LAST          (2 * ED_POS_RANGE - 1)
138 #define ED_POS_LEVEL_SETTINGS_FIRST     (2 * ED_POS_RANGE)
139 #define ED_POS_LEVEL_SETTINGS_LAST      (3 * ED_POS_RANGE - 1)
140 #define ED_POS_ELEMENT_TABS_FIRST       (3 * ED_POS_RANGE)
141 #define ED_POS_ELEMENT_TABS_LAST        (4 * ED_POS_RANGE - 1)
142 #define ED_POS_ELEMENT_SETTINGS_FIRST   (4 * ED_POS_RANGE)
143 #define ED_POS_ELEMENT_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
144
145 #define ED_LEVEL_TABS_XPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
146 #define ED_LEVEL_TABS_YPOS(n)           (ED_POS_LEVEL_TABS_FIRST + (n))
147
148 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
149 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
150
151 #define ED_ELEMENT_TABS_XPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
152 #define ED_ELEMENT_TABS_YPOS(n)         (ED_POS_ELEMENT_TABS_FIRST + (n))
153
154 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
155 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
156
157 #define IS_POS_LEVEL_TABS(n)          ((n) >= ED_POS_LEVEL_TABS_FIRST && \
158                                        (n) <= ED_POS_LEVEL_TABS_LAST)
159 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
160                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
161 #define IS_POS_ELEMENT_TABS(n)        ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
162                                        (n) <= ED_POS_ELEMENT_TABS_LAST)
163 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
164                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
165
166 #define ED_LEVEL_TABS_LINE(n)           ((n) - ED_POS_LEVEL_TABS_FIRST)
167 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
168 #define ED_ELEMENT_TABS_LINE(n)         ((n) - ED_POS_ELEMENT_TABS_FIRST)
169 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
170
171 #define ED_LEVEL_TABS_X(n)              (ED_LEVEL_TABS_XSTART + \
172                                          (n) * ED_SETTINGS_TABS_XOFFSET)
173 #define ED_LEVEL_TABS_Y(n)              (ED_LEVEL_TABS_YSTART + \
174                                          (n) * ED_SETTINGS_TABS_YOFFSET)
175
176 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
177                                          (n) * ED_SETTINGS_XOFFSET)
178 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
179                                          (n) * ED_SETTINGS_YOFFSET)
180
181 #define ED_ELEMENT_TABS_X(n)            (ED_ELEMENT_TABS_XSTART +       \
182                                          (n) * ED_SETTINGS_TABS_XOFFSET)
183 #define ED_ELEMENT_TABS_Y(n)            (ED_ELEMENT_TABS_YSTART +       \
184                                          (n) * ED_SETTINGS_TABS_YOFFSET)
185
186 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
187                                          (n) * ED_SETTINGS_XOFFSET)
188 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
189                                          (n) * ED_SETTINGS_YOFFSET)
190
191 #define ED_POS_TO_LEVEL_TABS_X(n)       \
192   (ED_LEVEL_TABS_X(ED_LEVEL_TABS_LINE(n)))
193 #define ED_POS_TO_LEVEL_TABS_Y(n)       \
194   (ED_LEVEL_TABS_Y(ED_LEVEL_TABS_LINE(n)))
195
196 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
197   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
198 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
199   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
200
201 #define ED_POS_TO_ELEMENT_TABS_X(n)     \
202   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
203 #define ED_POS_TO_ELEMENT_TABS_Y(n)     \
204   (ED_ELEMENT_TABS_Y(ED_ELEMENT_TABS_LINE(n)))
205
206 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
207   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
208 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
209   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
210
211 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_TABS(n) ? \
212                                          ED_POS_TO_LEVEL_TABS_X(n) : \
213                                          IS_POS_LEVEL_SETTINGS(n) ?     \
214                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
215                                          IS_POS_ELEMENT_TABS(n) ?       \
216                                          ED_POS_TO_ELEMENT_TABS_X(n) : \
217                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
218                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
219 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_TABS(n) ? \
220                                          ED_POS_TO_LEVEL_TABS_Y(n) : \
221                                          IS_POS_LEVEL_SETTINGS(n) ?     \
222                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
223                                          IS_POS_ELEMENT_TABS(n) ?       \
224                                          ED_POS_TO_ELEMENT_TABS_Y(n) : \
225                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
226                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
227
228 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
229                                          ED_DRAWINGAREA_TILE_SIZE)
230 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
231                                          ED_DRAWINGAREA_TILE_SIZE)
232
233 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
234                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
235 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
236                                          (ED_CHECKBUTTON_YSIZE -        \
237                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
238
239 #define ED_AREA_XOFFSET_2(n)      (0)
240 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
241                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
242
243 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
244                                     ED_SETTINGS_XOFF((i).xoffset) +     \
245                                     ED_AREA_XOFFSET_1((i).x) -          \
246                                     ED_AREA_XOFFSET_2((i).area_xsize))
247 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
248                                     ED_SETTINGS_YOFF((i).yoffset) +     \
249                                     ED_AREA_YOFFSET_1((i).y) -          \
250                                     ED_AREA_YOFFSET_2((i).area_ysize))
251
252 // values for element content drawing areas
253 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
254 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
255 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
256 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
257
258 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
259 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
260 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
261 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
262
263 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
264 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
265 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
266 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
267
268 // element content
269 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
270 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
271
272 // yamyam content
273 #define ED_XPOS_YAM                     0
274 #define ED_YPOS_YAM                     5
275 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
276 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
277 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
278 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
279 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
280                                          ED_SETTINGS_XOFF(n))
281 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
282                                          ED_SETTINGS_YOFF(n) +          \
283                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
284                                          ED_AREA_YOFFSET_2(3))
285
286 // magic ball content
287 #define ED_XPOS_BALL                    0
288 #define ED_YPOS_BALL                    6
289 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
290 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
291 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
292 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
293 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
294                                          ED_SETTINGS_XOFF(n))
295 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
296                                          ED_SETTINGS_YOFF(n) +          \
297                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
298                                          ED_AREA_YOFFSET_2(3))
299
300 // values for scrolling gadgets for drawing area
301 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
302 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
303
304 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
305 #define ED_SCROLL_UP_YPOS               (0)
306 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
307 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
308 #define ED_SCROLL_LEFT_XPOS             (0)
309 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
310 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
311 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
312 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
313                                          ED_SCROLLBUTTON_XSIZE)
314 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
315 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
316 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
317 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
318 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
319                                          ED_SCROLLBUTTON_YSIZE)
320 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
321 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
322
323 // values for scrolling gadgets for element list
324 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
325 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
326
327 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
328                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
329                                          ED_ELEMENTLIST_XSIZE)
330 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
331 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
332 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
333                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
334                                          ED_ELEMENTLIST_YSIZE -         \
335                                          ED_SCROLLBUTTON2_YSIZE)
336 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
337 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
338                                          ED_SCROLLBUTTON2_YSIZE)
339 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
340 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
341                                          ED_ELEMENTLIST_YSIZE -         \
342                                          2 * ED_SCROLLBUTTON2_YSIZE)
343
344 // values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText()
345 #define INFOTEXT_FONT           FONT_TEXT_2
346 #define INFOTEXT_XSIZE          SXSIZE
347 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
348 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
349 #define INFOTEXT_X              (editor.settings.tooltip.x)
350 #define INFOTEXT_Y              (editor.settings.tooltip.y)
351 #define INFOTEXT_XY_REDEFINED   (INFOTEXT_X != -1 || INFOTEXT_Y != -1)
352 #define INFOTEXT_XPOS           SX + (INFOTEXT_XY_REDEFINED ? INFOTEXT_X : 0)
353 #define INFOTEXT_YPOS           SY + (INFOTEXT_XY_REDEFINED ? INFOTEXT_Y : \
354                                       SYSIZE - INFOTEXT_YSIZE)
355
356
357 // ----------------------------------------------------------------------------
358 // editor gadget definitions
359 // ----------------------------------------------------------------------------
360
361 enum
362 {
363   GADGET_ID_NONE = -1,
364
365   // drawing toolbox buttons
366
367   GADGET_ID_SINGLE_ITEMS,
368   GADGET_ID_CONNECTED_ITEMS,
369   GADGET_ID_LINE,
370   GADGET_ID_ARC,
371   GADGET_ID_RECTANGLE,
372   GADGET_ID_FILLED_BOX,
373   GADGET_ID_WRAP_UP,
374   GADGET_ID_TEXT,
375   GADGET_ID_FLOOD_FILL,
376   GADGET_ID_WRAP_LEFT,
377   GADGET_ID_ZOOM,
378   GADGET_ID_WRAP_RIGHT,
379   GADGET_ID_RANDOM_PLACEMENT,
380   GADGET_ID_GRAB_BRUSH,
381   GADGET_ID_WRAP_DOWN,
382   GADGET_ID_PICK_ELEMENT,
383
384   GADGET_ID_UNDO,
385   GADGET_ID_CONF,
386   GADGET_ID_SAVE,
387   GADGET_ID_CLEAR,
388   GADGET_ID_TEST,
389   GADGET_ID_EXIT,
390
391   GADGET_ID_CUSTOM_COPY_FROM,
392   GADGET_ID_CUSTOM_COPY_TO,
393   GADGET_ID_CUSTOM_EXCHANGE,
394   GADGET_ID_CUSTOM_COPY,
395   GADGET_ID_CUSTOM_PASTE,
396
397   GADGET_ID_PROPERTIES,
398   GADGET_ID_ELEMENT_LEFT,
399   GADGET_ID_ELEMENT_MIDDLE,
400   GADGET_ID_ELEMENT_RIGHT,
401   GADGET_ID_PALETTE,
402
403   // counter gadget identifiers
404
405   GADGET_ID_SELECT_LEVEL_DOWN,
406   GADGET_ID_SELECT_LEVEL_TEXT,
407   GADGET_ID_SELECT_LEVEL_UP,
408   GADGET_ID_LEVEL_XSIZE_DOWN,
409   GADGET_ID_LEVEL_XSIZE_TEXT,
410   GADGET_ID_LEVEL_XSIZE_UP,
411   GADGET_ID_LEVEL_YSIZE_DOWN,
412   GADGET_ID_LEVEL_YSIZE_TEXT,
413   GADGET_ID_LEVEL_YSIZE_UP,
414   GADGET_ID_LEVEL_RANDOM_DOWN,
415   GADGET_ID_LEVEL_RANDOM_TEXT,
416   GADGET_ID_LEVEL_RANDOM_UP,
417   GADGET_ID_LEVEL_GEMSLIMIT_DOWN,
418   GADGET_ID_LEVEL_GEMSLIMIT_TEXT,
419   GADGET_ID_LEVEL_GEMSLIMIT_UP,
420   GADGET_ID_LEVEL_TIMELIMIT_DOWN,
421   GADGET_ID_LEVEL_TIMELIMIT_TEXT,
422   GADGET_ID_LEVEL_TIMELIMIT_UP,
423   GADGET_ID_LEVEL_TIMESCORE_DOWN,
424   GADGET_ID_LEVEL_TIMESCORE_TEXT,
425   GADGET_ID_LEVEL_TIMESCORE_UP,
426   GADGET_ID_LEVEL_RANDOM_SEED_DOWN,
427   GADGET_ID_LEVEL_RANDOM_SEED_TEXT,
428   GADGET_ID_LEVEL_RANDOM_SEED_UP,
429   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
430   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
431   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
432   GADGET_ID_ELEMENT_VALUE1_DOWN,
433   GADGET_ID_ELEMENT_VALUE1_TEXT,
434   GADGET_ID_ELEMENT_VALUE1_UP,
435   GADGET_ID_ELEMENT_VALUE2_DOWN,
436   GADGET_ID_ELEMENT_VALUE2_TEXT,
437   GADGET_ID_ELEMENT_VALUE2_UP,
438   GADGET_ID_ELEMENT_VALUE3_DOWN,
439   GADGET_ID_ELEMENT_VALUE3_TEXT,
440   GADGET_ID_ELEMENT_VALUE3_UP,
441   GADGET_ID_ELEMENT_VALUE4_DOWN,
442   GADGET_ID_ELEMENT_VALUE4_TEXT,
443   GADGET_ID_ELEMENT_VALUE4_UP,
444   GADGET_ID_YAMYAM_CONTENT_DOWN,
445   GADGET_ID_YAMYAM_CONTENT_TEXT,
446   GADGET_ID_YAMYAM_CONTENT_UP,
447   GADGET_ID_BALL_CONTENT_DOWN,
448   GADGET_ID_BALL_CONTENT_TEXT,
449   GADGET_ID_BALL_CONTENT_UP,
450   GADGET_ID_ANDROID_CONTENT_DOWN,
451   GADGET_ID_ANDROID_CONTENT_TEXT,
452   GADGET_ID_ANDROID_CONTENT_UP,
453   GADGET_ID_ENVELOPE_XSIZE_DOWN,
454   GADGET_ID_ENVELOPE_XSIZE_TEXT,
455   GADGET_ID_ENVELOPE_XSIZE_UP,
456   GADGET_ID_ENVELOPE_YSIZE_DOWN,
457   GADGET_ID_ENVELOPE_YSIZE_TEXT,
458   GADGET_ID_ENVELOPE_YSIZE_UP,
459   GADGET_ID_INVENTORY_SIZE_DOWN,
460   GADGET_ID_INVENTORY_SIZE_TEXT,
461   GADGET_ID_INVENTORY_SIZE_UP,
462   GADGET_ID_MM_BALL_CONTENT_DOWN,
463   GADGET_ID_MM_BALL_CONTENT_TEXT,
464   GADGET_ID_MM_BALL_CONTENT_UP,
465   GADGET_ID_CUSTOM_SCORE_DOWN,
466   GADGET_ID_CUSTOM_SCORE_TEXT,
467   GADGET_ID_CUSTOM_SCORE_UP,
468   GADGET_ID_CUSTOM_GEMCOUNT_DOWN,
469   GADGET_ID_CUSTOM_GEMCOUNT_TEXT,
470   GADGET_ID_CUSTOM_GEMCOUNT_UP,
471   GADGET_ID_CUSTOM_VALUE_FIX_DOWN,
472   GADGET_ID_CUSTOM_VALUE_FIX_TEXT,
473   GADGET_ID_CUSTOM_VALUE_FIX_UP,
474   GADGET_ID_CUSTOM_VALUE_RND_DOWN,
475   GADGET_ID_CUSTOM_VALUE_RND_TEXT,
476   GADGET_ID_CUSTOM_VALUE_RND_UP,
477   GADGET_ID_PUSH_DELAY_FIX_DOWN,
478   GADGET_ID_PUSH_DELAY_FIX_TEXT,
479   GADGET_ID_PUSH_DELAY_FIX_UP,
480   GADGET_ID_PUSH_DELAY_RND_DOWN,
481   GADGET_ID_PUSH_DELAY_RND_TEXT,
482   GADGET_ID_PUSH_DELAY_RND_UP,
483   GADGET_ID_DROP_DELAY_FIX_DOWN,
484   GADGET_ID_DROP_DELAY_FIX_TEXT,
485   GADGET_ID_DROP_DELAY_FIX_UP,
486   GADGET_ID_DROP_DELAY_RND_DOWN,
487   GADGET_ID_DROP_DELAY_RND_TEXT,
488   GADGET_ID_DROP_DELAY_RND_UP,
489   GADGET_ID_MOVE_DELAY_FIX_DOWN,
490   GADGET_ID_MOVE_DELAY_FIX_TEXT,
491   GADGET_ID_MOVE_DELAY_FIX_UP,
492   GADGET_ID_MOVE_DELAY_RND_DOWN,
493   GADGET_ID_MOVE_DELAY_RND_TEXT,
494   GADGET_ID_MOVE_DELAY_RND_UP,
495   GADGET_ID_STEP_DELAY_FIX_DOWN,
496   GADGET_ID_STEP_DELAY_FIX_TEXT,
497   GADGET_ID_STEP_DELAY_FIX_UP,
498   GADGET_ID_STEP_DELAY_RND_DOWN,
499   GADGET_ID_STEP_DELAY_RND_TEXT,
500   GADGET_ID_STEP_DELAY_RND_UP,
501   GADGET_ID_EXPLOSION_DELAY_DOWN,
502   GADGET_ID_EXPLOSION_DELAY_TEXT,
503   GADGET_ID_EXPLOSION_DELAY_UP,
504   GADGET_ID_IGNITION_DELAY_DOWN,
505   GADGET_ID_IGNITION_DELAY_TEXT,
506   GADGET_ID_IGNITION_DELAY_UP,
507   GADGET_ID_CHANGE_DELAY_FIX_DOWN,
508   GADGET_ID_CHANGE_DELAY_FIX_TEXT,
509   GADGET_ID_CHANGE_DELAY_FIX_UP,
510   GADGET_ID_CHANGE_DELAY_RND_DOWN,
511   GADGET_ID_CHANGE_DELAY_RND_TEXT,
512   GADGET_ID_CHANGE_DELAY_RND_UP,
513   GADGET_ID_CHANGE_CONT_RND_DOWN,
514   GADGET_ID_CHANGE_CONT_RND_TEXT,
515   GADGET_ID_CHANGE_CONT_RND_UP,
516   GADGET_ID_GROUP_CONTENT_DOWN,
517   GADGET_ID_GROUP_CONTENT_TEXT,
518   GADGET_ID_GROUP_CONTENT_UP,
519
520   // drawing area identifiers
521
522   GADGET_ID_DRAWING_LEVEL,
523   GADGET_ID_YAMYAM_CONTENT_0,
524   GADGET_ID_YAMYAM_CONTENT_1,
525   GADGET_ID_YAMYAM_CONTENT_2,
526   GADGET_ID_YAMYAM_CONTENT_3,
527   GADGET_ID_YAMYAM_CONTENT_4,
528   GADGET_ID_YAMYAM_CONTENT_5,
529   GADGET_ID_YAMYAM_CONTENT_6,
530   GADGET_ID_YAMYAM_CONTENT_7,
531   GADGET_ID_MAGIC_BALL_CONTENT_0,
532   GADGET_ID_MAGIC_BALL_CONTENT_1,
533   GADGET_ID_MAGIC_BALL_CONTENT_2,
534   GADGET_ID_MAGIC_BALL_CONTENT_3,
535   GADGET_ID_MAGIC_BALL_CONTENT_4,
536   GADGET_ID_MAGIC_BALL_CONTENT_5,
537   GADGET_ID_MAGIC_BALL_CONTENT_6,
538   GADGET_ID_MAGIC_BALL_CONTENT_7,
539   GADGET_ID_ANDROID_CONTENT,
540   GADGET_ID_AMOEBA_CONTENT,
541   GADGET_ID_START_ELEMENT,
542   GADGET_ID_ARTWORK_ELEMENT,
543   GADGET_ID_EXPLOSION_ELEMENT,
544   GADGET_ID_INVENTORY_CONTENT,
545   GADGET_ID_MM_BALL_CONTENT,
546   GADGET_ID_CUSTOM_GRAPHIC,
547   GADGET_ID_CUSTOM_CONTENT,
548   GADGET_ID_CUSTOM_MOVE_ENTER,
549   GADGET_ID_CUSTOM_MOVE_LEAVE,
550   GADGET_ID_CUSTOM_CHANGE_TARGET,
551   GADGET_ID_CUSTOM_CHANGE_CONTENT,
552   GADGET_ID_CUSTOM_CHANGE_TRIGGER,
553   GADGET_ID_CUSTOM_CHANGE_ACTION,
554   GADGET_ID_GROUP_CONTENT,
555   GADGET_ID_RANDOM_BACKGROUND,
556
557   // text input identifiers
558
559   GADGET_ID_LEVEL_NAME,
560   GADGET_ID_LEVEL_AUTHOR,
561   GADGET_ID_LEVELSET_NAME,
562   GADGET_ID_LEVELSET_AUTHOR,
563   GADGET_ID_ELEMENT_NAME,
564
565   // text area identifiers
566
567   GADGET_ID_ENVELOPE_INFO,
568
569   // selectbox identifiers
570
571   GADGET_ID_TIME_OR_STEPS,
572   GADGET_ID_TIME_SCORE_BASE,
573   GADGET_ID_GAME_ENGINE_TYPE,
574   GADGET_ID_LEVELSET_SAVE_MODE,
575   GADGET_ID_WIND_DIRECTION,
576   GADGET_ID_PLAYER_SPEED,
577   GADGET_ID_MM_BALL_CHOICE_MODE,
578   GADGET_ID_CUSTOM_WALK_TO_ACTION,
579   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
580   GADGET_ID_CUSTOM_DEADLINESS,
581   GADGET_ID_CUSTOM_MOVE_PATTERN,
582   GADGET_ID_CUSTOM_MOVE_DIRECTION,
583   GADGET_ID_CUSTOM_MOVE_STEPSIZE,
584   GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
585   GADGET_ID_CUSTOM_SMASH_TARGETS,
586   GADGET_ID_CUSTOM_SLIPPERY_TYPE,
587   GADGET_ID_CUSTOM_ACCESS_TYPE,
588   GADGET_ID_CUSTOM_ACCESS_LAYER,
589   GADGET_ID_CUSTOM_ACCESS_PROTECTED,
590   GADGET_ID_CUSTOM_ACCESS_DIRECTION,
591   GADGET_ID_CHANGE_TIME_UNITS,
592   GADGET_ID_CHANGE_DIRECT_ACTION,
593   GADGET_ID_CHANGE_OTHER_ACTION,
594   GADGET_ID_CHANGE_SIDE,
595   GADGET_ID_CHANGE_PLAYER,
596   GADGET_ID_CHANGE_PAGE,
597   GADGET_ID_CHANGE_REPLACE_WHEN,
598   GADGET_ID_ACTION_TYPE,
599   GADGET_ID_ACTION_MODE,
600   GADGET_ID_ACTION_ARG,
601   GADGET_ID_SELECT_CHANGE_PAGE,
602   GADGET_ID_GROUP_CHOICE_MODE,
603
604   // textbutton identifiers
605
606   GADGET_ID_LEVELCONFIG_LEVEL,
607   GADGET_ID_LEVELCONFIG_LEVELSET,
608   GADGET_ID_LEVELCONFIG_EDITOR,
609   GADGET_ID_PROPERTIES_INFO,
610   GADGET_ID_PROPERTIES_CONFIG,
611   GADGET_ID_PROPERTIES_CONFIG_1,
612   GADGET_ID_PROPERTIES_CONFIG_2,
613   GADGET_ID_PROPERTIES_CHANGE,
614   GADGET_ID_SAVE_AS_TEMPLATE_1,
615   GADGET_ID_SAVE_AS_TEMPLATE_2,
616   GADGET_ID_SAVE_LEVELSET,
617   GADGET_ID_ADD_CHANGE_PAGE,
618   GADGET_ID_DEL_CHANGE_PAGE,
619
620   // graphicbutton identifiers
621
622   GADGET_ID_PREV_CHANGE_PAGE,
623   GADGET_ID_NEXT_CHANGE_PAGE,
624   GADGET_ID_COPY_CHANGE_PAGE,
625   GADGET_ID_PASTE_CHANGE_PAGE,
626
627   // gadgets for scrolling of drawing area
628
629   GADGET_ID_SCROLL_UP,
630   GADGET_ID_SCROLL_DOWN,
631   GADGET_ID_SCROLL_LEFT,
632   GADGET_ID_SCROLL_RIGHT,
633   GADGET_ID_SCROLL_HORIZONTAL,
634   GADGET_ID_SCROLL_VERTICAL,
635
636   // gadgets for scrolling element list
637
638   GADGET_ID_SCROLL_LIST_UP,
639   GADGET_ID_SCROLL_LIST_DOWN,
640   GADGET_ID_SCROLL_LIST_VERTICAL,
641
642   // checkbuttons/radiobuttons for level/element properties
643
644   GADGET_ID_AUTO_COUNT_GEMS,
645   GADGET_ID_RATE_TIME_OVER_SCORE,
646   GADGET_ID_USE_LEVELSET_ARTWORK,
647   GADGET_ID_COPY_LEVEL_TEMPLATE,
648   GADGET_ID_RANDOM_PERCENTAGE,
649   GADGET_ID_RANDOM_QUANTITY,
650   GADGET_ID_RANDOM_RESTRICTED,
651   GADGET_ID_STICK_ELEMENT,
652   GADGET_ID_EM_SLIPPERY_GEMS,
653   GADGET_ID_EM_EXPLODES_BY_FIRE,
654   GADGET_ID_USE_SPRING_BUG,
655   GADGET_ID_USE_TIME_ORB_BUG,
656   GADGET_ID_USE_LIFE_BUGS,
657   GADGET_ID_RANDOM_BALL_CONTENT,
658   GADGET_ID_INITIAL_BALL_ACTIVE,
659   GADGET_ID_GROW_INTO_DIGGABLE,
660   GADGET_ID_SB_FIELDS_NEEDED,
661   GADGET_ID_SB_OBJECTS_NEEDED,
662   GADGET_ID_AUTO_EXIT_SOKOBAN,
663   GADGET_ID_SOLVED_BY_ONE_PLAYER,
664   GADGET_ID_FINISH_DIG_COLLECT,
665   GADGET_ID_KEEP_WALKABLE_CE,
666   GADGET_ID_CONTINUOUS_SNAPPING,
667   GADGET_ID_BLOCK_SNAP_FIELD,
668   GADGET_ID_BLOCK_LAST_FIELD,
669   GADGET_ID_SP_BLOCK_LAST_FIELD,
670   GADGET_ID_INSTANT_RELOCATION,
671   GADGET_ID_SHIFTED_RELOCATION,
672   GADGET_ID_LAZY_RELOCATION,
673   GADGET_ID_USE_START_ELEMENT,
674   GADGET_ID_USE_ARTWORK_ELEMENT,
675   GADGET_ID_USE_EXPLOSION_ELEMENT,
676   GADGET_ID_INITIAL_GRAVITY,
677   GADGET_ID_USE_INITIAL_INVENTORY,
678   GADGET_ID_CAN_PASS_TO_WALKABLE,
679   GADGET_ID_CAN_FALL_INTO_ACID,
680   GADGET_ID_CAN_MOVE_INTO_ACID,
681   GADGET_ID_DONT_COLLIDE_WITH,
682   GADGET_ID_BD_DIAGONAL_MOVEMENTS,
683   GADGET_ID_ENVELOPE_AUTOWRAP,
684   GADGET_ID_ENVELOPE_CENTERED,
685   GADGET_ID_MM_LASER_RED,
686   GADGET_ID_MM_LASER_GREEN,
687   GADGET_ID_MM_LASER_BLUE,
688   GADGET_ID_DF_LASER_RED,
689   GADGET_ID_DF_LASER_GREEN,
690   GADGET_ID_DF_LASER_BLUE,
691   GADGET_ID_ROTATE_MM_BALL_CONTENT,
692   GADGET_ID_EXPLODE_MM_BALL,
693   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
694   GADGET_ID_CUSTOM_CAN_EXPLODE,
695   GADGET_ID_CUSTOM_EXPLODE_FIRE,
696   GADGET_ID_CUSTOM_EXPLODE_SMASH,
697   GADGET_ID_CUSTOM_EXPLODE_IMPACT,
698   GADGET_ID_CUSTOM_WALK_TO_OBJECT,
699   GADGET_ID_CUSTOM_DEADLY,
700   GADGET_ID_CUSTOM_CAN_MOVE,
701   GADGET_ID_CUSTOM_CAN_FALL,
702   GADGET_ID_CUSTOM_CAN_SMASH,
703   GADGET_ID_CUSTOM_SLIPPERY,
704   GADGET_ID_CUSTOM_ACCESSIBLE,
705   GADGET_ID_CUSTOM_GRAV_REACHABLE,
706   GADGET_ID_CUSTOM_USE_LAST_VALUE,
707   GADGET_ID_CUSTOM_USE_GRAPHIC,
708   GADGET_ID_CUSTOM_USE_TEMPLATE_1,
709   GADGET_ID_CUSTOM_USE_TEMPLATE_2,
710   GADGET_ID_CUSTOM_USE_TEMPLATE_3,
711   GADGET_ID_CUSTOM_CAN_CHANGE,
712   GADGET_ID_CHANGE_USE_CONTENT,
713   GADGET_ID_CHANGE_USE_EXPLOSION,
714   GADGET_ID_CHANGE_ONLY_COMPLETE,
715   GADGET_ID_CHANGE_USE_RANDOM,
716   GADGET_ID_CHANGE_HAS_ACTION,
717   GADGET_ID_CHANGE_DELAY,
718   GADGET_ID_CHANGE_BY_DIRECT_ACT,
719   GADGET_ID_CHANGE_BY_OTHER_ACT,
720
721   NUM_STATIC_GADGET_IDS
722 };
723
724 // gadgets for buttons in element list (dynamic)
725 #define GADGET_ID_ELEMENTLIST_FIRST     (NUM_STATIC_GADGET_IDS)
726 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
727                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
728
729 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
730
731 // radio button numbers
732 enum
733 {
734   RADIO_NR_NONE,
735   RADIO_NR_DRAWING_TOOLBOX,
736   RADIO_NR_RANDOM_ELEMENTS
737 };
738
739 // values for counter gadgets
740 enum
741 {
742   ED_COUNTER_ID_SELECT_LEVEL,
743   ED_COUNTER_ID_LEVEL_XSIZE,
744   ED_COUNTER_ID_LEVEL_YSIZE,
745   ED_COUNTER_ID_LEVEL_GEMSLIMIT,
746   ED_COUNTER_ID_LEVEL_TIMELIMIT,
747   ED_COUNTER_ID_LEVEL_TIMESCORE,
748   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
749   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
750   ED_COUNTER_ID_LEVEL_RANDOM,
751   ED_COUNTER_ID_ELEMENT_VALUE1,
752   ED_COUNTER_ID_ELEMENT_VALUE2,
753   ED_COUNTER_ID_ELEMENT_VALUE3,
754   ED_COUNTER_ID_ELEMENT_VALUE4,
755   ED_COUNTER_ID_YAMYAM_CONTENT,
756   ED_COUNTER_ID_BALL_CONTENT,
757   ED_COUNTER_ID_ANDROID_CONTENT,
758   ED_COUNTER_ID_ENVELOPE_XSIZE,
759   ED_COUNTER_ID_ENVELOPE_YSIZE,
760   ED_COUNTER_ID_INVENTORY_SIZE,
761   ED_COUNTER_ID_MM_BALL_CONTENT,
762   ED_COUNTER_ID_CUSTOM_SCORE,
763   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
764   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
765   ED_COUNTER_ID_CUSTOM_VALUE_RND,
766   ED_COUNTER_ID_PUSH_DELAY_FIX,
767   ED_COUNTER_ID_PUSH_DELAY_RND,
768   ED_COUNTER_ID_DROP_DELAY_FIX,
769   ED_COUNTER_ID_DROP_DELAY_RND,
770   ED_COUNTER_ID_MOVE_DELAY_FIX,
771   ED_COUNTER_ID_MOVE_DELAY_RND,
772   ED_COUNTER_ID_STEP_DELAY_FIX,
773   ED_COUNTER_ID_STEP_DELAY_RND,
774   ED_COUNTER_ID_EXPLOSION_DELAY,
775   ED_COUNTER_ID_IGNITION_DELAY,
776   ED_COUNTER_ID_GROUP_CONTENT,
777   ED_COUNTER_ID_CHANGE_DELAY_FIX,
778   ED_COUNTER_ID_CHANGE_DELAY_RND,
779   ED_COUNTER_ID_CHANGE_CONT_RND,
780
781   ED_NUM_COUNTERBUTTONS
782 };
783
784 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
785 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
786 #define ED_COUNTER_ID_LEVELSET_FIRST    ED_COUNTER_ID_LEVELSET_NUM_LEVELS
787 #define ED_COUNTER_ID_LEVELSET_LAST     ED_COUNTER_ID_LEVELSET_NUM_LEVELS
788 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
789 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
790
791 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
792 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
793 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
794 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
795 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
796 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
797
798 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
799 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
800
801 // values for scrollbutton gadgets
802 enum
803 {
804   ED_SCROLLBUTTON_ID_AREA_UP,
805   ED_SCROLLBUTTON_ID_AREA_DOWN,
806   ED_SCROLLBUTTON_ID_AREA_LEFT,
807   ED_SCROLLBUTTON_ID_AREA_RIGHT,
808   ED_SCROLLBUTTON_ID_LIST_UP,
809   ED_SCROLLBUTTON_ID_LIST_DOWN,
810
811   ED_NUM_SCROLLBUTTONS
812 };
813
814 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
815 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
816
817 // values for scrollbar gadgets
818 enum
819 {
820   ED_SCROLLBAR_ID_AREA_HORIZONTAL,
821   ED_SCROLLBAR_ID_AREA_VERTICAL,
822   ED_SCROLLBAR_ID_LIST_VERTICAL,
823
824   ED_NUM_SCROLLBARS
825 };
826
827 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
828 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
829
830 // values for text input gadgets
831 enum
832 {
833   ED_TEXTINPUT_ID_LEVEL_NAME,
834   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
835   ED_TEXTINPUT_ID_LEVELSET_NAME,
836   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
837   ED_TEXTINPUT_ID_ELEMENT_NAME,
838
839   ED_NUM_TEXTINPUT
840 };
841
842 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
843 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
844
845 #define ED_TEXTINPUT_ID_LEVELSET_FIRST  ED_TEXTINPUT_ID_LEVELSET_NAME
846 #define ED_TEXTINPUT_ID_LEVELSET_LAST   ED_TEXTINPUT_ID_LEVELSET_AUTHOR
847
848 // values for text area gadgets
849 enum
850 {
851   ED_TEXTAREA_ID_ENVELOPE_INFO,
852
853   ED_NUM_TEXTAREAS
854 };
855
856 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
857 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
858
859 // values for selectbox gadgets
860 enum
861 {
862   ED_SELECTBOX_ID_TIME_OR_STEPS,
863   ED_SELECTBOX_ID_TIME_SCORE_BASE,
864   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
865   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
866   ED_SELECTBOX_ID_WIND_DIRECTION,
867   ED_SELECTBOX_ID_PLAYER_SPEED,
868   ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
869   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
870   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
871   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
872   ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
873   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
874   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
875   ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
876   ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
877   ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
878   ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
879   ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
880   ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
881   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
882   ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
883   ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
884   ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
885   ED_SELECTBOX_ID_CHANGE_SIDE,
886   ED_SELECTBOX_ID_CHANGE_PLAYER,
887   ED_SELECTBOX_ID_CHANGE_PAGE,
888   ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
889   ED_SELECTBOX_ID_ACTION_TYPE,
890   ED_SELECTBOX_ID_ACTION_MODE,
891   ED_SELECTBOX_ID_ACTION_ARG,
892   ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
893   ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
894
895   ED_NUM_SELECTBOX
896 };
897
898 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
899 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_GAME_ENGINE_TYPE
900
901 #define ED_SELECTBOX_ID_LEVELSET_FIRST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
902 #define ED_SELECTBOX_ID_LEVELSET_LAST   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
903
904 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
905 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
906 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
907 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
908 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
909 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
910
911 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
912 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
913
914 // values for textbutton gadgets
915 enum
916 {
917   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
918   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
919   ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
920   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
921   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
922   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
923   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
924   ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
925   ED_TEXTBUTTON_ID_SAVE_LEVELSET,
926   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
927   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
928   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
929   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
930
931   ED_NUM_TEXTBUTTONS
932 };
933
934 #define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
935 #define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
936
937 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
938 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
939
940 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
941 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
942
943 // values for graphicbutton gadgets
944 enum
945 {
946   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
947   ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
948   ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
949   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
950
951   ED_NUM_GRAPHICBUTTONS
952 };
953
954 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
955 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
956
957 // values for checkbutton gadgets
958 enum
959 {
960   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
961   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
962   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
963   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
964   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
965   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
966   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
967   ED_CHECKBUTTON_ID_STICK_ELEMENT,
968   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
969   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
970   ED_CHECKBUTTON_ID_USE_SPRING_BUG,
971   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
972   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
973   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
974   ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
975   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
976   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
977   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
978   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
979   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
980   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
981   ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
982   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
983   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
984   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
985   ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
986   ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
987   ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
988   ED_CHECKBUTTON_ID_LAZY_RELOCATION,
989   ED_CHECKBUTTON_ID_USE_START_ELEMENT,
990   ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
991   ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
992   ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
993   ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
994   ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
995   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
996   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
997   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
998   ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
999   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
1000   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
1001   ED_CHECKBUTTON_ID_MM_LASER_RED,
1002   ED_CHECKBUTTON_ID_MM_LASER_GREEN,
1003   ED_CHECKBUTTON_ID_MM_LASER_BLUE,
1004   ED_CHECKBUTTON_ID_DF_LASER_RED,
1005   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
1006   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
1007   ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
1008   ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
1009   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
1010   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
1011   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
1012   ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
1013   ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
1014   ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
1015   ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
1016   ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
1017   ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
1018   ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
1019   ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
1020   ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
1021   ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
1022   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
1023   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
1024   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
1025   ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
1026   ED_CHECKBUTTON_ID_CHANGE_DELAY,
1027   ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
1028   ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
1029   ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
1030   ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
1031   ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
1032   ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
1033   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
1034
1035   ED_NUM_CHECKBUTTONS
1036 };
1037
1038 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
1039 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
1040
1041 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
1042 #define ED_CHECKBUTTON_ID_LEVELSET_LAST  ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
1043
1044 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
1045 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
1046
1047 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
1048 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
1049 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
1050 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
1051 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
1052 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
1053
1054 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
1055 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
1056
1057 // values for radiobutton gadgets
1058 enum
1059 {
1060   ED_RADIOBUTTON_ID_PERCENTAGE,
1061   ED_RADIOBUTTON_ID_QUANTITY,
1062
1063   ED_NUM_RADIOBUTTONS
1064 };
1065
1066 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
1067 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
1068
1069 // values for drawing area gadgets
1070 enum
1071 {
1072   ED_DRAWING_ID_DRAWING_LEVEL,
1073   ED_DRAWING_ID_YAMYAM_CONTENT_0,
1074   ED_DRAWING_ID_YAMYAM_CONTENT_1,
1075   ED_DRAWING_ID_YAMYAM_CONTENT_2,
1076   ED_DRAWING_ID_YAMYAM_CONTENT_3,
1077   ED_DRAWING_ID_YAMYAM_CONTENT_4,
1078   ED_DRAWING_ID_YAMYAM_CONTENT_5,
1079   ED_DRAWING_ID_YAMYAM_CONTENT_6,
1080   ED_DRAWING_ID_YAMYAM_CONTENT_7,
1081   ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
1082   ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
1083   ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
1084   ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
1085   ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
1086   ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
1087   ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
1088   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
1089   ED_DRAWING_ID_ANDROID_CONTENT,
1090   ED_DRAWING_ID_AMOEBA_CONTENT,
1091   ED_DRAWING_ID_START_ELEMENT,
1092   ED_DRAWING_ID_ARTWORK_ELEMENT,
1093   ED_DRAWING_ID_EXPLOSION_ELEMENT,
1094   ED_DRAWING_ID_INVENTORY_CONTENT,
1095   ED_DRAWING_ID_MM_BALL_CONTENT,
1096   ED_DRAWING_ID_CUSTOM_GRAPHIC,
1097   ED_DRAWING_ID_CUSTOM_CONTENT,
1098   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
1099   ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
1100   ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
1101   ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
1102   ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
1103   ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
1104   ED_DRAWING_ID_GROUP_CONTENT,
1105   ED_DRAWING_ID_RANDOM_BACKGROUND,
1106
1107   ED_NUM_DRAWING_AREAS
1108 };
1109
1110 #define ED_DRAWING_ID_EDITOR_FIRST      ED_DRAWING_ID_RANDOM_BACKGROUND
1111 #define ED_DRAWING_ID_EDITOR_LAST       ED_DRAWING_ID_RANDOM_BACKGROUND
1112
1113
1114 // ----------------------------------------------------------------------------
1115 // some internally used definitions
1116 // ----------------------------------------------------------------------------
1117
1118 // values for CopyLevelToUndoBuffer()
1119 #define UNDO_IMMEDIATE                  0
1120 #define UNDO_ACCUMULATE                 1
1121
1122 // values for scrollbars
1123 #define ED_SCROLL_NO                    0
1124 #define ED_SCROLL_LEFT                  1
1125 #define ED_SCROLL_RIGHT                 2
1126 #define ED_SCROLL_UP                    4
1127 #define ED_SCROLL_DOWN                  8
1128
1129 // screens in the level editor
1130 #define ED_MODE_DRAWING                 0
1131 #define ED_MODE_LEVELCONFIG             1
1132 #define ED_MODE_PROPERTIES              2
1133 #define ED_MODE_PALETTE                 3
1134
1135 // sub-screens in the global settings section
1136 #define ED_MODE_LEVELCONFIG_LEVEL       ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
1137 #define ED_MODE_LEVELCONFIG_LEVELSET    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
1138 #define ED_MODE_LEVELCONFIG_EDITOR      ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
1139
1140 // sub-screens in the element properties section
1141 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
1142 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
1143 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
1144 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
1145 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
1146
1147 // how many steps can be cancelled
1148 #define NUM_UNDO_STEPS                  (64 + 1)
1149
1150 // values for elements with score for certain actions
1151 #define MIN_SCORE                       0
1152 #define MAX_SCORE                       999
1153
1154 // values for elements with count for collecting
1155 #define MIN_COLLECT_COUNT               0
1156 #define MAX_COLLECT_COUNT               999
1157
1158 // values for random placement
1159 #define RANDOM_USE_PERCENTAGE           0
1160 #define RANDOM_USE_QUANTITY             1
1161
1162 // values for level set save mode
1163 #define LEVELSET_SAVE_MODE_UPDATE       0
1164 #define LEVELSET_SAVE_MODE_CREATE       1
1165
1166 // default value for element tile size in drawing area
1167 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
1168 #define DEFAULT_EDITOR_TILESIZE_MM      TILESIZE
1169
1170
1171 // ----------------------------------------------------------------------------
1172 // some internally used data structure definitions
1173 // ----------------------------------------------------------------------------
1174
1175 static struct
1176 {
1177   int graphic;
1178   int gadget_id;
1179   struct XYTileSize *pos;
1180   int gadget_type;
1181   char *infotext;
1182   char shortcut;
1183 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1184 {
1185   // note: some additional characters are already reserved for "cheat mode"
1186   // shortcuts (":XYZ" style) -- for details, see "events.c"
1187
1188   // ---------- toolbox control buttons ---------------------------------------
1189
1190   {
1191     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1192     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1193     "draw single items",                        's'
1194   },
1195   {
1196     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1197     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1198     "draw connected items",                     'd'
1199   },
1200   {
1201     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1202     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1203     "draw lines",                               'l'
1204   },
1205   {
1206     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1207     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1208     "draw arcs",                                'a'
1209   },
1210   {
1211     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1212     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1213     "draw outline rectangles",                  'r'
1214   },
1215   {
1216     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1217     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1218     "draw filled rectangles",                   'R'
1219   },
1220   {
1221     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1222     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1223     "wrap (rotate) level up",                   0
1224   },
1225   {
1226     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1227     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1228     "enter text elements",                      't'
1229   },
1230   {
1231     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1232     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1233     "flood fill",                               'f'
1234   },
1235   {
1236     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1237     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1238     "wrap (rotate) level left",                 0
1239   },
1240   {
1241     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1242     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1243     "zoom level tile size",                     '+'
1244   },
1245   {
1246     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1247     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1248     "wrap (rotate) level right",                0
1249   },
1250   {
1251     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1252     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1253     "random element placement",                 0
1254   },
1255   {
1256     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1257     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1258     "grab brush",                               'b'
1259   },
1260   {
1261     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1262     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1263     "wrap (rotate) level down",                 0
1264   },
1265   {
1266     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1267     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1268     "pick drawing element",                     ','
1269   },
1270
1271   // ---------- level control buttons -----------------------------------------
1272
1273   {
1274     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1275     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1276     "undo/redo last operation",                 'u'
1277   },
1278   {
1279     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_CONF,
1280     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1281     "level and editor settings",                'I'
1282   },
1283   {
1284     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1285     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1286     "save level",                               'S'
1287   },
1288   {
1289     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1290     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1291     "clear level",                              'C'
1292   },
1293   {
1294     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1295     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1296     "test level",                               'T'
1297   },
1298   {
1299     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1300     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1301     "exit level editor",                        'E'
1302   },
1303
1304   // ---------- CE and GE control buttons -------------------------------------
1305
1306   {
1307     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1308     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1309     "copy settings from other element",         0
1310   },
1311   {
1312     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1313     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1314     "copy settings to other element",           0
1315   },
1316   {
1317     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1318     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1319     "exchange element with other element",      0
1320   },
1321   {
1322     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1323     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1324     "copy settings from this element",          0
1325   },
1326   {
1327     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1328     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1329     "paste settings to this element",           0
1330   },
1331
1332   // ---------- palette control buttons ---------------------------------------
1333
1334   {
1335     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1336     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1337     "properties of drawing element",            'p'
1338   },
1339   {
1340     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1341     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1342     "properties of drawing element 1",          '1'
1343   },
1344   {
1345     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1346     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1347     "properties of drawing element 2",          '2'
1348   },
1349   {
1350     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1351     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1352     "properties of drawing element 3",          '3'
1353   },
1354   {
1355     IMG_GFX_EDITOR_BUTTON_PALETTE,              GADGET_ID_PALETTE,
1356     &editor.button.palette,                     GD_TYPE_NORMAL_BUTTON,
1357     "show list of elements",                    'e'
1358   }
1359 };
1360
1361 static int random_placement_value = 10;
1362 static int random_placement_method = RANDOM_USE_QUANTITY;
1363 static int random_placement_background_element = EL_SAND;
1364 static boolean random_placement_background_restricted = FALSE;
1365 static boolean stick_element_properties_window = FALSE;
1366 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1367 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1368 static struct ElementChangeInfo custom_element_change;
1369 static struct ElementGroupInfo group_element_info;
1370 static struct ElementInfo custom_element;
1371
1372 static char levelset_name[MAX_LEVEL_NAME_LEN + 1];
1373 static char levelset_author[MAX_LEVEL_AUTHOR_LEN + 1];
1374 static int levelset_num_levels = 100;
1375 static boolean levelset_use_levelset_artwork = FALSE;
1376 static boolean levelset_copy_level_template = FALSE;
1377 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
1378
1379 static struct
1380 {
1381   int x, y;
1382   int min_value, max_value;
1383   int gadget_id_down, gadget_id_up;
1384   int gadget_id_text;
1385   int gadget_id_align;
1386   int *value;
1387   char *text_above, *text_left, *text_right;
1388 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1389 {
1390   // ---------- current level number ------------------------------------------
1391
1392   {
1393     -1, -1,     // these values are not constant, but can change at runtime
1394     1,                                  100,
1395     GADGET_ID_SELECT_LEVEL_DOWN,        GADGET_ID_SELECT_LEVEL_UP,
1396     GADGET_ID_SELECT_LEVEL_TEXT,        GADGET_ID_NONE,
1397     &level_nr,
1398     NULL,                               NULL, NULL
1399   },
1400
1401   // ---------- level and editor settings -------------------------------------
1402
1403   {
1404     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1405     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
1406     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
1407     GADGET_ID_LEVEL_XSIZE_TEXT,         GADGET_ID_NONE,
1408     &level.fieldx,
1409     "playfield size:",                  NULL, "width",
1410   },
1411   {
1412     -1,                                 ED_LEVEL_SETTINGS_YPOS(4),
1413     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
1414     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
1415     GADGET_ID_LEVEL_YSIZE_TEXT,         GADGET_ID_LEVEL_XSIZE_UP,
1416     &level.fieldy,
1417     NULL,                               " ", "height",
1418   },
1419   {
1420     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
1421     0,                                  999,
1422     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,     GADGET_ID_LEVEL_GEMSLIMIT_UP,
1423     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,     GADGET_ID_NONE,
1424     &level.gems_needed,
1425     NULL,                               "number of gems to collect:", NULL
1426   },
1427   {
1428     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(8),
1429     0,                                  9999,
1430     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
1431     GADGET_ID_LEVEL_TIMELIMIT_TEXT,     GADGET_ID_NONE,
1432     &level.time,
1433     "time or step limit to solve level:", NULL, NULL
1434   },
1435   {
1436     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
1437     0,                                  999,
1438     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
1439     GADGET_ID_LEVEL_TIMESCORE_TEXT,     GADGET_ID_NONE,
1440     &level.score[SC_TIME_BONUS],
1441     "score for time or steps left:",    NULL, NULL
1442   },
1443   {
1444     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(13),
1445     0,                                  9999,
1446     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,   GADGET_ID_LEVEL_RANDOM_SEED_UP,
1447     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,   GADGET_ID_NONE,
1448     &level.random_seed,
1449     NULL,                               "random seed:", "(0 => random)"
1450   },
1451   {
1452     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1453     1,                                  MAX_LEVELS,
1454     GADGET_ID_LEVELSET_NUM_LEVELS_DOWN, GADGET_ID_LEVELSET_NUM_LEVELS_UP,
1455     GADGET_ID_LEVELSET_NUM_LEVELS_TEXT, GADGET_ID_NONE,
1456     &levelset_num_levels,
1457     "number of levels:",                NULL, NULL,
1458   },
1459   {
1460     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1461     1,                                  100,
1462     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
1463     GADGET_ID_LEVEL_RANDOM_TEXT,        GADGET_ID_NONE,
1464     &random_placement_value,
1465     "random element placement:",        NULL, "in"
1466   },
1467
1468   // ---------- element settings: configure (various elements) ----------------
1469
1470   {
1471     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1472     MIN_SCORE,                          MAX_SCORE,
1473     GADGET_ID_ELEMENT_VALUE1_DOWN,      GADGET_ID_ELEMENT_VALUE1_UP,
1474     GADGET_ID_ELEMENT_VALUE1_TEXT,      GADGET_ID_NONE,
1475     NULL,                               // will be set when used
1476     NULL,                               NULL, NULL
1477   },
1478   {
1479     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
1480     MIN_SCORE,                          MAX_SCORE,
1481     GADGET_ID_ELEMENT_VALUE2_DOWN,      GADGET_ID_ELEMENT_VALUE2_UP,
1482     GADGET_ID_ELEMENT_VALUE2_TEXT,      GADGET_ID_NONE,
1483     NULL,                               // will be set when used
1484     NULL,                               NULL, NULL
1485   },
1486   {
1487     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1488     MIN_SCORE,                          MAX_SCORE,
1489     GADGET_ID_ELEMENT_VALUE3_DOWN,      GADGET_ID_ELEMENT_VALUE3_UP,
1490     GADGET_ID_ELEMENT_VALUE3_TEXT,      GADGET_ID_NONE,
1491     NULL,                               // will be set when used
1492     NULL,                               NULL, NULL
1493   },
1494   {
1495     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1496     MIN_SCORE,                          MAX_SCORE,
1497     GADGET_ID_ELEMENT_VALUE4_DOWN,      GADGET_ID_ELEMENT_VALUE4_UP,
1498     GADGET_ID_ELEMENT_VALUE4_TEXT,      GADGET_ID_NONE,
1499     NULL,                               // will be set when used
1500     NULL,                               NULL, NULL
1501   },
1502   {
1503     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1504     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1505     GADGET_ID_YAMYAM_CONTENT_DOWN,      GADGET_ID_YAMYAM_CONTENT_UP,
1506     GADGET_ID_YAMYAM_CONTENT_TEXT,      GADGET_ID_NONE,
1507     &level.num_yamyam_contents,
1508     NULL,                               NULL, "number of content areas"
1509   },
1510   {
1511     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1512     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1513     GADGET_ID_BALL_CONTENT_DOWN,        GADGET_ID_BALL_CONTENT_UP,
1514     GADGET_ID_BALL_CONTENT_TEXT,        GADGET_ID_NONE,
1515     &level.num_ball_contents,
1516     NULL,                               NULL, "number of content areas"
1517   },
1518   {
1519     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1520     MIN_ANDROID_ELEMENTS,               MAX_ANDROID_ELEMENTS,
1521     GADGET_ID_ANDROID_CONTENT_DOWN,     GADGET_ID_ANDROID_CONTENT_UP,
1522     GADGET_ID_ANDROID_CONTENT_TEXT,     GADGET_ID_NONE,
1523     &level.num_android_clone_elements,
1524     NULL,                               NULL, "number of clonable elements"
1525   },
1526   {
1527     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1528     MIN_ENVELOPE_XSIZE,                 MAX_ENVELOPE_XSIZE,
1529     GADGET_ID_ENVELOPE_XSIZE_DOWN,      GADGET_ID_ENVELOPE_XSIZE_UP,
1530     GADGET_ID_ENVELOPE_XSIZE_TEXT,      GADGET_ID_NONE,
1531     NULL,                               // will be set when used
1532     NULL,                               NULL, "width",
1533   },
1534   {
1535     -1,                                 ED_ELEMENT_SETTINGS_YPOS(0),
1536     MIN_ENVELOPE_YSIZE,                 MAX_ENVELOPE_YSIZE,
1537     GADGET_ID_ENVELOPE_YSIZE_DOWN,      GADGET_ID_ENVELOPE_YSIZE_UP,
1538     GADGET_ID_ENVELOPE_YSIZE_TEXT,      GADGET_ID_ENVELOPE_XSIZE_UP,
1539     NULL,                               // will be set when used
1540     NULL,                               " ", "height",
1541   },
1542   {
1543     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1544     MIN_INITIAL_INVENTORY_SIZE,         MAX_INITIAL_INVENTORY_SIZE,
1545     GADGET_ID_INVENTORY_SIZE_DOWN,      GADGET_ID_INVENTORY_SIZE_UP,
1546     GADGET_ID_INVENTORY_SIZE_TEXT,      GADGET_ID_NONE,
1547     &level.initial_inventory_size[0],
1548     NULL,                               NULL, "number of inventory elements"
1549   },
1550   {
1551     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1552     MIN_ELEMENTS_IN_GROUP,              MAX_MM_BALL_CONTENTS,
1553     GADGET_ID_MM_BALL_CONTENT_DOWN,     GADGET_ID_MM_BALL_CONTENT_UP,
1554     GADGET_ID_MM_BALL_CONTENT_TEXT,     GADGET_ID_NONE,
1555     &level.num_mm_ball_contents,
1556     NULL,                               NULL, "number of content elements"
1557   },
1558
1559   // ---------- element settings: configure 1 (custom elements) ---------------
1560
1561   {
1562     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1563     MIN_SCORE,                          MAX_SCORE,
1564     GADGET_ID_CUSTOM_SCORE_DOWN,        GADGET_ID_CUSTOM_SCORE_UP,
1565     GADGET_ID_CUSTOM_SCORE_TEXT,        GADGET_ID_NONE,
1566     &custom_element.collect_score_initial,
1567     NULL,                               "CE score", " "
1568   },
1569   {
1570     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1571     MIN_COLLECT_COUNT,                  MAX_COLLECT_COUNT,
1572     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,     GADGET_ID_CUSTOM_GEMCOUNT_UP,
1573     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,     GADGET_ID_CUSTOM_SCORE_UP,
1574     &custom_element.collect_count_initial,
1575     NULL,                               "CE count", NULL
1576   },
1577   {
1578     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1579     0,                                  9999,
1580     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1581     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,    GADGET_ID_NONE,
1582     &custom_element.ce_value_fixed_initial,
1583     NULL,                               "CE value", NULL
1584   },
1585   {
1586     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1587     0,                                  9999,
1588     GADGET_ID_CUSTOM_VALUE_RND_DOWN,    GADGET_ID_CUSTOM_VALUE_RND_UP,
1589     GADGET_ID_CUSTOM_VALUE_RND_TEXT,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1590     &custom_element.ce_value_random_initial,
1591     NULL,                               "+random", NULL
1592   },
1593   {
1594     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1595     0,                                  999,
1596     GADGET_ID_PUSH_DELAY_FIX_DOWN,      GADGET_ID_PUSH_DELAY_FIX_UP,
1597     GADGET_ID_PUSH_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1598     &custom_element.push_delay_fixed,
1599     NULL,                               "push delay", NULL
1600   },
1601   {
1602     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1603     0,                                  999,
1604     GADGET_ID_PUSH_DELAY_RND_DOWN,      GADGET_ID_PUSH_DELAY_RND_UP,
1605     GADGET_ID_PUSH_DELAY_RND_TEXT,      GADGET_ID_PUSH_DELAY_FIX_UP,
1606     &custom_element.push_delay_random,
1607     NULL,                               "+random", NULL
1608   },
1609   {
1610     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(7),
1611     0,                                  999,
1612     GADGET_ID_DROP_DELAY_FIX_DOWN,      GADGET_ID_DROP_DELAY_FIX_UP,
1613     GADGET_ID_DROP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1614     &custom_element.drop_delay_fixed,
1615     NULL,                               "drop delay", NULL
1616   },
1617   {
1618     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
1619     0,                                  999,
1620     GADGET_ID_DROP_DELAY_RND_DOWN,      GADGET_ID_DROP_DELAY_RND_UP,
1621     GADGET_ID_DROP_DELAY_RND_TEXT,      GADGET_ID_DROP_DELAY_FIX_UP,
1622     &custom_element.drop_delay_random,
1623     NULL,                               "+random", NULL
1624   },
1625
1626   // ---------- element settings: configure 2 (custom elements) ---------------
1627
1628   {
1629     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1630     0,                                  999,
1631     GADGET_ID_MOVE_DELAY_FIX_DOWN,      GADGET_ID_MOVE_DELAY_FIX_UP,
1632     GADGET_ID_MOVE_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1633     &custom_element.move_delay_fixed,
1634     NULL,                               "move delay", NULL
1635   },
1636   {
1637     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1638     0,                                  999,
1639     GADGET_ID_MOVE_DELAY_RND_DOWN,      GADGET_ID_MOVE_DELAY_RND_UP,
1640     GADGET_ID_MOVE_DELAY_RND_TEXT,      GADGET_ID_MOVE_DELAY_FIX_UP,
1641     &custom_element.move_delay_random,
1642     NULL,                               "+random", NULL
1643   },
1644   {
1645     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1646     0,                                  999,
1647     GADGET_ID_STEP_DELAY_FIX_DOWN,      GADGET_ID_STEP_DELAY_FIX_UP,
1648     GADGET_ID_STEP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1649     &custom_element.step_delay_fixed,
1650     NULL,                               "step delay", NULL
1651   },
1652   {
1653     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1654     0,                                  999,
1655     GADGET_ID_STEP_DELAY_RND_DOWN,      GADGET_ID_STEP_DELAY_RND_UP,
1656     GADGET_ID_STEP_DELAY_RND_TEXT,      GADGET_ID_STEP_DELAY_FIX_UP,
1657     &custom_element.step_delay_random,
1658     NULL,                               "+random", NULL
1659   },
1660   {
1661     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
1662     0,                                  999,
1663     GADGET_ID_EXPLOSION_DELAY_DOWN,     GADGET_ID_EXPLOSION_DELAY_UP,
1664     GADGET_ID_EXPLOSION_DELAY_TEXT,     GADGET_ID_NONE,
1665     &custom_element.explosion_delay,
1666     NULL,                               "explosion delay", NULL
1667   },
1668   {
1669     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
1670     0,                                  999,
1671     GADGET_ID_IGNITION_DELAY_DOWN,      GADGET_ID_IGNITION_DELAY_UP,
1672     GADGET_ID_IGNITION_DELAY_TEXT,      GADGET_ID_NONE,
1673     &custom_element.ignition_delay,
1674     NULL,                               "ignition delay", "(by fire)"
1675   },
1676
1677   // ---------- element settings: configure (group elements) ------------------
1678
1679   {
1680     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1681     MIN_ELEMENTS_IN_GROUP,              MAX_ELEMENTS_IN_GROUP,
1682     GADGET_ID_GROUP_CONTENT_DOWN,       GADGET_ID_GROUP_CONTENT_UP,
1683     GADGET_ID_GROUP_CONTENT_TEXT,       GADGET_ID_NONE,
1684     &group_element_info.num_elements,
1685     NULL,                               NULL, "number of elements in group"
1686   },
1687
1688   // ---------- element settings: advanced (custom elements) ------------------
1689
1690   {
1691     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(2),
1692     0,                                  999,
1693     GADGET_ID_CHANGE_DELAY_FIX_DOWN,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1694     GADGET_ID_CHANGE_DELAY_FIX_TEXT,    GADGET_ID_NONE,
1695     &custom_element_change.delay_fixed,
1696     NULL,                               "CE delay", NULL,
1697   },
1698   {
1699     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
1700     0,                                  999,
1701     GADGET_ID_CHANGE_DELAY_RND_DOWN,    GADGET_ID_CHANGE_DELAY_RND_UP,
1702     GADGET_ID_CHANGE_DELAY_RND_TEXT,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1703     &custom_element_change.delay_random,
1704     NULL,                               "+random", NULL
1705   },
1706   {
1707     ED_ELEMENT_SETTINGS_XPOS(3),        ED_ELEMENT_SETTINGS_YPOS(12),
1708     0,                                  100,
1709     GADGET_ID_CHANGE_CONT_RND_DOWN,     GADGET_ID_CHANGE_CONT_RND_UP,
1710     GADGET_ID_CHANGE_CONT_RND_TEXT,     GADGET_ID_NONE,
1711     &custom_element_change.random_percentage,
1712     NULL,                               "use random replace:", "%"
1713   },
1714 };
1715
1716 static struct
1717 {
1718   int x, y;
1719   int gadget_id;
1720   int size;
1721   char *value;
1722   char *text_above, *infotext;
1723 } textinput_info[ED_NUM_TEXTINPUT] =
1724 {
1725   {
1726     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1727     GADGET_ID_LEVEL_NAME,
1728     MAX_LEVEL_NAME_LEN,
1729     level.name,
1730     "Title:", "Title for this level"
1731   },
1732   {
1733     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1734     GADGET_ID_LEVEL_AUTHOR,
1735     MAX_LEVEL_AUTHOR_LEN,
1736     level.author,
1737     "Author:", "Author for this level"
1738   },
1739   {
1740     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1741     GADGET_ID_LEVELSET_NAME,
1742     MAX_LEVEL_NAME_LEN,
1743     levelset_name,
1744     "Title:", "Title for this or new level set"
1745   },
1746   {
1747     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1748     GADGET_ID_LEVELSET_AUTHOR,
1749     MAX_LEVEL_AUTHOR_LEN,
1750     levelset_author,
1751     "Author:", "Author for this or new level set"
1752   },
1753   {
1754     -1, -1,     // these values are not constant, but can change at runtime
1755     GADGET_ID_ELEMENT_NAME,
1756     MAX_ELEMENT_NAME_LEN - 2,           // currently 2 chars less editable
1757     custom_element.description,
1758     NULL, "Element name"
1759   }
1760 };
1761
1762 static struct
1763 {
1764   int x, y;
1765   int gadget_id;
1766   int xsize, ysize;
1767   char *value;
1768   char *text_above, *text_above_cropped, *infotext;
1769 } textarea_info[ED_NUM_TEXTAREAS] =
1770 {
1771   {
1772     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1773     GADGET_ID_ENVELOPE_INFO,
1774     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
1775     NULL,
1776     "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
1777   }
1778 };
1779
1780 static struct ValueTextInfo options_time_or_steps[] =
1781 {
1782   { 0,                          "seconds"                       },
1783   { 1,                          "steps"                         },
1784
1785   { -1,                         NULL                            }
1786 };
1787
1788 static struct ValueTextInfo options_time_score_base[] =
1789 {
1790   { 1,                          "per second/step"               },
1791   { 10,                         "per 10 seconds/steps"          },
1792
1793   { -1,                         NULL                            }
1794 };
1795
1796 static struct ValueTextInfo options_game_engine_type[] =
1797 {
1798   { GAME_ENGINE_TYPE_RND,       "Rocks'n'Diamonds"              },
1799   { GAME_ENGINE_TYPE_BD,        "Boulder Dash"                  },
1800   { GAME_ENGINE_TYPE_EM,        "Emerald Mine"                  },
1801   { GAME_ENGINE_TYPE_SP,        "Supaplex"                      },
1802   { GAME_ENGINE_TYPE_MM,        "Mirror Magic"                  },
1803
1804   { -1,                         NULL                            }
1805 };
1806
1807 static struct ValueTextInfo options_levelset_save_mode[] =
1808 {
1809   { LEVELSET_SAVE_MODE_UPDATE,  "Update this level set"         },
1810   { LEVELSET_SAVE_MODE_CREATE,  "Create new level set"          },
1811
1812   { -1,                         NULL                            }
1813 };
1814
1815 static struct ValueTextInfo options_wind_direction[] =
1816 {
1817   { MV_START_NONE,              "none"                          },
1818   { MV_START_LEFT,              "left"                          },
1819   { MV_START_RIGHT,             "right"                         },
1820   { MV_START_UP,                "up"                            },
1821   { MV_START_DOWN,              "down"                          },
1822
1823   { -1,                         NULL                            }
1824 };
1825
1826 static struct ValueTextInfo options_player_speed[] =
1827 {
1828   { 0,                          "frozen"                        },
1829   { 1,                          "very slow"                     },
1830   { 2,                          "slow"                          },
1831   { 4,                          "normal"                        },
1832   { 8,                          "fast"                          },
1833   { 16,                         "very fast"                     },
1834   { 32,                         "ultrafast"                     },
1835
1836   { -1,                         NULL                            }
1837 };
1838
1839 static struct ValueTextInfo options_access_type[] =
1840 {
1841   { EP_WALKABLE,                "walkable"                      },
1842   { EP_PASSABLE,                "passable"                      },
1843
1844   { -1,                         NULL                            }
1845 };
1846
1847 static struct ValueTextInfo options_access_layer[] =
1848 {
1849   { EP_ACCESSIBLE_OVER,         "over"                          },
1850   { EP_ACCESSIBLE_INSIDE,       "inside"                        },
1851   { EP_ACCESSIBLE_UNDER,        "under"                         },
1852
1853   { -1,                         NULL                            }
1854 };
1855
1856 static struct ValueTextInfo options_access_protected[] =
1857 {
1858   { 0,                          "unprotected"                   },
1859   { 1,                          "protected"                     },
1860
1861   { -1,                         NULL                            }
1862 };
1863
1864 static struct ValueTextInfo options_access_direction[] =
1865 {
1866   { MV_NO_DIRECTION,            "no direction"                  },
1867   { MV_LEFT,                    "left"                          },
1868   { MV_RIGHT,                   "right"                         },
1869   { MV_UP,                      "up"                            },
1870   { MV_DOWN,                    "down"                          },
1871   { MV_LEFT  | MV_UP,           "left + up"                     },
1872   { MV_LEFT  | MV_DOWN,         "left + down"                   },
1873   { MV_RIGHT | MV_UP,           "right + up"                    },
1874   { MV_RIGHT | MV_DOWN,         "right + down"                  },
1875   { MV_HORIZONTAL,              "horizontal"                    },
1876   { MV_VERTICAL,                "vertical"                      },
1877   { MV_HORIZONTAL | MV_UP,      "horizontal + up"               },
1878   { MV_HORIZONTAL | MV_DOWN,    "horizontal + down"             },
1879   { MV_VERTICAL   | MV_LEFT,    "vertical + left"               },
1880   { MV_VERTICAL   | MV_RIGHT,   "vertical + right"              },
1881   { MV_ALL_DIRECTIONS,          "all directions"                },
1882
1883   { -1,                         NULL                            }
1884 };
1885
1886 static struct ValueTextInfo options_walk_to_action[] =
1887 {
1888   { EP_DIGGABLE,                "diggable"                      },
1889   { EP_COLLECTIBLE_ONLY,        "collectible"                   },
1890   { EP_DROPPABLE,               "collectible & droppable"       },
1891   { EP_THROWABLE,               "collectible & throwable"       },
1892   { EP_PUSHABLE,                "pushable"                      },
1893
1894   { -1,                         NULL                            }
1895 };
1896
1897 static struct ValueTextInfo options_move_pattern[] =
1898 {
1899   { MV_LEFT,                    "left"                          },
1900   { MV_RIGHT,                   "right"                         },
1901   { MV_UP,                      "up"                            },
1902   { MV_DOWN,                    "down"                          },
1903   { MV_HORIZONTAL,              "horizontal"                    },
1904   { MV_VERTICAL,                "vertical"                      },
1905   { MV_ALL_DIRECTIONS,          "all directions"                },
1906   { MV_WIND_DIRECTION,          "wind direction"                },
1907   { MV_TOWARDS_PLAYER,          "towards player"                },
1908   { MV_AWAY_FROM_PLAYER,        "away from player"              },
1909   { MV_ALONG_LEFT_SIDE,         "along left side"               },
1910   { MV_ALONG_RIGHT_SIDE,        "along right side"              },
1911   { MV_TURNING_LEFT,            "turning left"                  },
1912   { MV_TURNING_RIGHT,           "turning right"                 },
1913   { MV_TURNING_LEFT_RIGHT,      "turning left, right"           },
1914   { MV_TURNING_RIGHT_LEFT,      "turning right, left"           },
1915   { MV_TURNING_RANDOM,          "turning random"                },
1916   { MV_MAZE_RUNNER,             "maze runner style"             },
1917   { MV_MAZE_HUNTER,             "maze hunter style"             },
1918   { MV_WHEN_PUSHED,             "when pushed"                   },
1919   { MV_WHEN_DROPPED,            "when dropped/thrown"           },
1920
1921   { -1,                         NULL                            }
1922 };
1923
1924 static struct ValueTextInfo options_move_direction[] =
1925 {
1926   { MV_START_AUTOMATIC,         "automatic"                     },
1927   { MV_START_LEFT,              "left"                          },
1928   { MV_START_RIGHT,             "right"                         },
1929   { MV_START_UP,                "up"                            },
1930   { MV_START_DOWN,              "down"                          },
1931   { MV_START_RANDOM,            "random"                        },
1932   { MV_START_PREVIOUS,          "previous"                      },
1933
1934   { -1,                         NULL                            }
1935 };
1936
1937 static struct ValueTextInfo options_move_stepsize[] =
1938 {
1939   { 0,                          "not moving"                    },
1940   { 1,                          "very slow"                     },
1941   { 2,                          "slow"                          },
1942   { 4,                          "normal"                        },
1943   { 8,                          "fast"                          },
1944   { 16,                         "very fast"                     },
1945   { 32,                         "even faster"                   },
1946
1947   { -1,                         NULL                            }
1948 };
1949
1950 static struct ValueTextInfo options_move_leave_type[] =
1951 {
1952   { LEAVE_TYPE_UNLIMITED,       "leave behind"                  },
1953   { LEAVE_TYPE_LIMITED,         "change it to"                  },
1954
1955   { -1,                         NULL                            }
1956 };
1957
1958 static struct ValueTextInfo options_smash_targets[] =
1959 {
1960   { EP_CAN_SMASH_PLAYER,        "player"                        },
1961 #if 0
1962   { EP_CAN_SMASH_ENEMIES,       "enemies"                       },
1963 #endif
1964   { EP_CAN_SMASH_EVERYTHING,    "everything"                    },
1965
1966   { -1,                         NULL                            }
1967 };
1968
1969 static struct ValueTextInfo options_slippery_type[] =
1970 {
1971   { SLIPPERY_ANY_RANDOM,        "random"                        },
1972   { SLIPPERY_ANY_LEFT_RIGHT,    "left, right"                   },
1973   { SLIPPERY_ANY_RIGHT_LEFT,    "right, left"                   },
1974   { SLIPPERY_ONLY_LEFT,         "only left"                     },
1975   { SLIPPERY_ONLY_RIGHT,        "only right"                    },
1976
1977   { -1,                         NULL                            }
1978 };
1979
1980 static struct ValueTextInfo options_deadliness[] =
1981 {
1982   { EP_DONT_RUN_INTO,           "running into"                  },
1983   { EP_DONT_COLLIDE_WITH,       "colliding with"                },
1984   { EP_DONT_GET_HIT_BY,         "getting hit by"                },
1985   { EP_DONT_TOUCH,              "touching"                      },
1986
1987   { -1,                         NULL                            }
1988 };
1989
1990 static struct ValueTextInfo options_explosion_type[] =
1991 {
1992   { EXPLODES_3X3,               "3x3"                           },
1993   { EXPLODES_CROSS,             "3+3"                           },
1994   { EXPLODES_1X1,               "1x1"                           },
1995
1996   { -1,                         NULL                            }
1997 };
1998
1999 static struct ValueTextInfo options_time_units[] =
2000 {
2001   { 1,                          "frames"                        },
2002   { FRAMES_PER_SECOND,          "seconds"                       },
2003
2004   { -1,                         NULL                            }
2005 };
2006
2007 static struct ValueTextInfo options_change_direct_action[] =
2008 {
2009   { CE_TOUCHED_BY_PLAYER,       "touched by player"             },
2010   { CE_PRESSED_BY_PLAYER,       "pressed by player"             },
2011   { CE_SWITCHED_BY_PLAYER,      "switched by player"            },
2012   { CE_SNAPPED_BY_PLAYER,       "snapped by player"             },
2013   { CE_PUSHED_BY_PLAYER,        "pushed by player"              },
2014   { CE_ENTERED_BY_PLAYER,       "entered by player"             },
2015   { CE_LEFT_BY_PLAYER,          "left by player"                },
2016   { CE_DROPPED_BY_PLAYER,       "dropped/thrown by player"      },
2017   { CE_SWITCHED,                "switched"                      },
2018   { CE_HITTING_SOMETHING,       "hitting something"             },
2019   { CE_HIT_BY_SOMETHING,        "hit by something"              },
2020 #if 0
2021   { CE_BLOCKED,                 "blocked"                       },
2022 #endif
2023   { CE_IMPACT,                  "impact (on something)"         },
2024   { CE_SMASHED,                 "smashed (from above)"          },
2025 #if 0
2026   { CE_VALUE_CHANGES,           "CE value changes"              },
2027   { CE_SCORE_CHANGES,           "CE score changes"              },
2028 #endif
2029   { CE_VALUE_GETS_ZERO,         "CE value gets 0"               },
2030   { CE_SCORE_GETS_ZERO,         "CE score gets 0"               },
2031   { CE_UNDEFINED,               " "                             },
2032   { CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]"                },
2033   { CE_CLICKED_BY_MOUSE,        "clicked by mouse"              },
2034   { CE_PRESSED_BY_MOUSE,        "pressed by mouse"              },
2035   { CE_UNDEFINED,               " "                             },
2036   { CE_HEADLINE_SPECIAL_EVENTS, "[static states]"               },
2037   { CE_NEXT_TO_PLAYER,          "next to player"                },
2038
2039   { -1,                         NULL                            }
2040 };
2041
2042 static struct ValueTextInfo options_change_other_action[] =
2043 {
2044   { CE_PLAYER_TOUCHES_X,        "player touches"                },
2045   { CE_PLAYER_PRESSES_X,        "player presses"                },
2046   { CE_PLAYER_SWITCHES_X,       "player switches"               },
2047   { CE_PLAYER_SNAPS_X,          "player snaps"                  },
2048   { CE_PLAYER_PUSHES_X,         "player pushes"                 },
2049   { CE_PLAYER_ENTERS_X,         "player enters"                 },
2050   { CE_PLAYER_LEAVES_X,         "player leaves"                 },
2051   { CE_PLAYER_DIGS_X,           "player digs"                   },
2052   { CE_PLAYER_COLLECTS_X,       "player collects"               },
2053   { CE_PLAYER_DROPS_X,          "player drops/throws"           },
2054   { CE_TOUCHING_X,              "touching"                      },
2055   { CE_HITTING_X,               "hitting"                       },
2056   { CE_DIGGING_X,               "digging"                       },
2057   { CE_HIT_BY_X,                "hit by"                        },
2058   { CE_SWITCH_OF_X,             "switch of"                     },
2059   { CE_CHANGE_OF_X,             "change by page of"             },
2060   { CE_EXPLOSION_OF_X,          "explosion of"                  },
2061   { CE_MOVE_OF_X,               "move of"                       },
2062   { CE_CREATION_OF_X,           "creation of"                   },
2063   { CE_VALUE_CHANGES_OF_X,      "CE value changes of"           },
2064   { CE_SCORE_CHANGES_OF_X,      "CE score changes of"           },
2065   { CE_VALUE_GETS_ZERO_OF_X,    "CE value gets 0 of"            },
2066   { CE_SCORE_GETS_ZERO_OF_X,    "CE score gets 0 of"            },
2067   { CE_UNDEFINED,               " "                             },
2068   { CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]"                },
2069   { CE_MOUSE_CLICKED_ON_X,      "mouse clicked on"              },
2070   { CE_MOUSE_PRESSED_ON_X,      "mouse pressed on"              },
2071   { CE_UNDEFINED,               " "                             },
2072   { CE_HEADLINE_SPECIAL_EVENTS, "[static states]"               },
2073   { CE_PLAYER_NEXT_TO_X,        "player next to"                },
2074   { CE_NEXT_TO_X,               "next to"                       },
2075
2076   { -1,                         NULL                            }
2077 };
2078
2079 static struct ValueTextInfo options_change_trigger_side[] =
2080 {
2081   { CH_SIDE_LEFT,               "left"                          },
2082   { CH_SIDE_RIGHT,              "right"                         },
2083   { CH_SIDE_TOP,                "top"                           },
2084   { CH_SIDE_BOTTOM,             "bottom"                        },
2085   { CH_SIDE_LEFT_RIGHT,         "left/right"                    },
2086   { CH_SIDE_TOP_BOTTOM,         "top/bottom"                    },
2087   { CH_SIDE_ANY,                "any"                           },
2088
2089   { -1,                         NULL                            }
2090 };
2091
2092 static struct ValueTextInfo options_change_trigger_player[] =
2093 {
2094   { CH_PLAYER_1,                "1"                             },
2095   { CH_PLAYER_2,                "2"                             },
2096   { CH_PLAYER_3,                "3"                             },
2097   { CH_PLAYER_4,                "4"                             },
2098   { CH_PLAYER_ANY,              "any"                           },
2099
2100   { -1,                         NULL                            }
2101 };
2102
2103 static struct ValueTextInfo options_change_trigger_page[] =
2104 {
2105   { (1u << 0),                  "1"                             },
2106   { (1u << 1),                  "2"                             },
2107   { (1u << 2),                  "3"                             },
2108   { (1u << 3),                  "4"                             },
2109   { (1u << 4),                  "5"                             },
2110   { (1u << 5),                  "6"                             },
2111   { (1u << 6),                  "7"                             },
2112   { (1u << 7),                  "8"                             },
2113   { (1u << 8),                  "9"                             },
2114   { (1u << 9),                  "10"                            },
2115   { (1u << 10),                 "11"                            },
2116   { (1u << 11),                 "12"                            },
2117   { (1u << 12),                 "13"                            },
2118   { (1u << 13),                 "14"                            },
2119   { (1u << 14),                 "15"                            },
2120   { (1u << 15),                 "16"                            },
2121   { (1u << 16),                 "17"                            },
2122   { (1u << 17),                 "18"                            },
2123   { (1u << 18),                 "19"                            },
2124   { (1u << 19),                 "20"                            },
2125   { (1u << 20),                 "21"                            },
2126   { (1u << 21),                 "22"                            },
2127   { (1u << 22),                 "23"                            },
2128   { (1u << 23),                 "24"                            },
2129   { (1u << 24),                 "25"                            },
2130   { (1u << 25),                 "26"                            },
2131   { (1u << 26),                 "27"                            },
2132   { (1u << 27),                 "28"                            },
2133   { (1u << 28),                 "29"                            },
2134   { (1u << 29),                 "30"                            },
2135   { (1u << 30),                 "31"                            },
2136   { (1u << 31),                 "32"                            },
2137   { CH_PAGE_ANY,                "any"                           },
2138
2139   { -1,                         NULL                            }
2140 };
2141
2142 static struct ValueTextInfo options_change_replace_when[] =
2143 {
2144   { CP_WHEN_EMPTY,              "empty"                         },
2145   { CP_WHEN_WALKABLE,           "walkable"                      },
2146   { CP_WHEN_DIGGABLE,           "diggable"                      },
2147   { CP_WHEN_COLLECTIBLE,        "collectible"                   },
2148   { CP_WHEN_REMOVABLE,          "removable"                     },
2149   { CP_WHEN_DESTRUCTIBLE,       "destructible"                  },
2150
2151   { -1,                         NULL                            }
2152 };
2153
2154 static struct ValueTextInfo options_action_type[] =
2155 {
2156   { CA_NO_ACTION,               "no action"                     },
2157   { CA_UNDEFINED,               " "                             },
2158   { CA_HEADLINE_LEVEL_ACTIONS,  "[level]"                       },
2159   { CA_RESTART_LEVEL,           "restart level"                 },
2160   { CA_SHOW_ENVELOPE,           "show envelope"                 },
2161   { CA_SET_LEVEL_TIME,          "set time"                      },
2162   { CA_SET_LEVEL_SCORE,         "set score"                     },
2163   { CA_SET_LEVEL_GEMS,          "set gems"                      },
2164   { CA_SET_LEVEL_WIND,          "set wind dir."                 },
2165   { CA_SET_LEVEL_RANDOM_SEED,   "set random seed"               },
2166   { CA_UNDEFINED,               " "                             },
2167   { CA_HEADLINE_PLAYER_ACTIONS, "[player]"                      },
2168   { CA_MOVE_PLAYER,             "move player"                   },
2169   { CA_MOVE_PLAYER_NEW,         "move player new"               },
2170   { CA_EXIT_PLAYER,             "exit player"                   },
2171   { CA_KILL_PLAYER,             "kill player"                   },
2172   { CA_SET_PLAYER_KEYS,         "set keys"                      },
2173   { CA_SET_PLAYER_SPEED,        "set speed"                     },
2174   { CA_SET_PLAYER_SHIELD,       "set shield"                    },
2175   { CA_SET_PLAYER_GRAVITY,      "set gravity"                   },
2176   { CA_SET_PLAYER_ARTWORK,      "set artwork"                   },
2177   { CA_SET_PLAYER_INVENTORY,    "set inventory"                 },
2178   { CA_UNDEFINED,               " "                             },
2179   { CA_HEADLINE_CE_ACTIONS,     "[CE]"                          },
2180   { CA_SET_CE_VALUE,            "set CE value"                  },
2181   { CA_SET_CE_SCORE,            "set CE score"                  },
2182   { CA_SET_CE_ARTWORK,          "set CE artwork"                },
2183   { CA_UNDEFINED,               " "                             },
2184   { CA_HEADLINE_ENGINE_ACTIONS, "[engine]"                      },
2185   { CA_SET_ENGINE_SCAN_MODE,    "set scan mode"                 },
2186
2187   { -1,                         NULL                            }
2188 };
2189
2190 static struct ValueTextInfo options_action_mode_none[] =
2191 {
2192   { CA_MODE_UNDEFINED,          " "                             },
2193
2194   { -1,                         NULL                            }
2195 };
2196
2197 static struct ValueTextInfo options_action_mode_assign[] =
2198 {
2199   { CA_MODE_SET,                "="                             },
2200
2201   { -1,                         NULL                            }
2202 };
2203
2204 static struct ValueTextInfo options_action_mode_add_remove[] =
2205 {
2206   { CA_MODE_ADD,                "+"                             },
2207   { CA_MODE_SUBTRACT,           "-"                             },
2208
2209   { -1,                         NULL                            }
2210 };
2211
2212 static struct ValueTextInfo options_action_mode_calculate[] =
2213 {
2214   { CA_MODE_SET,                "="                             },
2215   { CA_MODE_ADD,                "+"                             },
2216   { CA_MODE_SUBTRACT,           "-"                             },
2217   { CA_MODE_MULTIPLY,           "*"                             },
2218   { CA_MODE_DIVIDE,             "/"                             },
2219   { CA_MODE_MODULO,             "%"                             },
2220
2221   { -1,                         NULL                            }
2222 };
2223
2224 static struct ValueTextInfo options_action_arg_none[] =
2225 {
2226   { CA_ARG_UNDEFINED,           "         "                     },
2227
2228   { -1,                         NULL                            }
2229 };
2230
2231 static struct ValueTextInfo options_action_arg_player[] =
2232 {
2233   { CA_ARG_PLAYER_HEADLINE,     "[player]"                      },
2234   { CA_ARG_PLAYER_1,            "1"                             },
2235   { CA_ARG_PLAYER_2,            "2"                             },
2236   { CA_ARG_PLAYER_3,            "3"                             },
2237   { CA_ARG_PLAYER_4,            "4"                             },
2238   { CA_ARG_PLAYER_ANY,          "any"                           },
2239   { CA_ARG_PLAYER_TRIGGER,      "trigger"                       },
2240   { CA_ARG_PLAYER_ACTION,       "action ->"                     },
2241
2242   { -1,                         NULL                            }
2243 };
2244
2245 static struct ValueTextInfo options_action_arg_number[] =
2246 {
2247   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2248   { CA_ARG_0,                   "0"                             },
2249   { CA_ARG_1,                   "1"                             },
2250   { CA_ARG_2,                   "2"                             },
2251   { CA_ARG_3,                   "3"                             },
2252   { CA_ARG_4,                   "4"                             },
2253   { CA_ARG_5,                   "5"                             },
2254   { CA_ARG_10,                  "10"                            },
2255   { CA_ARG_100,                 "100"                           },
2256   { CA_ARG_1000,                "1000"                          },
2257   { CA_ARG_UNDEFINED,           " "                             },
2258   { CA_ARG_NUMBER_MIN,          "min"                           },
2259   { CA_ARG_NUMBER_MAX,          "max"                           },
2260   { CA_ARG_UNDEFINED,           " "                             },
2261   { CA_ARG_NUMBER_RESET,        "reset"                         },
2262   { CA_ARG_UNDEFINED,           " "                             },
2263   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
2264   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
2265   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2266   { CA_ARG_UNDEFINED,           " "                             },
2267   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2268   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2269   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2270   { CA_ARG_UNDEFINED,           " "                             },
2271   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2272   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2273   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2274   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2275   { CA_ARG_UNDEFINED,           " "                             },
2276   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2277   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2278   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2279   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2280
2281   { -1,                         NULL                            }
2282 };
2283
2284 static struct ValueTextInfo options_action_arg_value[] =
2285 {
2286   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2287   { CA_ARG_0,                   "0"                             },
2288   { CA_ARG_1,                   "1"                             },
2289   { CA_ARG_2,                   "2"                             },
2290   { CA_ARG_3,                   "3"                             },
2291   { CA_ARG_4,                   "4"                             },
2292   { CA_ARG_5,                   "5"                             },
2293   { CA_ARG_10,                  "10"                            },
2294   { CA_ARG_100,                 "100"                           },
2295   { CA_ARG_1000,                "1000"                          },
2296   { CA_ARG_UNDEFINED,           " "                             },
2297   { CA_ARG_NUMBER_MIN,          "min"                           },
2298   { CA_ARG_NUMBER_MAX,          "max"                           },
2299   { CA_ARG_UNDEFINED,           " "                             },
2300   { CA_ARG_NUMBER_RESET,        "reset"                         },
2301   { CA_ARG_UNDEFINED,           " "                             },
2302   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
2303   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
2304   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2305   { CA_ARG_UNDEFINED,           " "                             },
2306   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2307   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2308   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2309   { CA_ARG_UNDEFINED,           " "                             },
2310   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2311   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2312   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2313   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2314   { CA_ARG_UNDEFINED,           " "                             },
2315   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2316   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2317   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2318   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2319   { CA_ARG_UNDEFINED,           " "                             },
2320   { CA_ARG_ELEMENT_NR_HEADLINE, "[element]"                     },
2321   { CA_ARG_ELEMENT_NR_TARGET,   "target"                        },
2322   { CA_ARG_ELEMENT_NR_TRIGGER,  "trigger"                       },
2323   { CA_ARG_ELEMENT_NR_ACTION,   "action ->"                     },
2324
2325   { -1,                         NULL                            }
2326 };
2327
2328 static struct ValueTextInfo options_action_arg_envelope[] =
2329 {
2330   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2331   { CA_ARG_1,                   "1"                             },
2332   { CA_ARG_2,                   "2"                             },
2333   { CA_ARG_3,                   "3"                             },
2334   { CA_ARG_4,                   "4"                             },
2335   { CA_ARG_UNDEFINED,           " "                             },
2336   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2337   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2338   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2339   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2340
2341   { -1,                         NULL                            }
2342 };
2343
2344 static struct ValueTextInfo options_action_arg_key[] =
2345 {
2346   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2347   { CA_ARG_1,                   "1"                             },
2348   { CA_ARG_2,                   "2"                             },
2349   { CA_ARG_3,                   "3"                             },
2350   { CA_ARG_4,                   "4"                             },
2351   { CA_ARG_5,                   "5"                             },
2352   { CA_ARG_6,                   "6"                             },
2353   { CA_ARG_7,                   "7"                             },
2354   { CA_ARG_8,                   "8"                             },
2355   { CA_ARG_UNDEFINED,           " "                             },
2356   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2357   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2358   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2359   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2360
2361   { -1,                         NULL                            }
2362 };
2363
2364 static struct ValueTextInfo options_action_arg_speed[] =
2365 {
2366   { CA_ARG_SPEED_HEADLINE,      "[speed]"                       },
2367   { CA_ARG_SPEED_NOT_MOVING,    "frozen"                        },
2368   { CA_ARG_SPEED_VERY_SLOW,     "very slow"                     },
2369   { CA_ARG_SPEED_SLOW,          "slow"                          },
2370   { CA_ARG_SPEED_NORMAL,        "normal"                        },
2371   { CA_ARG_SPEED_FAST,          "fast"                          },
2372   { CA_ARG_SPEED_VERY_FAST,     "very fast"                     },
2373   { CA_ARG_SPEED_EVEN_FASTER,   "ultrafast"                     },
2374   { CA_ARG_UNDEFINED,           " "                             },
2375   { CA_ARG_SPEED_SLOWER,        "slower"                        },
2376   { CA_ARG_SPEED_FASTER,        "faster"                        },
2377   { CA_ARG_UNDEFINED,           " "                             },
2378   { CA_ARG_SPEED_RESET,         "reset"                         },
2379
2380   { -1,                         NULL                            }
2381 };
2382
2383 static struct ValueTextInfo options_action_arg_shield[] =
2384 {
2385   { CA_ARG_SHIELD_HEADLINE,     "[shield]"                      },
2386   { CA_ARG_SHIELD_OFF,          "off"                           },
2387   { CA_ARG_SHIELD_NORMAL,       "normal"                        },
2388   { CA_ARG_SHIELD_DEADLY,       "deadly"                        },
2389
2390   { -1,                         NULL                            }
2391 };
2392
2393 static struct ValueTextInfo options_action_arg_artwork[] =
2394 {
2395   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2396   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2397   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2398   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2399   { CA_ARG_UNDEFINED,           " "                             },
2400   { CA_ARG_ELEMENT_RESET,       "reset"                         },
2401
2402   { -1,                         NULL                            }
2403 };
2404
2405 static struct ValueTextInfo options_action_arg_gravity[] =
2406 {
2407   { CA_ARG_GRAVITY_HEADLINE,    "[gravity]"                     },
2408   { CA_ARG_GRAVITY_ON,          "on"                            },
2409   { CA_ARG_GRAVITY_OFF,         "off"                           },
2410   { CA_ARG_GRAVITY_TOGGLE,      "toggle"                        },
2411
2412   { -1,                         NULL                            }
2413 };
2414
2415 static struct ValueTextInfo options_action_arg_direction[] =
2416 {
2417   { CA_ARG_DIRECTION_HEADLINE,  "[dir.]"                        },
2418   { CA_ARG_DIRECTION_NONE,      "none"                          },
2419   { CA_ARG_DIRECTION_LEFT,      "left"                          },
2420   { CA_ARG_DIRECTION_RIGHT,     "right"                         },
2421   { CA_ARG_DIRECTION_UP,        "up"                            },
2422   { CA_ARG_DIRECTION_DOWN,      "down"                          },
2423   { CA_ARG_DIRECTION_TRIGGER,   "trigger"                       },
2424   { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                   },
2425
2426   { -1,                         NULL                            }
2427 };
2428
2429 static struct ValueTextInfo options_action_arg_scan_mode[] =
2430 {
2431   { CA_ARG_SCAN_MODE_HEADLINE,  "[mode]"                        },
2432   { CA_ARG_SCAN_MODE_NORMAL,    "normal"                        },
2433   { CA_ARG_SCAN_MODE_REVERSE,   "reverse"                       },
2434
2435   { -1,                         NULL                            }
2436 };
2437
2438 static struct ValueTextInfo options_action_arg_inventory[] =
2439 {
2440   { CA_ARG_INVENTORY_HEADLINE,  "[add]"                         },
2441   { CA_ARG_ELEMENT_TARGET,      "+ target"                      },
2442   { CA_ARG_ELEMENT_TRIGGER,     "+ trigger"                     },
2443   { CA_ARG_ELEMENT_ACTION,      "+ action"                      },
2444   { CA_ARG_UNDEFINED,           " "                             },
2445   { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]"                     },
2446   { CA_ARG_INVENTORY_RM_TARGET, "- target"                      },
2447   { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger"                     },
2448   { CA_ARG_INVENTORY_RM_ACTION, "- action"                      },
2449   { CA_ARG_INVENTORY_RM_FIRST,  "- first"                       },
2450   { CA_ARG_INVENTORY_RM_LAST,   "- last"                        },
2451   { CA_ARG_INVENTORY_RM_ALL,    "- all"                         },
2452   { CA_ARG_UNDEFINED,           " "                             },
2453   { CA_ARG_INVENTORY_RESET,     "reset"                         },
2454
2455   { -1,                         NULL                            }
2456 };
2457
2458 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2459 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2460 {
2461   { -1,                         NULL                            }
2462 };
2463
2464 static struct ValueTextInfo options_group_choice_mode[] =
2465 {
2466   { ANIM_RANDOM,                "random"                        },
2467   { ANIM_LOOP,                  "loop"                          },
2468   { ANIM_LINEAR,                "linear"                        },
2469   { ANIM_PINGPONG,              "pingpong"                      },
2470   { ANIM_PINGPONG2,             "pingpong 2"                    },
2471   { ANIM_LEVEL_NR,              "level number"                  },
2472
2473   { -1,                         NULL                            }
2474 };
2475
2476 static struct ValueTextInfo *action_arg_modes[] =
2477 {
2478   options_action_mode_none,
2479   options_action_mode_assign,
2480   options_action_mode_add_remove,
2481   options_action_mode_calculate,
2482 };
2483
2484 static struct
2485 {
2486   int value;
2487   int mode;
2488   struct ValueTextInfo *options;
2489 }
2490 action_arg_options[] =
2491 {
2492   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2493   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2494   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2495   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2496   { CA_MOVE_PLAYER_NEW,         0,      options_action_arg_direction,   },
2497   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2498   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2499   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2500   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2501   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2502   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2503   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2504   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2505   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2506   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2507   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2508   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2509   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2510   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2511   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2512   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2513   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2514
2515   { -1,                         FALSE,  NULL                            }
2516 };
2517
2518 static struct
2519 {
2520   int x, y;
2521   int gadget_id;
2522   int gadget_id_align;
2523   int size;     // char size of selectbox or '-1' (dynamically determined)
2524   struct ValueTextInfo *options;
2525   int *value;
2526   char *text_above, *text_left, *text_right, *infotext;
2527 } selectbox_info[ED_NUM_SELECTBOX] =
2528 {
2529   // ---------- level and editor settings -------------------------------------
2530
2531   {
2532     -1,                                 ED_LEVEL_SETTINGS_YPOS(8),
2533     GADGET_ID_TIME_OR_STEPS,            GADGET_ID_LEVEL_TIMELIMIT_UP,
2534     -1,
2535     options_time_or_steps,
2536     &level.use_step_counter,
2537     NULL, NULL, "(0 => no limit)",      "time or step limit"
2538   },
2539   {
2540     -1,                                 ED_LEVEL_SETTINGS_YPOS(10),
2541     GADGET_ID_TIME_SCORE_BASE,          GADGET_ID_LEVEL_TIMESCORE_UP,
2542     -1,
2543     options_time_score_base,
2544     &level.time_score_base,
2545     NULL, NULL, NULL,                   "time score for 1 or 10 seconds/steps"
2546   },
2547   {
2548     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(12),
2549     GADGET_ID_GAME_ENGINE_TYPE,         GADGET_ID_NONE,
2550     -1,
2551     options_game_engine_type,
2552     &level.game_engine_type,
2553     NULL, "game engine:", NULL,         "game engine"
2554   },
2555   {
2556     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
2557     GADGET_ID_LEVELSET_SAVE_MODE,       GADGET_ID_NONE,
2558     -1,
2559     options_levelset_save_mode,
2560     &levelset_save_mode,
2561     "Action:", NULL, NULL,              "action when saving level set"
2562   },
2563
2564   // ---------- element settings: configure (several elements) ----------------
2565
2566   {
2567     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2568     GADGET_ID_WIND_DIRECTION,           GADGET_ID_NONE,
2569     -1,
2570     options_wind_direction,
2571     &level.wind_direction_initial,
2572     NULL, "initial wind direction:", NULL,      "initial wind direction"
2573   },
2574   {
2575     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
2576     GADGET_ID_PLAYER_SPEED,             GADGET_ID_NONE,
2577     -1,
2578     options_player_speed,
2579     &level.initial_player_stepsize[0],
2580     NULL, "initial player speed:", NULL,        "initial player speed"
2581   },
2582   {
2583     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2584     GADGET_ID_MM_BALL_CHOICE_MODE,      GADGET_ID_NONE,
2585     -1,
2586     options_group_choice_mode,
2587     &level.mm_ball_choice_mode,
2588     NULL, "choice type:", NULL,         "type of content choice"
2589   },
2590
2591   // ---------- element settings: configure 1 (custom elements) ---------------
2592
2593   {
2594     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2595     GADGET_ID_CUSTOM_ACCESS_TYPE,       GADGET_ID_NONE,
2596     -1,
2597     options_access_type,
2598     &custom_element.access_type,
2599     NULL, NULL, NULL,                   "type of access to this field"
2600   },
2601   {
2602     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2603     GADGET_ID_CUSTOM_ACCESS_LAYER,      GADGET_ID_CUSTOM_ACCESS_TYPE,
2604     -1,
2605     options_access_layer,
2606     &custom_element.access_layer,
2607     NULL, NULL, NULL,                   "layer of access for this field"
2608   },
2609   {
2610     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2611     GADGET_ID_CUSTOM_ACCESS_PROTECTED,  GADGET_ID_CUSTOM_ACCESS_LAYER,
2612     -1,
2613     options_access_protected,
2614     &custom_element.access_protected,
2615     NULL, NULL, NULL,                   "protected access for this field"
2616   },
2617   {
2618     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2619     GADGET_ID_CUSTOM_ACCESS_DIRECTION,  GADGET_ID_NONE,
2620     -1,
2621     options_access_direction,
2622     &custom_element.access_direction,
2623     NULL, "from", NULL,                 "access direction for this field"
2624   },
2625   {
2626     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2627     GADGET_ID_CUSTOM_WALK_TO_ACTION,    GADGET_ID_NONE,
2628     -1,
2629     options_walk_to_action,
2630     &custom_element.walk_to_action,
2631     NULL, NULL, NULL,                   "diggable/collectible/pushable"
2632   },
2633
2634   // ---------- element settings: configure 2 (custom elements) ---------------
2635
2636   {
2637     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(1),
2638     GADGET_ID_CUSTOM_MOVE_PATTERN,      GADGET_ID_NONE,
2639     -1,
2640     options_move_pattern,
2641     &custom_element.move_pattern,
2642     NULL, "can move", NULL,             "element move pattern"
2643   },
2644   {
2645     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2646     GADGET_ID_CUSTOM_MOVE_DIRECTION,    GADGET_ID_NONE,
2647     -1,
2648     options_move_direction,
2649     &custom_element.move_direction_initial,
2650     NULL, "starts moving", NULL,        "initial element move direction"
2651   },
2652   {
2653     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2654     GADGET_ID_CUSTOM_MOVE_STEPSIZE,     GADGET_ID_NONE,
2655     -1,
2656     options_move_stepsize,
2657     &custom_element.move_stepsize,
2658     NULL, "move/fall speed", NULL,      "speed of element movement"
2659   },
2660   {
2661     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2662     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,   GADGET_ID_NONE,
2663     -1,
2664     options_move_leave_type,
2665     &custom_element.move_leave_type,
2666     // left text with leading spaces to place gadget next to "can dig" gadget
2667     // (needed because drawing area gadgets created after selectbox gadgets)
2668     // NULL, "can dig:    can", ":",    "leave behind or change element"
2669     NULL, "            can", ":",       "leave behind or change element"
2670   },
2671   {
2672     -1,                                 ED_ELEMENT_SETTINGS_YPOS(8),
2673     GADGET_ID_CUSTOM_SMASH_TARGETS,     GADGET_ID_CUSTOM_CAN_SMASH,
2674     -1,
2675     options_smash_targets,
2676     &custom_element.smash_targets,
2677     NULL, "can smash", NULL,            "elements that can be smashed"
2678   },
2679   {
2680     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
2681     GADGET_ID_CUSTOM_SLIPPERY_TYPE,     GADGET_ID_NONE,
2682     -1,
2683     options_slippery_type,
2684     &custom_element.slippery_type,
2685     NULL, "slippery", NULL,             "where other elements fall down"
2686   },
2687   {
2688     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(10),
2689     GADGET_ID_CUSTOM_DEADLINESS,        GADGET_ID_NONE,
2690     -1,
2691     options_deadliness,
2692     &custom_element.deadliness,
2693     NULL, "deadly when", NULL,          "deadliness of element"
2694   },
2695   {
2696     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(11),
2697     GADGET_ID_CUSTOM_EXPLOSION_TYPE,    GADGET_ID_NONE,
2698     -1,
2699     options_explosion_type,
2700     &custom_element.explosion_type,
2701     NULL, "can explode", NULL,          "explosion type"
2702   },
2703
2704   // ---------- element settings: advanced (custom elements) ------------------
2705
2706   {
2707     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(3),
2708     GADGET_ID_CHANGE_TIME_UNITS,        GADGET_ID_NONE,
2709     -1,
2710     options_time_units,
2711     &custom_element_change.delay_frames,
2712     NULL, "delay time given in", NULL,  "delay time units for change"
2713   },
2714   {
2715     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(4),
2716     GADGET_ID_CHANGE_DIRECT_ACTION,     GADGET_ID_NONE,
2717     -1,
2718     options_change_direct_action,
2719     &custom_element_change.direct_action,
2720     NULL, NULL, NULL,                   "type of direct action"
2721   },
2722   {
2723     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(5),
2724     GADGET_ID_CHANGE_OTHER_ACTION,      GADGET_ID_NONE,
2725     -1,
2726     options_change_other_action,
2727     &custom_element_change.other_action,
2728     NULL, NULL, "element:",             "type of other element action"
2729   },
2730   {
2731     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(6),
2732     GADGET_ID_CHANGE_SIDE,              GADGET_ID_NONE,
2733     -1,
2734     options_change_trigger_side,
2735     &custom_element_change.trigger_side,
2736     NULL, "at", "side",                 "element side triggering change"
2737   },
2738   {
2739     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2740     GADGET_ID_CHANGE_PLAYER,            GADGET_ID_NONE,
2741     -1,
2742     options_change_trigger_player,
2743     &custom_element_change.trigger_player,
2744     NULL, "player:", " ",               "player that causes change"
2745   },
2746   {
2747     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2748     GADGET_ID_CHANGE_PAGE,              GADGET_ID_CHANGE_PLAYER,
2749     -1,
2750     options_change_trigger_page,
2751     &custom_element_change.trigger_page,
2752     NULL, "page:", NULL,                "change page that causes change"
2753   },
2754   {
2755     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(10),
2756     GADGET_ID_CHANGE_REPLACE_WHEN,      GADGET_ID_NONE,
2757     -1,
2758     options_change_replace_when,
2759     &custom_element_change.replace_when,
2760     NULL, "replace when", NULL,         "which elements can be replaced"
2761   },
2762   {
2763     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
2764     GADGET_ID_ACTION_TYPE,              GADGET_ID_NONE,
2765     15,
2766     options_action_type,
2767     &custom_element_change.action_type,
2768     NULL, NULL, NULL,                   "action on specified condition"
2769   },
2770   {
2771     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2772     GADGET_ID_ACTION_MODE,              GADGET_ID_ACTION_TYPE,
2773     -1,
2774     options_action_mode_none,
2775     &custom_element_change.action_mode,
2776     NULL, NULL, NULL,                   "action operator"
2777   },
2778   {
2779     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2780     GADGET_ID_ACTION_ARG,               GADGET_ID_ACTION_MODE,
2781     -1,
2782     options_action_arg_none,
2783     &custom_element_change.action_arg,
2784     NULL, NULL, NULL,                   "action parameter"
2785   },
2786   {
2787     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
2788     GADGET_ID_SELECT_CHANGE_PAGE,       GADGET_ID_NONE,
2789     3,
2790     options_change_page,
2791     &custom_element.current_change_page,
2792     NULL, NULL, NULL,                   "element change page"
2793   },
2794
2795   // ---------- element settings: configure (group elements) ------------------
2796
2797   {
2798     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2799     GADGET_ID_GROUP_CHOICE_MODE,        GADGET_ID_NONE,
2800     -1,
2801     options_group_choice_mode,
2802     &group_element_info.choice_mode,
2803     NULL, "choice type:", NULL,         "type of group element choice"
2804   },
2805 };
2806
2807 static struct
2808 {
2809   int x, y;
2810   int gadget_id;
2811   int gadget_id_align;
2812   int size;
2813   char *text;
2814   char *text_above, *text_left, *text_right, *infotext;
2815 } textbutton_info[ED_NUM_TEXTBUTTONS] =
2816 {
2817   // ---------- level and editor settings (tabs) ------------------------------
2818
2819   {
2820     ED_LEVEL_TABS_XPOS(0),              ED_LEVEL_TABS_YPOS(0),
2821     GADGET_ID_LEVELCONFIG_LEVEL,        GADGET_ID_NONE,
2822     8,                                  "Level",
2823     NULL, NULL, NULL,                   "Configure level settings"
2824   },
2825   {
2826     -1,                                 -1,
2827     GADGET_ID_LEVELCONFIG_LEVELSET,     GADGET_ID_LEVELCONFIG_LEVEL,
2828     8,                                  "Levelset",
2829     NULL, NULL, NULL,                   "Update this or create new level set"
2830   },
2831   {
2832     -1,                                 -1,
2833     GADGET_ID_LEVELCONFIG_EDITOR,       GADGET_ID_LEVELCONFIG_LEVELSET,
2834     8,                                  "Editor",
2835     NULL, NULL, NULL,                   "Configure editor settings"
2836   },
2837
2838   // ---------- element settings (tabs) ---------------------------------------
2839
2840   {
2841     ED_ELEMENT_TABS_XPOS(0),            ED_ELEMENT_TABS_YPOS(0),
2842     GADGET_ID_PROPERTIES_INFO,          GADGET_ID_NONE,
2843     8,                                  "Info",
2844     NULL, NULL, NULL,                   "Show information about element"
2845   },
2846   {
2847     -1,                                 -1,
2848     GADGET_ID_PROPERTIES_CONFIG,        GADGET_ID_PROPERTIES_INFO,
2849     8,                                  "Config",
2850     NULL, NULL, NULL,                   "Configure element properties"
2851   },
2852   {
2853     -1,                                 -1,
2854     GADGET_ID_PROPERTIES_CONFIG_1,      GADGET_ID_PROPERTIES_INFO,
2855     8,                                  "Config 1",
2856     NULL, NULL, NULL,                   "Configure element properties, part 1"
2857   },
2858   {
2859     -1,                                 -1,
2860     GADGET_ID_PROPERTIES_CONFIG_2,      GADGET_ID_PROPERTIES_CONFIG_1,
2861     8,                                  "Config 2",
2862     NULL, NULL, NULL,                   "Configure element properties, part 2"
2863   },
2864   {
2865     -1,                                 -1,
2866     GADGET_ID_PROPERTIES_CHANGE,        GADGET_ID_PROPERTIES_CONFIG_2,
2867     8,                                  "Change",
2868     NULL, NULL, NULL,                   "Configure custom element change pages"
2869   },
2870
2871   // ---------- level and editor settings (buttons) ---------------------------
2872
2873   {
2874     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
2875     GADGET_ID_SAVE_LEVELSET,            GADGET_ID_LEVELSET_SAVE_MODE,
2876     -1,                                 "Save",
2877     NULL, NULL, NULL,                   "Update or create level set"
2878   },
2879   {
2880     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(6),
2881     GADGET_ID_SAVE_AS_TEMPLATE_2,       GADGET_ID_NONE,
2882     -1,                                 "Save",
2883     NULL, NULL,                         "this level as level template",
2884     "Save current settings as new template"
2885   },
2886
2887   // ---------- element settings (buttons) ------------------------------------
2888
2889   {
2890     -1,                                 -1,
2891     GADGET_ID_SAVE_AS_TEMPLATE_1,       GADGET_ID_CUSTOM_USE_TEMPLATE_1,
2892     -1,                                 "Save",
2893     NULL, " ",                          "As Template",
2894     "Save current settings as new template"
2895   },
2896   {
2897     -1,                                 -1,
2898     GADGET_ID_ADD_CHANGE_PAGE,          GADGET_ID_PASTE_CHANGE_PAGE,
2899     -1,                                 "New",
2900     NULL, NULL, NULL,                   "Add new change page"
2901   },
2902   {
2903     -1,                                 -1,
2904     GADGET_ID_DEL_CHANGE_PAGE,          GADGET_ID_ADD_CHANGE_PAGE,
2905     -1,                                 "Delete",
2906     NULL, NULL, NULL,                   "Delete current change page"
2907   },
2908 };
2909
2910 static struct
2911 {
2912   int graphic;
2913   int x, y;
2914   int gadget_id;
2915   int gadget_id_align;
2916   char *text_left, *text_right, *infotext;
2917 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
2918 {
2919   {
2920     IMG_EDITOR_COUNTER_DOWN,
2921     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
2922     GADGET_ID_PREV_CHANGE_PAGE,         GADGET_ID_NONE,
2923     NULL, NULL,                         "select previous change page"
2924   },
2925   {
2926     IMG_EDITOR_COUNTER_UP,
2927     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2928     GADGET_ID_NEXT_CHANGE_PAGE,         GADGET_ID_SELECT_CHANGE_PAGE,
2929     NULL, "change page",                "select next change page"
2930   },
2931   {
2932     IMG_GFX_EDITOR_BUTTON_CP_COPY,
2933     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2934     GADGET_ID_COPY_CHANGE_PAGE,         GADGET_ID_NEXT_CHANGE_PAGE,
2935     " ", NULL,                          "copy settings from this change page"
2936   },
2937   {
2938     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
2939     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2940     GADGET_ID_PASTE_CHANGE_PAGE,        GADGET_ID_COPY_CHANGE_PAGE,
2941     NULL, NULL,                         "paste settings to this change page"
2942   },
2943 };
2944
2945 static struct
2946 {
2947   int x, y;
2948 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
2949
2950 static struct
2951 {
2952   int graphic;
2953   int gadget_id;
2954   char *infotext;
2955 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
2956 {
2957   {
2958     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
2959     GADGET_ID_SCROLL_UP,
2960     "scroll level editing area up"
2961   },
2962   {
2963     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
2964     GADGET_ID_SCROLL_DOWN,
2965     "scroll level editing area down"
2966   },
2967   {
2968     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
2969     GADGET_ID_SCROLL_LEFT,
2970     "scroll level editing area left"
2971   },
2972   {
2973     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
2974     GADGET_ID_SCROLL_RIGHT,
2975     "scroll level editing area right"
2976   },
2977   {
2978     IMG_EDITOR_PALETTE_SCROLL_UP,
2979     GADGET_ID_SCROLL_LIST_UP,
2980     "scroll element list up ('Page Up')"
2981   },
2982   {
2983     IMG_EDITOR_PALETTE_SCROLL_DOWN,
2984     GADGET_ID_SCROLL_LIST_DOWN,
2985     "scroll element list down ('Page Down')"
2986   },
2987 };
2988
2989 static struct
2990 {
2991   int x, y;
2992   int width, height;
2993   int wheel_x, wheel_y;
2994   int wheel_width, wheel_height;
2995 } scrollbar_pos[ED_NUM_SCROLLBARS];
2996
2997 static struct
2998 {
2999   int graphic;
3000   int type;
3001   int gadget_id;
3002   char *infotext;
3003 } scrollbar_info[ED_NUM_SCROLLBARS] =
3004 {
3005   {
3006     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3007     GD_TYPE_SCROLLBAR_HORIZONTAL,
3008     GADGET_ID_SCROLL_HORIZONTAL,
3009     "scroll level editing area horizontally"
3010   },
3011   {
3012     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
3013     GD_TYPE_SCROLLBAR_VERTICAL,
3014     GADGET_ID_SCROLL_VERTICAL,
3015     "scroll level editing area vertically"
3016   },
3017   {
3018     IMG_EDITOR_PALETTE_SCROLLBAR,
3019     GD_TYPE_SCROLLBAR_VERTICAL,
3020     GADGET_ID_SCROLL_LIST_VERTICAL,
3021     "scroll element list vertically"
3022   }
3023 };
3024
3025
3026 static struct
3027 {
3028   int x, y;
3029   int gadget_id;
3030   int gadget_id_align;
3031   int radio_button_nr;
3032   int *value;
3033   int checked_value;
3034   char *text_left, *text_right, *infotext;
3035 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
3036 {
3037   {
3038     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
3039     GADGET_ID_RANDOM_PERCENTAGE,        GADGET_ID_LEVEL_RANDOM_UP,
3040     RADIO_NR_RANDOM_ELEMENTS,
3041     &random_placement_method,           RANDOM_USE_PERCENTAGE,
3042     " ", "percentage",                  "use percentage for random elements"
3043   },
3044   {
3045     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
3046     GADGET_ID_RANDOM_QUANTITY,          GADGET_ID_RANDOM_PERCENTAGE,
3047     RADIO_NR_RANDOM_ELEMENTS,
3048     &random_placement_method,           RANDOM_USE_QUANTITY,
3049     " ", "quantity",                    "use quantity for random elements"
3050   }
3051 };
3052
3053 static struct
3054 {
3055   int x, y;
3056   int gadget_id;
3057   int gadget_id_align;
3058   boolean *value;
3059   char *text_above, *text_left, *text_right, *infotext;
3060 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
3061 {
3062   // ---------- level and editor settings -------------------------------------
3063
3064   {
3065     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(6),
3066     GADGET_ID_AUTO_COUNT_GEMS,          GADGET_ID_NONE,
3067     &level.auto_count_gems,
3068     NULL, NULL,
3069     "automatically count gems needed",  "set counter to number of gems"
3070   },
3071   {
3072     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(11),
3073     GADGET_ID_RATE_TIME_OVER_SCORE,     GADGET_ID_NONE,
3074     &level.rate_time_over_score,
3075     NULL, NULL,
3076     "rate time/steps used over score",  "sort high scores by playing time/steps"
3077   },
3078   {
3079     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(7),
3080     GADGET_ID_USE_LEVELSET_ARTWORK,     GADGET_ID_NONE,
3081     &levelset_use_levelset_artwork,
3082     NULL, NULL,
3083     "use current custom artwork",       "use custom artwork of this level set"
3084   },
3085   {
3086     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(8),
3087     GADGET_ID_COPY_LEVEL_TEMPLATE,      GADGET_ID_NONE,
3088     &levelset_copy_level_template,
3089     NULL, NULL,
3090     "copy current level template",      "copy level template of this level set"
3091   },
3092   {
3093     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(1),
3094     GADGET_ID_RANDOM_RESTRICTED,        GADGET_ID_NONE,
3095     &random_placement_background_restricted,
3096     NULL, NULL,
3097     "restrict random placement to:",    "set random placement restriction"
3098   },
3099   {
3100     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
3101     GADGET_ID_CUSTOM_USE_TEMPLATE_3,    GADGET_ID_NONE,
3102     &setup.editor.use_template_for_new_levels,
3103     "Template for new levels and CE/GE:", NULL,
3104     "use template for new levels",      "use template for level properties"
3105   },
3106   {
3107     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
3108     GADGET_ID_CUSTOM_USE_TEMPLATE_2,    GADGET_ID_NONE,
3109     &level.use_custom_template,
3110     NULL, NULL,
3111     "use template for custom elements", "use template for custom properties"
3112   },
3113
3114   // ---------- element settings: configure (various elements) ----------------
3115
3116   {
3117     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3118     GADGET_ID_STICK_ELEMENT,            GADGET_ID_NONE,
3119     &stick_element_properties_window,
3120     NULL, NULL,
3121     "stick this screen to edit content","stick this screen to edit content"
3122   },
3123   {
3124     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3125     GADGET_ID_EM_SLIPPERY_GEMS,         GADGET_ID_NONE,
3126     &level.em_slippery_gems,
3127     NULL, NULL,
3128     "slip down from certain flat walls","use EM/DC style slipping behaviour"
3129   },
3130   {
3131     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3132     GADGET_ID_EM_EXPLODES_BY_FIRE,      GADGET_ID_NONE,
3133     &level.em_explodes_by_fire,
3134     NULL, NULL,
3135     "explodes with chain reaction",     "use R'n'D style explosion behaviour"
3136   },
3137   {
3138     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3139     GADGET_ID_USE_SPRING_BUG,           GADGET_ID_NONE,
3140     &level.use_spring_bug,
3141     NULL, NULL,
3142     "use spring pushing bug",           "use odd spring pushing behaviour"
3143   },
3144   {
3145     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3146     GADGET_ID_USE_TIME_ORB_BUG,         GADGET_ID_NONE,
3147     &level.use_time_orb_bug,
3148     NULL, NULL,
3149     "use time orb bug",                 "use odd time orb behaviour"
3150   },
3151   {
3152     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3153     GADGET_ID_USE_LIFE_BUGS,            GADGET_ID_NONE,
3154     &level.use_life_bugs,
3155     NULL, NULL,
3156     "use buggy element behaviour",      "use odd (historic) element behaviour"
3157   },
3158   {
3159     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3160     GADGET_ID_RANDOM_BALL_CONTENT,      GADGET_ID_NONE,
3161     &level.ball_random,
3162     NULL, NULL,
3163     "create single random element",     "only create one element from content"
3164   },
3165   {
3166     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3167     GADGET_ID_INITIAL_BALL_ACTIVE,      GADGET_ID_NONE,
3168     &level.ball_active_initial,
3169     NULL, NULL,
3170     "magic ball initially activated",   "activate magic ball after level start"
3171   },
3172   {
3173     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3174     GADGET_ID_GROW_INTO_DIGGABLE,       GADGET_ID_NONE,
3175     &level.grow_into_diggable,
3176     NULL, NULL,
3177     "can grow into anything diggable",  "grow into more than just sand"
3178   },
3179   {
3180     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3181     GADGET_ID_SB_FIELDS_NEEDED,         GADGET_ID_NONE,
3182     &level.sb_fields_needed,
3183     NULL, NULL,
3184     "all fields need to be filled",     "require all SB fields to be solved"
3185   },
3186   {
3187     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3188     GADGET_ID_SB_OBJECTS_NEEDED,        GADGET_ID_NONE,
3189     &level.sb_objects_needed,
3190     NULL, NULL,
3191     "all objects need to be placed",    "require all SB objects to be solved"
3192   },
3193   {
3194     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3195     GADGET_ID_AUTO_EXIT_SOKOBAN,        GADGET_ID_NONE,
3196     &level.auto_exit_sokoban,
3197     NULL, NULL,
3198     "exit level if all tasks solved",   "automatically finish Sokoban levels"
3199   },
3200   {
3201     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
3202     GADGET_ID_SOLVED_BY_ONE_PLAYER,     GADGET_ID_NONE,
3203     &level.solved_by_one_player,
3204     NULL, NULL,
3205     "only one player must enter exit",  "level solved by first player in exit"
3206   },
3207   {
3208     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3209     GADGET_ID_FINISH_DIG_COLLECT,       GADGET_ID_NONE,
3210     &level.finish_dig_collect,
3211     NULL, NULL,
3212     "CE action on finished dig/collect", "only finished dig/collect triggers CE"
3213   },
3214   {
3215     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3216     GADGET_ID_KEEP_WALKABLE_CE,         GADGET_ID_NONE,
3217     &level.keep_walkable_ce,
3218     NULL, NULL,
3219     "keep walkable CE changed to player", "keep CE changing to player if walkable"
3220   },
3221   {
3222     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3223     GADGET_ID_CONTINUOUS_SNAPPING,      GADGET_ID_NONE,
3224     &level.continuous_snapping,
3225     NULL, NULL,
3226     "continuous snapping",              "use snapping without releasing key"
3227   },
3228   {
3229     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
3230     GADGET_ID_BLOCK_SNAP_FIELD,         GADGET_ID_NONE,
3231     &level.block_snap_field,
3232     NULL, NULL,
3233     "block snapped field when snapping", "use snapping delay to show animation"
3234   },
3235   {
3236     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3237     GADGET_ID_BLOCK_LAST_FIELD,         GADGET_ID_NONE,
3238     &level.block_last_field,
3239     NULL, NULL,
3240     "block last field when moving",     "player blocks last field when moving"
3241   },
3242   {
3243     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3244     GADGET_ID_SP_BLOCK_LAST_FIELD,      GADGET_ID_NONE,
3245     &level.sp_block_last_field,
3246     NULL, NULL,
3247     "block last field when moving",     "player blocks last field when moving"
3248   },
3249   {
3250     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3251     GADGET_ID_INSTANT_RELOCATION,       GADGET_ID_NONE,
3252     &level.instant_relocation,
3253     NULL, NULL,
3254     "no scrolling when relocating",     "player gets relocated without delay"
3255   },
3256   {
3257     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3258     GADGET_ID_SHIFTED_RELOCATION,       GADGET_ID_NONE,
3259     &level.shifted_relocation,
3260     NULL, NULL,
3261     "no centering when relocating",     "level not centered after relocation"
3262   },
3263   {
3264     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3265     GADGET_ID_LAZY_RELOCATION,          GADGET_ID_NONE,
3266     &level.lazy_relocation,
3267     NULL, NULL,
3268     "only redraw off-screen relocation","no redraw if relocation target visible"
3269   },
3270   {
3271     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
3272     GADGET_ID_USE_START_ELEMENT,        GADGET_ID_NONE,
3273     &level.use_start_element[0],
3274     NULL, NULL,
3275     "use level start element:",        "start level at this element's position"
3276   },
3277   {
3278     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
3279     GADGET_ID_USE_ARTWORK_ELEMENT,      GADGET_ID_NONE,
3280     &level.use_artwork_element[0],
3281     NULL, NULL,
3282     "use artwork from element:",        "use player artwork from other element"
3283   },
3284   {
3285     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
3286     GADGET_ID_USE_EXPLOSION_ELEMENT,    GADGET_ID_NONE,
3287     &level.use_explosion_element[0],
3288     NULL, NULL,
3289     "use explosion from element:",      "use explosion properties from element"
3290   },
3291   {
3292     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
3293     GADGET_ID_INITIAL_GRAVITY,          GADGET_ID_NONE,
3294     &level.initial_player_gravity[0],
3295     NULL, NULL,
3296     "use initial gravity",              "set initial player gravity"
3297   },
3298   {
3299     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3300     GADGET_ID_USE_INITIAL_INVENTORY,    GADGET_ID_NONE,
3301     &level.use_initial_inventory[0],
3302     NULL, NULL,
3303     "use initial inventory:",           "use collected elements on level start"
3304   },
3305   {
3306     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
3307     GADGET_ID_CAN_PASS_TO_WALKABLE,     GADGET_ID_NONE,
3308     &level.can_pass_to_walkable,
3309     NULL, NULL,
3310     "can pass to walkable element",     "player can pass to empty or walkable"
3311   },
3312   {
3313     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3314     GADGET_ID_CAN_FALL_INTO_ACID,       GADGET_ID_NONE,
3315     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3316     NULL, NULL,
3317     "can fall into acid (with gravity)","player can fall into acid pool"
3318   },
3319   {
3320     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3321     GADGET_ID_CAN_MOVE_INTO_ACID,       GADGET_ID_NONE,
3322     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
3323     NULL, NULL,
3324     "can move into acid",               "element can move into acid pool"
3325   },
3326   {
3327     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3328     GADGET_ID_DONT_COLLIDE_WITH,        GADGET_ID_NONE,
3329     &custom_element_properties[EP_DONT_COLLIDE_WITH],
3330     NULL, NULL,
3331     "deadly when colliding with",       "element is deadly when hitting player"
3332   },
3333   {
3334     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
3335     GADGET_ID_BD_DIAGONAL_MOVEMENTS,    GADGET_ID_NONE,
3336     &level.bd_diagonal_movements,
3337     NULL, NULL,
3338     "can move diagonally",              "player can move diagonally"
3339   },
3340   {
3341     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3342     GADGET_ID_ENVELOPE_AUTOWRAP,        GADGET_ID_NONE,
3343     &level.envelope[0].autowrap,
3344     NULL, NULL,
3345     "auto-wrap",                        "automatically wrap envelope text"
3346   },
3347   {
3348     -1,                                 ED_ELEMENT_SETTINGS_YPOS(1),
3349     GADGET_ID_ENVELOPE_CENTERED,        GADGET_ID_ENVELOPE_AUTOWRAP,
3350     &level.envelope[0].centered,
3351     NULL, " ",
3352     "centered",                         "automatically center envelope text"
3353   },
3354   {
3355     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3356     GADGET_ID_MM_LASER_RED,             GADGET_ID_NONE,
3357     &level.mm_laser_red,
3358     "choose color components for laser:", NULL,
3359     "red",                              "use red color components in laser"
3360   },
3361   {
3362     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3363     GADGET_ID_MM_LASER_GREEN,           GADGET_ID_NONE,
3364     &level.mm_laser_green,
3365     NULL, NULL,
3366     "green",                            "use green color components in laser"
3367   },
3368   {
3369     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3370     GADGET_ID_MM_LASER_BLUE,            GADGET_ID_NONE,
3371     &level.mm_laser_blue,
3372     NULL, NULL,
3373     "blue",                             "use blue color components in laser"
3374   },
3375   {
3376     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3377     GADGET_ID_DF_LASER_RED,             GADGET_ID_NONE,
3378     &level.df_laser_red,
3379     "choose color components for laser:", NULL,
3380     "red",                              "use red color components in laser"
3381   },
3382   {
3383     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3384     GADGET_ID_DF_LASER_GREEN,           GADGET_ID_NONE,
3385     &level.df_laser_green,
3386     NULL, NULL,
3387     "green",                            "use green color components in laser"
3388   },
3389   {
3390     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
3391     GADGET_ID_DF_LASER_BLUE,            GADGET_ID_NONE,
3392     &level.df_laser_blue,
3393     NULL, NULL,
3394     "blue",                             "use blue color components in laser"
3395   },
3396   {
3397     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
3398     GADGET_ID_ROTATE_MM_BALL_CONTENT,   GADGET_ID_NONE,
3399     &level.rotate_mm_ball_content,
3400     NULL, NULL,
3401     "randomly rotate created content",  "randomly rotate newly created content"
3402   },
3403   {
3404     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
3405     GADGET_ID_EXPLODE_MM_BALL,          GADGET_ID_NONE,
3406     &level.explode_mm_ball,
3407     NULL, NULL,
3408     "explode ball instead of melting",  "use explosion to release ball content"
3409   },
3410
3411   // ---------- element settings: configure 1 (custom elements) ---------------
3412
3413   {
3414     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3415     GADGET_ID_CUSTOM_USE_GRAPHIC,       GADGET_ID_NONE,
3416     &custom_element.use_gfx_element,
3417     NULL, NULL,
3418     "use graphic of element:",          "use existing element graphic"
3419   },
3420   {
3421     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
3422     GADGET_ID_CUSTOM_USE_TEMPLATE_1,    GADGET_ID_NONE,
3423     &level.use_custom_template,
3424     NULL, NULL,
3425     "use template",                     "use template for custom properties"
3426   },
3427   {
3428     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
3429     GADGET_ID_CUSTOM_ACCESSIBLE,        GADGET_ID_NONE,
3430     &custom_element_properties[EP_ACCESSIBLE],
3431     NULL, NULL,
3432     NULL,                               "player can walk to or pass this field"
3433   },
3434   {
3435     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3436     GADGET_ID_CUSTOM_GRAV_REACHABLE,    GADGET_ID_NONE,
3437     &custom_element_properties[EP_GRAVITY_REACHABLE],
3438     NULL, NULL,
3439     "reachable despite gravity",        "player can walk/dig despite gravity"
3440   },
3441   {
3442     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
3443     GADGET_ID_CUSTOM_USE_LAST_VALUE,    GADGET_ID_NONE,
3444     &custom_element.use_last_ce_value,
3445     NULL, NULL,
3446     "use last CE value after change",   "use last CE value after change"
3447   },
3448   {
3449     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
3450     GADGET_ID_CUSTOM_WALK_TO_OBJECT,    GADGET_ID_NONE,
3451     &custom_element_properties[EP_WALK_TO_OBJECT],
3452     NULL, NULL,
3453     NULL,                               "player can dig/collect/push element"
3454   },
3455   {
3456     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
3457     GADGET_ID_CUSTOM_INDESTRUCTIBLE,    GADGET_ID_NONE,
3458     &custom_element_properties[EP_INDESTRUCTIBLE],
3459     NULL, NULL,
3460     "indestructible",                   "element is indestructible"
3461   },
3462
3463   // ---------- element settings: configure 2 (custom elements) ---------------
3464
3465   {
3466     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3467     GADGET_ID_CUSTOM_CAN_MOVE,          GADGET_ID_NONE,
3468     &custom_element_properties[EP_CAN_MOVE],
3469     NULL, NULL,
3470     NULL,                               "element can move with some pattern"
3471   },
3472   {
3473     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
3474     GADGET_ID_CUSTOM_CAN_FALL,          GADGET_ID_NONE,
3475     &custom_element_properties[EP_CAN_FALL],
3476     NULL, NULL,
3477     "can fall",                         "element can fall down"
3478   },
3479   {
3480     -1,                                 ED_ELEMENT_SETTINGS_YPOS(8),
3481     GADGET_ID_CUSTOM_CAN_SMASH,         GADGET_ID_CUSTOM_CAN_FALL,
3482     &custom_element_properties[EP_CAN_SMASH],
3483     NULL, " ",
3484     NULL,                               "element can smash other elements"
3485   },
3486   {
3487     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3488     GADGET_ID_CUSTOM_SLIPPERY,          GADGET_ID_NONE,
3489     &custom_element_properties[EP_SLIPPERY],
3490     NULL, NULL,
3491     NULL,                               "other elements can fall down from it"
3492   },
3493   {
3494     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
3495     GADGET_ID_CUSTOM_DEADLY,            GADGET_ID_NONE,
3496     &custom_element_properties[EP_DEADLY],
3497     NULL, NULL,
3498     NULL,                               "element can kill the player"
3499   },
3500   {
3501     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
3502     GADGET_ID_CUSTOM_CAN_EXPLODE,       GADGET_ID_NONE,
3503     &custom_element_properties[EP_CAN_EXPLODE],
3504     NULL, NULL,
3505     NULL,                               "element can explode"
3506   },
3507   {
3508     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(12),
3509     GADGET_ID_CUSTOM_EXPLODE_FIRE,      GADGET_ID_NONE,
3510     &custom_element_properties[EP_EXPLODES_BY_FIRE],
3511     NULL, NULL,
3512     "by fire",                          "element can explode by fire/explosion"
3513   },
3514   {
3515     -1,                                 ED_ELEMENT_SETTINGS_YPOS(12),
3516     GADGET_ID_CUSTOM_EXPLODE_SMASH,     GADGET_ID_CUSTOM_EXPLODE_FIRE,
3517     &custom_element_properties[EP_EXPLODES_SMASHED],
3518     NULL, " ",
3519     "smashed",                          "element can explode when smashed"
3520   },
3521   {
3522     -1,                                 ED_ELEMENT_SETTINGS_YPOS(12),
3523     GADGET_ID_CUSTOM_EXPLODE_IMPACT,    GADGET_ID_CUSTOM_EXPLODE_SMASH,
3524     &custom_element_properties[EP_EXPLODES_IMPACT],
3525     NULL, " ",
3526     "impact",                           "element can explode on impact"
3527   },
3528
3529   // ---------- element settings: advanced (custom elements) ------------------
3530
3531   {
3532     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3533     GADGET_ID_CUSTOM_CAN_CHANGE,        GADGET_ID_NONE,
3534     &custom_element_change.can_change,
3535     NULL, NULL,
3536     "element changes to:",              "change element on specified condition"
3537   },
3538   {
3539     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
3540     GADGET_ID_CHANGE_DELAY,             GADGET_ID_NONE,
3541     &custom_element_change_events[CE_DELAY],
3542     NULL, NULL,
3543     NULL,                               "element changes after delay"
3544   },
3545   {
3546     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
3547     GADGET_ID_CHANGE_BY_DIRECT_ACT,     GADGET_ID_NONE,
3548     &custom_element_change_events[CE_BY_DIRECT_ACTION],
3549     NULL, NULL,
3550     NULL,                               "element changes by direct action"
3551   },
3552   {
3553     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
3554     GADGET_ID_CHANGE_BY_OTHER_ACT,      GADGET_ID_NONE,
3555     &custom_element_change_events[CE_BY_OTHER_ACTION],
3556     NULL, NULL,
3557     NULL,                               "element changes by other element"
3558   },
3559   {
3560     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
3561     GADGET_ID_CHANGE_USE_EXPLOSION,     GADGET_ID_NONE,
3562     &custom_element_change.explode,
3563     NULL, NULL,
3564     "explode instead of change",        "element explodes instead of change"
3565   },
3566   {
3567     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
3568     GADGET_ID_CHANGE_USE_CONTENT,       GADGET_ID_NONE,
3569     &custom_element_change.use_target_content,
3570     NULL, NULL,
3571     "use extended change target:",      "element changes to more elements"
3572   },
3573   {
3574     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(11),
3575     GADGET_ID_CHANGE_ONLY_COMPLETE,     GADGET_ID_NONE,
3576     &custom_element_change.only_if_complete,
3577     NULL, NULL,
3578     "replace all or nothing",           "only replace when all can be changed"
3579   },
3580   {
3581     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(12),
3582     GADGET_ID_CHANGE_USE_RANDOM,        GADGET_ID_NONE,
3583     &custom_element_change.use_random_replace,
3584     NULL, NULL,
3585     NULL,                               "use percentage for random replace"
3586   },
3587   {
3588     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
3589     GADGET_ID_CHANGE_HAS_ACTION,        GADGET_ID_NONE,
3590     &custom_element_change.has_action,
3591     NULL, NULL,
3592     NULL,                               "execute action on specified condition"
3593   },
3594 };
3595
3596 static struct
3597 {
3598   int x, y;
3599   int xoffset, yoffset;
3600   int gadget_id;
3601   int gadget_id_align;
3602   int *value;
3603   int area_xsize, area_ysize;
3604   char *text_left, *text_right, *text_above, *text_below, *infotext;
3605 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
3606 {
3607   // ---------- level playfield content ---------------------------------------
3608
3609   {
3610     0,                                  0,
3611     0,                                  0,
3612     GADGET_ID_DRAWING_LEVEL,            GADGET_ID_NONE,
3613     NULL,
3614     -1, -1,     // these values are not constant, but can change at runtime
3615     NULL, NULL, NULL, NULL,             NULL
3616   },
3617
3618   // ---------- yam yam content -----------------------------------------------
3619
3620   {
3621     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3622     ED_AREA_YAMYAM_CONTENT_XOFF(0),     ED_AREA_YAMYAM_CONTENT_YOFF(0),
3623     GADGET_ID_YAMYAM_CONTENT_0,         GADGET_ID_NONE,
3624     &level.yamyam_content[0].e[0][0],   3, 3,
3625     NULL, NULL, NULL, "1",              NULL
3626   },
3627   {
3628     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3629     ED_AREA_YAMYAM_CONTENT_XOFF(1),     ED_AREA_YAMYAM_CONTENT_YOFF(1),
3630     GADGET_ID_YAMYAM_CONTENT_1,         GADGET_ID_NONE,
3631     &level.yamyam_content[1].e[0][0],   3, 3,
3632     NULL, NULL, NULL, "2",              NULL
3633   },
3634   {
3635     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3636     ED_AREA_YAMYAM_CONTENT_XOFF(2),     ED_AREA_YAMYAM_CONTENT_YOFF(2),
3637     GADGET_ID_YAMYAM_CONTENT_2,         GADGET_ID_NONE,
3638     &level.yamyam_content[2].e[0][0],   3, 3,
3639     NULL, NULL, NULL, "3",              NULL
3640   },
3641   {
3642     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3643     ED_AREA_YAMYAM_CONTENT_XOFF(3),     ED_AREA_YAMYAM_CONTENT_YOFF(3),
3644     GADGET_ID_YAMYAM_CONTENT_3,         GADGET_ID_NONE,
3645     &level.yamyam_content[3].e[0][0],   3, 3,
3646     NULL, NULL, NULL, "4",              NULL
3647   },
3648   {
3649     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3650     ED_AREA_YAMYAM_CONTENT_XOFF(4),     ED_AREA_YAMYAM_CONTENT_YOFF(4),
3651     GADGET_ID_YAMYAM_CONTENT_4,         GADGET_ID_NONE,
3652     &level.yamyam_content[4].e[0][0],   3, 3,
3653     NULL, NULL, NULL, "5",              NULL
3654   },
3655   {
3656     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3657     ED_AREA_YAMYAM_CONTENT_XOFF(5),     ED_AREA_YAMYAM_CONTENT_YOFF(5),
3658     GADGET_ID_YAMYAM_CONTENT_5,         GADGET_ID_NONE,
3659     &level.yamyam_content[5].e[0][0],   3, 3,
3660     NULL, NULL, NULL, "6",              NULL
3661   },
3662   {
3663     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3664     ED_AREA_YAMYAM_CONTENT_XOFF(6),     ED_AREA_YAMYAM_CONTENT_YOFF(6),
3665     GADGET_ID_YAMYAM_CONTENT_6,         GADGET_ID_NONE,
3666     &level.yamyam_content[6].e[0][0],   3, 3,
3667     NULL, NULL, NULL, "7",              NULL
3668   },
3669   {
3670     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3671     ED_AREA_YAMYAM_CONTENT_XOFF(7),     ED_AREA_YAMYAM_CONTENT_YOFF(7),
3672     GADGET_ID_YAMYAM_CONTENT_7,         GADGET_ID_NONE,
3673     &level.yamyam_content[7].e[0][0],   3, 3,
3674     NULL, NULL, NULL, "8",              NULL
3675   },
3676
3677   // ---------- magic ball content --------------------------------------------
3678
3679   {
3680     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3681     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0), ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
3682     GADGET_ID_MAGIC_BALL_CONTENT_0,     GADGET_ID_NONE,
3683     &level.ball_content[0].e[0][0],     3, 3,
3684     NULL, NULL, NULL, "1",              NULL
3685   },
3686   {
3687     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3688     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1), ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
3689     GADGET_ID_MAGIC_BALL_CONTENT_1,     GADGET_ID_NONE,
3690     &level.ball_content[1].e[0][0],     3, 3,
3691     NULL, NULL, NULL, "2",              NULL
3692   },
3693   {
3694     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3695     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2), ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
3696     GADGET_ID_MAGIC_BALL_CONTENT_2,     GADGET_ID_NONE,
3697     &level.ball_content[2].e[0][0],     3, 3,
3698     NULL, NULL, NULL, "3",              NULL
3699   },
3700   {
3701     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3702     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3), ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
3703     GADGET_ID_MAGIC_BALL_CONTENT_3,     GADGET_ID_NONE,
3704     &level.ball_content[3].e[0][0],     3, 3,
3705     NULL, NULL, NULL, "4",              NULL
3706   },
3707   {
3708     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3709     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4), ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
3710     GADGET_ID_MAGIC_BALL_CONTENT_4,     GADGET_ID_NONE,
3711     &level.ball_content[4].e[0][0],     3, 3,
3712     NULL, NULL, NULL, "5",              NULL
3713   },
3714   {
3715     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3716     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5), ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
3717     GADGET_ID_MAGIC_BALL_CONTENT_5,     GADGET_ID_NONE,
3718     &level.ball_content[5].e[0][0],     3, 3,
3719     NULL, NULL, NULL, "6",              NULL
3720   },
3721   {
3722     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3723     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6), ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
3724     GADGET_ID_MAGIC_BALL_CONTENT_6,     GADGET_ID_NONE,
3725     &level.ball_content[6].e[0][0],     3, 3,
3726     NULL, NULL, NULL, "7",              NULL
3727   },
3728   {
3729     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3730     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7), ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
3731     GADGET_ID_MAGIC_BALL_CONTENT_7,     GADGET_ID_NONE,
3732     &level.ball_content[7].e[0][0],     3, 3,
3733     NULL, NULL, NULL, "8",              NULL
3734   },
3735
3736   // ---------- android content -----------------------------------------------
3737
3738   {
3739     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(6),
3740     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3741     GADGET_ID_ANDROID_CONTENT,          GADGET_ID_NONE,
3742     &level.android_clone_element[0],    MAX_ANDROID_ELEMENTS, 1,
3743     NULL, NULL, "elements:", NULL,      "elements android can clone"
3744   },
3745
3746   // ---------- amoeba content ------------------------------------------------
3747
3748   {
3749     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(3),
3750     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3751     GADGET_ID_AMOEBA_CONTENT,           GADGET_ID_NONE,
3752     &level.amoeba_content,              1, 1,
3753     "content:", NULL, NULL, NULL,       "amoeba content"
3754   },
3755
3756   // ---------- level start element -------------------------------------------
3757
3758   {
3759     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(10),
3760     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3761     GADGET_ID_START_ELEMENT,            GADGET_ID_USE_START_ELEMENT,
3762     &level.start_element[0],            1, 1,
3763     NULL, NULL, NULL, NULL,             "level start element"
3764   },
3765
3766   // ---------- player artwork element ----------------------------------------
3767
3768   {
3769     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(11),
3770     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3771     GADGET_ID_ARTWORK_ELEMENT,          GADGET_ID_USE_ARTWORK_ELEMENT,
3772     &level.artwork_element[0],          1, 1,
3773     NULL, NULL, NULL, NULL,             "element for player artwork"
3774   },
3775
3776   // ---------- player explosion element --------------------------------------
3777
3778   {
3779     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(12),
3780     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3781     GADGET_ID_EXPLOSION_ELEMENT,        GADGET_ID_USE_EXPLOSION_ELEMENT,
3782     &level.explosion_element[0],        1, 1,
3783     NULL, NULL, NULL, NULL,             "element for player explosion"
3784   },
3785
3786   // ---------- player initial inventory --------------------------------------
3787
3788   {
3789     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3790     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3791     GADGET_ID_INVENTORY_CONTENT,        GADGET_ID_USE_INITIAL_INVENTORY,
3792     &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
3793     NULL, NULL, NULL, NULL,             "content for initial inventory"
3794   },
3795
3796   // ---------- gray ball content -----------------------------------------
3797
3798   {
3799     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
3800     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3801     GADGET_ID_MM_BALL_CONTENT,          GADGET_ID_NONE,
3802     &level.mm_ball_content[0],          MAX_MM_BALL_CONTENTS, 1,
3803     "content:", NULL, NULL, NULL,       "content for gray ball"
3804   },
3805
3806   // ---------- element settings: configure 1 (custom elements) ---------------
3807
3808   // ---------- custom graphic ------------------------------------------------
3809
3810   {
3811     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3812     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3813     GADGET_ID_CUSTOM_GRAPHIC,           GADGET_ID_CUSTOM_USE_GRAPHIC,
3814     &custom_element.gfx_element_initial, 1, 1,
3815     NULL, NULL, NULL, NULL,             "custom graphic element"
3816   },
3817
3818   // ---------- element settings: configure 2 (custom elements) ---------------
3819
3820   // ---------- custom content (when exploding) -------------------------------
3821
3822   {
3823     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(11),
3824     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
3825     GADGET_ID_CUSTOM_CONTENT,           GADGET_ID_NONE, // align three rows
3826     &custom_element.content.e[0][0],    3, 3,
3827     "content:", NULL, NULL, NULL,       NULL
3828   },
3829
3830   // ---------- custom enter and leave element (when moving) ------------------
3831
3832   {
3833     ED_AREA_1X1_SETTINGS_XPOS(1),       ED_AREA_1X1_SETTINGS_YPOS(3),
3834     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3835     GADGET_ID_CUSTOM_MOVE_ENTER,        GADGET_ID_NONE,
3836     &custom_element.move_enter_element, 1, 1,
3837     "can dig:", " ", NULL, NULL,        "element that can be digged/collected"
3838   },
3839   {
3840     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(3),
3841     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3842     GADGET_ID_CUSTOM_MOVE_LEAVE,        GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
3843     &custom_element.move_leave_element, 1, 1,
3844     NULL, NULL, NULL, NULL,             "element that will be left behind"
3845   },
3846
3847   // ---------- element settings: advanced (custom elements) ------------------
3848
3849   // ---------- custom change target ------------------------------------------
3850
3851   {
3852     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3853     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3854     GADGET_ID_CUSTOM_CHANGE_TARGET,     GADGET_ID_CUSTOM_CAN_CHANGE,
3855     &custom_element_change.target_element, 1, 1,
3856     NULL, "after/when:", NULL, NULL,    "new target element after change"
3857   },
3858
3859   // ---------- custom change content (extended change target) ----------------
3860
3861   {
3862     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(9),
3863     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
3864     GADGET_ID_CUSTOM_CHANGE_CONTENT,    GADGET_ID_NONE, // align three rows
3865     &custom_element_change.target_content.e[0][0], 3, 3,
3866     NULL, NULL, NULL, NULL,             "new extended elements after change"
3867   },
3868
3869   // ---------- custom change trigger (element causing change) ----------------
3870
3871   {
3872     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(5),
3873     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3874     GADGET_ID_CUSTOM_CHANGE_TRIGGER,    GADGET_ID_CHANGE_OTHER_ACTION,
3875     &custom_element_change.initial_trigger_element, 1, 1,
3876     NULL, NULL, NULL, NULL,             "other element triggering change"
3877   },
3878
3879   // ---------- custom change action (element used for action) ----------------
3880
3881   {
3882     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(13),
3883     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3884     GADGET_ID_CUSTOM_CHANGE_ACTION,     GADGET_ID_ACTION_ARG,
3885     &custom_element_change.action_element, 1, 1,
3886     NULL, NULL, NULL, NULL,             "element used as action parameter"
3887   },
3888
3889   // ---------- group element content -----------------------------------------
3890
3891   {
3892     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
3893     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3894     GADGET_ID_GROUP_CONTENT,            GADGET_ID_NONE,
3895     &group_element_info.element[0],     MAX_ELEMENTS_IN_GROUP, 1,
3896     "content:", NULL, NULL, NULL,       NULL
3897   },
3898
3899   // ---------- random background (for random painting) -----------------------
3900
3901   {
3902     -1,                                 ED_AREA_1X1_LSETTINGS_YPOS(1),
3903     0,                                  ED_AREA_1X1_LSETTINGS_YOFF,
3904     GADGET_ID_RANDOM_BACKGROUND,        GADGET_ID_RANDOM_RESTRICTED,
3905     &random_placement_background_element, 1, 1,
3906     NULL, NULL, NULL, NULL,             "random placement background"
3907   },
3908 };
3909
3910
3911 // ----------------------------------------------------------------------------
3912 // some internally used variables
3913 // ----------------------------------------------------------------------------
3914
3915 // maximal size of level editor drawing area
3916 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
3917
3918 // actual size of level editor drawing area
3919 static int ed_fieldx, ed_fieldy;
3920
3921 // actual position of level editor drawing area in level playfield
3922 static int level_xpos = -1, level_ypos = -1;
3923
3924 // actual tile size used to display playfield drawing area
3925 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
3926 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
3927
3928 #define IN_ED_FIELD(x, y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
3929
3930 // drawing elements on the three mouse buttons
3931 static int new_element1 = EL_WALL;
3932 static int new_element2 = EL_EMPTY;
3933 static int new_element3 = EL_SAND;
3934
3935 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
3936 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
3937                                 (button) == 2 ? new_element2 : \
3938                                 (button) == 3 ? new_element3 : EL_EMPTY)
3939
3940 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
3941
3942 static int use_permanent_palette = TRUE;
3943
3944 #define PX              (use_permanent_palette ? DX : SX)
3945 #define PY              (use_permanent_palette ? DY : SY)
3946 #define PXSIZE          (use_permanent_palette ? DXSIZE : SXSIZE)
3947 #define PYSIZE          (use_permanent_palette ? DYSIZE : SYSIZE)
3948
3949 // forward declaration for internal use
3950 static void CopyBrushToCursor(int, int);
3951 static void DeleteBrushFromCursor(void);
3952 static void ModifyEditorCounterValue(int, int);
3953 static void ModifyEditorCounterLimits(int, int, int);
3954 static void ModifyEditorSelectboxValue(int, int);
3955 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
3956 static void ModifyEditorDrawingArea(int, int, int);
3957 static void ModifyEditorElementList(void);
3958 static void AdjustElementListScrollbar(void);
3959 static void RedrawDrawingElements(void);
3960 static void DrawDrawingWindowExt(boolean);
3961 static void DrawDrawingWindow(void);
3962 static void DrawLevelConfigWindow(void);
3963 static void DrawPropertiesWindow(void);
3964 static void DrawPaletteWindow(void);
3965 static void UpdateCustomElementGraphicGadgets(void);
3966 static boolean checkPropertiesConfig(int);
3967 static void SetAutomaticNumberOfGemsNeeded(void);
3968 static void ClearEditorGadgetInfoText(void);
3969 static void CopyLevelToUndoBuffer(int);
3970 static void HandleDrawingAreas(struct GadgetInfo *);
3971 static void HandleCounterButtons(struct GadgetInfo *);
3972 static void HandleTextInputGadgets(struct GadgetInfo *);
3973 static void HandleTextAreaGadgets(struct GadgetInfo *);
3974 static void HandleSelectboxGadgets(struct GadgetInfo *);
3975 static void HandleTextbuttonGadgets(struct GadgetInfo *);
3976 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
3977 static void HandleRadiobuttons(struct GadgetInfo *);
3978 static void HandleCheckbuttons(struct GadgetInfo *);
3979 static void HandleControlButtons(struct GadgetInfo *);
3980 static void HandleDrawingAreaInfo(struct GadgetInfo *);
3981 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
3982 static boolean AskToCopyAndModifyLevelTemplate(void);
3983 static boolean getDrawModeHiRes(void);
3984 static int getTabulatorBarWidth(void);
3985 static int getTabulatorBarHeight(void);
3986 static Pixel getTabulatorBarColor(void);
3987 static int numHiresTiles(int);
3988
3989 static int num_editor_gadgets = 0;      // dynamically determined
3990
3991 static struct GadgetInfo **level_editor_gadget = NULL;
3992 static int *right_gadget_border = NULL;
3993
3994 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
3995 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
3996 static boolean draw_with_brush = FALSE;
3997 static int properties_element = 0;
3998
3999 static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4000 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4001 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
4002 static int undo_buffer_position = 0;
4003 static int undo_buffer_steps = 0;
4004 static int redo_buffer_steps = 0;
4005
4006 static int edit_mode;
4007 static int edit_mode_levelconfig;
4008 static int edit_mode_properties;
4009
4010 static int element_shift = 0;
4011
4012 static int editor_el_players[] =
4013 {
4014   EL_PLAYER_1,
4015   EL_PLAYER_2,
4016   EL_PLAYER_3,
4017   EL_PLAYER_4
4018 };
4019 static int *editor_el_players_ptr = editor_el_players;
4020 static int num_editor_el_players = ARRAY_SIZE(editor_el_players);
4021
4022 static int editor_hl_boulderdash[] =
4023 {
4024   EL_INTERNAL_CASCADE_BD_ACTIVE,
4025   EL_CHAR('B'),
4026   EL_CHAR('D'),
4027   EL_EMPTY,
4028 };
4029
4030 static int editor_el_boulderdash[] =
4031 {
4032   EL_EMPTY,
4033   EL_SAND,
4034   EL_BD_ROCK,
4035   EL_BD_DIAMOND,
4036
4037   EL_STEELWALL,
4038   EL_BD_WALL,
4039   EL_BD_EXPANDABLE_WALL,
4040   EL_BD_MAGIC_WALL,
4041
4042   EL_BD_AMOEBA,
4043   EL_BD_BUTTERFLY_UP,
4044   EL_BD_FIREFLY_UP,
4045   EL_EXIT_CLOSED,
4046
4047   EL_BD_BUTTERFLY_LEFT,
4048   EL_BD_FIREFLY_LEFT,
4049   EL_BD_BUTTERFLY_RIGHT,
4050   EL_BD_FIREFLY_RIGHT,
4051
4052   EL_EMPTY,
4053   EL_BD_BUTTERFLY_DOWN,
4054   EL_BD_FIREFLY_DOWN,
4055   EL_EXIT_OPEN,
4056 };
4057 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
4058 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
4059 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
4060 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
4061
4062 static int editor_hl_boulderdash_native[] =
4063 {
4064   EL_INTERNAL_CASCADE_BD_NATIVE_ACTIVE,
4065   EL_CHAR('B'),
4066   EL_CHAR('D'),
4067   EL_EMPTY,
4068 };
4069
4070 static int editor_el_boulderdash_native[] =
4071 {
4072   EL_EMPTY,
4073   EL_BD_SAND,
4074   EL_BD_ROCK,
4075   EL_BD_DIAMOND,
4076
4077   EL_BD_STEELWALL,
4078   EL_BD_WALL,
4079   EL_EMPTY,
4080   EL_BD_MAGIC_WALL,
4081
4082   EL_BD_AMOEBA,
4083   EL_BD_BUTTERFLY_UP,
4084   EL_BD_FIREFLY_UP,
4085   EL_EXIT_CLOSED,
4086
4087   EL_BD_BUTTERFLY_LEFT,
4088   EL_BD_FIREFLY_LEFT,
4089   EL_BD_BUTTERFLY_RIGHT,
4090   EL_BD_FIREFLY_RIGHT,
4091
4092   EL_BD_INBOX,
4093   EL_BD_BUTTERFLY_DOWN,
4094   EL_BD_FIREFLY_DOWN,
4095   EL_EXIT_OPEN,
4096
4097   EL_BD_AMOEBA_2,
4098   EL_BD_BUTTERFLY_2_UP,
4099   EL_BD_FIREFLY_2_UP,
4100   EL_EMPTY,
4101
4102   EL_BD_BUTTERFLY_2_LEFT,
4103   EL_BD_FIREFLY_2_LEFT,
4104   EL_BD_BUTTERFLY_2_RIGHT,
4105   EL_BD_FIREFLY_2_RIGHT,
4106
4107   EL_EMPTY,
4108   EL_BD_BUTTERFLY_2_DOWN,
4109   EL_BD_FIREFLY_2_DOWN,
4110   EL_EMPTY,
4111
4112   EL_EMPTY,
4113   EL_BD_DRAGONFLY_UP,
4114   EL_BD_STONEFLY_UP,
4115   EL_EMPTY,
4116
4117   EL_BD_DRAGONFLY_LEFT,
4118   EL_BD_STONEFLY_LEFT,
4119   EL_BD_DRAGONFLY_RIGHT,
4120   EL_BD_STONEFLY_RIGHT,
4121
4122   EL_EMPTY,
4123   EL_BD_DRAGONFLY_DOWN,
4124   EL_BD_STONEFLY_DOWN,
4125   EL_EMPTY,
4126
4127   EL_EMPTY,
4128   EL_BD_BITER_UP,
4129   EL_BD_COW_UP,
4130   EL_EMPTY,
4131
4132   EL_BD_BITER_LEFT,
4133   EL_BD_COW_LEFT,
4134   EL_BD_BITER_RIGHT,
4135   EL_BD_COW_RIGHT,
4136
4137   EL_EMPTY,
4138   EL_BD_BITER_DOWN,
4139   EL_BD_COW_DOWN,
4140   EL_EMPTY,
4141
4142   EL_EMPTY,
4143   EL_BD_SAND,
4144   EL_BD_SAND_BALL,
4145   EL_BD_SAND_LOOSE,
4146
4147   EL_BD_SAND_SLOPED_UP_LEFT,
4148   EL_BD_SAND_SLOPED_UP_RIGHT,
4149   EL_BD_WALL_SLOPED_UP_LEFT,
4150   EL_BD_WALL_SLOPED_UP_RIGHT,
4151
4152   EL_BD_SAND_SLOPED_DOWN_LEFT,
4153   EL_BD_SAND_SLOPED_DOWN_RIGHT,
4154   EL_BD_WALL_SLOPED_DOWN_LEFT,
4155   EL_BD_WALL_SLOPED_DOWN_RIGHT,
4156
4157   EL_BD_FLYING_DIAMOND,
4158   EL_BD_FLYING_ROCK,
4159   EL_BD_STEELWALL_SLOPED_UP_LEFT,
4160   EL_BD_STEELWALL_SLOPED_UP_RIGHT,
4161
4162   EL_BD_NUT,
4163   EL_BD_MEGA_ROCK,
4164   EL_BD_STEELWALL_SLOPED_DOWN_LEFT,
4165   EL_BD_STEELWALL_SLOPED_DOWN_RIGHT,
4166
4167   EL_BD_SAND_2,
4168   EL_BD_WALL_NON_SLOPED,
4169   EL_BD_WALL,
4170   EL_BD_MAGIC_WALL,
4171
4172   EL_BD_EXIT_CLOSED,
4173   EL_BD_EXIT_OPEN,
4174   EL_BD_INVISIBLE_EXIT_CLOSED,
4175   EL_BD_INVISIBLE_EXIT_OPEN,
4176
4177   EL_BD_STEELWALL,
4178   EL_BD_STEELWALL_EXPLODABLE,
4179   EL_BD_STEELWALL_DIGGABLE,
4180   EL_BD_WALL_DIGGABLE,
4181
4182   EL_BD_EXPANDABLE_WALL_HORIZONTAL,
4183   EL_BD_EXPANDABLE_WALL_VERTICAL,
4184   EL_BD_EXPANDABLE_WALL_ANY,
4185   EL_BD_CREATURE_SWITCH,
4186
4187   EL_BD_EXPANDABLE_STEELWALL_HORIZONTAL,
4188   EL_BD_EXPANDABLE_STEELWALL_VERTICAL,
4189   EL_BD_EXPANDABLE_STEELWALL_ANY,
4190   EL_BD_EXPANDABLE_WALL_SWITCH_HORIZONTAL,
4191
4192   EL_BD_BITER_SWITCH_1,
4193   EL_BD_REPLICATOR_SWITCH,
4194   EL_BD_CONVEYOR_SWITCH,
4195   EL_BD_CONVEYOR_DIR_SWITCH_RIGHT,
4196
4197   EL_BD_ACID,
4198   EL_BD_FALLING_WALL,
4199   EL_BD_BOX,
4200   EL_BD_TIME_PENALTY,
4201
4202   EL_BD_GRAVESTONE,
4203   EL_BD_ROCK_GLUED,
4204   EL_BD_DIAMOND_GLUED,
4205   EL_BD_DIAMOND_KEY,
4206
4207   EL_BD_TRAPPED_DIAMOND,
4208   EL_BD_CLOCK,
4209   EL_BD_SAND_GLUED,
4210   EL_BD_WATER,
4211
4212   EL_BD_KEY_1,
4213   EL_BD_KEY_2,
4214   EL_BD_KEY_3,
4215   EL_EMPTY,
4216
4217   EL_BD_WALL_KEY_1,
4218   EL_BD_WALL_KEY_2,
4219   EL_BD_WALL_KEY_3,
4220   EL_BD_WALL_DIAMOND,
4221
4222   EL_BD_GATE_1,
4223   EL_BD_GATE_2,
4224   EL_BD_GATE_3,
4225   EL_BD_POT,
4226
4227   EL_BD_GRAVITY_SWITCH,
4228   EL_BD_PNEUMATIC_HAMMER,
4229   EL_BD_TELEPORTER,
4230   EL_BD_SKELETON,
4231
4232   EL_BD_AMOEBA,
4233   EL_BD_AMOEBA_2,
4234   EL_BD_REPLICATOR,
4235   EL_BD_BLADDER_SPENDER,
4236
4237   EL_BD_CONVEYOR_LEFT,
4238   EL_BD_CONVEYOR_RIGHT,
4239   EL_BD_BOMB,
4240   EL_BD_NITRO_PACK,
4241
4242   EL_BD_LAVA,
4243   EL_BD_SWEET,
4244   EL_BD_VOODOO_DOLL,
4245   EL_BD_SLIME,
4246
4247   EL_BD_BLADDER,
4248   EL_BD_WAITING_ROCK,
4249   EL_BD_CHASING_ROCK,
4250   EL_BD_GHOST,
4251
4252   EL_BD_PLAYER,
4253   EL_BD_PLAYER_WITH_BOMB,
4254   EL_BD_PLAYER_GLUED,
4255   EL_BD_PLAYER_STIRRING,
4256 };
4257 static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
4258 static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
4259 static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
4260 static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
4261
4262 static int editor_hl_emerald_mine[] =
4263 {
4264   EL_INTERNAL_CASCADE_EM_ACTIVE,
4265   EL_CHAR('E'),
4266   EL_CHAR('M'),
4267   EL_EMPTY,
4268 };
4269
4270 static int editor_el_emerald_mine[] =
4271 {
4272   EL_SAND,
4273   EL_ROCK,
4274   EL_QUICKSAND_EMPTY,
4275   EL_QUICKSAND_FULL,
4276
4277   EL_STEELWALL,
4278   EL_WALL,
4279   EL_WALL_SLIPPERY,
4280   EL_MAGIC_WALL,
4281
4282   EL_EMERALD,
4283   EL_DIAMOND,
4284   EL_NUT,
4285   EL_BOMB,
4286
4287   EL_EM_DYNAMITE,
4288   EL_EM_DYNAMITE_ACTIVE,
4289   EL_EM_EXIT_CLOSED,
4290   EL_EM_EXIT_OPEN,
4291
4292   EL_YAMYAM_UP,
4293   EL_BUG_UP,
4294   EL_SPACESHIP_UP,
4295   EL_ROBOT,
4296
4297   EL_BUG_LEFT,
4298   EL_SPACESHIP_LEFT,
4299   EL_BUG_RIGHT,
4300   EL_SPACESHIP_RIGHT,
4301
4302   EL_ROBOT_WHEEL,
4303   EL_BUG_DOWN,
4304   EL_SPACESHIP_DOWN,
4305   EL_INVISIBLE_WALL,
4306
4307   EL_ACID_POOL_TOPLEFT,
4308   EL_ACID,
4309   EL_ACID_POOL_TOPRIGHT,
4310   EL_AMOEBA_DROP,
4311
4312   EL_ACID_POOL_BOTTOMLEFT,
4313   EL_ACID_POOL_BOTTOM,
4314   EL_ACID_POOL_BOTTOMRIGHT,
4315   EL_AMOEBA_WET,
4316
4317   EL_EM_KEY_1,
4318   EL_EM_KEY_2,
4319   EL_EM_KEY_3,
4320   EL_EM_KEY_4,
4321
4322   EL_EM_GATE_1,
4323   EL_EM_GATE_2,
4324   EL_EM_GATE_3,
4325   EL_EM_GATE_4,
4326
4327   EL_EM_GATE_1_GRAY,
4328   EL_EM_GATE_2_GRAY,
4329   EL_EM_GATE_3_GRAY,
4330   EL_EM_GATE_4_GRAY,
4331 };
4332 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
4333 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
4334 static int num_editor_hl_emerald_mine = ARRAY_SIZE(editor_hl_emerald_mine);
4335 static int num_editor_el_emerald_mine = ARRAY_SIZE(editor_el_emerald_mine);
4336
4337 static int editor_hl_emerald_mine_club[] =
4338 {
4339   EL_INTERNAL_CASCADE_EMC_ACTIVE,
4340   EL_CHAR('E'),
4341   EL_CHAR('M'),
4342   EL_CHAR('C'),
4343 };
4344
4345 static int editor_el_emerald_mine_club[] =
4346 {
4347   EL_EMC_KEY_5,
4348   EL_EMC_KEY_6,
4349   EL_EMC_KEY_7,
4350   EL_EMC_KEY_8,
4351
4352   EL_EMC_GATE_5,
4353   EL_EMC_GATE_6,
4354   EL_EMC_GATE_7,
4355   EL_EMC_GATE_8,
4356
4357   EL_EMC_GATE_5_GRAY,
4358   EL_EMC_GATE_6_GRAY,
4359   EL_EMC_GATE_7_GRAY,
4360   EL_EMC_GATE_8_GRAY,
4361
4362   EL_EMC_STEELWALL_1,
4363   EL_EMC_STEELWALL_2,
4364   EL_EMC_STEELWALL_3,
4365   EL_EMC_STEELWALL_4,
4366
4367   EL_EMC_WALL_13,
4368   EL_EMC_WALL_14,
4369   EL_EMC_WALL_15,
4370   EL_EMC_WALL_16,
4371
4372   EL_EMC_WALL_SLIPPERY_1,
4373   EL_EMC_WALL_SLIPPERY_2,
4374   EL_EMC_WALL_SLIPPERY_3,
4375   EL_EMC_WALL_SLIPPERY_4,
4376
4377   EL_EMC_WALL_1,
4378   EL_EMC_WALL_2,
4379   EL_EMC_WALL_3,
4380   EL_EMC_WALL_4,
4381
4382   EL_EMC_WALL_5,
4383   EL_EMC_WALL_6,
4384   EL_EMC_WALL_7,
4385   EL_EMC_WALL_8,
4386
4387   EL_EMC_WALL_9,
4388   EL_EMC_WALL_10,
4389   EL_EMC_WALL_11,
4390   EL_EMC_WALL_12,
4391
4392   EL_EMC_GRASS,
4393   EL_EMC_FAKE_GRASS,
4394   EL_EMC_PLANT,
4395   EL_EMC_DRIPPER,
4396
4397   EL_EMC_MAGIC_BALL,
4398   EL_EMC_MAGIC_BALL_SWITCH,
4399   EL_EMC_LENSES,
4400   EL_EMC_MAGNIFIER,
4401
4402   EL_SPRING_LEFT,
4403   EL_SPRING,
4404   EL_SPRING_RIGHT,
4405   EL_EMC_SPRING_BUMPER,
4406
4407   EL_BALLOON,
4408   EL_YAMYAM_UP,
4409   EL_BALLOON_SWITCH_UP,
4410   EL_BALLOON_SWITCH_ANY,
4411
4412   EL_YAMYAM_LEFT,
4413   EL_BALLOON_SWITCH_LEFT,
4414   EL_YAMYAM_RIGHT,
4415   EL_BALLOON_SWITCH_RIGHT,
4416
4417   EL_EMC_ANDROID,
4418   EL_YAMYAM_DOWN,
4419   EL_BALLOON_SWITCH_DOWN,
4420   EL_BALLOON_SWITCH_NONE,
4421 };
4422 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
4423 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
4424 static int num_editor_hl_emerald_mine_club = ARRAY_SIZE(editor_hl_emerald_mine_club);
4425 static int num_editor_el_emerald_mine_club = ARRAY_SIZE(editor_el_emerald_mine_club);
4426
4427 static int editor_hl_rnd[] =
4428 {
4429   EL_INTERNAL_CASCADE_RND_ACTIVE,
4430   EL_CHAR('R'),
4431   EL_CHAR('N'),
4432   EL_CHAR('D'),
4433 };
4434
4435 static int editor_el_rnd[] =
4436 {
4437   EL_DYNAMITE,                  // RND
4438   EL_DYNAMITE_ACTIVE,           // RND
4439   EL_EMPTY,
4440   EL_EMPTY,
4441
4442   EL_KEY_1,
4443   EL_KEY_2,
4444   EL_KEY_3,
4445   EL_KEY_4,
4446
4447   EL_GATE_1,
4448   EL_GATE_2,
4449   EL_GATE_3,
4450   EL_GATE_4,
4451
4452   EL_GATE_1_GRAY,
4453   EL_GATE_2_GRAY,
4454   EL_GATE_3_GRAY,
4455   EL_GATE_4_GRAY,
4456
4457   EL_ARROW_LEFT,
4458   EL_ARROW_RIGHT,
4459   EL_ARROW_UP,
4460   EL_ARROW_DOWN,
4461
4462   EL_AMOEBA_DEAD,
4463   EL_AMOEBA_DRY,
4464   EL_AMOEBA_FULL,
4465   EL_GAME_OF_LIFE,
4466
4467   EL_EMERALD_YELLOW,
4468   EL_EMERALD_RED,
4469   EL_EMERALD_PURPLE,
4470   EL_BIOMAZE,
4471
4472   EL_WALL_EMERALD_YELLOW,
4473   EL_WALL_EMERALD_RED,
4474   EL_WALL_EMERALD_PURPLE,
4475   EL_WALL_BD_DIAMOND,
4476
4477   EL_SPEED_PILL,
4478   EL_PACMAN_UP,
4479   EL_TIME_ORB_FULL,
4480   EL_TIME_ORB_EMPTY,
4481
4482   EL_PACMAN_LEFT,
4483   EL_DARK_YAMYAM,
4484   EL_PACMAN_RIGHT,
4485   EL_YAMYAM,                    // RND
4486
4487   EL_BLACK_ORB,
4488   EL_PACMAN_DOWN,
4489   EL_LAMP,
4490   EL_LAMP_ACTIVE,
4491
4492   EL_DYNABOMB_INCREASE_NUMBER,
4493   EL_DYNABOMB_INCREASE_SIZE,
4494   EL_DYNABOMB_INCREASE_POWER,
4495   EL_STONEBLOCK,
4496
4497   EL_MOLE,
4498   EL_PENGUIN,
4499   EL_PIG,
4500   EL_DRAGON,
4501
4502   EL_BUG,
4503   EL_MOLE_UP,
4504   EL_BD_BUTTERFLY,
4505   EL_BD_FIREFLY,
4506
4507   EL_MOLE_LEFT,
4508   EL_SATELLITE,
4509   EL_MOLE_RIGHT,
4510   EL_PACMAN,
4511
4512   EL_SPACESHIP,
4513   EL_MOLE_DOWN,
4514   EL_INVISIBLE_STEELWALL,
4515   EL_INVISIBLE_WALL,
4516
4517   EL_EXPANDABLE_WALL,
4518   EL_EXPANDABLE_WALL_HORIZONTAL,
4519   EL_EXPANDABLE_WALL_VERTICAL,
4520   EL_EXPANDABLE_WALL_ANY,
4521 };
4522 static int *editor_hl_rnd_ptr = editor_hl_rnd;
4523 static int *editor_el_rnd_ptr = editor_el_rnd;
4524 static int num_editor_hl_rnd = ARRAY_SIZE(editor_hl_rnd);
4525 static int num_editor_el_rnd = ARRAY_SIZE(editor_el_rnd);
4526
4527 static int editor_hl_sokoban[] =
4528 {
4529   EL_INTERNAL_CASCADE_SB_ACTIVE,
4530   EL_CHAR('S'),
4531   EL_CHAR('B'),
4532   EL_EMPTY,
4533 };
4534
4535 static int editor_el_sokoban[] =
4536 {
4537   EL_SOKOBAN_OBJECT,
4538   EL_SOKOBAN_FIELD_EMPTY,
4539   EL_SOKOBAN_FIELD_FULL,
4540   EL_SOKOBAN_FIELD_PLAYER,
4541 };
4542 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
4543 static int *editor_el_sokoban_ptr = editor_el_sokoban;
4544 static int num_editor_hl_sokoban = ARRAY_SIZE(editor_hl_sokoban);
4545 static int num_editor_el_sokoban = ARRAY_SIZE(editor_el_sokoban);
4546
4547 static int editor_hl_supaplex[] =
4548 {
4549   EL_INTERNAL_CASCADE_SP_ACTIVE,
4550   EL_CHAR('S'),
4551   EL_CHAR('P'),
4552   EL_EMPTY,
4553 };
4554
4555 static int editor_el_supaplex[] =
4556 {
4557   EL_SP_MURPHY,
4558   EL_EMPTY,
4559   EL_SP_BASE,
4560   EL_SP_BUGGY_BASE,
4561
4562   EL_SP_INFOTRON,
4563   EL_SP_ZONK,
4564   EL_SP_SNIKSNAK,
4565   EL_SP_ELECTRON,
4566
4567   EL_SP_DISK_RED,
4568   EL_SP_DISK_ORANGE,
4569   EL_SP_DISK_YELLOW,
4570   EL_SP_TERMINAL,
4571
4572   EL_SP_EXIT_CLOSED,
4573   EL_SP_PORT_HORIZONTAL,
4574   EL_SP_PORT_VERTICAL,
4575   EL_SP_PORT_ANY,
4576
4577   EL_SP_PORT_LEFT,
4578   EL_SP_PORT_RIGHT,
4579   EL_SP_PORT_UP,
4580   EL_SP_PORT_DOWN,
4581
4582   EL_SP_GRAVITY_PORT_LEFT,
4583   EL_SP_GRAVITY_PORT_RIGHT,
4584   EL_SP_GRAVITY_PORT_UP,
4585   EL_SP_GRAVITY_PORT_DOWN,
4586
4587   EL_SP_GRAVITY_ON_PORT_LEFT,
4588   EL_SP_GRAVITY_ON_PORT_RIGHT,
4589   EL_SP_GRAVITY_ON_PORT_UP,
4590   EL_SP_GRAVITY_ON_PORT_DOWN,
4591
4592   EL_SP_GRAVITY_OFF_PORT_LEFT,
4593   EL_SP_GRAVITY_OFF_PORT_RIGHT,
4594   EL_SP_GRAVITY_OFF_PORT_UP,
4595   EL_SP_GRAVITY_OFF_PORT_DOWN,
4596
4597   EL_SP_HARDWARE_GRAY,
4598   EL_SP_HARDWARE_GREEN,
4599   EL_SP_HARDWARE_BLUE,
4600   EL_SP_HARDWARE_RED,
4601
4602   EL_SP_HARDWARE_BASE_1,
4603   EL_SP_HARDWARE_BASE_2,
4604   EL_SP_HARDWARE_BASE_3,
4605   EL_SP_HARDWARE_BASE_4,
4606
4607   EL_SP_HARDWARE_BASE_5,
4608   EL_SP_HARDWARE_BASE_6,
4609   EL_SP_HARDWARE_YELLOW,
4610   EL_SP_CHIP_TOP,
4611
4612   EL_SP_CHIP_SINGLE,
4613   EL_SP_CHIP_LEFT,
4614   EL_SP_CHIP_RIGHT,
4615   EL_SP_CHIP_BOTTOM,
4616 };
4617 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
4618 static int *editor_el_supaplex_ptr = editor_el_supaplex;
4619 static int num_editor_hl_supaplex = ARRAY_SIZE(editor_hl_supaplex);
4620 static int num_editor_el_supaplex = ARRAY_SIZE(editor_el_supaplex);
4621
4622 static int editor_hl_diamond_caves[] =
4623 {
4624   EL_INTERNAL_CASCADE_DC_ACTIVE,
4625   EL_CHAR('D'),
4626   EL_CHAR('C'),
4627   EL_CHAR('2'),
4628 };
4629
4630 static int editor_el_diamond_caves[] =
4631 {
4632   EL_EM_STEEL_EXIT_CLOSED,      // DC2
4633   EL_EM_STEEL_EXIT_OPEN,        // DC2
4634   EL_WALL_EMERALD,              // DC2
4635   EL_WALL_DIAMOND,              // DC2
4636
4637   EL_PEARL,
4638   EL_CRYSTAL,
4639   EL_WALL_PEARL,
4640   EL_WALL_CRYSTAL,
4641
4642   EL_CONVEYOR_BELT_1_LEFT,
4643   EL_CONVEYOR_BELT_1_MIDDLE,
4644   EL_CONVEYOR_BELT_1_RIGHT,
4645   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4646
4647   EL_CONVEYOR_BELT_2_LEFT,
4648   EL_CONVEYOR_BELT_2_MIDDLE,
4649   EL_CONVEYOR_BELT_2_RIGHT,
4650   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4651
4652   EL_CONVEYOR_BELT_3_LEFT,
4653   EL_CONVEYOR_BELT_3_MIDDLE,
4654   EL_CONVEYOR_BELT_3_RIGHT,
4655   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4656
4657   EL_CONVEYOR_BELT_4_LEFT,
4658   EL_CONVEYOR_BELT_4_MIDDLE,
4659   EL_CONVEYOR_BELT_4_RIGHT,
4660   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4661
4662   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4663   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4664   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4665   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4666
4667   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4668   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4669   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4670   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4671
4672   EL_TIMEGATE_CLOSED,
4673   EL_TIMEGATE_OPEN,
4674   EL_TIMEGATE_SWITCH,
4675   EL_DC_TIMEGATE_SWITCH,
4676
4677   EL_SWITCHGATE_CLOSED,
4678   EL_SWITCHGATE_OPEN,
4679   EL_SWITCHGATE_SWITCH_UP,
4680   EL_SWITCHGATE_SWITCH_DOWN,
4681
4682   EL_LIGHT_SWITCH,
4683   EL_LIGHT_SWITCH_ACTIVE,
4684   EL_DC_SWITCHGATE_SWITCH_UP,
4685   EL_DC_SWITCHGATE_SWITCH_DOWN,
4686
4687   EL_STEEL_EXIT_CLOSED,
4688   EL_STEEL_EXIT_OPEN,
4689   EL_STEELWALL_SLIPPERY,
4690   EL_INVISIBLE_SAND,
4691
4692   EL_QUICKSAND_FAST_EMPTY,
4693   EL_QUICKSAND_FAST_FULL,
4694   EL_LANDMINE,
4695   EL_DC_LANDMINE,
4696
4697   EL_SHIELD_NORMAL,
4698   EL_SHIELD_DEADLY,
4699   EL_EXTRA_TIME,
4700   EL_DC_MAGIC_WALL,
4701
4702   EL_ENVELOPE_1,
4703   EL_ENVELOPE_2,
4704   EL_ENVELOPE_3,
4705   EL_ENVELOPE_4,
4706
4707   EL_SIGN_RADIOACTIVITY,
4708   EL_SIGN_WHEELCHAIR,
4709   EL_SIGN_PARKING,
4710   EL_SIGN_NO_ENTRY,
4711
4712   EL_SIGN_GIVE_WAY,
4713   EL_SIGN_ENTRY_FORBIDDEN,
4714   EL_SIGN_EMERGENCY_EXIT,
4715   EL_SIGN_YIN_YANG,
4716
4717 #if 0
4718   EL_SIGN_SPERMS,
4719   EL_SIGN_BULLET,
4720   EL_SIGN_HEART,
4721   EL_SIGN_CROSS,
4722
4723   EL_SIGN_FRANKIE,
4724   EL_EMPTY,
4725   EL_EMPTY,
4726   EL_EMPTY,
4727
4728   EL_SPERMS,
4729   EL_BULLET,
4730   EL_HEART,
4731   EL_CROSS,
4732
4733   EL_FRANKIE,
4734   EL_EMPTY,
4735   EL_EMPTY,
4736   EL_EMPTY,
4737 #endif
4738
4739   EL_DC_STEELWALL_2_SINGLE,
4740   EL_DC_STEELWALL_2_TOP,
4741   EL_SIGN_EXCLAMATION,
4742   EL_SIGN_STOP,
4743
4744   EL_DC_STEELWALL_2_LEFT,
4745   EL_DC_STEELWALL_2_MIDDLE,
4746   EL_DC_STEELWALL_2_HORIZONTAL,
4747   EL_DC_STEELWALL_2_RIGHT,
4748
4749   EL_DC_STEELWALL_1_TOPLEFT,
4750   EL_DC_STEELWALL_2_VERTICAL,
4751   EL_DC_STEELWALL_1_TOPRIGHT,
4752   EL_DC_GATE_WHITE,
4753
4754   EL_DC_STEELWALL_1_VERTICAL,
4755   EL_DC_STEELWALL_2_BOTTOM,
4756   EL_DC_KEY_WHITE,
4757   EL_DC_GATE_WHITE_GRAY,
4758
4759   EL_DC_STEELWALL_1_BOTTOMLEFT,
4760   EL_DC_STEELWALL_1_HORIZONTAL,
4761   EL_DC_STEELWALL_1_BOTTOMRIGHT,
4762   EL_DC_GATE_FAKE_GRAY,
4763
4764   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4765   EL_DC_STEELWALL_1_BOTTOM,
4766   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4767   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4768
4769   EL_DC_STEELWALL_1_RIGHT,
4770   EL_EMPTY,
4771   EL_DC_STEELWALL_1_LEFT,
4772   EL_EXPANDABLE_STEELWALL_VERTICAL,
4773
4774   EL_DC_STEELWALL_1_TOPRIGHT_2,
4775   EL_DC_STEELWALL_1_TOP,
4776   EL_DC_STEELWALL_1_TOPLEFT_2,
4777   EL_EXPANDABLE_STEELWALL_ANY,
4778 };
4779 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
4780 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
4781 static int num_editor_hl_diamond_caves = ARRAY_SIZE(editor_hl_diamond_caves);
4782 static int num_editor_el_diamond_caves = ARRAY_SIZE(editor_el_diamond_caves);
4783
4784 static int editor_hl_dx_boulderdash[] =
4785 {
4786   EL_INTERNAL_CASCADE_DX_ACTIVE,
4787   EL_CHAR('D'),
4788   EL_CHAR('X'),
4789   EL_EMPTY,
4790 };
4791
4792 static int editor_el_dx_boulderdash[] =
4793 {
4794   EL_EMPTY,
4795   EL_TUBE_RIGHT_DOWN,
4796   EL_TUBE_HORIZONTAL_DOWN,
4797   EL_TUBE_LEFT_DOWN,
4798
4799   EL_TUBE_HORIZONTAL,
4800   EL_TUBE_VERTICAL_RIGHT,
4801   EL_TUBE_ANY,
4802   EL_TUBE_VERTICAL_LEFT,
4803
4804   EL_TUBE_VERTICAL,
4805   EL_TUBE_RIGHT_UP,
4806   EL_TUBE_HORIZONTAL_UP,
4807   EL_TUBE_LEFT_UP,
4808
4809   EL_TRAP,
4810   EL_DX_SUPABOMB,
4811   EL_EMPTY,
4812   EL_EMPTY
4813 };
4814 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
4815 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
4816 static int num_editor_hl_dx_boulderdash = ARRAY_SIZE(editor_hl_dx_boulderdash);
4817 static int num_editor_el_dx_boulderdash = ARRAY_SIZE(editor_el_dx_boulderdash);
4818
4819 static int editor_hl_mirror_magic[] =
4820 {
4821   EL_INTERNAL_CASCADE_MM_ACTIVE,
4822   EL_CHAR('M'),
4823   EL_CHAR('M'),
4824   EL_EMPTY,
4825 };
4826
4827 static int editor_el_mirror_magic[] =
4828 {
4829   EL_MM_MCDUFFIN_RIGHT,
4830   EL_MM_MCDUFFIN_UP,
4831   EL_MM_MCDUFFIN_LEFT,
4832   EL_MM_MCDUFFIN_DOWN,
4833
4834   EL_MM_MIRROR_START,
4835   EL_MM_MIRROR_FIXED_START,
4836   EL_MM_POLARIZER_START,
4837   EL_MM_POLARIZER_CROSS_START,
4838
4839   EL_MM_TELEPORTER_RED_START,
4840   EL_MM_TELEPORTER_YELLOW_START,
4841   EL_MM_TELEPORTER_GREEN_START,
4842   EL_MM_TELEPORTER_BLUE_START,
4843
4844   EL_MM_PRISM,
4845   EL_MM_FUSE_ACTIVE,
4846   EL_MM_PACMAN_RIGHT,
4847   EL_MM_EXIT_CLOSED,
4848
4849   EL_MM_KETTLE,
4850   EL_MM_BOMB,
4851   EL_MM_KEY,
4852   EL_MM_FUEL_FULL,
4853
4854   EL_MM_LIGHTBULB,
4855   EL_MM_LIGHTBULB_ACTIVE,
4856   EL_MM_GRAY_BALL,
4857   EL_MM_LIGHTBALL,
4858
4859   EL_MM_STEEL_WALL,
4860   EL_MM_WOODEN_WALL,
4861   EL_MM_ICE_WALL,
4862   EL_MM_AMOEBA_WALL,
4863
4864   EL_MM_STEEL_LOCK,
4865   EL_MM_WOODEN_LOCK,
4866   EL_MM_STEEL_BLOCK,
4867   EL_MM_WOODEN_BLOCK,
4868
4869   EL_MM_STEEL_GRID_FIXED_1,
4870   EL_MM_STEEL_GRID_FIXED_2,
4871   EL_MM_STEEL_GRID_FIXED_3,
4872   EL_MM_STEEL_GRID_FIXED_4,
4873
4874   EL_MM_WOODEN_GRID_FIXED_1,
4875   EL_MM_WOODEN_GRID_FIXED_2,
4876   EL_MM_WOODEN_GRID_FIXED_3,
4877   EL_MM_WOODEN_GRID_FIXED_4,
4878
4879   EL_MM_ENVELOPE_1,
4880   EL_MM_ENVELOPE_2,
4881   EL_MM_ENVELOPE_3,
4882   EL_MM_ENVELOPE_4
4883 };
4884 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
4885 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
4886 static int num_editor_hl_mirror_magic = ARRAY_SIZE(editor_hl_mirror_magic);
4887 static int num_editor_el_mirror_magic = ARRAY_SIZE(editor_el_mirror_magic);
4888
4889 static int editor_hl_deflektor[] =
4890 {
4891   EL_INTERNAL_CASCADE_DF_ACTIVE,
4892   EL_CHAR('D'),
4893   EL_CHAR('F'),
4894   EL_EMPTY,
4895 };
4896
4897 static int editor_el_deflektor[] =
4898 {
4899   EL_DF_LASER_RIGHT,
4900   EL_DF_LASER_UP,
4901   EL_DF_LASER_LEFT,
4902   EL_DF_LASER_DOWN,
4903
4904   EL_DF_RECEIVER_RIGHT,
4905   EL_DF_RECEIVER_UP,
4906   EL_DF_RECEIVER_LEFT,
4907   EL_DF_RECEIVER_DOWN,
4908
4909   EL_DF_MIRROR_START,
4910   EL_DF_MIRROR_ROTATING_START,
4911   EL_DF_MIRROR_FIXED_START,
4912   EL_DF_CELL,
4913
4914   EL_DF_FIBRE_OPTIC_RED_1,
4915   EL_DF_FIBRE_OPTIC_YELLOW_1,
4916   EL_DF_FIBRE_OPTIC_GREEN_1,
4917   EL_DF_FIBRE_OPTIC_BLUE_1,
4918
4919   EL_DF_STEEL_GRID_FIXED_START,
4920   EL_DF_STEEL_GRID_ROTATING_START,
4921   EL_DF_WOODEN_GRID_FIXED_START,
4922   EL_DF_WOODEN_GRID_ROTATING_START,
4923
4924   EL_DF_STEEL_WALL,
4925   EL_DF_WOODEN_WALL,
4926   EL_DF_REFRACTOR,
4927   EL_DF_MINE,
4928
4929   EL_DF_SLOPE_1,
4930   EL_DF_SLOPE_2,
4931   EL_DF_SLOPE_3,
4932   EL_DF_SLOPE_4
4933 };
4934 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
4935 static int *editor_el_deflektor_ptr = editor_el_deflektor;
4936 static int num_editor_hl_deflektor = ARRAY_SIZE(editor_hl_deflektor);
4937 static int num_editor_el_deflektor = ARRAY_SIZE(editor_el_deflektor);
4938
4939 static int editor_hl_chars[] =
4940 {
4941   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4942   EL_CHAR('T'),
4943   EL_CHAR('X'),
4944   EL_CHAR('T'),
4945 };
4946
4947 static int editor_el_chars[] =
4948 {
4949   EL_CHAR(' '),
4950   EL_CHAR('!'),
4951   EL_CHAR('"'),
4952   EL_CHAR('#'),
4953
4954   EL_CHAR('$'),
4955   EL_CHAR('%'),
4956   EL_CHAR('&'),
4957   EL_CHAR('\''),
4958
4959   EL_CHAR('('),
4960   EL_CHAR(')'),
4961   EL_CHAR('*'),
4962   EL_CHAR('+'),
4963
4964   EL_CHAR(','),
4965   EL_CHAR('-'),
4966   EL_CHAR('.'),
4967   EL_CHAR('/'),
4968
4969   EL_CHAR('0'),
4970   EL_CHAR('1'),
4971   EL_CHAR('2'),
4972   EL_CHAR('3'),
4973
4974   EL_CHAR('4'),
4975   EL_CHAR('5'),
4976   EL_CHAR('6'),
4977   EL_CHAR('7'),
4978
4979   EL_CHAR('8'),
4980   EL_CHAR('9'),
4981   EL_CHAR(':'),
4982   EL_CHAR(';'),
4983
4984   EL_CHAR('<'),
4985   EL_CHAR('='),
4986   EL_CHAR('>'),
4987   EL_CHAR('?'),
4988
4989   EL_CHAR('@'),
4990   EL_CHAR('A'),
4991   EL_CHAR('B'),
4992   EL_CHAR('C'),
4993
4994   EL_CHAR('D'),
4995   EL_CHAR('E'),
4996   EL_CHAR('F'),
4997   EL_CHAR('G'),
4998
4999   EL_CHAR('H'),
5000   EL_CHAR('I'),
5001   EL_CHAR('J'),
5002   EL_CHAR('K'),
5003
5004   EL_CHAR('L'),
5005   EL_CHAR('M'),
5006   EL_CHAR('N'),
5007   EL_CHAR('O'),
5008
5009   EL_CHAR('P'),
5010   EL_CHAR('Q'),
5011   EL_CHAR('R'),
5012   EL_CHAR('S'),
5013
5014   EL_CHAR('T'),
5015   EL_CHAR('U'),
5016   EL_CHAR('V'),
5017   EL_CHAR('W'),
5018
5019   EL_CHAR('X'),
5020   EL_CHAR('Y'),
5021   EL_CHAR('Z'),
5022   EL_CHAR('['),
5023
5024   EL_CHAR('\\'),
5025   EL_CHAR(']'),
5026   EL_CHAR('^'),
5027   EL_CHAR('_'),
5028
5029   EL_CHAR(CHAR_BYTE_COPYRIGHT),
5030   EL_CHAR(CHAR_BYTE_UMLAUT_A),
5031   EL_CHAR(CHAR_BYTE_UMLAUT_O),
5032   EL_CHAR(CHAR_BYTE_UMLAUT_U),
5033
5034   EL_CHAR(CHAR_BYTE_DEGREE),
5035   EL_CHAR(CHAR_BYTE_REGISTERED),
5036   EL_CHAR(FONT_ASCII_CURSOR),
5037   EL_CHAR(FONT_ASCII_BUTTON),
5038
5039   EL_CHAR(FONT_ASCII_UP),
5040   EL_CHAR(FONT_ASCII_DOWN),
5041   EL_CHAR(' '),
5042   EL_CHAR(' ')
5043 };
5044 static int *editor_hl_chars_ptr = editor_hl_chars;
5045 static int *editor_el_chars_ptr = editor_el_chars;
5046 static int num_editor_hl_chars = ARRAY_SIZE(editor_hl_chars);
5047 static int num_editor_el_chars = ARRAY_SIZE(editor_el_chars);
5048
5049 static int editor_hl_steel_chars[] =
5050 {
5051   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
5052   EL_STEEL_CHAR('T'),
5053   EL_STEEL_CHAR('X'),
5054   EL_STEEL_CHAR('T'),
5055 };
5056
5057 static int editor_el_steel_chars[] =
5058 {
5059   EL_STEEL_CHAR(' '),
5060   EL_STEEL_CHAR('!'),
5061   EL_STEEL_CHAR('"'),
5062   EL_STEEL_CHAR('#'),
5063
5064   EL_STEEL_CHAR('$'),
5065   EL_STEEL_CHAR('%'),
5066   EL_STEEL_CHAR('&'),
5067   EL_STEEL_CHAR('\''),
5068
5069   EL_STEEL_CHAR('('),
5070   EL_STEEL_CHAR(')'),
5071   EL_STEEL_CHAR('*'),
5072   EL_STEEL_CHAR('+'),
5073
5074   EL_STEEL_CHAR(','),
5075   EL_STEEL_CHAR('-'),
5076   EL_STEEL_CHAR('.'),
5077   EL_STEEL_CHAR('/'),
5078
5079   EL_STEEL_CHAR('0'),
5080   EL_STEEL_CHAR('1'),
5081   EL_STEEL_CHAR('2'),
5082   EL_STEEL_CHAR('3'),
5083
5084   EL_STEEL_CHAR('4'),
5085   EL_STEEL_CHAR('5'),
5086   EL_STEEL_CHAR('6'),
5087   EL_STEEL_CHAR('7'),
5088
5089   EL_STEEL_CHAR('8'),
5090   EL_STEEL_CHAR('9'),
5091   EL_STEEL_CHAR(':'),
5092   EL_STEEL_CHAR(';'),
5093
5094   EL_STEEL_CHAR('<'),
5095   EL_STEEL_CHAR('='),
5096   EL_STEEL_CHAR('>'),
5097   EL_STEEL_CHAR('?'),
5098
5099   EL_STEEL_CHAR('@'),
5100   EL_STEEL_CHAR('A'),
5101   EL_STEEL_CHAR('B'),
5102   EL_STEEL_CHAR('C'),
5103
5104   EL_STEEL_CHAR('D'),
5105   EL_STEEL_CHAR('E'),
5106   EL_STEEL_CHAR('F'),
5107   EL_STEEL_CHAR('G'),
5108
5109   EL_STEEL_CHAR('H'),
5110   EL_STEEL_CHAR('I'),
5111   EL_STEEL_CHAR('J'),
5112   EL_STEEL_CHAR('K'),
5113
5114   EL_STEEL_CHAR('L'),
5115   EL_STEEL_CHAR('M'),
5116   EL_STEEL_CHAR('N'),
5117   EL_STEEL_CHAR('O'),
5118
5119   EL_STEEL_CHAR('P'),
5120   EL_STEEL_CHAR('Q'),
5121   EL_STEEL_CHAR('R'),
5122   EL_STEEL_CHAR('S'),
5123
5124   EL_STEEL_CHAR('T'),
5125   EL_STEEL_CHAR('U'),
5126   EL_STEEL_CHAR('V'),
5127   EL_STEEL_CHAR('W'),
5128
5129   EL_STEEL_CHAR('X'),
5130   EL_STEEL_CHAR('Y'),
5131   EL_STEEL_CHAR('Z'),
5132   EL_STEEL_CHAR('['),
5133
5134   EL_STEEL_CHAR('\\'),
5135   EL_STEEL_CHAR(']'),
5136   EL_STEEL_CHAR('^'),
5137   EL_STEEL_CHAR('_'),
5138
5139   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
5140   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
5141   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
5142   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
5143
5144   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
5145   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
5146   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
5147   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
5148
5149   EL_STEEL_CHAR(FONT_ASCII_UP),
5150   EL_STEEL_CHAR(FONT_ASCII_DOWN),
5151   EL_STEEL_CHAR(' '),
5152   EL_STEEL_CHAR(' ')
5153 };
5154 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
5155 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
5156 static int num_editor_hl_steel_chars = ARRAY_SIZE(editor_hl_steel_chars);
5157 static int num_editor_el_steel_chars = ARRAY_SIZE(editor_el_steel_chars);
5158
5159 static int editor_hl_custom[] =
5160 {
5161   EL_INTERNAL_CASCADE_CE_ACTIVE,
5162   EL_CHAR('C'),
5163   EL_CHAR('E'),
5164   EL_EMPTY,
5165 };
5166
5167 static int editor_el_custom[] =
5168 {
5169   EL_CUSTOM_START + 0,
5170   EL_CUSTOM_START + 1,
5171   EL_CUSTOM_START + 2,
5172   EL_CUSTOM_START + 3,
5173
5174   EL_CUSTOM_START + 4,
5175   EL_CUSTOM_START + 5,
5176   EL_CUSTOM_START + 6,
5177   EL_CUSTOM_START + 7,
5178
5179   EL_CUSTOM_START + 8,
5180   EL_CUSTOM_START + 9,
5181   EL_CUSTOM_START + 10,
5182   EL_CUSTOM_START + 11,
5183
5184   EL_CUSTOM_START + 12,
5185   EL_CUSTOM_START + 13,
5186   EL_CUSTOM_START + 14,
5187   EL_CUSTOM_START + 15,
5188
5189   EL_CUSTOM_START + 16,
5190   EL_CUSTOM_START + 17,
5191   EL_CUSTOM_START + 18,
5192   EL_CUSTOM_START + 19,
5193
5194   EL_CUSTOM_START + 20,
5195   EL_CUSTOM_START + 21,
5196   EL_CUSTOM_START + 22,
5197   EL_CUSTOM_START + 23,
5198
5199   EL_CUSTOM_START + 24,
5200   EL_CUSTOM_START + 25,
5201   EL_CUSTOM_START + 26,
5202   EL_CUSTOM_START + 27,
5203
5204   EL_CUSTOM_START + 28,
5205   EL_CUSTOM_START + 29,
5206   EL_CUSTOM_START + 30,
5207   EL_CUSTOM_START + 31,
5208
5209   EL_CUSTOM_START + 32,
5210   EL_CUSTOM_START + 33,
5211   EL_CUSTOM_START + 34,
5212   EL_CUSTOM_START + 35,
5213
5214   EL_CUSTOM_START + 36,
5215   EL_CUSTOM_START + 37,
5216   EL_CUSTOM_START + 38,
5217   EL_CUSTOM_START + 39,
5218
5219   EL_CUSTOM_START + 40,
5220   EL_CUSTOM_START + 41,
5221   EL_CUSTOM_START + 42,
5222   EL_CUSTOM_START + 43,
5223
5224   EL_CUSTOM_START + 44,
5225   EL_CUSTOM_START + 45,
5226   EL_CUSTOM_START + 46,
5227   EL_CUSTOM_START + 47,
5228
5229   EL_CUSTOM_START + 48,
5230   EL_CUSTOM_START + 49,
5231   EL_CUSTOM_START + 50,
5232   EL_CUSTOM_START + 51,
5233
5234   EL_CUSTOM_START + 52,
5235   EL_CUSTOM_START + 53,
5236   EL_CUSTOM_START + 54,
5237   EL_CUSTOM_START + 55,
5238
5239   EL_CUSTOM_START + 56,
5240   EL_CUSTOM_START + 57,
5241   EL_CUSTOM_START + 58,
5242   EL_CUSTOM_START + 59,
5243
5244   EL_CUSTOM_START + 60,
5245   EL_CUSTOM_START + 61,
5246   EL_CUSTOM_START + 62,
5247   EL_CUSTOM_START + 63,
5248
5249   EL_CUSTOM_START + 64,
5250   EL_CUSTOM_START + 65,
5251   EL_CUSTOM_START + 66,
5252   EL_CUSTOM_START + 67,
5253
5254   EL_CUSTOM_START + 68,
5255   EL_CUSTOM_START + 69,
5256   EL_CUSTOM_START + 70,
5257   EL_CUSTOM_START + 71,
5258
5259   EL_CUSTOM_START + 72,
5260   EL_CUSTOM_START + 73,
5261   EL_CUSTOM_START + 74,
5262   EL_CUSTOM_START + 75,
5263
5264   EL_CUSTOM_START + 76,
5265   EL_CUSTOM_START + 77,
5266   EL_CUSTOM_START + 78,
5267   EL_CUSTOM_START + 79,
5268
5269   EL_CUSTOM_START + 80,
5270   EL_CUSTOM_START + 81,
5271   EL_CUSTOM_START + 82,
5272   EL_CUSTOM_START + 83,
5273
5274   EL_CUSTOM_START + 84,
5275   EL_CUSTOM_START + 85,
5276   EL_CUSTOM_START + 86,
5277   EL_CUSTOM_START + 87,
5278
5279   EL_CUSTOM_START + 88,
5280   EL_CUSTOM_START + 89,
5281   EL_CUSTOM_START + 90,
5282   EL_CUSTOM_START + 91,
5283
5284   EL_CUSTOM_START + 92,
5285   EL_CUSTOM_START + 93,
5286   EL_CUSTOM_START + 94,
5287   EL_CUSTOM_START + 95,
5288
5289   EL_CUSTOM_START + 96,
5290   EL_CUSTOM_START + 97,
5291   EL_CUSTOM_START + 98,
5292   EL_CUSTOM_START + 99,
5293
5294   EL_CUSTOM_START + 100,
5295   EL_CUSTOM_START + 101,
5296   EL_CUSTOM_START + 102,
5297   EL_CUSTOM_START + 103,
5298
5299   EL_CUSTOM_START + 104,
5300   EL_CUSTOM_START + 105,
5301   EL_CUSTOM_START + 106,
5302   EL_CUSTOM_START + 107,
5303
5304   EL_CUSTOM_START + 108,
5305   EL_CUSTOM_START + 109,
5306   EL_CUSTOM_START + 110,
5307   EL_CUSTOM_START + 111,
5308
5309   EL_CUSTOM_START + 112,
5310   EL_CUSTOM_START + 113,
5311   EL_CUSTOM_START + 114,
5312   EL_CUSTOM_START + 115,
5313
5314   EL_CUSTOM_START + 116,
5315   EL_CUSTOM_START + 117,
5316   EL_CUSTOM_START + 118,
5317   EL_CUSTOM_START + 119,
5318
5319   EL_CUSTOM_START + 120,
5320   EL_CUSTOM_START + 121,
5321   EL_CUSTOM_START + 122,
5322   EL_CUSTOM_START + 123,
5323
5324   EL_CUSTOM_START + 124,
5325   EL_CUSTOM_START + 125,
5326   EL_CUSTOM_START + 126,
5327   EL_CUSTOM_START + 127,
5328
5329   EL_CUSTOM_START + 128,
5330   EL_CUSTOM_START + 129,
5331   EL_CUSTOM_START + 130,
5332   EL_CUSTOM_START + 131,
5333
5334   EL_CUSTOM_START + 132,
5335   EL_CUSTOM_START + 133,
5336   EL_CUSTOM_START + 134,
5337   EL_CUSTOM_START + 135,
5338
5339   EL_CUSTOM_START + 136,
5340   EL_CUSTOM_START + 137,
5341   EL_CUSTOM_START + 138,
5342   EL_CUSTOM_START + 139,
5343
5344   EL_CUSTOM_START + 140,
5345   EL_CUSTOM_START + 141,
5346   EL_CUSTOM_START + 142,
5347   EL_CUSTOM_START + 143,
5348
5349   EL_CUSTOM_START + 144,
5350   EL_CUSTOM_START + 145,
5351   EL_CUSTOM_START + 146,
5352   EL_CUSTOM_START + 147,
5353
5354   EL_CUSTOM_START + 148,
5355   EL_CUSTOM_START + 149,
5356   EL_CUSTOM_START + 150,
5357   EL_CUSTOM_START + 151,
5358
5359   EL_CUSTOM_START + 152,
5360   EL_CUSTOM_START + 153,
5361   EL_CUSTOM_START + 154,
5362   EL_CUSTOM_START + 155,
5363
5364   EL_CUSTOM_START + 156,
5365   EL_CUSTOM_START + 157,
5366   EL_CUSTOM_START + 158,
5367   EL_CUSTOM_START + 159,
5368
5369   EL_CUSTOM_START + 160,
5370   EL_CUSTOM_START + 161,
5371   EL_CUSTOM_START + 162,
5372   EL_CUSTOM_START + 163,
5373
5374   EL_CUSTOM_START + 164,
5375   EL_CUSTOM_START + 165,
5376   EL_CUSTOM_START + 166,
5377   EL_CUSTOM_START + 167,
5378
5379   EL_CUSTOM_START + 168,
5380   EL_CUSTOM_START + 169,
5381   EL_CUSTOM_START + 170,
5382   EL_CUSTOM_START + 171,
5383
5384   EL_CUSTOM_START + 172,
5385   EL_CUSTOM_START + 173,
5386   EL_CUSTOM_START + 174,
5387   EL_CUSTOM_START + 175,
5388
5389   EL_CUSTOM_START + 176,
5390   EL_CUSTOM_START + 177,
5391   EL_CUSTOM_START + 178,
5392   EL_CUSTOM_START + 179,
5393
5394   EL_CUSTOM_START + 180,
5395   EL_CUSTOM_START + 181,
5396   EL_CUSTOM_START + 182,
5397   EL_CUSTOM_START + 183,
5398
5399   EL_CUSTOM_START + 184,
5400   EL_CUSTOM_START + 185,
5401   EL_CUSTOM_START + 186,
5402   EL_CUSTOM_START + 187,
5403
5404   EL_CUSTOM_START + 188,
5405   EL_CUSTOM_START + 189,
5406   EL_CUSTOM_START + 190,
5407   EL_CUSTOM_START + 191,
5408
5409   EL_CUSTOM_START + 192,
5410   EL_CUSTOM_START + 193,
5411   EL_CUSTOM_START + 194,
5412   EL_CUSTOM_START + 195,
5413
5414   EL_CUSTOM_START + 196,
5415   EL_CUSTOM_START + 197,
5416   EL_CUSTOM_START + 198,
5417   EL_CUSTOM_START + 199,
5418
5419   EL_CUSTOM_START + 200,
5420   EL_CUSTOM_START + 201,
5421   EL_CUSTOM_START + 202,
5422   EL_CUSTOM_START + 203,
5423
5424   EL_CUSTOM_START + 204,
5425   EL_CUSTOM_START + 205,
5426   EL_CUSTOM_START + 206,
5427   EL_CUSTOM_START + 207,
5428
5429   EL_CUSTOM_START + 208,
5430   EL_CUSTOM_START + 209,
5431   EL_CUSTOM_START + 210,
5432   EL_CUSTOM_START + 211,
5433
5434   EL_CUSTOM_START + 212,
5435   EL_CUSTOM_START + 213,
5436   EL_CUSTOM_START + 214,
5437   EL_CUSTOM_START + 215,
5438
5439   EL_CUSTOM_START + 216,
5440   EL_CUSTOM_START + 217,
5441   EL_CUSTOM_START + 218,
5442   EL_CUSTOM_START + 219,
5443
5444   EL_CUSTOM_START + 220,
5445   EL_CUSTOM_START + 221,
5446   EL_CUSTOM_START + 222,
5447   EL_CUSTOM_START + 223,
5448
5449   EL_CUSTOM_START + 224,
5450   EL_CUSTOM_START + 225,
5451   EL_CUSTOM_START + 226,
5452   EL_CUSTOM_START + 227,
5453
5454   EL_CUSTOM_START + 228,
5455   EL_CUSTOM_START + 229,
5456   EL_CUSTOM_START + 230,
5457   EL_CUSTOM_START + 231,
5458
5459   EL_CUSTOM_START + 232,
5460   EL_CUSTOM_START + 233,
5461   EL_CUSTOM_START + 234,
5462   EL_CUSTOM_START + 235,
5463
5464   EL_CUSTOM_START + 236,
5465   EL_CUSTOM_START + 237,
5466   EL_CUSTOM_START + 238,
5467   EL_CUSTOM_START + 239,
5468
5469   EL_CUSTOM_START + 240,
5470   EL_CUSTOM_START + 241,
5471   EL_CUSTOM_START + 242,
5472   EL_CUSTOM_START + 243,
5473
5474   EL_CUSTOM_START + 244,
5475   EL_CUSTOM_START + 245,
5476   EL_CUSTOM_START + 246,
5477   EL_CUSTOM_START + 247,
5478
5479   EL_CUSTOM_START + 248,
5480   EL_CUSTOM_START + 249,
5481   EL_CUSTOM_START + 250,
5482   EL_CUSTOM_START + 251,
5483
5484   EL_CUSTOM_START + 252,
5485   EL_CUSTOM_START + 253,
5486   EL_CUSTOM_START + 254,
5487   EL_CUSTOM_START + 255
5488 };
5489 static int *editor_hl_custom_ptr = editor_hl_custom;
5490 static int *editor_el_custom_ptr = editor_el_custom;
5491 static int num_editor_hl_custom = ARRAY_SIZE(editor_hl_custom);
5492 static int num_editor_el_custom = ARRAY_SIZE(editor_el_custom);
5493
5494 static int editor_hl_group[] =
5495 {
5496   EL_INTERNAL_CASCADE_GE_ACTIVE,
5497   EL_CHAR('G'),
5498   EL_CHAR('E'),
5499   EL_EMPTY,
5500 };
5501
5502 static int editor_el_group[] =
5503 {
5504   EL_GROUP_START + 0,
5505   EL_GROUP_START + 1,
5506   EL_GROUP_START + 2,
5507   EL_GROUP_START + 3,
5508
5509   EL_GROUP_START + 4,
5510   EL_GROUP_START + 5,
5511   EL_GROUP_START + 6,
5512   EL_GROUP_START + 7,
5513
5514   EL_GROUP_START + 8,
5515   EL_GROUP_START + 9,
5516   EL_GROUP_START + 10,
5517   EL_GROUP_START + 11,
5518
5519   EL_GROUP_START + 12,
5520   EL_GROUP_START + 13,
5521   EL_GROUP_START + 14,
5522   EL_GROUP_START + 15,
5523
5524   EL_GROUP_START + 16,
5525   EL_GROUP_START + 17,
5526   EL_GROUP_START + 18,
5527   EL_GROUP_START + 19,
5528
5529   EL_GROUP_START + 20,
5530   EL_GROUP_START + 21,
5531   EL_GROUP_START + 22,
5532   EL_GROUP_START + 23,
5533
5534   EL_GROUP_START + 24,
5535   EL_GROUP_START + 25,
5536   EL_GROUP_START + 26,
5537   EL_GROUP_START + 27,
5538
5539   EL_GROUP_START + 28,
5540   EL_GROUP_START + 29,
5541   EL_GROUP_START + 30,
5542   EL_GROUP_START + 31
5543 };
5544 static int *editor_hl_group_ptr = editor_hl_group;
5545 static int *editor_el_group_ptr = editor_el_group;
5546 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
5547 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
5548
5549 static int editor_hl_empty_space[] =
5550 {
5551   EL_INTERNAL_CASCADE_ES_ACTIVE,
5552   EL_CHAR('E'),
5553   EL_CHAR('S'),
5554   EL_EMPTY,
5555 };
5556
5557 static int editor_el_empty_space[] =
5558 {
5559   EL_EMPTY_SPACE_1,
5560   EL_EMPTY_SPACE_2,
5561   EL_EMPTY_SPACE_3,
5562   EL_EMPTY_SPACE_4,
5563
5564   EL_EMPTY_SPACE_5,
5565   EL_EMPTY_SPACE_6,
5566   EL_EMPTY_SPACE_7,
5567   EL_EMPTY_SPACE_8,
5568
5569   EL_EMPTY_SPACE_9,
5570   EL_EMPTY_SPACE_10,
5571   EL_EMPTY_SPACE_11,
5572   EL_EMPTY_SPACE_12,
5573
5574   EL_EMPTY_SPACE_13,
5575   EL_EMPTY_SPACE_14,
5576   EL_EMPTY_SPACE_15,
5577   EL_EMPTY_SPACE_16
5578 };
5579 static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
5580 static int *editor_el_empty_space_ptr = editor_el_empty_space;
5581 static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
5582 static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
5583
5584 static int editor_hl_reference[] =
5585 {
5586   EL_INTERNAL_CASCADE_REF_ACTIVE,
5587   EL_CHAR('R'),
5588   EL_CHAR('E'),
5589   EL_CHAR('F')
5590 };
5591
5592 static int editor_el_reference[] =
5593 {
5594   EL_TRIGGER_PLAYER,
5595   EL_TRIGGER_ELEMENT,
5596   EL_TRIGGER_CE_VALUE,
5597   EL_TRIGGER_CE_SCORE,
5598
5599   EL_SELF,
5600   EL_ANY_ELEMENT,
5601   EL_CURRENT_CE_VALUE,
5602   EL_CURRENT_CE_SCORE,
5603
5604   EL_PREV_CE_8,
5605   EL_PREV_CE_7,
5606   EL_PREV_CE_6,
5607   EL_PREV_CE_5,
5608
5609   EL_PREV_CE_4,
5610   EL_PREV_CE_3,
5611   EL_PREV_CE_2,
5612   EL_PREV_CE_1,
5613
5614   EL_NEXT_CE_1,
5615   EL_NEXT_CE_2,
5616   EL_NEXT_CE_3,
5617   EL_NEXT_CE_4,
5618
5619   EL_NEXT_CE_5,
5620   EL_NEXT_CE_6,
5621   EL_NEXT_CE_7,
5622   EL_NEXT_CE_8,
5623 };
5624 static int *editor_hl_reference_ptr = editor_hl_reference;
5625 static int *editor_el_reference_ptr = editor_el_reference;
5626 static int num_editor_hl_reference = ARRAY_SIZE(editor_hl_reference);
5627 static int num_editor_el_reference = ARRAY_SIZE(editor_el_reference);
5628
5629 static int editor_hl_user_defined[] =
5630 {
5631   EL_INTERNAL_CASCADE_USER_ACTIVE,
5632   EL_CHAR('M'),
5633   EL_CHAR('Y'),
5634   EL_EMPTY,
5635 };
5636
5637 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
5638 static int *editor_el_user_defined_ptr = NULL;
5639 static int num_editor_hl_user_defined = ARRAY_SIZE(editor_hl_user_defined);
5640 static int num_editor_el_user_defined = 0;
5641
5642 static int editor_hl_dynamic[] =
5643 {
5644   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
5645   EL_CHAR('U'),
5646   EL_CHAR('S'),
5647   EL_CHAR('E'),
5648 };
5649
5650 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
5651 static int *editor_el_dynamic_ptr = NULL;
5652 static int num_editor_hl_dynamic = ARRAY_SIZE(editor_hl_dynamic);
5653 static int num_editor_el_dynamic = 0;
5654
5655 static int editor_hl_empty[] = { EL_EMPTY };
5656 static int *editor_el_empty = NULL;     // dynamically allocated
5657
5658 static int *editor_hl_empty_ptr = editor_hl_empty;
5659 static int *editor_el_empty_ptr = NULL;
5660 static int num_editor_hl_empty = 0;
5661 static int num_editor_el_empty = 0;     // dynamically determined, if needed
5662
5663 static boolean use_el_empty = FALSE;
5664
5665 static int *editor_elements = NULL;     // dynamically allocated
5666 static int num_editor_elements = 0;     // dynamically determined
5667
5668 static boolean setup_editor_cascade_never = FALSE;
5669
5670 static boolean setup_editor_el_players                  = TRUE;
5671 static boolean setup_editor_el_boulderdash              = TRUE;
5672 static boolean setup_editor_el_boulderdash_native       = TRUE;
5673 static boolean setup_editor_el_emerald_mine             = TRUE;
5674 static boolean setup_editor_el_emerald_mine_club        = TRUE;
5675 static boolean setup_editor_el_more                     = TRUE;
5676 static boolean setup_editor_el_sokoban                  = TRUE;
5677 static boolean setup_editor_el_supaplex                 = TRUE;
5678 static boolean setup_editor_el_diamond_caves            = TRUE;
5679 static boolean setup_editor_el_dx_boulderdash           = TRUE;
5680 static boolean setup_editor_el_mirror_magic             = TRUE;
5681 static boolean setup_editor_el_deflektor                = TRUE;
5682 static boolean setup_editor_el_chars                    = TRUE;
5683 static boolean setup_editor_el_steel_chars              = TRUE;
5684 static boolean setup_editor_el_custom                   = TRUE;
5685 static boolean setup_editor_el_user_defined             = TRUE;
5686 static boolean setup_editor_el_dynamic                  = TRUE;
5687
5688 static int editor_hl_unused[] = { EL_EMPTY };
5689 static int *editor_hl_unused_ptr = editor_hl_unused;
5690 static int num_editor_hl_unused = 0;
5691
5692 static struct
5693 {
5694   boolean *setup_value;
5695   boolean *setup_cascade_value;
5696
5697   int **headline_list;
5698   int *headline_list_size;
5699
5700   int **element_list;
5701   int *element_list_size;
5702
5703   boolean last_setup_value;
5704 }
5705 editor_elements_info[] =
5706 {
5707   {
5708     &setup_editor_el_players,
5709     &setup_editor_cascade_never,
5710     &editor_hl_unused_ptr,              &num_editor_hl_unused,
5711     &editor_el_players_ptr,             &num_editor_el_players
5712   },
5713   {
5714     &setup_editor_el_boulderdash,
5715     &setup.editor_cascade.el_bd,
5716     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
5717     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
5718   },
5719   {
5720     &setup_editor_el_boulderdash_native,
5721     &setup.editor_cascade.el_bd_native,
5722     &editor_hl_boulderdash_native_ptr,  &num_editor_hl_boulderdash_native,
5723     &editor_el_boulderdash_native_ptr,  &num_editor_el_boulderdash_native
5724   },
5725   {
5726     &setup_editor_el_emerald_mine,
5727     &setup.editor_cascade.el_em,
5728     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
5729     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
5730   },
5731   {
5732     &setup_editor_el_emerald_mine_club,
5733     &setup.editor_cascade.el_emc,
5734     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
5735     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
5736   },
5737   {
5738     &setup_editor_el_more,
5739     &setup.editor_cascade.el_rnd,
5740     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
5741     &editor_el_rnd_ptr,                 &num_editor_el_rnd
5742   },
5743   {
5744     &setup_editor_el_sokoban,
5745     &setup.editor_cascade.el_sb,
5746     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
5747     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
5748   },
5749   {
5750     &setup_editor_el_supaplex,
5751     &setup.editor_cascade.el_sp,
5752     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
5753     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
5754   },
5755   {
5756     &setup_editor_el_diamond_caves,
5757     &setup.editor_cascade.el_dc,
5758     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
5759     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
5760   },
5761   {
5762     &setup_editor_el_dx_boulderdash,
5763     &setup.editor_cascade.el_dx,
5764     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
5765     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
5766   },
5767   {
5768     &setup_editor_el_mirror_magic,
5769     &setup.editor_cascade.el_mm,
5770     &editor_hl_mirror_magic_ptr,        &num_editor_hl_mirror_magic,
5771     &editor_el_mirror_magic_ptr,        &num_editor_el_mirror_magic
5772   },
5773   {
5774     &setup_editor_el_deflektor,
5775     &setup.editor_cascade.el_df,
5776     &editor_hl_deflektor_ptr,           &num_editor_hl_deflektor,
5777     &editor_el_deflektor_ptr,           &num_editor_el_deflektor
5778   },
5779   {
5780     &setup_editor_el_chars,
5781     &setup.editor_cascade.el_chars,
5782     &editor_hl_chars_ptr,               &num_editor_hl_chars,
5783     &editor_el_chars_ptr,               &num_editor_el_chars
5784   },
5785   {
5786     &setup_editor_el_steel_chars,
5787     &setup.editor_cascade.el_steel_chars,
5788     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
5789     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
5790   },
5791   {
5792     &setup_editor_el_custom,
5793     &setup.editor_cascade.el_ce,
5794     &editor_hl_custom_ptr,              &num_editor_hl_custom,
5795     &editor_el_custom_ptr,              &num_editor_el_custom
5796   },
5797   {
5798     &setup_editor_el_custom,
5799     &setup.editor_cascade.el_ge,
5800     &editor_hl_group_ptr,               &num_editor_hl_group,
5801     &editor_el_group_ptr,               &num_editor_el_group
5802   },
5803   {
5804     &setup_editor_el_custom,
5805     &setup.editor_cascade.el_es,
5806     &editor_hl_empty_space_ptr,         &num_editor_hl_empty_space,
5807     &editor_el_empty_space_ptr,         &num_editor_el_empty_space
5808   },
5809   {
5810     &setup_editor_el_custom,
5811     &setup.editor_cascade.el_ref,
5812     &editor_hl_reference_ptr,           &num_editor_hl_reference,
5813     &editor_el_reference_ptr,           &num_editor_el_reference
5814   },
5815   {
5816     &setup_editor_el_user_defined,
5817     &setup.editor_cascade.el_user,
5818     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
5819     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
5820   },
5821   {
5822     &setup_editor_el_dynamic,
5823     &setup.editor_cascade.el_dynamic,
5824     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
5825     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
5826   },
5827   {
5828     &use_el_empty,
5829     &use_el_empty,
5830     &editor_hl_empty_ptr,               &num_editor_hl_empty,
5831     &editor_el_empty_ptr,               &num_editor_el_empty,
5832   },
5833   {
5834     NULL,
5835     NULL,
5836     NULL,                               NULL,
5837     NULL,                               NULL
5838   }
5839 };
5840
5841 static struct XY xy_directions[] =
5842 {
5843   { -1,  0 },
5844   { +1,  0 },
5845   {  0, -1 },
5846   {  0, +1 }
5847 };
5848
5849
5850 // ----------------------------------------------------------------------------
5851 // functions
5852 // ----------------------------------------------------------------------------
5853
5854 static int getMaxInfoTextLength(void)
5855 {
5856   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
5857 }
5858
5859 static int getTextWidthForGadget(char *text)
5860 {
5861   if (text == NULL)
5862     return 0;
5863
5864   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
5865 }
5866
5867 static int getTextWidthForDrawingArea(char *text)
5868 {
5869   if (text == NULL)
5870     return 0;
5871
5872   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
5873 }
5874
5875 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
5876 {
5877   return (gi->x + gi->width + getTextWidthForGadget(text));
5878 }
5879
5880 static char *getElementInfoText(int element)
5881 {
5882   char *info_text = NULL;
5883
5884   if (element < MAX_NUM_ELEMENTS)
5885   {
5886     if (strlen(element_info[element].description) > 0)
5887       info_text = element_info[element].description;
5888     else if (element_info[element].custom_description != NULL)
5889       info_text = element_info[element].custom_description;
5890     else if (element_info[element].editor_description != NULL)
5891       info_text = element_info[element].editor_description;
5892   }
5893
5894   if (info_text == NULL)
5895     info_text = INFOTEXT_UNKNOWN_ELEMENT;
5896
5897   return info_text;
5898 }
5899
5900 static char *getElementDescriptionFilenameExt(char *basename)
5901 {
5902   char *elements_subdir = ELEMENTS_DIRECTORY;
5903   static char *elements_subdir2 = NULL;
5904   static char *filename = NULL;
5905
5906   if (elements_subdir2 == NULL)
5907     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
5908
5909   checked_free(filename);
5910
5911   // 1st try: look for element description in current level set directory
5912   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
5913   if (fileExists(filename))
5914     return filename;
5915
5916   free(filename);
5917
5918   // 2nd try: look for element description in the game's base directory
5919   filename = getPath3(options.docs_directory, elements_subdir, basename);
5920   if (fileExists(filename))
5921     return filename;
5922
5923   return NULL;
5924 }
5925
5926 static char *getElementDescriptionFilename(int element)
5927 {
5928   char basename[MAX_FILENAME_LEN];
5929   char *filename;
5930
5931   // 1st try: look for element description file for exactly this element
5932   sprintf(basename, "%s.txt", element_info[element].token_name);
5933   filename = getElementDescriptionFilenameExt(basename);
5934   if (filename != NULL)
5935     return filename;
5936
5937   // 2nd try: look for element description file for this element's class
5938   sprintf(basename, "%s.txt", element_info[element].class_name);
5939   filename = getElementDescriptionFilenameExt(basename);
5940   if (filename != NULL)
5941     return filename;
5942
5943   // 3rd try: look for generic fallback text file for any element
5944   filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
5945   if (filename != NULL)
5946     return filename;
5947
5948   return NULL;
5949 }
5950
5951 static boolean suppressBorderElement(void)
5952 {
5953   return (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
5954           lev_fieldx <= MAX_ED_FIELDX &&
5955           lev_fieldy <= MAX_ED_FIELDY);
5956 }
5957
5958 static void InitDynamicEditorElementList(int **elements, int *num_elements)
5959 {
5960   boolean element_found[NUM_FILE_ELEMENTS];
5961   int i, x, y;
5962
5963   // initialize list of used elements to "not used"
5964   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5965     element_found[i] = FALSE;
5966
5967   // find all elements used in current level
5968   for (y = 0; y < lev_fieldy; y++)
5969   {
5970     for (x = 0; x < lev_fieldx; x++)
5971     {
5972       if (Tile[x][y] >= NUM_FILE_ELEMENTS)      // should never happen
5973         continue;
5974
5975       if (IS_MM_WALL(Tile[x][y]))
5976         element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
5977       else
5978         element_found[Tile[x][y]] = TRUE;
5979     }
5980   }
5981
5982   *num_elements = 0;
5983
5984   // count number of elements used in current level
5985   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5986     if (element_found[i])
5987       (*num_elements)++;
5988
5989   // add space for up to 3 more elements for padding that may be needed
5990   *num_elements += 3;
5991
5992   // free memory for old list of elements, if needed
5993   checked_free(*elements);
5994
5995   // allocate memory for new list of elements
5996   *elements = checked_malloc(*num_elements * sizeof(int));
5997
5998   *num_elements = 0;
5999
6000   // add all elements used in current level (non-custom/group/empty elements)
6001   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6002     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
6003                               IS_GROUP_ELEMENT(i) ||
6004                               IS_EMPTY_ELEMENT(i)))
6005       (*elements)[(*num_elements)++] = i;
6006
6007   // add all elements used in current level (custom/group/empty elements)
6008   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6009     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
6010                              IS_GROUP_ELEMENT(i) ||
6011                              IS_EMPTY_ELEMENT(i)))
6012       (*elements)[(*num_elements)++] = i;
6013
6014   while (*num_elements % 4)     // pad with empty elements, if needed
6015     (*elements)[(*num_elements)++] = EL_EMPTY;
6016 }
6017
6018 static void ReinitializeElementList_EnableSections(void)
6019 {
6020   // default: enable all element sections
6021
6022   setup_editor_el_players               = TRUE;
6023   setup_editor_el_boulderdash           = TRUE;
6024   setup_editor_el_boulderdash_native    = TRUE;
6025   setup_editor_el_emerald_mine          = TRUE;
6026   setup_editor_el_emerald_mine_club     = TRUE;
6027   setup_editor_el_more                  = TRUE;
6028   setup_editor_el_sokoban               = TRUE;
6029   setup_editor_el_supaplex              = TRUE;
6030   setup_editor_el_diamond_caves         = TRUE;
6031   setup_editor_el_dx_boulderdash        = TRUE;
6032   setup_editor_el_mirror_magic          = TRUE;
6033   setup_editor_el_deflektor             = TRUE;
6034   setup_editor_el_chars                 = TRUE;
6035   setup_editor_el_steel_chars           = TRUE;
6036
6037   setup_editor_el_custom                = TRUE;
6038   setup_editor_el_user_defined          = TRUE;
6039   setup_editor_el_dynamic               = TRUE;
6040
6041   // now disable all element sections not to be displayed
6042
6043   if (!setup.editor.el_classic)
6044   {
6045     setup_editor_el_players             = FALSE;
6046     setup_editor_el_boulderdash         = FALSE;
6047     setup_editor_el_boulderdash_native  = FALSE;
6048     setup_editor_el_emerald_mine        = FALSE;
6049     setup_editor_el_emerald_mine_club   = FALSE;
6050     setup_editor_el_more                = FALSE;
6051     setup_editor_el_sokoban             = FALSE;
6052     setup_editor_el_supaplex            = FALSE;
6053     setup_editor_el_diamond_caves       = FALSE;
6054     setup_editor_el_dx_boulderdash      = FALSE;
6055     setup_editor_el_mirror_magic        = FALSE;
6056     setup_editor_el_deflektor           = FALSE;
6057     setup_editor_el_chars               = FALSE;
6058     setup_editor_el_steel_chars         = FALSE;
6059   }
6060
6061   if (!setup.editor.el_custom)
6062   {
6063     setup_editor_el_custom              = FALSE;
6064   }
6065
6066   if (!setup.editor.el_user_defined)
6067   {
6068     setup_editor_el_user_defined        = FALSE;
6069   }
6070
6071   if (!setup.editor.el_dynamic)
6072   {
6073     setup_editor_el_dynamic             = FALSE;
6074   }
6075
6076   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
6077   {
6078     setup_editor_el_boulderdash_native  = FALSE;
6079     setup_editor_el_mirror_magic        = FALSE;
6080     setup_editor_el_deflektor           = FALSE;
6081   }
6082   else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
6083   {
6084     setup_editor_el_players             = FALSE;
6085     setup_editor_el_boulderdash         = FALSE;
6086     setup_editor_el_emerald_mine        = FALSE;
6087     setup_editor_el_emerald_mine_club   = FALSE;
6088     setup_editor_el_more                = FALSE;
6089     setup_editor_el_sokoban             = FALSE;
6090     setup_editor_el_supaplex            = FALSE;
6091     setup_editor_el_diamond_caves       = FALSE;
6092     setup_editor_el_dx_boulderdash      = FALSE;
6093     setup_editor_el_mirror_magic        = FALSE;
6094     setup_editor_el_deflektor           = FALSE;
6095     setup_editor_el_chars               = FALSE;
6096     setup_editor_el_steel_chars         = FALSE;
6097
6098     setup_editor_el_custom              = FALSE;
6099   }
6100   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6101   {
6102     setup_editor_el_boulderdash         = FALSE;
6103     setup_editor_el_boulderdash_native  = FALSE;
6104     setup_editor_el_more                = FALSE;
6105     setup_editor_el_sokoban             = FALSE;
6106     setup_editor_el_supaplex            = FALSE;
6107     setup_editor_el_diamond_caves       = FALSE;
6108     setup_editor_el_dx_boulderdash      = FALSE;
6109     setup_editor_el_mirror_magic        = FALSE;
6110     setup_editor_el_deflektor           = FALSE;
6111     setup_editor_el_steel_chars         = FALSE;
6112
6113     setup_editor_el_custom              = FALSE;
6114   }
6115   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6116   {
6117     setup_editor_el_players             = FALSE;
6118     setup_editor_el_boulderdash         = FALSE;
6119     setup_editor_el_boulderdash_native  = FALSE;
6120     setup_editor_el_emerald_mine        = FALSE;
6121     setup_editor_el_emerald_mine_club   = FALSE;
6122     setup_editor_el_more                = FALSE;
6123     setup_editor_el_sokoban             = FALSE;
6124     setup_editor_el_diamond_caves       = FALSE;
6125     setup_editor_el_dx_boulderdash      = FALSE;
6126     setup_editor_el_mirror_magic        = FALSE;
6127     setup_editor_el_deflektor           = FALSE;
6128     setup_editor_el_chars               = FALSE;
6129     setup_editor_el_steel_chars         = FALSE;
6130
6131     setup_editor_el_custom              = FALSE;
6132   }
6133   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
6134   {
6135     setup_editor_el_players             = FALSE;
6136     setup_editor_el_boulderdash         = FALSE;
6137     setup_editor_el_boulderdash_native  = FALSE;
6138     setup_editor_el_emerald_mine        = FALSE;
6139     setup_editor_el_emerald_mine_club   = FALSE;
6140     setup_editor_el_more                = FALSE;
6141     setup_editor_el_sokoban             = FALSE;
6142     setup_editor_el_supaplex            = FALSE;
6143     setup_editor_el_diamond_caves       = FALSE;
6144     setup_editor_el_dx_boulderdash      = FALSE;
6145     setup_editor_el_steel_chars         = FALSE;
6146
6147     setup_editor_el_custom              = FALSE;
6148   }
6149 }
6150
6151 static void ReinitializeElementList(void)
6152 {
6153   static boolean initialization_needed = TRUE;
6154   int pos = 0;
6155   int i, j;
6156
6157   ReinitializeElementList_EnableSections();
6158
6159   if (initialization_needed)
6160   {
6161     LoadSetup_EditorCascade();          // load last editor cascade state
6162
6163     // initialize editor cascade element from saved cascade state
6164     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6165     {
6166       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
6167       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
6168
6169       if (IS_EDITOR_CASCADE(*cascade_element))
6170         *cascade_element =
6171           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
6172            EL_CASCADE_INACTIVE(*cascade_element));
6173     }
6174
6175     initialization_needed = FALSE;
6176   }
6177
6178   checked_free(editor_elements);
6179
6180   // reload optional user defined element list for each invocation of editor
6181   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
6182                                    &num_editor_el_user_defined);
6183
6184   // initialize dynamic level element list for each invocation of editor
6185   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
6186                                &num_editor_el_dynamic);
6187
6188   // initialize list of empty elements (used for padding, if needed)
6189   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
6190     editor_el_empty[i] = EL_EMPTY;
6191
6192   // do some sanity checks for each element from element list
6193   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6194   {
6195     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
6196     {
6197       int element = (*editor_elements_info[i].element_list)[j];
6198
6199       if (element >= NUM_FILE_ELEMENTS)
6200         Warn("editor element %d is runtime element", element);
6201
6202       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
6203         Warn("no element description text for element %d", element);
6204     }
6205   }
6206
6207   num_editor_elements = 0;
6208   use_el_empty = FALSE;
6209
6210   // determine size of element list
6211   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6212   {
6213     if (*editor_elements_info[i].setup_value)
6214     {
6215       boolean found_inactive_cascade = FALSE;
6216
6217       if (setup.editor.el_headlines)
6218       {
6219         // required for correct padding of palette headline buttons
6220         if (*editor_elements_info[i].headline_list_size > 0)
6221           num_editor_elements += ED_ELEMENTLIST_COLS;
6222
6223         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
6224         {
6225           int element = (*editor_elements_info[i].headline_list)[j];
6226
6227           if (IS_EDITOR_CASCADE_INACTIVE(element))
6228             found_inactive_cascade = TRUE;
6229         }
6230       }
6231
6232       if (found_inactive_cascade)
6233         continue;
6234
6235       // required for correct padding of palette element buttons
6236       int element_list_size = *editor_elements_info[i].element_list_size;
6237       int element_rows =
6238         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
6239       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
6240
6241       num_editor_elements += element_buttons;
6242     }
6243   }
6244
6245   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
6246   {
6247     // offer at least as many elements as element buttons exist
6248     use_el_empty = TRUE;
6249     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
6250
6251     num_editor_elements += num_editor_el_empty;
6252   }
6253   else
6254   {
6255     num_editor_el_empty = 0;
6256   }
6257
6258   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
6259
6260   // fill element list
6261   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6262   {
6263     boolean found_inactive_cascade = FALSE;
6264
6265     if (*editor_elements_info[i].setup_value)
6266     {
6267       if (setup.editor.el_headlines)
6268       {
6269         // required for correct padding of palette headline buttons
6270         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
6271                              ED_ELEMENTLIST_COLS : 0);
6272
6273         for (j = 0; j < headline_size; j++)
6274         {
6275           // use empty elements for padding of palette headline buttons
6276           int element = (j < *editor_elements_info[i].headline_list_size ?
6277                          (*editor_elements_info[i].headline_list)[j] :
6278                          editor_el_empty[0]);
6279
6280           editor_elements[pos++] = element;
6281
6282           if (IS_EDITOR_CASCADE_INACTIVE(element))
6283             found_inactive_cascade = TRUE;
6284         }
6285       }
6286
6287       if (found_inactive_cascade)
6288         continue;
6289
6290       // required for correct padding of palette element buttons
6291       int element_list_size = *editor_elements_info[i].element_list_size;
6292       int element_rows =
6293         (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
6294       int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
6295
6296       // copy all elements from element list
6297       for (j = 0; j < element_list_size; j++)
6298         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
6299
6300       // use empty elements for padding of palette element buttons
6301       for (j = 0; j < element_buttons - element_list_size; j++)
6302         editor_elements[pos++] = editor_el_empty[0];
6303     }
6304   }
6305
6306   // (this function is also called before editor gadgets are initialized!)
6307   AdjustElementListScrollbar();
6308 }
6309
6310 void PrintEditorElementList(void)
6311 {
6312   boolean *stop = &setup_editor_el_user_defined;
6313   int i, j;
6314
6315   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
6316   {
6317     int cascade_element = (*editor_elements_info[i].headline_list)[0];
6318
6319     if (IS_EDITOR_CASCADE(cascade_element))
6320     {
6321       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
6322       char *headline = element_info[cascade_element_show].editor_description;
6323
6324       PrintLineWithPrefix("# ", "-", 77);
6325       Print("# %s\n", headline);
6326       PrintLineWithPrefix("# ", "-", 77);
6327     }
6328
6329     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
6330     {
6331       int element = (*editor_elements_info[i].headline_list)[j];
6332
6333       if (IS_EDITOR_CASCADE(element))
6334         element = EL_CHAR_MINUS;
6335
6336       Print("# %s\n", element_info[element].token_name);
6337     }
6338
6339     if (j > 0)
6340       Print("#\n");
6341
6342     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
6343     {
6344       int element = (*editor_elements_info[i].element_list)[j];
6345
6346       Print("# %s\n", element_info[element].token_name);
6347     }
6348
6349     if (j > 0)
6350       Print("#\n");
6351   }
6352 }
6353
6354 static void ReinitializeElementListButtons(void)
6355 {
6356   static boolean last_setup_value_headlines = FALSE;
6357   static boolean initialization_needed = TRUE;
6358   int i;
6359
6360   if (!initialization_needed)   // check if editor element setup has changed
6361   {
6362     if (last_setup_value_headlines != setup.editor.el_headlines)
6363       initialization_needed = TRUE;
6364
6365     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6366       if (editor_elements_info[i].last_setup_value !=
6367           *editor_elements_info[i].setup_value)
6368         initialization_needed = TRUE;
6369   }
6370
6371   if (!initialization_needed)
6372     return;
6373
6374   FreeLevelEditorGadgets();
6375   CreateLevelEditorGadgets();
6376
6377   // store current setup values for next invocation of this function
6378   last_setup_value_headlines = setup.editor.el_headlines;
6379   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
6380     editor_elements_info[i].last_setup_value =
6381       *editor_elements_info[i].setup_value;
6382
6383   initialization_needed = FALSE;
6384 }
6385
6386 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
6387                               boolean input)
6388 {
6389   int border_graphic =
6390     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
6391   struct GraphicInfo *g = &graphic_info[border_graphic];
6392   Bitmap *src_bitmap = g->bitmap;
6393   int src_x = g->src_x;
6394   int src_y = g->src_y;
6395   int border_size = g->border_size;
6396   int border_xpos = g->width  - border_size;
6397   int border_ypos = g->height - border_size;
6398   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
6399   int i;
6400
6401   BlitBitmap(src_bitmap, drawto, src_x, src_y,
6402              border_size, border_size,
6403              dest_x - border_size, dest_y - border_size);
6404   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
6405              border_size, border_size,
6406              dest_x + width, dest_y - border_size);
6407   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
6408              border_size, border_size,
6409              dest_x - border_size, dest_y + height);
6410   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
6411              border_size, border_size,
6412              dest_x + width, dest_y + height);
6413
6414   for (i = 0; i < width / tilesize; i++)
6415   {
6416     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
6417                tilesize, border_size,
6418                dest_x + i * tilesize, dest_y - border_size);
6419     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
6420                tilesize, border_size,
6421                dest_x + i * tilesize, dest_y + height);
6422   }
6423
6424   for (i = 0; i < height / tilesize; i++)
6425   {
6426     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
6427                border_size, tilesize,
6428                dest_x - border_size, dest_y + i * tilesize);
6429     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
6430                border_size, tilesize,
6431                dest_x + width, dest_y + i * tilesize);
6432   }
6433
6434   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
6435 }
6436
6437 static void DrawEditorLevelBorderLine(int x, int y, int xsize, int ysize)
6438 {
6439   int xsize_tile = MAX(ed_tilesize, xsize);
6440   int ysize_tile = MAX(ed_tilesize, ysize);
6441   int xsize_full = xsize + 1;
6442   int ysize_full = ysize + 1;
6443   int xsize_thin = (xsize < ed_tilesize ? 1 : xsize);
6444   int ysize_thin = (ysize < ed_tilesize ? 1 : ysize);
6445   Pixel line_color = getTabulatorBarColor();
6446
6447   if (line_color == BLACK_PIXEL)                // black => transparent
6448     return;
6449
6450   FillRectangle(drawto, SX + x, SY + y, xsize_tile, ysize_tile, BLACK_PIXEL);
6451   FillRectangle(drawto, SX + x, SY + y, xsize_full, ysize_full, line_color);
6452   FillRectangle(drawto, SX + x, SY + y, xsize_thin, ysize_thin, BLACK_PIXEL);
6453 }
6454
6455 static void DrawEditorLevelBorderLinesIfNeeded(void)
6456 {
6457   int xsize = lev_fieldx * ed_tilesize;
6458   int ysize = lev_fieldy * ed_tilesize;
6459   int line_size = getTabulatorBarHeight();
6460
6461   if (!suppressBorderElement())
6462     return;
6463
6464   // draw little border line around editable level playfield
6465
6466   if (xsize < SXSIZE)
6467     DrawEditorLevelBorderLine(xsize, 0, line_size, ysize);
6468
6469   if (ysize < SYSIZE)
6470     DrawEditorLevelBorderLine(0, ysize, xsize, line_size);
6471
6472   if (xsize < SXSIZE && ysize < SYSIZE)
6473     DrawEditorLevelBorderLine(xsize, ysize, line_size, line_size);
6474 }
6475
6476 static void DrawEditorElement(int x, int y, int element)
6477 {
6478   DrawSizedElement(x, y, element, ed_tilesize);
6479 }
6480
6481 static void DrawEditorElementThruMask(int x, int y, int element)
6482 {
6483   DrawSizedElementThruMask(x, y, element, ed_tilesize);
6484 }
6485
6486 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
6487 {
6488   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
6489 }
6490
6491 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
6492 {
6493   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
6494   DrawEditorLevelBorderLinesIfNeeded();
6495 }
6496
6497 static void DrawDrawingArea(int id)
6498 {
6499   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
6500   int x, y;
6501
6502   int *value = drawingarea_info[id].value;
6503   int area_xsize = drawingarea_info[id].area_xsize;
6504   int area_ysize = drawingarea_info[id].area_ysize;
6505   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
6506
6507   for (x = 0; x < area_xsize; x++)
6508     for (y = 0; y < area_ysize; y++)
6509       DrawSizedGraphicExt(drawto,
6510                           gi->x + x * tilesize,
6511                           gi->y + y * tilesize,
6512                           el2edimg(value[x * area_ysize + y]), 0, tilesize);
6513 }
6514
6515 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
6516 {
6517   int x, y;
6518   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
6519   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
6520
6521   BlitBitmap(drawto, drawto,
6522              SX + (dx == -1 ? ed_tilesize : 0),
6523              SY + (dy == -1 ? ed_tilesize : 0),
6524              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
6525              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
6526              SX + (dx == +1 ? ed_tilesize : 0),
6527              SY + (dy == +1 ? ed_tilesize : 0));
6528
6529   if (dx)
6530   {
6531     x = (dx == 1 ? 0 : ed_fieldx - 1);
6532     for (y = 0; y < ed_fieldy; y++)
6533       DrawEditorElementOrWall(x, y, from_x, from_y);
6534   }
6535   else if (dy)
6536   {
6537     y = (dy == 1 ? 0 : ed_fieldy - 1);
6538     for (x = 0; x < ed_fieldx; x++)
6539       DrawEditorElementOrWall(x, y, from_x, from_y);
6540   }
6541
6542   redraw_mask |= REDRAW_FIELD;
6543   BackToFront();
6544 }
6545
6546 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
6547                                    int *x, int *y)
6548 {
6549   getSizedGraphicSource(el2edimg(element), 0, tile_size, bitmap, x, y);
6550 }
6551
6552 static void CreateControlButtons(void)
6553 {
6554   struct GadgetInfo *gi;
6555   int i;
6556
6557   // create toolbox buttons
6558   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
6559   {
6560     int id = controlbutton_info[i].gadget_id;
6561     int type = controlbutton_info[i].gadget_type;
6562     int graphic = controlbutton_info[i].graphic;
6563     struct XYTileSize *pos = controlbutton_info[i].pos;
6564     struct GraphicInfo *gd = &graphic_info[graphic];
6565     Bitmap *deco_bitmap = NULL;
6566     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6567     int tile_size = 0, deco_shift = 0;
6568     boolean deco_masked = FALSE;
6569     int gd_x1 = gd->src_x;
6570     int gd_y1 = gd->src_y;
6571     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6572     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6573     int gd_x1a = gd->src_x + gd->active_xoffset;
6574     int gd_y1a = gd->src_y + gd->active_yoffset;
6575     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
6576     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
6577     int x = pos->x;
6578     int y = pos->y;
6579     unsigned int event_mask;
6580     int radio_button_nr = RADIO_NR_NONE;
6581     boolean checked = FALSE;
6582
6583     if (type == GD_TYPE_RADIO_BUTTON)
6584     {
6585       event_mask = GD_EVENT_PRESSED;
6586       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
6587
6588       if (id == drawing_function)
6589         checked = TRUE;
6590     }
6591     else
6592     {
6593       if (id == GADGET_ID_WRAP_LEFT ||
6594           id == GADGET_ID_WRAP_RIGHT ||
6595           id == GADGET_ID_WRAP_UP ||
6596           id == GADGET_ID_WRAP_DOWN)
6597         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6598       else
6599         event_mask = GD_EVENT_RELEASED;
6600     }
6601
6602     if (id == GADGET_ID_PROPERTIES ||
6603         id == GADGET_ID_PALETTE)
6604     {
6605       x += DX;
6606       y += DY;
6607     }
6608     else if (id == GADGET_ID_ELEMENT_LEFT ||
6609              id == GADGET_ID_ELEMENT_MIDDLE ||
6610              id == GADGET_ID_ELEMENT_RIGHT)
6611     {
6612       x += DX;
6613       y += DY;
6614
6615       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
6616                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
6617                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
6618
6619       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
6620                                    editor.button.element_left.tile_size :
6621                                    id == GADGET_ID_ELEMENT_MIDDLE ?
6622                                    editor.button.element_middle.tile_size :
6623                                    id == GADGET_ID_ELEMENT_RIGHT ?
6624                                    editor.button.element_right.tile_size : 0);
6625
6626       // make sure that decoration does not overlap gadget border
6627       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
6628
6629       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
6630
6631       deco_xpos = (gd->width  - tile_size) / 2;
6632       deco_ypos = (gd->height - tile_size) / 2;
6633       deco_shift = 1;
6634       deco_masked = gd->draw_masked;
6635     }
6636     else
6637     {
6638       x += EX;
6639       y += EY;
6640     }
6641
6642     gi = CreateGadget(GDI_CUSTOM_ID, id,
6643                       GDI_CUSTOM_TYPE_ID, i,
6644                       GDI_IMAGE_ID, graphic,
6645                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
6646                       GDI_X, x,
6647                       GDI_Y, y,
6648                       GDI_WIDTH, gd->width,
6649                       GDI_HEIGHT, gd->height,
6650                       GDI_TYPE, type,
6651                       GDI_STATE, GD_BUTTON_UNPRESSED,
6652                       GDI_RADIO_NR, radio_button_nr,
6653                       GDI_CHECKED, checked,
6654                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6655                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6656                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6657                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
6658                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6659                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6660                       GDI_DECORATION_SIZE, tile_size, tile_size,
6661                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
6662                       GDI_DECORATION_MASKED, deco_masked,
6663                       GDI_EVENT_MASK, event_mask,
6664                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6665                       GDI_CALLBACK_ACTION, HandleControlButtons,
6666                       GDI_END);
6667
6668     if (gi == NULL)
6669       Fail("cannot create gadget");
6670
6671     level_editor_gadget[id] = gi;
6672   }
6673
6674   // these values are not constant, but can change at runtime
6675   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
6676   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
6677   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
6678   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
6679   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
6680   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
6681   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
6682   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
6683   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
6684   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
6685   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
6686   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
6687
6688   // create buttons for scrolling of drawing area and element list
6689   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
6690   {
6691     int id = scrollbutton_info[i].gadget_id;
6692     int graphic = scrollbutton_info[i].graphic;
6693     struct GraphicInfo *gd = &graphic_info[graphic];
6694     Bitmap *gd_bitmap = gd->bitmap;
6695     int gd_x1 = gd->src_x;
6696     int gd_y1 = gd->src_y;
6697     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6698     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6699     int width  = gd->width;
6700     int height = gd->height;
6701     int x = scrollbutton_pos[i].x;
6702     int y = scrollbutton_pos[i].y;
6703     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6704
6705     if (id == GADGET_ID_SCROLL_LIST_UP ||
6706         id == GADGET_ID_SCROLL_LIST_DOWN)
6707     {
6708       x += PX;
6709       y += PY;
6710     }
6711     else
6712     {
6713       x += SX;
6714       y += SY;
6715     }
6716
6717     gi = CreateGadget(GDI_CUSTOM_ID, id,
6718                       GDI_CUSTOM_TYPE_ID, i,
6719                       GDI_IMAGE_ID, graphic,
6720                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
6721                       GDI_X, x,
6722                       GDI_Y, y,
6723                       GDI_WIDTH, width,
6724                       GDI_HEIGHT, height,
6725                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6726                       GDI_STATE, GD_BUTTON_UNPRESSED,
6727                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6728                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6729                       GDI_EVENT_MASK, event_mask,
6730                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6731                       GDI_CALLBACK_ACTION, HandleControlButtons,
6732                       GDI_END);
6733
6734     if (gi == NULL)
6735       Fail("cannot create gadget");
6736
6737     level_editor_gadget[id] = gi;
6738   }
6739
6740   // create buttons for element list
6741   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
6742   {
6743     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
6744     int graphic = IMG_EDITOR_PALETTE_BUTTON;
6745     struct GraphicInfo *gd = &graphic_info[graphic];
6746     Bitmap *gd_bitmap = gd->bitmap;
6747     Bitmap *deco_bitmap;
6748     int deco_x, deco_y, deco_xpos, deco_ypos;
6749     int gd_x1 = gd->src_x;
6750     int gd_y1 = gd->src_y;
6751     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6752     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6753     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
6754     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
6755     int x = PX + ED_ELEMENTLIST_XPOS + xx * gd->width;
6756     int y = PY + ED_ELEMENTLIST_YPOS + yy * gd->height;
6757     int element = editor_elements[i];
6758     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
6759     unsigned int event_mask = GD_EVENT_RELEASED;
6760
6761     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
6762
6763     deco_xpos = (gd->width  - tile_size) / 2;
6764     deco_ypos = (gd->height - tile_size) / 2;
6765
6766     gi = CreateGadget(GDI_CUSTOM_ID, id,
6767                       GDI_CUSTOM_TYPE_ID, i,
6768                       GDI_IMAGE_ID, graphic,
6769                       GDI_INFO_TEXT, getElementInfoText(element),
6770                       GDI_X, x,
6771                       GDI_Y, y,
6772                       GDI_WIDTH, gd->width,
6773                       GDI_HEIGHT, gd->height,
6774                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6775                       GDI_STATE, GD_BUTTON_UNPRESSED,
6776                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
6777                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
6778                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6779                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6780                       GDI_DECORATION_SIZE, tile_size, tile_size,
6781                       GDI_DECORATION_SHIFTING, 1, 1,
6782                       GDI_EVENT_MASK, event_mask,
6783                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6784                       GDI_CALLBACK_ACTION, HandleControlButtons,
6785                       GDI_END);
6786
6787     if (gi == NULL)
6788       Fail("cannot create gadget");
6789
6790     level_editor_gadget[id] = gi;
6791   }
6792 }
6793
6794 static void CreateCounterButtons(void)
6795 {
6796   int max_infotext_len = getMaxInfoTextLength();
6797   int i;
6798
6799   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
6800   {
6801     int j;
6802     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
6803     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
6804
6805     // determine horizontal position to the right of specified gadget
6806     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6807       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
6808            ED_GADGET_TEXT_DISTANCE);
6809
6810     // determine horizontal offset for leading text
6811     if (counterbutton_info[i].text_left != NULL)
6812       x += getTextWidthForGadget(counterbutton_info[i].text_left);
6813
6814     for (j = 0; j < 2; j++)
6815     {
6816       struct GadgetInfo *gi;
6817       int id = (j == 0 ?
6818                 counterbutton_info[i].gadget_id_down :
6819                 counterbutton_info[i].gadget_id_up);
6820       int graphic;
6821       struct GraphicInfo *gd;
6822       int gd_x1, gd_x2, gd_y1, gd_y2;
6823       unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6824       char infotext[max_infotext_len + 1];
6825
6826       if (i == ED_COUNTER_ID_SELECT_LEVEL)
6827       {
6828         graphic = (j == 0 ?
6829                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
6830                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
6831
6832         event_mask |= GD_EVENT_RELEASED;
6833
6834         if (j == 0)
6835         {
6836           x = DX + editor.button.prev_level.x;
6837           y = DY + editor.button.prev_level.y;
6838         }
6839         else
6840         {
6841           x = DX + editor.button.next_level.x;
6842           y = DY + editor.button.next_level.y;
6843         }
6844       }
6845       else
6846       {
6847         graphic = (j == 0 ?
6848                    IMG_EDITOR_COUNTER_DOWN :
6849                    IMG_EDITOR_COUNTER_UP);
6850       }
6851
6852       gd = &graphic_info[graphic];
6853
6854       gd_x1 = gd->src_x;
6855       gd_y1 = gd->src_y;
6856       gd_x2 = gd->src_x + gd->pressed_xoffset;
6857       gd_y2 = gd->src_y + gd->pressed_yoffset;
6858
6859       sprintf(infotext, "%s counter value by 1, 5 or 10",
6860               (j == 0 ? "decrease" : "increase"));
6861
6862       gi = CreateGadget(GDI_CUSTOM_ID, id,
6863                         GDI_CUSTOM_TYPE_ID, i,
6864                         GDI_IMAGE_ID, graphic,
6865                         GDI_INFO_TEXT, infotext,
6866                         GDI_X, x,
6867                         GDI_Y, y,
6868                         GDI_WIDTH, gd->width,
6869                         GDI_HEIGHT, gd->height,
6870                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6871                         GDI_STATE, GD_BUTTON_UNPRESSED,
6872                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6873                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6874                         GDI_EVENT_MASK, event_mask,
6875                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6876                         GDI_CALLBACK_ACTION, HandleCounterButtons,
6877                         GDI_END);
6878
6879       if (gi == NULL)
6880         Fail("cannot create gadget");
6881
6882       level_editor_gadget[id] = gi;
6883       right_gadget_border[id] =
6884         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
6885
6886       x += gi->width + ED_GADGET_SMALL_DISTANCE;        // text count button
6887
6888       if (j == 0)
6889       {
6890         int font_type = FONT_INPUT_1;
6891         int font_type_active = FONT_INPUT_1_ACTIVE;
6892
6893         id = counterbutton_info[i].gadget_id_text;
6894
6895         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
6896
6897         if (i == ED_COUNTER_ID_SELECT_LEVEL)
6898         {
6899           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
6900
6901           font_type = FONT_LEVEL_NUMBER;
6902           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
6903
6904           x = DX + editor.input.level_number.x;
6905           y = DY + editor.input.level_number.y;
6906         }
6907         else
6908         {
6909           graphic = IMG_EDITOR_COUNTER_INPUT;
6910         }
6911
6912         gd = &graphic_info[graphic];
6913
6914         gd_x1 = gd->src_x;
6915         gd_y1 = gd->src_y;
6916         gd_x2 = gd->src_x + gd->active_xoffset;
6917         gd_y2 = gd->src_y + gd->active_yoffset;
6918
6919         gi = CreateGadget(GDI_CUSTOM_ID, id,
6920                           GDI_CUSTOM_TYPE_ID, i,
6921                           GDI_IMAGE_ID, graphic,
6922                           GDI_INFO_TEXT, "enter counter value",
6923                           GDI_X, x,
6924                           GDI_Y, y,
6925                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
6926                           GDI_NUMBER_VALUE, 0,
6927                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
6928                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
6929                           GDI_TEXT_SIZE, 3,     // minimal counter text size
6930                           GDI_TEXT_FONT, font_type,
6931                           GDI_TEXT_FONT_ACTIVE, font_type_active,
6932                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6933                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6934                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
6935                           GDI_DESIGN_WIDTH, gd->width,
6936                           GDI_EVENT_MASK, event_mask,
6937                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6938                           GDI_CALLBACK_ACTION, HandleCounterButtons,
6939                           GDI_END);
6940
6941         if (gi == NULL)
6942           Fail("cannot create gadget");
6943
6944         level_editor_gadget[id] = gi;
6945         right_gadget_border[id] =
6946           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
6947
6948         x += gi->width + ED_GADGET_SMALL_DISTANCE;      // up count button
6949       }
6950     }
6951   }
6952 }
6953
6954 static void CreateDrawingAreas(void)
6955 {
6956   int i;
6957
6958   // these values are not constant, but can change at runtime
6959   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
6960   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
6961
6962   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
6963   {
6964     struct GadgetInfo *gi;
6965     int id = drawingarea_info[i].gadget_id;
6966     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
6967     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
6968     int area_xsize = drawingarea_info[i].area_xsize;
6969     int area_ysize = drawingarea_info[i].area_ysize;
6970     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
6971                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
6972     unsigned int event_mask =
6973       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
6974       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
6975
6976     // determine horizontal position to the right of specified gadget
6977     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
6978       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
6979            ED_DRAWINGAREA_TEXT_DISTANCE);
6980
6981     // determine horizontal offset for leading text
6982     if (drawingarea_info[i].text_left != NULL)
6983       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
6984
6985     gi = CreateGadget(GDI_CUSTOM_ID, id,
6986                       GDI_CUSTOM_TYPE_ID, i,
6987                       GDI_X, x,
6988                       GDI_Y, y,
6989                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
6990                       GDI_AREA_SIZE, area_xsize, area_ysize,
6991                       GDI_ITEM_SIZE, item_size, item_size,
6992                       GDI_EVENT_MASK, event_mask,
6993                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
6994                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
6995                       GDI_END);
6996
6997     if (gi == NULL)
6998       Fail("cannot create gadget");
6999
7000     level_editor_gadget[id] = gi;
7001     right_gadget_border[id] =
7002       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
7003   }
7004 }
7005
7006 static void CreateTextInputGadgets(void)
7007 {
7008   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
7009   int max_infotext_len = getMaxInfoTextLength();
7010   int i;
7011
7012   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
7013   {
7014     int gd_x1 = gd->src_x;
7015     int gd_y1 = gd->src_y;
7016     int gd_x2 = gd->src_x + gd->active_xoffset;
7017     int gd_y2 = gd->src_y + gd->active_yoffset;
7018     struct GadgetInfo *gi;
7019     unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
7020     char infotext[MAX_OUTPUT_LINESIZE + 1];
7021     int id = textinput_info[i].gadget_id;
7022     int x, y;
7023
7024     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
7025     {
7026       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
7027       int border_size = gd->border_size;
7028       int font_nr = FONT_INPUT_1;
7029       int font_height = getFontHeight(font_nr);
7030       int xoffset = element_border + TILEX + element_border + 3 * border_size;
7031       int yoffset = element_border + (TILEY - font_height) / 2;
7032
7033       x = (editor.settings.element_name.x != -1 ?
7034            editor.settings.element_name.x :
7035            editor.settings.element_graphic.x + xoffset) - border_size;
7036       y = (editor.settings.element_name.y != -1 ?
7037            editor.settings.element_name.y :
7038            editor.settings.element_graphic.y + yoffset) - border_size;
7039     }
7040     else
7041     {
7042       x = ED_SETTINGS_X(textinput_info[i].x);
7043       y = ED_SETTINGS_Y(textinput_info[i].y);
7044     }
7045
7046     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
7047     infotext[max_infotext_len] = '\0';
7048
7049     gi = CreateGadget(GDI_CUSTOM_ID, id,
7050                       GDI_CUSTOM_TYPE_ID, i,
7051                       GDI_INFO_TEXT, infotext,
7052                       GDI_X, SX + x,
7053                       GDI_Y, SY + y,
7054                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
7055                       GDI_TEXT_VALUE, textinput_info[i].value,
7056                       GDI_TEXT_SIZE, textinput_info[i].size,
7057                       GDI_TEXT_FONT, FONT_INPUT_1,
7058                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
7059                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7060                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7061                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
7062                       GDI_DESIGN_WIDTH, gd->width,
7063                       GDI_EVENT_MASK, event_mask,
7064                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7065                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
7066                       GDI_END);
7067
7068     if (gi == NULL)
7069       Fail("cannot create gadget");
7070
7071     level_editor_gadget[id] = gi;
7072   }
7073 }
7074
7075 static void CreateTextAreaGadgets(void)
7076 {
7077   int max_infotext_len = getMaxInfoTextLength();
7078   int i;
7079
7080   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
7081   {
7082     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
7083     int gd_x1 = gd->src_x;
7084     int gd_y1 = gd->src_y;
7085     int gd_x2 = gd->src_x + gd->active_xoffset;
7086     int gd_y2 = gd->src_y + gd->active_yoffset;
7087     struct GadgetInfo *gi;
7088     unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
7089     char infotext[MAX_OUTPUT_LINESIZE + 1];
7090     int id = textarea_info[i].gadget_id;
7091     int area_xsize = textarea_info[i].xsize;
7092     int area_ysize = textarea_info[i].ysize;
7093
7094     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
7095     infotext[max_infotext_len] = '\0';
7096
7097     gi = CreateGadget(GDI_CUSTOM_ID, id,
7098                       GDI_CUSTOM_TYPE_ID, i,
7099                       GDI_INFO_TEXT, infotext,
7100                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
7101                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
7102                       GDI_TYPE, GD_TYPE_TEXT_AREA,
7103                       GDI_AREA_SIZE, area_xsize, area_ysize,
7104                       GDI_TEXT_FONT, FONT_INPUT_1,
7105                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
7106                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7107                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7108                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
7109                       GDI_DESIGN_WIDTH, gd->width,
7110                       GDI_EVENT_MASK, event_mask,
7111                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7112                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
7113                       GDI_END);
7114
7115     if (gi == NULL)
7116       Fail("cannot create gadget");
7117
7118     level_editor_gadget[id] = gi;
7119   }
7120 }
7121
7122 static void CreateSelectboxGadgets(void)
7123 {
7124   int max_infotext_len = getMaxInfoTextLength();
7125   int i, j;
7126
7127   for (i = 0; i < ED_NUM_SELECTBOX; i++)
7128   {
7129     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
7130     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
7131     int gd_x1 = gd->src_x;
7132     int gd_y1 = gd->src_y;
7133     int gd_x2 = gd->src_x + gd->active_xoffset;
7134     int gd_y2 = gd->src_y + gd->active_yoffset;
7135     int selectbox_button_xsize = gd2->width;
7136     struct GadgetInfo *gi;
7137     char infotext[MAX_OUTPUT_LINESIZE + 1];
7138     int id = selectbox_info[i].gadget_id;
7139     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
7140     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
7141     unsigned int event_mask =
7142       GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
7143
7144     if (selectbox_info[i].size == -1)   // dynamically determine size
7145     {
7146       // (we cannot use -1 for uninitialized values if we directly compare
7147       // with results from strlen(), because the '<' and '>' operation will
7148       // implicitely cast -1 to an unsigned integer value!)
7149       selectbox_info[i].size = 0;
7150
7151       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
7152         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
7153           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
7154
7155       selectbox_info[i].size++;         // add one character empty space
7156     }
7157
7158     // determine horizontal position to the right of specified gadget
7159     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
7160       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
7161            ED_GADGET_TEXT_DISTANCE);
7162
7163     // determine horizontal offset for leading text
7164     if (selectbox_info[i].text_left != NULL)
7165       x += getTextWidthForGadget(selectbox_info[i].text_left);
7166
7167     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
7168     infotext[max_infotext_len] = '\0';
7169
7170     gi = CreateGadget(GDI_CUSTOM_ID, id,
7171                       GDI_CUSTOM_TYPE_ID, i,
7172                       GDI_INFO_TEXT, infotext,
7173                       GDI_X, x,
7174                       GDI_Y, y,
7175                       GDI_TYPE, GD_TYPE_SELECTBOX,
7176                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
7177                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
7178                       GDI_TEXT_SIZE, selectbox_info[i].size,
7179                       GDI_TEXT_FONT, FONT_INPUT_1,
7180                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
7181                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
7182                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7183                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7184                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
7185                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
7186                       GDI_DESIGN_WIDTH, gd->width,
7187                       GDI_EVENT_MASK, event_mask,
7188                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7189                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
7190                       GDI_END);
7191
7192     if (gi == NULL)
7193       Fail("cannot create gadget");
7194
7195     level_editor_gadget[id] = gi;
7196     right_gadget_border[id] =
7197       getRightGadgetBorder(gi, selectbox_info[i].text_right);
7198   }
7199 }
7200
7201 static void CreateTextbuttonGadgets(void)
7202 {
7203   int max_infotext_len = getMaxInfoTextLength();
7204   int i;
7205
7206   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
7207   {
7208     int id = textbutton_info[i].gadget_id;
7209     int is_tab_button =
7210       ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_EDITOR) ||
7211        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
7212     int graphic =
7213       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
7214     int gadget_distance =
7215       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
7216     struct GraphicInfo *gd = &graphic_info[graphic];
7217     int gd_x1 = gd->src_x;
7218     int gd_y1 = gd->src_y;
7219     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7220     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7221     int gd_x1a = gd->src_x + gd->active_xoffset;
7222     int gd_y1a = gd->src_y + gd->active_yoffset;
7223     int border_xsize = gd->border_size + gd->draw_xoffset;
7224     int border_ysize = gd->border_size;
7225     struct GadgetInfo *gi;
7226     unsigned int event_mask = GD_EVENT_RELEASED;
7227     char infotext[MAX_OUTPUT_LINESIZE + 1];
7228     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
7229     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
7230
7231     if (textbutton_info[i].size == -1)  // dynamically determine size
7232       textbutton_info[i].size = strlen(textbutton_info[i].text);
7233
7234     sprintf(infotext, "%s", textbutton_info[i].infotext);
7235     infotext[max_infotext_len] = '\0';
7236
7237     // determine horizontal position to the right of specified gadget
7238     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
7239     {
7240       int gadget_id_align = textbutton_info[i].gadget_id_align;
7241
7242       x = right_gadget_border[gadget_id_align] + gadget_distance;
7243
7244       if (textbutton_info[i].y == -1)
7245         y = level_editor_gadget[gadget_id_align]->y;
7246     }
7247
7248     // determine horizontal offset for leading text
7249     if (textbutton_info[i].text_left != NULL)
7250       x += getTextWidthForGadget(textbutton_info[i].text_left);
7251
7252     gi = CreateGadget(GDI_CUSTOM_ID, id,
7253                       GDI_CUSTOM_TYPE_ID, i,
7254                       GDI_IMAGE_ID, graphic,
7255                       GDI_INFO_TEXT, infotext,
7256                       GDI_X, x,
7257                       GDI_Y, y,
7258                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
7259                       GDI_TEXT_VALUE, textbutton_info[i].text,
7260                       GDI_TEXT_SIZE, textbutton_info[i].size,
7261                       GDI_TEXT_FONT, FONT_INPUT_2,
7262                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
7263                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7264                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7265                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7266                       GDI_BORDER_SIZE, border_xsize, border_ysize,
7267                       GDI_DESIGN_WIDTH, gd->width,
7268                       GDI_DECORATION_SHIFTING, 1, 1,
7269                       GDI_EVENT_MASK, event_mask,
7270                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7271                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
7272                       GDI_END);
7273
7274     if (gi == NULL)
7275       Fail("cannot create gadget");
7276
7277     level_editor_gadget[id] = gi;
7278     right_gadget_border[id] =
7279       getRightGadgetBorder(gi, textbutton_info[i].text_right);
7280   }
7281 }
7282
7283 static void CreateGraphicbuttonGadgets(void)
7284 {
7285   struct GadgetInfo *gi;
7286   int i;
7287
7288   // create buttons for scrolling of drawing area and element list
7289   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
7290   {
7291     int id = graphicbutton_info[i].gadget_id;
7292     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
7293     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
7294     int graphic = graphicbutton_info[i].graphic;
7295     struct GraphicInfo *gd = &graphic_info[graphic];
7296     int gd_x1 = gd->src_x;
7297     int gd_y1 = gd->src_y;
7298     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7299     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7300     unsigned int event_mask = GD_EVENT_RELEASED;
7301
7302     // determine horizontal position to the right of specified gadget
7303     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
7304       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
7305            ED_GADGET_TEXT_DISTANCE);
7306
7307     // determine horizontal offset for leading text
7308     if (graphicbutton_info[i].text_left != NULL)
7309       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
7310
7311     gi = CreateGadget(GDI_CUSTOM_ID, id,
7312                       GDI_CUSTOM_TYPE_ID, i,
7313                       GDI_IMAGE_ID, graphic,
7314                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
7315                       GDI_X, x,
7316                       GDI_Y, y,
7317                       GDI_WIDTH, gd->width,
7318                       GDI_HEIGHT, gd->height,
7319                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7320                       GDI_STATE, GD_BUTTON_UNPRESSED,
7321                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7322                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7323                       GDI_EVENT_MASK, event_mask,
7324                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7325                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
7326                       GDI_END);
7327
7328     if (gi == NULL)
7329       Fail("cannot create gadget");
7330
7331     level_editor_gadget[id] = gi;
7332     right_gadget_border[id] =
7333       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
7334   }
7335 }
7336
7337 static void CreateScrollbarGadgets(void)
7338 {
7339   int i;
7340
7341   // these values are not constant, but can change at runtime
7342   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
7343     SX + ED_SCROLL_HORIZONTAL_XPOS;
7344   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
7345     SY + ED_SCROLL_HORIZONTAL_YPOS;
7346   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
7347     ED_SCROLL_HORIZONTAL_XSIZE;
7348   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
7349     ED_SCROLL_HORIZONTAL_YSIZE;
7350   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
7351   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
7352   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
7353   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
7354
7355   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
7356     SX + ED_SCROLL_VERTICAL_XPOS;
7357   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
7358     SY + ED_SCROLL_VERTICAL_YPOS;
7359   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
7360     ED_SCROLL_VERTICAL_XSIZE;
7361   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
7362     ED_SCROLL_VERTICAL_YSIZE;
7363   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
7364   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
7365   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
7366   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
7367
7368   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
7369     PX + ED_SCROLL2_VERTICAL_XPOS;
7370   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
7371     PY + ED_SCROLL2_VERTICAL_YPOS;
7372   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
7373     ED_SCROLL2_VERTICAL_XSIZE;
7374   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
7375     ED_SCROLL2_VERTICAL_YSIZE;
7376   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = PX;
7377   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = PY;
7378   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = PXSIZE;
7379   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = PYSIZE;
7380
7381   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
7382   {
7383     int id = scrollbar_info[i].gadget_id;
7384     int graphic = scrollbar_info[i].graphic;
7385     struct GraphicInfo *gd = &graphic_info[graphic];
7386     int gd_x1 = gd->src_x;
7387     int gd_y1 = gd->src_y;
7388     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7389     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7390     struct GadgetInfo *gi;
7391     int items_max, items_visible, item_position;
7392     unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
7393
7394     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
7395     {
7396       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
7397       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
7398       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
7399     }
7400     else        // drawing area scrollbars
7401     {
7402       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
7403       {
7404         items_max = MAX(lev_fieldx + 2, ed_fieldx);
7405         items_visible = ed_fieldx;
7406         item_position = 0;
7407       }
7408       else
7409       {
7410         items_max = MAX(lev_fieldy + 2, ed_fieldy);
7411         items_visible = ed_fieldy;
7412         item_position = 0;
7413       }
7414     }
7415
7416     gi = CreateGadget(GDI_CUSTOM_ID, id,
7417                       GDI_CUSTOM_TYPE_ID, i,
7418                       GDI_IMAGE_ID, graphic,
7419                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
7420                       GDI_X, scrollbar_pos[i].x,
7421                       GDI_Y, scrollbar_pos[i].y,
7422                       GDI_WIDTH, scrollbar_pos[i].width,
7423                       GDI_HEIGHT, scrollbar_pos[i].height,
7424                       GDI_TYPE, scrollbar_info[i].type,
7425                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
7426                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
7427                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
7428                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
7429                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
7430                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
7431                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
7432                       GDI_STATE, GD_BUTTON_UNPRESSED,
7433                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7434                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7435                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
7436                       GDI_EVENT_MASK, event_mask,
7437                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7438                       GDI_CALLBACK_ACTION, HandleControlButtons,
7439                       GDI_END);
7440
7441     if (gi == NULL)
7442       Fail("cannot create gadget");
7443
7444     level_editor_gadget[id] = gi;
7445   }
7446 }
7447
7448 static void CreateCheckbuttonGadgets(void)
7449 {
7450   struct GadgetInfo *gi;
7451   int i;
7452
7453   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
7454   {
7455     int id = checkbutton_info[i].gadget_id;
7456     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
7457                    IMG_EDITOR_CHECKBOX);
7458     struct GraphicInfo *gd = &graphic_info[graphic];
7459     int gd_x1 = gd->src_x;
7460     int gd_y1 = gd->src_y;
7461     int gd_x2 = gd->src_x + gd->pressed_xoffset;
7462     int gd_y2 = gd->src_y + gd->pressed_yoffset;
7463     int gd_x1a = gd->src_x + gd->active_xoffset;
7464     int gd_y1a = gd->src_y + gd->active_yoffset;
7465     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7466     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7467     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
7468     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
7469     unsigned int event_mask = GD_EVENT_PRESSED;
7470
7471     // determine horizontal position to the right of specified gadget
7472     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
7473       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
7474            ED_GADGET_TEXT_DISTANCE);
7475
7476     // determine horizontal offset for leading text
7477     if (checkbutton_info[i].text_left != NULL)
7478       x += getTextWidthForGadget(checkbutton_info[i].text_left);
7479
7480     gi = CreateGadget(GDI_CUSTOM_ID, id,
7481                       GDI_CUSTOM_TYPE_ID, i,
7482                       GDI_IMAGE_ID, graphic,
7483                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
7484                       GDI_X, x,
7485                       GDI_Y, y,
7486                       GDI_WIDTH, gd->width,
7487                       GDI_HEIGHT, gd->height,
7488                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
7489                       GDI_CHECKED, *checkbutton_info[i].value,
7490                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7491                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7492                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7493                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7494                       GDI_EVENT_MASK, event_mask,
7495                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7496                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
7497                       GDI_END);
7498
7499     if (gi == NULL)
7500       Fail("cannot create gadget");
7501
7502     level_editor_gadget[id] = gi;
7503     right_gadget_border[id] =
7504       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
7505   }
7506 }
7507
7508 static void CreateRadiobuttonGadgets(void)
7509 {
7510   int graphic = IMG_EDITOR_RADIOBUTTON;
7511   struct GraphicInfo *gd = &graphic_info[graphic];
7512   int gd_x1 = gd->src_x;
7513   int gd_y1 = gd->src_y;
7514   int gd_x2 = gd->src_x + gd->pressed_xoffset;
7515   int gd_y2 = gd->src_y + gd->pressed_yoffset;
7516   int gd_x1a = gd->src_x + gd->active_xoffset;
7517   int gd_y1a = gd->src_y + gd->active_yoffset;
7518   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
7519   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
7520   struct GadgetInfo *gi;
7521   int i;
7522
7523   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
7524   {
7525     int id = radiobutton_info[i].gadget_id;
7526     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
7527     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
7528     unsigned int event_mask = GD_EVENT_PRESSED;
7529
7530     int checked =
7531       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
7532
7533     // determine horizontal position to the right of specified gadget
7534     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
7535       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
7536            ED_GADGET_TEXT_DISTANCE);
7537
7538     // determine horizontal offset for leading text
7539     if (radiobutton_info[i].text_left != NULL)
7540       x += getTextWidthForGadget(radiobutton_info[i].text_left);
7541
7542     gi = CreateGadget(GDI_CUSTOM_ID, id,
7543                       GDI_CUSTOM_TYPE_ID, i,
7544                       GDI_IMAGE_ID, graphic,
7545                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
7546                       GDI_X, x,
7547                       GDI_Y, y,
7548                       GDI_WIDTH, gd->width,
7549                       GDI_HEIGHT, gd->height,
7550                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
7551                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
7552                       GDI_CHECKED, checked,
7553                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
7554                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
7555                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
7556                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
7557                       GDI_EVENT_MASK, event_mask,
7558                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
7559                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
7560                       GDI_END);
7561
7562     if (gi == NULL)
7563       Fail("cannot create gadget");
7564
7565     level_editor_gadget[id] = gi;
7566     right_gadget_border[id] =
7567       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
7568   }
7569 }
7570
7571 void CreateLevelEditorGadgets(void)
7572 {
7573   // force EDITOR font inside level editor
7574   SetFontStatus(GAME_MODE_EDITOR);
7575
7576   // these values are not constant, but can change at runtime
7577   ed_fieldx = MAX_ED_FIELDX - 1;
7578   ed_fieldy = MAX_ED_FIELDY - 1;
7579
7580   num_editor_gadgets = NUM_EDITOR_GADGETS;
7581
7582   // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
7583
7584   level_editor_gadget =
7585     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
7586   right_gadget_border =
7587     checked_calloc(num_editor_gadgets * sizeof(int));
7588
7589   // set number of empty (padding) element buttons to maximum number of buttons
7590   num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
7591
7592   editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
7593   editor_el_empty_ptr = editor_el_empty;
7594
7595   use_permanent_palette = !editor.palette.show_as_separate_screen;
7596
7597   InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
7598
7599   ReinitializeElementList();
7600
7601   CreateControlButtons();
7602   CreateScrollbarGadgets();
7603
7604   // order of function calls is important because of cross-references
7605   CreateCheckbuttonGadgets();
7606   CreateCounterButtons();
7607   CreateRadiobuttonGadgets();
7608   CreateTextInputGadgets();
7609   CreateTextAreaGadgets();
7610   CreateSelectboxGadgets();
7611   CreateGraphicbuttonGadgets();
7612   CreateTextbuttonGadgets();
7613   CreateDrawingAreas();
7614
7615   ResetFontStatus();
7616 }
7617
7618 void FreeLevelEditorGadgets(void)
7619 {
7620   int i;
7621
7622   // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
7623
7624   for (i = 0; i < num_editor_gadgets; i++)
7625   {
7626     FreeGadget(level_editor_gadget[i]);
7627
7628     level_editor_gadget[i] = NULL;
7629   }
7630
7631   checked_free(level_editor_gadget);
7632   checked_free(right_gadget_border);
7633
7634   checked_free(editor_el_empty);
7635 }
7636
7637 static void MapCounterButtons(int id)
7638 {
7639   int font_nr = FONT_TEXT_1;
7640   int font_height = getFontHeight(font_nr);
7641   int gadget_id_down = counterbutton_info[id].gadget_id_down;
7642   int gadget_id_text = counterbutton_info[id].gadget_id_text;
7643   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
7644   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
7645   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
7646   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
7647   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
7648   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7649   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7650   int yoffset = (gi_down->height - font_height) / 2;
7651   int x_left = gi_down->x - xoffset_left;
7652   int x_right;  // set after gadget position was modified
7653   int y_above = gi_down->y - yoffset_above;
7654   int x = gi_down->x;
7655   int y;        // set after gadget position was modified
7656
7657   // counter limits must be changed first to prevent value truncation
7658   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
7659                             counterbutton_info[id].max_value);
7660
7661   // right text position might have changed after setting position above
7662   x_right = gi_up->x + gi_up->width + xoffset_right;
7663
7664   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
7665
7666   // set position for "value[1,2,3,4]" counter gadgets (score in most cases)
7667   if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
7668       id <= ED_COUNTER_ID_ELEMENT_VALUE4)
7669   {
7670     ModifyGadget(gi_down, GDI_Y,
7671                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
7672     ModifyGadget(gi_text, GDI_Y,
7673                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
7674     ModifyGadget(gi_up,   GDI_Y,
7675                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
7676   }
7677
7678   // vertical position might have changed after setting position above
7679   y = gi_up->y + yoffset;
7680
7681   if (counterbutton_info[id].text_above)
7682     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
7683
7684   if (counterbutton_info[id].text_left)
7685     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
7686
7687   if (counterbutton_info[id].text_right)
7688     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
7689
7690   MapGadget(gi_down);
7691   MapGadget(gi_text);
7692   MapGadget(gi_up);
7693 }
7694
7695 static void MapControlButtons(void)
7696 {
7697   int counter_id;
7698   int i;
7699
7700   // map toolbox buttons (excluding special CE toolbox buttons)
7701   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
7702     MapGadget(level_editor_gadget[i]);
7703
7704   // map toolbox buttons (element properties buttons)
7705   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_7_BUTTONS; i++)
7706     MapGadget(level_editor_gadget[i]);
7707
7708   if (use_permanent_palette)
7709   {
7710     // map buttons to select elements
7711     for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7712       MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
7713     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
7714     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
7715     MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
7716   }
7717
7718   // map buttons to select level
7719   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
7720   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
7721   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
7722   MapCounterButtons(counter_id);
7723 }
7724
7725 static void MapDrawingArea(int id)
7726 {
7727   int font_nr = FONT_TEXT_1;
7728   int font_height = getFontHeight(font_nr);
7729   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
7730   int area_xsize = gi->drawing.area_xsize;
7731   int area_ysize = gi->drawing.area_ysize;
7732   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
7733   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
7734   int x_left  = gi->x - xoffset_left;
7735   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
7736   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
7737   int x_below = gi->x + (gi->width - xoffset_below) / 2;
7738   int y_side  = gi->y + (gi->height - font_height) / 2;
7739   int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
7740   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
7741
7742   if (drawingarea_info[id].text_left)
7743     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
7744
7745   if (drawingarea_info[id].text_right)
7746     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
7747
7748   if (drawingarea_info[id].text_above)
7749     DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
7750
7751   if (drawingarea_info[id].text_below)
7752     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
7753
7754   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
7755   {
7756     DrawElementBorder(gi->x, gi->y,
7757                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
7758                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
7759
7760     DrawDrawingArea(id);
7761   }
7762
7763   MapGadget(gi);
7764 }
7765
7766 static void MapTextInputGadget(int id)
7767 {
7768   int font_nr = FONT_TEXT_1;
7769   int font_height = getFontHeight(font_nr);
7770   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
7771   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7772   int x_above = ED_SETTINGS_X(textinput_info[id].x);
7773   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
7774
7775   if (textinput_info[id].text_above)
7776     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
7777
7778   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
7779
7780   MapGadget(gi);
7781 }
7782
7783 static void MapTextAreaGadget(int id)
7784 {
7785   int font_nr = FONT_TEXT_1;
7786   int font_height = getFontHeight(font_nr);
7787   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
7788   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7789   int x_above = ED_SETTINGS_X(textarea_info[id].x);
7790   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
7791   char *text_above = textarea_info[id].text_above;
7792
7793   if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
7794     text_above = textarea_info[id].text_above_cropped;
7795
7796   if (text_above)
7797     DrawTextS(x_above, y_above, font_nr, text_above);
7798
7799   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
7800
7801   MapGadget(gi);
7802 }
7803
7804 static void MapSelectboxGadget(int id)
7805 {
7806   int font_nr = FONT_TEXT_1;
7807   int font_height = getFontHeight(font_nr);
7808   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
7809   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
7810   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7811   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7812   int yoffset = (gi->height - font_height) / 2;
7813   int x_left = gi->x - xoffset_left;
7814   int x_right = gi->x + gi->width + xoffset_right;
7815   int y_above = gi->y - yoffset_above;
7816   int x = gi->x;
7817   int y = gi->y + yoffset;
7818
7819   if (selectbox_info[id].text_above)
7820     DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
7821
7822   if (selectbox_info[id].text_left)
7823     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
7824
7825   if (selectbox_info[id].text_right)
7826     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
7827
7828   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
7829
7830   MapGadget(gi);
7831 }
7832
7833 static void MapTextbuttonGadget(int id)
7834 {
7835   int font_nr = FONT_TEXT_1;
7836   int font_height = getFontHeight(font_nr);
7837   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
7838   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
7839   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7840   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7841   int yoffset = (gi->height - font_height) / 2;
7842   int x_left = gi->x - xoffset_left;
7843   int x_right = gi->x + gi->width + xoffset_right;
7844   int y_above = gi->y - yoffset_above;
7845   int x = gi->x;
7846   int y = gi->y + yoffset;
7847
7848   // only show button to delete change pages when more than minimum pages
7849   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
7850       custom_element.num_change_pages == MIN_CHANGE_PAGES)
7851     return;
7852
7853   if (textbutton_info[id].text_above)
7854     DrawText(x, y_above, textbutton_info[id].text_above, font_nr);
7855
7856   if (textbutton_info[id].text_left)
7857     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
7858
7859   if (textbutton_info[id].text_right)
7860     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
7861
7862   MapGadget(gi);
7863 }
7864
7865 static void MapGraphicbuttonGadget(int id)
7866 {
7867   int font_nr = FONT_TEXT_1;
7868   int font_height = getFontHeight(font_nr);
7869   struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
7870   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
7871   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7872   int yoffset = (gi->height - font_height) / 2;
7873   int x_left = gi->x - xoffset_left;
7874   int x_right = gi->x + gi->width + xoffset_right;
7875   int y = gi->y + yoffset;
7876
7877   if (graphicbutton_info[id].text_left)
7878     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
7879
7880   if (graphicbutton_info[id].text_right)
7881     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
7882
7883   MapGadget(gi);
7884 }
7885
7886 static void MapRadiobuttonGadget(int id)
7887 {
7888   int font_nr = FONT_TEXT_1;
7889   int font_height = getFontHeight(font_nr);
7890   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
7891   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
7892   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7893   int yoffset = (gi->height - font_height) / 2;
7894   int x_left = gi->x - xoffset_left;
7895   int x_right = gi->x + gi->width + xoffset_right;
7896   int y = gi->y + yoffset;
7897   boolean checked =
7898     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
7899
7900   if (radiobutton_info[id].text_left)
7901     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
7902
7903   if (radiobutton_info[id].text_right)
7904     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
7905
7906   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
7907
7908   MapGadget(gi);
7909 }
7910
7911 static void MapCheckbuttonGadget(int id)
7912 {
7913   int font_nr = FONT_TEXT_1;
7914   int font_height = getFontHeight(font_nr);
7915   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
7916   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
7917   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
7918   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
7919   int yoffset = (gi->height - font_height) / 2;
7920   int y_above = gi->y - yoffset_above;
7921   int x = gi->x;
7922   int x_left, x_right, y;       // set after gadget position was modified
7923
7924   // set position for gadgets with dynamically determined position
7925   if (checkbutton_info[id].x != -1)     // do not change dynamic positions
7926     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
7927   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
7928
7929   x_left = gi->x - xoffset_left;
7930   x_right = gi->x + gi->width + xoffset_right;
7931   y = gi->y + yoffset;
7932
7933   if (checkbutton_info[id].text_above)
7934     DrawText(x, y_above, checkbutton_info[id].text_above, font_nr);
7935
7936   if (checkbutton_info[id].text_left)
7937     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
7938
7939   if (checkbutton_info[id].text_right)
7940     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
7941
7942   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
7943
7944   MapGadget(gi);
7945 }
7946
7947 static void MapMainDrawingArea(void)
7948 {
7949   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
7950   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
7951   int i;
7952
7953   if (suppressBorderElement())
7954   {
7955     no_horizontal_scrollbar = (lev_fieldx <= ed_fieldx);
7956     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
7957   }
7958
7959   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
7960   {
7961     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
7962           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
7963          no_horizontal_scrollbar) ||
7964         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
7965           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
7966          no_vertical_scrollbar))
7967       continue;
7968
7969     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
7970   }
7971
7972   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
7973   {
7974     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
7975         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
7976       continue;
7977
7978     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
7979   }
7980
7981   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
7982 }
7983
7984 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
7985 {
7986   int i;
7987
7988   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
7989   {
7990     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
7991         i == GADGET_ID_CUSTOM_COPY_TO ||
7992         i == GADGET_ID_CUSTOM_EXCHANGE ||
7993         i == GADGET_ID_CUSTOM_COPY ||
7994         i == GADGET_ID_CUSTOM_PASTE)
7995     {
7996       if (map)
7997         MapGadget(level_editor_gadget[i]);
7998       else
7999         UnmapGadget(level_editor_gadget[i]);
8000     }
8001   }
8002 }
8003
8004 static void MapLevelEditorToolboxCustomGadgets(void)
8005 {
8006   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
8007 }
8008
8009 static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
8010 {
8011   if (IS_CUSTOM_ELEMENT(properties_element) ||
8012       IS_GROUP_ELEMENT(properties_element) ||
8013       IS_EMPTY_ELEMENT(properties_element))
8014     MapLevelEditorToolboxCustomGadgets();
8015 }
8016
8017 static void UnmapLevelEditorToolboxCustomGadgets(void)
8018 {
8019   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
8020 }
8021
8022 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
8023 {
8024   int i;
8025
8026   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
8027   {
8028     if (i != GADGET_ID_SINGLE_ITEMS &&
8029         i != GADGET_ID_PICK_ELEMENT)
8030     {
8031       struct GadgetInfo *gi = level_editor_gadget[i];
8032
8033       if (map)
8034       {
8035         MapGadget(gi);
8036       }
8037       else
8038       {
8039         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
8040         struct GraphicInfo *gd = &graphic_info[graphic];
8041
8042         UnmapGadget(gi);
8043
8044         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
8045                    gi->width, gi->height, gi->x, gi->y);
8046
8047         redraw_mask |= REDRAW_DOOR_3;
8048       }
8049     }
8050   }
8051 }
8052
8053 static void MapLevelEditorToolboxDrawingGadgets(void)
8054 {
8055   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
8056 }
8057
8058 static void UnmapLevelEditorToolboxDrawingGadgets(void)
8059 {
8060   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
8061 }
8062
8063 static void UnmapDrawingArea(int id)
8064 {
8065   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
8066 }
8067
8068 static void UnmapLevelEditorFieldGadgets(void)
8069 {
8070   int i;
8071
8072   for (i = 0; i < num_editor_gadgets; i++)
8073     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
8074                           level_editor_gadget[i]->y))
8075       UnmapGadget(level_editor_gadget[i]);
8076 }
8077
8078 void UnmapLevelEditorGadgets(void)
8079 {
8080   int i;
8081
8082   for (i = 0; i < num_editor_gadgets; i++)
8083     UnmapGadget(level_editor_gadget[i]);
8084 }
8085
8086 static void ResetUndoBuffer(void)
8087 {
8088   undo_buffer_position = -1;
8089   undo_buffer_steps = -1;
8090   redo_buffer_steps = 0;
8091
8092   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
8093
8094   level.changed = FALSE;
8095 }
8096
8097 static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
8098 {
8099   if (remap_toolbox_gadgets)
8100   {
8101     ModifyEditorElementList();
8102     RedrawDrawingElements();
8103   }
8104
8105   if (edit_mode == ED_MODE_LEVELCONFIG)
8106     DrawLevelConfigWindow();
8107   else if (edit_mode == ED_MODE_PROPERTIES)
8108     DrawPropertiesWindow();
8109   else if (edit_mode == ED_MODE_PALETTE)
8110     DrawPaletteWindow();
8111   else  // edit_mode == ED_MODE_DRAWING
8112     DrawDrawingWindowExt(remap_toolbox_gadgets);
8113 }
8114
8115 static void DrawEditModeWindow(void)
8116 {
8117   DrawEditModeWindowExt(TRUE);
8118 }
8119
8120 static void DrawEditModeWindow_PlayfieldOnly(void)
8121 {
8122   DrawEditModeWindowExt(FALSE);
8123 }
8124
8125 static void ChangeEditModeWindow(int new_edit_mode)
8126 {
8127   edit_mode = (new_edit_mode != edit_mode ? new_edit_mode : ED_MODE_DRAWING);
8128
8129   DrawEditModeWindow();
8130 }
8131
8132 static boolean LevelChanged(void)
8133 {
8134   boolean field_changed = FALSE;
8135   int x, y;
8136
8137   for (y = 0; y < lev_fieldy; y++) 
8138     for (x = 0; x < lev_fieldx; x++)
8139       if (Tile[x][y] != level.field[x][y])
8140         field_changed = TRUE;
8141
8142   return (level.changed || field_changed);
8143 }
8144
8145 static boolean PrepareSavingIntoPersonalLevelSet(void)
8146 {
8147   static LevelDirTree *last_copied_leveldir = NULL;
8148   static LevelDirTree *last_written_leveldir = NULL;
8149   static int last_copied_level_nr = -1;
8150   static int last_written_level_nr = -1;
8151   LevelDirTree *leveldir_former = leveldir_current;
8152   int level_nr_former = level_nr;
8153   int new_level_nr;
8154
8155   // remember last mod/save so that for current session, we write
8156   // back to the same personal copy, asking only about overwrite.
8157   if (leveldir_current == last_copied_leveldir &&
8158       level_nr == last_copied_level_nr)
8159   {
8160     // "cd" to personal level set dir (as used when writing last copy)
8161     leveldir_current = last_written_leveldir;
8162     level_nr = last_written_level_nr;
8163
8164     return TRUE;
8165   }
8166
8167   if (!Request("This level is read-only! "
8168                "Save into personal level set?", REQ_ASK))
8169     return FALSE;
8170
8171   // "cd" to personal level set dir (for writing copy the first time)
8172   leveldir_current =
8173     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
8174
8175   // this may happen if "setup.internal.create_user_levelset" is FALSE
8176   // or if file "levelinfo.conf" is missing in personal user level set
8177   if (leveldir_current == NULL)
8178   {
8179     Request("Cannot find personal level set?!", REQ_CONFIRM);
8180
8181     leveldir_current = leveldir_former;
8182
8183     return FALSE;
8184   }
8185
8186   // find unused level number
8187   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
8188   {
8189     static char *level_filename = NULL;
8190
8191     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
8192
8193     if (!fileExists(level_filename))
8194       break;
8195   }
8196
8197   last_copied_leveldir = leveldir_former;
8198   last_copied_level_nr = level_nr_former;
8199
8200   last_written_leveldir = leveldir_current;
8201   last_written_level_nr = level_nr = new_level_nr;
8202
8203   return TRUE;
8204 }
8205
8206 static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
8207 {
8208   static char *filename_levelinfo = NULL, *mod_name = NULL;
8209   FILE *file;
8210
8211   // annotate this copy-and-mod in personal levelinfo.conf
8212   setString(&filename_levelinfo,
8213             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
8214
8215   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
8216   {
8217     fprintf(file, "\n");
8218     fprintf(file, "# level %d was modified from:\n", level_nr);
8219     fprintf(file, "# - previous level set name:    %s\n",
8220             former_name);
8221     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
8222             level.file_info.nr, level.name);
8223     fprintf(file, "# - previous author:            %s\n",
8224             level.author);
8225     fprintf(file, "# - previous save date:         ");
8226
8227     if (level.creation_date.src == DATE_SRC_LEVELFILE)
8228     {
8229       fprintf(file, "%04d-%02d-%02d\n",
8230               level.creation_date.year,
8231               level.creation_date.month,
8232               level.creation_date.day);
8233     }
8234     else
8235     {
8236       fprintf(file, "not recorded\n");
8237     }
8238
8239     fclose(file);
8240   }
8241
8242   if (level_nr > leveldir_current->last_level)
8243     UpdateUserLevelSet(getLoginName(), NULL, NULL, level_nr + 9);
8244
8245   // else: allow the save even if annotation failed
8246
8247   // now... spray graffiti on the old level vital statistics
8248   // user can change these; just trying to set a good baseline
8249
8250   // don't truncate names for fear of making offensive or silly:
8251   // long-named original author only recorded in levelinfo.conf.
8252   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
8253   if (!strEqual(level.author, leveldir_current->author))
8254   {
8255     setString(&mod_name, getStringCat3(leveldir_current->author,
8256                                        " after ", level.author));
8257
8258     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
8259       setString(&mod_name,
8260                 getStringCat2(leveldir_current->author, " (ed.)"));
8261
8262     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
8263       setString(&mod_name, leveldir_current->author);
8264
8265     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
8266
8267     // less worried about truncation here
8268     setString(&mod_name, getStringCat2("Mod: ", level.name));
8269     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
8270   }
8271 }
8272
8273 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
8274                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
8275 {
8276   int x, y;
8277
8278   for (x = 0; x < lev_fieldx; x++)
8279     for (y = 0; y < lev_fieldy; y++) 
8280       dst[x][y] = src[x][y];
8281 }
8282
8283 static int setSelectboxValue(int selectbox_id, int new_value)
8284 {
8285   int new_index_value = 0;
8286   int i;
8287
8288   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
8289     if (selectbox_info[selectbox_id].options[i].value == new_value)
8290       new_index_value = i;
8291
8292   *selectbox_info[selectbox_id].value =
8293     selectbox_info[selectbox_id].options[new_index_value].value;
8294
8295   return new_index_value;
8296 }
8297
8298 static void setSelectboxSpecialActionVariablesIfNeeded(void)
8299 {
8300   int i;
8301
8302   // change action mode and arg variables according to action type variable
8303   for (i = 0; action_arg_options[i].value != -1; i++)
8304   {
8305     if (action_arg_options[i].value == custom_element_change.action_type)
8306     {
8307       int mode = action_arg_options[i].mode;
8308
8309       // only change if corresponding selectbox has changed
8310       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
8311           action_arg_modes[mode])
8312         custom_element_change.action_mode = -1;
8313
8314       // only change if corresponding selectbox has changed
8315       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
8316           action_arg_options[i].options)
8317         custom_element_change.action_arg = -1;
8318
8319       break;
8320     }
8321   }
8322 }
8323
8324 static void setSelectboxSpecialActionOptions(void)
8325 {
8326   int i;
8327
8328   // change action mode and arg selectbox according to action type selectbox
8329   for (i = 0; action_arg_options[i].value != -1; i++)
8330   {
8331     if (action_arg_options[i].value == custom_element_change.action_type)
8332     {
8333       int mode = action_arg_options[i].mode;
8334
8335       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
8336                                    action_arg_modes[mode]);
8337       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
8338                                  custom_element_change.action_mode);
8339
8340       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
8341                                    action_arg_options[i].options);
8342       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
8343                                  custom_element_change.action_arg);
8344       break;
8345     }
8346   }
8347 }
8348
8349 static void copy_custom_element_settings(int element_from, int element_to)
8350 {
8351   struct ElementInfo *ei_from = &element_info[element_from];
8352   struct ElementInfo *ei_to = &element_info[element_to];
8353
8354   copyElementInfo(ei_from, ei_to);
8355 }
8356
8357 static void replace_custom_element_in_settings(int element_from,
8358                                                int element_to)
8359 {
8360   int i, j, x, y;
8361
8362   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8363   {
8364     struct ElementInfo *ei = &element_info[i];
8365
8366     for (y = 0; y < 3; y++)
8367       for (x = 0; x < 3; x++)
8368         if (ei->content.e[x][y] == element_from)
8369           ei->content.e[x][y] = element_to;
8370
8371     for (j = 0; j < ei->num_change_pages; j++)
8372     {
8373       struct ElementChangeInfo *change = &ei->change_page[j];
8374
8375       if (change->target_element == element_from)
8376         change->target_element = element_to;
8377
8378       if (change->initial_trigger_element == element_from)
8379         change->initial_trigger_element = element_to;
8380
8381       if (change->action_element == element_from)
8382         change->action_element = element_to;
8383
8384       for (y = 0; y < 3; y++)
8385         for (x = 0; x < 3; x++)
8386           if (change->target_content.e[x][y] == element_from)
8387             change->target_content.e[x][y] = element_to;
8388     }
8389
8390     if (ei->group != NULL)                              // group or internal
8391       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
8392         if (ei->group->element[j] == element_from)
8393           ei->group->element[j] = element_to;
8394   }
8395 }
8396
8397 static void replace_custom_element_in_playfield(int element_from,
8398                                                 int element_to)
8399 {
8400   int x, y;
8401
8402   for (x = 0; x < lev_fieldx; x++)
8403     for (y = 0; y < lev_fieldy; y++)
8404       if (Tile[x][y] == element_from)
8405         Tile[x][y] = element_to;
8406 }
8407
8408 static boolean CopyCustomElement(int element_old, int element_new,
8409                                  int copy_mode)
8410 {
8411   int copy_mode_orig = copy_mode;
8412
8413   if (copy_mode == GADGET_ID_CUSTOM_COPY)
8414   {
8415     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
8416                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
8417     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
8418   }
8419   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
8420   {
8421     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
8422                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
8423     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
8424
8425     level.changed = TRUE;
8426   }
8427   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
8428   {
8429     Request("Please choose custom element!", REQ_CONFIRM);
8430
8431     return FALSE;
8432   }
8433   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
8434   {
8435     Request("Please choose group element!", REQ_CONFIRM);
8436
8437     return FALSE;
8438   }
8439   else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
8440   {
8441     Request("Please choose empty element!", REQ_CONFIRM);
8442
8443     return FALSE;
8444   }
8445   else
8446   {
8447     level.changed = TRUE;
8448   }
8449
8450   // when modifying custom/group element, ask for copying level template
8451   if (copy_mode_orig != GADGET_ID_CUSTOM_COPY && level.use_custom_template)
8452   {
8453     if (!AskToCopyAndModifyLevelTemplate())
8454       return FALSE;
8455   }
8456
8457   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
8458   {
8459     copy_custom_element_settings(element_new, element_old);
8460   }
8461   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
8462   {
8463     copy_custom_element_settings(element_old, element_new);
8464   }
8465   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
8466   {
8467     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
8468     copy_custom_element_settings(element_new, element_old);
8469     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
8470
8471     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
8472     replace_custom_element_in_settings(element_new, element_old);
8473     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
8474
8475     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
8476     replace_custom_element_in_playfield(element_new, element_old);
8477     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
8478   }
8479
8480   UpdateCustomElementGraphicGadgets();
8481   DrawPropertiesWindow();
8482
8483   return TRUE;
8484 }
8485
8486 static void CopyCustomElementPropertiesToEditor(int element)
8487 {
8488   int i;
8489   int current_change_page = element_info[element].current_change_page;
8490
8491   // dynamically (re)build selectbox for selecting change page
8492   for (i = 0; i < element_info[element].num_change_pages; i++)
8493   {
8494     sprintf(options_change_page_strings[i], "%d", i + 1);
8495
8496     options_change_page[i].value = i;
8497     options_change_page[i].text = options_change_page_strings[i];
8498   }
8499
8500   options_change_page[i].value = -1;
8501   options_change_page[i].text = NULL;
8502
8503   // needed here to initialize combined element properties
8504   InitElementPropertiesEngine(level.game_version);
8505
8506   element_info[element].change =
8507     &element_info[element].change_page[current_change_page];
8508
8509   custom_element = element_info[element];
8510   custom_element_change = *element_info[element].change;
8511
8512   // needed to initially set selectbox options for special action options
8513   setSelectboxSpecialActionOptions();
8514
8515   // needed to initially set selectbox value variables to reliable defaults
8516   for (i = 0; i < ED_NUM_SELECTBOX; i++)
8517     setSelectboxValue(i, *selectbox_info[i].value);
8518
8519   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
8520     custom_element_properties[i] = HAS_PROPERTY(element, i);
8521
8522   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
8523     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
8524
8525   // ---------- element settings: configure (custom elements) -----------------
8526
8527   // set accessible layer selectbox help value
8528   custom_element.access_type =
8529     (IS_WALKABLE(element) ? EP_WALKABLE :
8530      IS_PASSABLE(element) ? EP_PASSABLE :
8531      custom_element.access_type);
8532   custom_element.access_layer =
8533     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
8534      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
8535      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
8536      custom_element.access_layer);
8537   custom_element.access_protected =
8538     (IS_PROTECTED(element) ? 1 : 0);
8539   custom_element_properties[EP_ACCESSIBLE] =
8540     (IS_ACCESSIBLE_OVER(element) ||
8541      IS_ACCESSIBLE_INSIDE(element) ||
8542      IS_ACCESSIBLE_UNDER(element));
8543
8544   // set walk-to-object action selectbox help value
8545   custom_element.walk_to_action =
8546     (IS_DIGGABLE(element) ? EP_DIGGABLE :
8547      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
8548      IS_DROPPABLE(element) ? EP_DROPPABLE :
8549      IS_THROWABLE(element) ? EP_THROWABLE :
8550      IS_PUSHABLE(element) ? EP_PUSHABLE :
8551      custom_element.walk_to_action);
8552   custom_element_properties[EP_WALK_TO_OBJECT] =
8553     (IS_DIGGABLE(element) ||
8554      IS_COLLECTIBLE_ONLY(element) ||
8555      IS_DROPPABLE(element) ||
8556      IS_THROWABLE(element) ||
8557      IS_PUSHABLE(element));
8558
8559   // set smash targets selectbox help value
8560   custom_element.smash_targets =
8561     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
8562      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
8563      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
8564      custom_element.smash_targets);
8565   custom_element_properties[EP_CAN_SMASH] =
8566     (CAN_SMASH_EVERYTHING(element) ||
8567      CAN_SMASH_ENEMIES(element) ||
8568      CAN_SMASH_PLAYER(element));
8569
8570   // set deadliness selectbox help value
8571   custom_element.deadliness =
8572     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
8573      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
8574      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
8575      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
8576      custom_element.deadliness);
8577   custom_element_properties[EP_DEADLY] =
8578     (DONT_TOUCH(element) ||
8579      DONT_GET_HIT_BY(element) ||
8580      DONT_COLLIDE_WITH(element) ||
8581      DONT_RUN_INTO(element));
8582
8583   // ---------- element settings: advanced (custom elements) ------------------
8584
8585   // set "change by direct action" selectbox help value
8586   custom_element_change.direct_action =
8587     (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
8588      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
8589      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
8590      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
8591      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
8592      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
8593      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
8594      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
8595      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
8596      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
8597      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
8598      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
8599      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
8600      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
8601      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
8602      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
8603      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
8604      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
8605      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
8606      HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
8607      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
8608      custom_element_change.direct_action);
8609
8610   // set "change by other element action" selectbox help value
8611   custom_element_change.other_action =
8612     (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
8613      HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
8614      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
8615      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
8616      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
8617      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
8618      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
8619      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
8620      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
8621      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
8622      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
8623      HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
8624      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
8625      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
8626      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
8627      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
8628      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
8629      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
8630      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
8631      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
8632      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
8633      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
8634      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
8635      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
8636      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
8637      HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
8638      HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
8639      custom_element_change.other_action);
8640 }
8641
8642 static void CopyGroupElementPropertiesToEditor(int element)
8643 {
8644   group_element_info = *element_info[element].group;
8645   custom_element = element_info[element];       // needed for description
8646 }
8647
8648 static void CopyEmptyElementPropertiesToEditor(int element)
8649 {
8650   custom_element = element_info[element];
8651 }
8652
8653 static void CopyClassicElementPropertiesToEditor(int element)
8654 {
8655   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
8656     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
8657       getMoveIntoAcidProperty(&level, element);
8658
8659   if (MAYBE_DONT_COLLIDE_WITH(element))
8660     custom_element_properties[EP_DONT_COLLIDE_WITH] =
8661       getDontCollideWithProperty(&level, element);
8662 }
8663
8664 static void CopyElementPropertiesToEditor(int element)
8665 {
8666   if (IS_CUSTOM_ELEMENT(element))
8667     CopyCustomElementPropertiesToEditor(element);
8668   else if (IS_GROUP_ELEMENT(element))
8669     CopyGroupElementPropertiesToEditor(element);
8670   else if (IS_EMPTY_ELEMENT(element))
8671     CopyEmptyElementPropertiesToEditor(element);
8672   else
8673     CopyClassicElementPropertiesToEditor(element);
8674 }
8675
8676 static boolean AskToCopyAndModifyLevelTemplate(void)
8677 {
8678   if (Request("Copy and modify settings from level template?", REQ_ASK))
8679   {
8680     level.use_custom_template = FALSE;
8681
8682     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_1],
8683                  GDI_CHECKED, FALSE, GDI_END);
8684     ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE_2],
8685                  GDI_CHECKED, FALSE, GDI_END);
8686
8687     return TRUE;
8688   }
8689   else
8690   {
8691     LoadLevelTemplate(-1);      // this resets all element modifications ...
8692
8693     DrawEditModeWindow();       // ... and copies them to 'custom_element'
8694
8695     return FALSE;
8696   }
8697 }
8698
8699 static void CopyCustomElementPropertiesToGame(int element)
8700 {
8701   int i;
8702   int access_type_and_layer;
8703
8704   // mark that this custom element has been modified
8705   custom_element.modified_settings = TRUE;
8706   level.changed = TRUE;
8707
8708   if (level.use_custom_template)
8709     AskToCopyAndModifyLevelTemplate();
8710
8711   element_info[element] = custom_element;
8712   *element_info[element].change = custom_element_change;
8713
8714   // ---------- element settings: configure (custom elements) -----------------
8715
8716   // set accessible property from checkbox and selectbox
8717   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
8718   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
8719   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
8720   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
8721   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
8722   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
8723   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
8724                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
8725                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
8726   custom_element_properties[access_type_and_layer] =
8727     custom_element_properties[EP_ACCESSIBLE];
8728   custom_element_properties[EP_PROTECTED] =
8729     (custom_element.access_protected != 0 &&
8730      custom_element_properties[EP_ACCESSIBLE]);
8731
8732   // set walk-to-object property from checkbox and selectbox
8733   custom_element_properties[EP_DIGGABLE] = FALSE;
8734   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
8735   custom_element_properties[EP_DROPPABLE] = FALSE;
8736   custom_element_properties[EP_THROWABLE] = FALSE;
8737   custom_element_properties[EP_PUSHABLE] = FALSE;
8738   custom_element_properties[custom_element.walk_to_action] =
8739     custom_element_properties[EP_WALK_TO_OBJECT];
8740
8741   // set smash property from checkbox and selectbox
8742   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
8743   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
8744   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
8745   custom_element_properties[custom_element.smash_targets] =
8746     custom_element_properties[EP_CAN_SMASH];
8747
8748   // set deadliness property from checkbox and selectbox
8749   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
8750   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
8751   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
8752   custom_element_properties[EP_DONT_TOUCH] = FALSE;
8753   custom_element_properties[custom_element.deadliness] =
8754     custom_element_properties[EP_DEADLY];
8755
8756   // ---------- element settings: advanced (custom elements) ------------------
8757
8758   // set player change event from checkbox and selectbox
8759   custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
8760   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
8761   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
8762   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
8763   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
8764   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
8765   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
8766   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
8767   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
8768   custom_element_change_events[CE_SWITCHED] = FALSE;
8769   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
8770   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
8771   custom_element_change_events[CE_BLOCKED] = FALSE;
8772   custom_element_change_events[CE_IMPACT] = FALSE;
8773   custom_element_change_events[CE_SMASHED] = FALSE;
8774   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
8775   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
8776   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
8777   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
8778   custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
8779   custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
8780   custom_element_change_events[custom_element_change.direct_action] =
8781     custom_element_change_events[CE_BY_DIRECT_ACTION];
8782
8783   // set other element action change event from checkbox and selectbox
8784   custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
8785   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
8786   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
8787   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
8788   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
8789   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
8790   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
8791   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
8792   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
8793   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
8794   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
8795   custom_element_change_events[CE_NEXT_TO_X] = FALSE;
8796   custom_element_change_events[CE_TOUCHING_X] = FALSE;
8797   custom_element_change_events[CE_HITTING_X] = FALSE;
8798   custom_element_change_events[CE_DIGGING_X] = FALSE;
8799   custom_element_change_events[CE_HIT_BY_X] = FALSE;
8800   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
8801   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
8802   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
8803   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
8804   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
8805   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
8806   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
8807   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
8808   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
8809   custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
8810   custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
8811   custom_element_change_events[custom_element_change.other_action] =
8812     custom_element_change_events[CE_BY_OTHER_ACTION];
8813
8814   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
8815     SET_PROPERTY(element, i, custom_element_properties[i]);
8816
8817   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
8818     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
8819
8820   // copy change events also to special level editor variable
8821   custom_element = element_info[element];
8822   custom_element_change = *element_info[element].change;
8823
8824   // needed here to restore runtime value "element_info[element].gfx_element"
8825   InitElementPropertiesGfxElement();
8826 }
8827
8828 static void CopyGroupElementPropertiesToGame(int element)
8829 {
8830   // mark that this group element has been modified
8831   custom_element.modified_settings = TRUE;
8832   level.changed = TRUE;
8833
8834   if (level.use_custom_template)
8835     AskToCopyAndModifyLevelTemplate();
8836
8837   element_info[element] = custom_element;
8838   *element_info[element].group = group_element_info;
8839
8840   // needed here to restore runtime value "element_info[element].gfx_element"
8841   InitElementPropertiesGfxElement();
8842 }
8843
8844 static void CopyEmptyElementPropertiesToGame(int element)
8845 {
8846   // mark that this empty element has been modified
8847   custom_element.modified_settings = TRUE;
8848   level.changed = TRUE;
8849
8850   if (level.use_custom_template)
8851     AskToCopyAndModifyLevelTemplate();
8852
8853   element_info[element] = custom_element;
8854
8855   // needed here to restore runtime value "element_info[element].gfx_element"
8856   InitElementPropertiesGfxElement();
8857 }
8858
8859 static void CopyClassicElementPropertiesToGame(int element)
8860 {
8861   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
8862     setMoveIntoAcidProperty(&level, element,
8863                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
8864
8865   if (MAYBE_DONT_COLLIDE_WITH(element))
8866     setDontCollideWithProperty(&level, element,
8867                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
8868 }
8869
8870 static void CopyElementPropertiesToGame(int element)
8871 {
8872   if (IS_CUSTOM_ELEMENT(element))
8873     CopyCustomElementPropertiesToGame(element);
8874   else if (IS_GROUP_ELEMENT(element))
8875     CopyGroupElementPropertiesToGame(element);
8876   else if (IS_EMPTY_ELEMENT(element))
8877     CopyEmptyElementPropertiesToGame(element);
8878   else
8879     CopyClassicElementPropertiesToGame(element);
8880 }
8881
8882 #if DEBUG
8883 static void CheckElementDescriptions(void)
8884 {
8885   int i;
8886
8887   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8888     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
8889       Warn("no element description file for element '%s'", EL_NAME(i));
8890 }
8891 #endif
8892
8893 static int getMaxEdFieldX(boolean has_scrollbar)
8894 {
8895   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
8896   int sxsize = SXSIZE - scrollbar_width;
8897   int max_ed_fieldx = sxsize / ed_tilesize;
8898
8899   return max_ed_fieldx;
8900 }
8901
8902 static int getMaxEdFieldY(boolean has_scrollbar)
8903 {
8904   int infotext_height = (IN_PIX_FIELD(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY) ?
8905                          INFOTEXT_YSIZE_FULL : 0);
8906   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
8907   int sysize = SYSIZE - scrollbar_height - infotext_height;
8908   int max_ed_fieldy = sysize / ed_tilesize;
8909
8910   return max_ed_fieldy;
8911 }
8912
8913 static void InitZoomLevelSettings(int zoom_tilesize)
8914 {
8915   static int last_game_engine_type = GAME_ENGINE_TYPE_UNKNOWN;
8916
8917   if (zoom_tilesize == -1 && level.game_engine_type != last_game_engine_type)
8918   {
8919     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
8920     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
8921
8922     // make sure that tile size is always a power of 2
8923     ed_tilesize = (1 << log_2(ed_tilesize));
8924
8925     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
8926     {
8927       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
8928       ed_tilesize_default = DEFAULT_EDITOR_TILESIZE_MM;
8929     }
8930   }
8931
8932   last_game_engine_type = level.game_engine_type;
8933
8934   // limit zoom tilesize by upper and lower bound
8935   ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
8936
8937   // store zoom tilesize in auto setup file only if it was manually changed
8938   if (zoom_tilesize != -1)
8939     setup.auto_setup.editor_zoom_tilesize = ed_tilesize;
8940
8941   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
8942   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
8943 }
8944
8945 static void InitDrawingElements(void)
8946 {
8947   static int game_engine_type_last = GAME_ENGINE_TYPE_UNKNOWN;
8948
8949   if (level.game_engine_type == game_engine_type_last)
8950     return;
8951
8952   if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
8953   {
8954     new_element1 = EL_BD_WALL;
8955     new_element2 = EL_EMPTY;
8956     new_element3 = EL_BD_SAND;
8957   }
8958   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
8959   {
8960     new_element1 = EL_SP_CHIP_SINGLE;
8961     new_element2 = EL_EMPTY;
8962     new_element3 = EL_SP_BASE;
8963   }
8964   else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
8965   {
8966     new_element1 = EL_MM_MIRROR_START;
8967     new_element2 = EL_EMPTY;
8968     new_element3 = EL_MM_WOODEN_WALL;
8969   }
8970   else
8971   {
8972     new_element1 = EL_WALL;
8973     new_element2 = EL_EMPTY;
8974     new_element3 = EL_SAND;
8975   }
8976
8977   game_engine_type_last = level.game_engine_type;
8978 }
8979
8980 static void InitLevelSetInfo(void)
8981 {
8982   snprintf(levelset_name,   MAX_LEVEL_NAME_LEN + 1,
8983            "%s", leveldir_current->name);
8984   snprintf(levelset_author, MAX_LEVEL_AUTHOR_LEN + 1,
8985            "%s", leveldir_current->author);
8986
8987   levelset_num_levels = leveldir_current->levels;
8988
8989   levelset_use_levelset_artwork = FALSE;
8990   levelset_copy_level_template = FALSE;
8991
8992   levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
8993 }
8994
8995 static void ChangeEditorToLevelSet(char *levelset_subdir)
8996 {
8997   leveldir_current = getTreeInfoFromIdentifier(leveldir_first, levelset_subdir);
8998
8999   // the previous level set might have used custom artwork
9000   ReloadCustomArtwork(0);
9001
9002   LoadLevelSetup_SeriesInfo();
9003
9004   SaveLevelSetup_LastSeries();
9005   SaveLevelSetup_SeriesInfo();
9006
9007   TapeErase();
9008
9009   LoadLevel(level_nr);
9010   LoadScore(level_nr);
9011
9012   DrawLevelEd();
9013 }
9014
9015 static boolean useEditorDoorAnimation(void)
9016 {
9017   struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
9018   boolean door_1_viewport_unchanged =
9019     (vp_door_1->x      == DX     &&
9020      vp_door_1->y      == DY     &&
9021      vp_door_1->width  == DXSIZE &&
9022      vp_door_1->height == DYSIZE);
9023   boolean door_1_contains_toolbox =
9024     (EX >= DX &&
9025      EY >= DY &&
9026      EX + EXSIZE <= DX + DXSIZE &&
9027      EY + EYSIZE <= DY + DYSIZE);
9028
9029   return (door_1_viewport_unchanged && door_1_contains_toolbox);
9030 }
9031
9032 static void DrawEditorDoorBackground(int graphic, int x, int y,
9033                                      int width, int height)
9034 {
9035   struct GraphicInfo *g = &graphic_info[graphic];
9036
9037   if (g->bitmap != NULL)
9038     BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
9039                MIN(width, g->width), MIN(height, g->height), x, y);
9040   else
9041     ClearRectangle(drawto, x, y, width, height);
9042 }
9043
9044 static void DrawEditorDoorContent(void)
9045 {
9046   // needed for gadgets drawn on background (like palette scrollbar)
9047   SetDoorBackgroundImage(IMG_UNDEFINED);
9048
9049   // copy default editor door content to main double buffer
9050   DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
9051
9052   // draw bigger door
9053   DrawSpecialEditorDoor();
9054
9055   // draw new control window
9056   DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
9057
9058   // draw all toolbox gadgets to editor doors
9059   MapControlButtons();
9060
9061   // when returning from test game to properties page, redraw toolbox gadgets
9062   if (edit_mode == ED_MODE_PROPERTIES)
9063   {
9064     UnmapLevelEditorToolboxDrawingGadgets();
9065     UnmapLevelEditorToolboxCustomGadgets();
9066
9067     MapLevelEditorToolboxCustomGadgetsIfNeeded();
9068   }
9069
9070   // draw all palette gadgets to editor doors
9071   ModifyEditorElementList();
9072   RedrawDrawingElements();
9073
9074   // copy actual editor door content to door double buffer for OpenDoor()
9075   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
9076 }
9077
9078 void DrawLevelEd(void)
9079 {
9080   int fade_mask = REDRAW_FIELD;
9081
9082   FadeSoundsAndMusic();
9083
9084   if (CheckFadeAll())
9085     fade_mask = REDRAW_ALL;
9086
9087   FadeOut(fade_mask);
9088
9089   // needed if different viewport properties defined for editor
9090   ChangeViewportPropertiesIfNeeded();
9091
9092   ClearField();
9093
9094   InitZoomLevelSettings(-1);
9095   InitDrawingElements();
9096   InitLevelSetInfo();
9097
9098 #if DEBUG
9099   CheckElementDescriptions();
9100 #endif
9101
9102   if (level_editor_test_game)
9103   {
9104     CopyPlayfield(level.field, Tile);
9105     CopyPlayfield(TileBackup, level.field);
9106
9107     level_editor_test_game = FALSE;
9108   }
9109   else
9110   {
9111     edit_mode = ED_MODE_DRAWING;
9112     edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
9113     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
9114
9115     ResetUndoBuffer();
9116
9117     level_xpos = -1;
9118     level_ypos = -1;
9119   }
9120
9121   // redraw_mask |= REDRAW_ALL;
9122
9123   FreeLevelEditorGadgets();
9124   CreateLevelEditorGadgets();
9125
9126   ReinitializeElementList();            // update dynamic level element list
9127   ReinitializeElementListButtons();     // custom element may look different
9128
9129   InitElementPropertiesGfxElement();
9130
9131   UnmapAllGadgets();
9132
9133   DrawEditModeWindow_PlayfieldOnly();
9134
9135   DrawMaskedBorder(fade_mask);
9136
9137   // use door animation if door 1 viewport is unchanged and contains toolbox
9138   if (useEditorDoorAnimation())
9139   {
9140     FadeIn(fade_mask);
9141
9142     DrawEditorDoorContent();
9143
9144     OpenDoor(DOOR_OPEN_1 | DOOR_FORCE_ANIM);
9145   }
9146   else
9147   {
9148     DrawEditorDoorContent();
9149
9150     FadeIn(fade_mask);
9151   }
9152
9153   SetDoorState(DOOR_OPEN_1 | DOOR_OPEN_2);
9154 }
9155
9156 static void AdjustDrawingAreaGadgets(void)
9157 {
9158   int ed_xsize = lev_fieldx + 2;
9159   int ed_ysize = lev_fieldy + 2;
9160   int max_ed_fieldx = MAX_ED_FIELDX;
9161   int max_ed_fieldy = MAX_ED_FIELDY;
9162   boolean horizontal_scrollbar_needed;
9163   boolean vertical_scrollbar_needed;
9164   int x, y, width, height;
9165
9166   if (suppressBorderElement())
9167   {
9168     ed_xsize = lev_fieldx;
9169     ed_ysize = lev_fieldy;
9170   }
9171
9172   // check if we need any scrollbars
9173   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
9174   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
9175
9176   // check if we have a smaller editor field because of scrollbars
9177   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
9178   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
9179
9180   // check again if we now need more scrollbars because of less space
9181   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
9182   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
9183
9184   // check if editor field gets even smaller after adding new scrollbars
9185   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
9186   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
9187
9188   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
9189   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
9190
9191   x = SX + ed_fieldx * ed_tilesize;
9192   y = SY + ed_fieldy * ed_tilesize;
9193
9194   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
9195   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
9196
9197   // adjust drawing area gadget
9198   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
9199                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
9200                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
9201                GDI_END);
9202
9203   // adjust horizontal scrollbar gadgets
9204   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
9205                GDI_Y, y,
9206                GDI_END);
9207   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
9208                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
9209                GDI_Y, y,
9210                GDI_END);
9211   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
9212                GDI_Y, y,
9213                GDI_WIDTH, width,
9214                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
9215                GDI_END);
9216
9217   // adjust vertical scrollbar gadgets
9218   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
9219                GDI_X, x,
9220                GDI_END);
9221   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
9222                GDI_X, x,
9223                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
9224                GDI_END);
9225   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
9226                GDI_X, x,
9227                GDI_HEIGHT, height,
9228                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
9229                GDI_END);
9230 }
9231
9232 static void AdjustLevelScrollPosition(void)
9233 {
9234   if (level_xpos < -1)
9235     level_xpos = -1;
9236   if (level_xpos > lev_fieldx - ed_fieldx + 1)
9237     level_xpos = lev_fieldx - ed_fieldx + 1;
9238   if (lev_fieldx < ed_fieldx - 2)
9239     level_xpos = -1;
9240
9241   if (level_ypos < -1)
9242     level_ypos = -1;
9243   if (level_ypos > lev_fieldy - ed_fieldy + 1)
9244     level_ypos = lev_fieldy - ed_fieldy + 1;
9245   if (lev_fieldy < ed_fieldy - 2)
9246     level_ypos = -1;
9247
9248   if (suppressBorderElement())
9249   {
9250     level_xpos = 0;
9251     level_ypos = 0;
9252   }
9253 }
9254
9255 static void AdjustEditorScrollbar(int id)
9256 {
9257   struct GadgetInfo *gi = level_editor_gadget[id];
9258   int items_max, items_visible, item_position;
9259
9260   if (id == GADGET_ID_SCROLL_HORIZONTAL)
9261   {
9262     items_max = MAX(lev_fieldx + 2, ed_fieldx);
9263     items_visible = ed_fieldx;
9264     item_position = level_xpos + 1;
9265   }
9266   else
9267   {
9268     items_max = MAX(lev_fieldy + 2, ed_fieldy);
9269     items_visible = ed_fieldy;
9270     item_position = level_ypos + 1;
9271   }
9272
9273   if (item_position > items_max - items_visible)
9274     item_position = items_max - items_visible;
9275
9276   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
9277                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
9278 }
9279
9280 static void AdjustElementListScrollbar(void)
9281 {
9282   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
9283   int items_max, items_visible, item_position;
9284
9285   // correct position of element list scrollbar
9286   if (element_shift < 0)
9287     element_shift = 0;
9288   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
9289     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
9290
9291   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
9292   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
9293   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
9294
9295   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
9296                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
9297                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
9298 }
9299
9300 static void ModifyEditorCounterValue(int counter_id, int new_value)
9301 {
9302   int *counter_value = counterbutton_info[counter_id].value;
9303   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
9304   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9305
9306   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
9307
9308   if (counter_value != NULL)
9309     *counter_value = gi->textinput.number_value;
9310 }
9311
9312 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
9313 {
9314   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
9315   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9316
9317   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
9318
9319   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
9320       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
9321   {
9322     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
9323     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
9324
9325     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
9326     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
9327                  GDI_END);
9328   }
9329 }
9330
9331 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
9332 {
9333   int gadget_id = selectbox_info[selectbox_id].gadget_id;
9334   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9335   int new_index_value = setSelectboxValue(selectbox_id, new_value);
9336
9337   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
9338 }
9339
9340 static void ModifyEditorSelectboxOptions(int selectbox_id,
9341                                          struct ValueTextInfo *options)
9342 {
9343   int gadget_id = selectbox_info[selectbox_id].gadget_id;
9344   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9345
9346   selectbox_info[selectbox_id].options = options;
9347
9348   // set index to zero -- list may be shorter now (correct later, if needed)
9349   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
9350                GDI_SELECTBOX_OPTIONS, options, GDI_END);
9351 }
9352
9353 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
9354 {
9355   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
9356   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9357
9358   drawingarea_info[drawingarea_id].area_xsize = xsize;
9359   drawingarea_info[drawingarea_id].area_ysize = ysize;
9360
9361   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
9362 }
9363
9364 static void ModifyEditorElementList(void)
9365 {
9366   int i;
9367
9368   if (!use_permanent_palette && edit_mode != ED_MODE_PALETTE)
9369     return;
9370
9371   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
9372   {
9373     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
9374     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9375     struct GadgetDesign *gd = &gi->deco.design;
9376     int element = editor_elements[element_shift + i];
9377     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
9378
9379     UnmapGadget(gi);
9380
9381     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
9382
9383     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
9384
9385     MapGadget(gi);
9386   }
9387 }
9388
9389 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
9390 {
9391   int graphic = el2edimg(element);
9392   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
9393
9394   if (pos->x == -1 &&
9395       pos->y == -1)
9396     return;
9397
9398   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
9399 }
9400
9401 static void ModifyDrawingElementButton(int element, int id)
9402 {
9403   struct GadgetInfo *gi = level_editor_gadget[id];
9404   Bitmap *deco_bitmap;
9405   int deco_x, deco_y;
9406   int tile_size = gi->deco.width;
9407
9408   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
9409
9410   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
9411 }
9412
9413 static void PickDrawingElement(int button, int element)
9414 {
9415   struct
9416   {
9417     int *new_element;
9418     struct XYTileSize *pos;
9419     int id;
9420   } de, drawing_elements[] =
9421   {
9422     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
9423     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
9424     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
9425   };
9426
9427   if (button < 1 || button > 3)
9428     return;
9429
9430   if (IS_MM_WALL(element))
9431     element = map_mm_wall_element(element);
9432
9433   de = drawing_elements[button - 1];
9434
9435   *de.new_element = element;    // update global drawing element variable
9436
9437   DrawDrawingElementGraphic(element, de.pos);
9438   ModifyDrawingElementButton(element, de.id);
9439
9440   redraw_mask |= REDRAW_DOOR_1;
9441 }
9442
9443 static void RedrawDrawingElements(void)
9444 {
9445   PickDrawingElement(1, new_element1);
9446   PickDrawingElement(2, new_element2);
9447   PickDrawingElement(3, new_element3);
9448 }
9449
9450 static void DrawDrawingWindowExt(boolean remap_toolbox_gadgets)
9451 {
9452   stick_element_properties_window = FALSE;
9453
9454   SetMainBackgroundImage(IMG_UNDEFINED);
9455   ClearField();
9456
9457   UnmapLevelEditorFieldGadgets();
9458
9459   AdjustDrawingAreaGadgets();
9460   AdjustLevelScrollPosition();
9461   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
9462   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
9463
9464   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
9465
9466   MapMainDrawingArea();
9467
9468   if (remap_toolbox_gadgets)
9469   {
9470     UnmapLevelEditorToolboxCustomGadgets();
9471     MapLevelEditorToolboxDrawingGadgets();
9472   }
9473 }
9474
9475 static void DrawDrawingWindow(void)
9476 {
9477   DrawDrawingWindowExt(TRUE);
9478 }
9479
9480 static int getTabulatorBarWidth(void)
9481 {
9482   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
9483   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
9484
9485   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
9486 }
9487
9488 static int getTabulatorBarHeight(void)
9489 {
9490   return ED_TAB_BAR_HEIGHT;
9491 }
9492
9493 static Pixel getTabulatorBarColor(void)
9494 {
9495   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
9496   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
9497   int gd_x = gd->x + gd_gi1->border.width / 2;
9498   int gd_y = gd->y + gd_gi1->height - 1;
9499
9500   return GetPixel(gd->bitmap, gd_x, gd_y);
9501 }
9502
9503 static void DrawLevelConfigTabulatorGadgets(void)
9504 {
9505   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
9506   Pixel tab_color = getTabulatorBarColor();
9507   int id_first = ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST;
9508   int id_last  = ED_TAB_BUTTON_ID_LEVELCONFIG_LAST;
9509   int i;
9510
9511   for (i = id_first; i <= id_last; i++)
9512   {
9513     int gadget_id = textbutton_info[i].gadget_id;
9514     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9515     boolean active = (i != edit_mode_levelconfig);
9516
9517     // draw background line below tabulator button
9518     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
9519
9520     // draw solid line below inactive tabulator buttons
9521     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
9522       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
9523                     ED_GADGET_TINY_DISTANCE, tab_color);
9524
9525     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
9526     MapTextbuttonGadget(i);
9527   }
9528
9529   // draw little border line below tabulator buttons
9530   if (tab_color != BLACK_PIXEL)                 // black => transparent
9531     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
9532                   ED_GADGET_TINY_DISTANCE,
9533                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
9534 }
9535
9536 static void DrawPropertiesTabulatorGadgets(void)
9537 {
9538   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
9539   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
9540   int gd_x = gd->x + gd_gi1->border.width / 2;
9541   int gd_y = gd->y + gd_gi1->height - 1;
9542   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
9543   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
9544   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
9545   int i;
9546
9547   // draw two config tabulators for player elements
9548   if (IS_PLAYER_ELEMENT(properties_element))
9549     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
9550
9551   // draw two config and one "change" tabulator for custom elements
9552   if (IS_CUSTOM_ELEMENT(properties_element))
9553     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
9554
9555   for (i = id_first; i <= id_last; i++)
9556   {
9557     int gadget_id = textbutton_info[i].gadget_id;
9558     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
9559     boolean active = (i != edit_mode_properties);
9560
9561     // use "config 1" and "config 2" instead of "config" for players and CEs
9562     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
9563         (IS_PLAYER_ELEMENT(properties_element) ||
9564          IS_CUSTOM_ELEMENT(properties_element)))
9565       continue;
9566
9567     // draw background line below tabulator button
9568     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
9569
9570     // draw solid line below inactive tabulator buttons
9571     if (!active && tab_color != BLACK_PIXEL)    // black => transparent
9572       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
9573                     ED_GADGET_TINY_DISTANCE, tab_color);
9574
9575     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
9576     MapTextbuttonGadget(i);
9577   }
9578
9579   // draw little border line below tabulator buttons
9580   if (tab_color != BLACK_PIXEL)                 // black => transparent
9581     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
9582                   ED_GADGET_TINY_DISTANCE,
9583                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
9584 }
9585
9586 static void PrintInfoText(char *text, int font_nr, int xpos, int ypos)
9587 {
9588   DrawText(SX + xpos, SY + ypos, text, font_nr);
9589 }
9590
9591 static int PrintElementDescriptionFromFile(char *filename, int font_nr,
9592                                            int xpos, int ypos)
9593 {
9594   int font_width = getFontWidth(font_nr);
9595   int font_height = getFontHeight(font_nr);
9596   int max_chars_per_line = (SXSIZE - 2 * xpos) / font_width;
9597   int max_lines_drawable = (SYSIZE - ypos) / font_height - 1;
9598
9599   return DrawTextFile(SX + xpos, SY + ypos, filename, font_nr,
9600                       max_chars_per_line, -1, max_lines_drawable, 0, -1,
9601                       TRUE, FALSE, FALSE);
9602 }
9603
9604 static void DrawLevelConfigLevel(void)
9605 {
9606   int i;
9607
9608   // draw counter gadgets
9609   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
9610     MapCounterButtons(i);
9611
9612   // draw checkbutton gadgets
9613   for (i = ED_CHECKBUTTON_ID_LEVEL_FIRST; i<= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
9614     MapCheckbuttonGadget(i);
9615
9616   // draw selectbox gadgets
9617   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
9618     MapSelectboxGadget(i);
9619
9620   // draw text input gadgets
9621   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
9622     MapTextInputGadget(i);
9623 }
9624
9625 static char *getLevelSubdirFromSaveMode(int save_mode)
9626 {
9627   if (save_mode == LEVELSET_SAVE_MODE_CREATE)
9628     return getNewUserLevelSubdir();
9629
9630   return leveldir_current->subdir;
9631 }
9632
9633 static void DrawLevelConfigLevelSet_DirectoryInfo(void)
9634 {
9635   char *directory_text = "Level set directory:";
9636   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
9637   int font1_nr = FONT_TEXT_1;
9638   int font2_nr = FONT_TEXT_2;
9639   int font1_height = getFontHeight(font1_nr);
9640   int yoffset_above = font1_height + ED_GADGET_LINE_DISTANCE;
9641   int x = ED_LEVEL_SETTINGS_X(0);
9642   int y = ED_LEVEL_SETTINGS_Y(6);
9643
9644   PrintInfoText(directory_text, font1_nr, x, y - yoffset_above);
9645   PrintInfoText(directory_name, font2_nr, x, y);
9646 }
9647
9648 static void DrawLevelConfigLevelSet(void)
9649 {
9650   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
9651   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
9652   int i;
9653
9654   // draw counter gadgets
9655   for (i = ED_COUNTER_ID_LEVELSET_FIRST; i <= ED_COUNTER_ID_LEVELSET_LAST; i++)
9656     MapCounterButtons(i);
9657
9658   // draw checkbutton gadgets
9659   for (i = ED_CHECKBUTTON_ID_LEVELSET_FIRST; i <= ED_CHECKBUTTON_ID_LEVELSET_LAST; i++)
9660   {
9661     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE ||
9662         (i == ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK && !artwork_exists) ||
9663         (i == ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE  && !template_exists))
9664       continue;
9665
9666     MapCheckbuttonGadget(i);
9667   }
9668
9669   // draw selectbox gadgets
9670   for (i = ED_SELECTBOX_ID_LEVELSET_FIRST; i <= ED_SELECTBOX_ID_LEVELSET_LAST; i++)
9671     MapSelectboxGadget(i);
9672
9673   // draw text input gadgets
9674   for (i = ED_TEXTINPUT_ID_LEVELSET_FIRST; i <= ED_TEXTINPUT_ID_LEVELSET_LAST; i++)
9675     MapTextInputGadget(i);
9676
9677   // draw textbutton gadgets
9678   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
9679
9680   // draw info text
9681   DrawLevelConfigLevelSet_DirectoryInfo();
9682 }
9683
9684 static void DrawLevelConfigEditor(void)
9685 {
9686   int i;
9687
9688   // draw counter gadgets
9689   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
9690     MapCounterButtons(i);
9691
9692   // draw checkbutton gadgets
9693   for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
9694     MapCheckbuttonGadget(i);
9695
9696   // draw radiobutton gadgets
9697   for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
9698     MapRadiobuttonGadget(i);
9699
9700   // draw drawing area
9701   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
9702
9703   // draw textbutton gadgets
9704   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
9705 }
9706
9707 static void DrawLevelConfigWindow(void)
9708 {
9709   char *text = "Global Settings";
9710   int font_nr = FONT_TITLE_1;
9711   struct MenuPosInfo *pos = &editor.settings.headline;
9712   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
9713   int sy = SY + pos->y;
9714
9715   stick_element_properties_window = FALSE;
9716
9717   SetAutomaticNumberOfGemsNeeded();
9718
9719   UnmapLevelEditorFieldGadgets();
9720
9721   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
9722   ClearField();
9723
9724   DrawText(sx, sy, text, font_nr);
9725
9726   DrawLevelConfigTabulatorGadgets();
9727
9728   if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
9729     DrawLevelConfigLevel();
9730   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
9731     DrawLevelConfigLevelSet();
9732   else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
9733     DrawLevelConfigEditor();
9734 }
9735
9736 static void DrawCustomContentArea(void)
9737 {
9738   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
9739   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9740   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
9741   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
9742   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
9743   int xoffset = ED_GADGET_SPACE_DISTANCE;
9744
9745   // add distance for potential left text (without drawing area border)
9746   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
9747
9748   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
9749
9750   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
9751 }
9752
9753 static void DrawCustomChangeContentArea(void)
9754 {
9755   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
9756   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
9757   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
9758   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
9759   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
9760   int xoffset = ED_GADGET_SPACE_DISTANCE;
9761
9762   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
9763
9764   MapDrawingArea(id);
9765 }
9766
9767 static void RemoveElementContentArea(int id, int font_height)
9768 {
9769   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
9770
9771   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
9772                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
9773                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
9774                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
9775                  ED_GADGET_TEXT_DISTANCE + font_height);
9776 }
9777
9778 static void DrawYamYamContentAreas(void)
9779 {
9780   int font_nr = FONT_TEXT_1;
9781   int font_height = getFontHeight(font_nr);
9782   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
9783   int yoffset = (tilesize - font_height) / 2;
9784   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
9785   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
9786   int i;
9787
9788   // display counter to choose number of element content areas
9789   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
9790
9791   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
9792   {
9793     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
9794
9795     if (i < level.num_yamyam_contents)
9796     {
9797       MapDrawingArea(id);
9798     }
9799     else
9800     {
9801       UnmapDrawingArea(id);
9802
9803       // delete content areas in case of reducing number of them
9804       RemoveElementContentArea(id, font_height);
9805     }
9806   }
9807
9808   DrawText(x, y + 0 * tilesize, "content", font_nr);
9809   DrawText(x, y + 1 * tilesize, "when",    font_nr);
9810   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
9811 }
9812
9813 static void DrawMagicBallContentAreas(void)
9814 {
9815   int font_nr = FONT_TEXT_1;
9816   int font_height = getFontHeight(font_nr);
9817   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
9818   int yoffset = (tilesize - font_height) / 2;
9819   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
9820   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
9821   int i;
9822
9823   // display counter to choose number of element content areas
9824   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
9825
9826   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
9827   {
9828     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
9829
9830     if (i < level.num_ball_contents)
9831     {
9832       MapDrawingArea(id);
9833     }
9834     else
9835     {
9836       UnmapDrawingArea(id);
9837
9838       // delete content areas in case of reducing number of them
9839       RemoveElementContentArea(id, font_height);
9840     }
9841   }
9842
9843   DrawText(x, y + 0 * tilesize, "generated", font_nr);
9844   DrawText(x, y + 1 * tilesize, "when",      font_nr);
9845   DrawText(x, y + 2 * tilesize, "active",    font_nr);
9846 }
9847
9848 static void DrawAndroidElementArea(void)
9849 {
9850   int id = ED_DRAWING_ID_ANDROID_CONTENT;
9851   int num_elements = level.num_android_clone_elements;
9852   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
9853   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
9854   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
9855   int xsize = MAX_ANDROID_ELEMENTS;
9856   int ysize = 1;
9857
9858   // display counter to choose number of element areas
9859   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
9860
9861   if (drawingarea_info[id].text_left != NULL)
9862     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9863
9864   UnmapDrawingArea(id);
9865
9866   ModifyEditorDrawingArea(id, num_elements, 1);
9867
9868   // delete content areas in case of reducing number of them
9869   DrawBackground(sx, sy,
9870                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
9871                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
9872
9873   MapDrawingArea(id);
9874 }
9875
9876 static void DrawGroupElementArea(void)
9877 {
9878   int id = ED_DRAWING_ID_GROUP_CONTENT;
9879   int num_elements = group_element_info.num_elements;
9880   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
9881   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
9882   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
9883   int xsize = MAX_ELEMENTS_IN_GROUP;
9884   int ysize = 1;
9885
9886   if (drawingarea_info[id].text_left != NULL)
9887     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9888
9889   UnmapDrawingArea(id);
9890
9891   ModifyEditorDrawingArea(id, num_elements, 1);
9892
9893   // delete content areas in case of reducing number of them
9894   DrawBackground(sx, sy,
9895                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
9896                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
9897
9898   MapDrawingArea(id);
9899 }
9900
9901 static void DrawPlayerInitialInventoryArea(int element)
9902 {
9903   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
9904   int player_nr = GET_PLAYER_NR(element);
9905   int num_elements = level.initial_inventory_size[player_nr];
9906   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
9907   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
9908   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
9909   int xsize = MAX_INITIAL_INVENTORY_SIZE;
9910   int ysize = 1;
9911
9912   // determine horizontal position to the right of specified gadget
9913   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
9914     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
9915           ED_DRAWINGAREA_TEXT_DISTANCE);
9916
9917   // determine horizontal offset for leading text
9918   if (drawingarea_info[id].text_left != NULL)
9919     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9920
9921   UnmapDrawingArea(id);
9922
9923   ModifyEditorDrawingArea(id, num_elements, 1);
9924
9925   // delete content areas in case of reducing number of them
9926   DrawBackground(sx, sy,
9927                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
9928                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
9929
9930   MapDrawingArea(id);
9931 }
9932
9933 static void DrawMMBallContentArea(void)
9934 {
9935   int id = ED_DRAWING_ID_MM_BALL_CONTENT;
9936   int num_elements = level.num_mm_ball_contents;
9937   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
9938   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
9939   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
9940   int xsize = MAX_MM_BALL_CONTENTS;
9941   int ysize = 1;
9942
9943   if (drawingarea_info[id].text_left != NULL)
9944     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
9945
9946   UnmapDrawingArea(id);
9947
9948   ModifyEditorDrawingArea(id, num_elements, 1);
9949
9950   // delete content areas in case of reducing number of them
9951   DrawBackground(sx, sy,
9952                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
9953                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
9954
9955   MapDrawingArea(id);
9956 }
9957
9958 static void DrawEnvelopeTextArea(int envelope_nr)
9959 {
9960   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
9961   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
9962
9963   UnmapGadget(gi);
9964
9965   DrawBackground(gi->x, gi->y,
9966                  gi->textarea.crop_width, gi->textarea.crop_height);
9967
9968   if (envelope_nr != -1)
9969     textarea_info[id].value = level.envelope[envelope_nr].text;
9970
9971   ModifyGadget(gi, GDI_AREA_SIZE,
9972                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
9973                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
9974                GDI_END);
9975
9976   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
9977 }
9978
9979 static void DrawPropertiesInfo(void)
9980 {
9981   static struct
9982   {
9983     int value;
9984     char *text;
9985   }
9986   properties[] =
9987   {
9988     // configurable properties
9989
9990     { EP_WALKABLE_OVER,         "- player can walk over it"             },
9991     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
9992     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
9993     { EP_PASSABLE_OVER,         "- player can pass over it"             },
9994     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
9995     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
9996     { EP_PROTECTED,             "- player is protected by it"           },
9997
9998     { EP_DIGGABLE,              "- can be digged away"                  },
9999     { EP_COLLECTIBLE,           "- can be collected"                    },
10000     { EP_DROPPABLE,             "- can be dropped after collecting"     },
10001     { EP_THROWABLE,             "- can be thrown after collecting"      },
10002     { EP_PUSHABLE,              "- can be pushed"                       },
10003
10004     { EP_CAN_FALL,              "- can fall"                            },
10005     { EP_CAN_MOVE,              "- can move"                            },
10006
10007     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
10008 #if 0
10009     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
10010 #endif
10011     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
10012
10013     { EP_SLIPPERY,              "- slippery for falling elements"       },
10014     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
10015
10016     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
10017     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
10018     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
10019     { EP_DONT_TOUCH,            "- deadly when touching"                },
10020
10021     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
10022
10023     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
10024     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
10025     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
10026
10027     { EP_CAN_CHANGE,            "- can change to other element"         },
10028
10029     // pre-defined properties
10030     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
10031     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
10032     { EP_SWITCHABLE,            "- can be switched"                     },
10033 #if 0
10034     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
10035 #endif
10036
10037     { -1,                       NULL                                    }
10038   };
10039   char *filename = getElementDescriptionFilename(properties_element);
10040   char *num_elements_text = "In this level: ";
10041   char *num_similar_text = "Similar tiles: ";
10042   char *properties_text = "Standard properties: ";
10043   char *description_text = "Description:";
10044   char *no_description_text = "No description available.";
10045   char *none_text = "None";
10046   float percentage;
10047   int num_elements_in_level = 0;
10048   int num_similar_in_level = 0;
10049   int num_hires_tiles_in_level = 0;
10050   int num_standard_properties = 0;
10051   int font1_nr = FONT_TEXT_1;
10052   int font2_nr = FONT_TEXT_2;
10053   int font1_width = getFontWidth(font1_nr);
10054   int font1_height = getFontHeight(font1_nr);
10055   int font2_height = getFontHeight(font2_nr);
10056   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
10057   int font2_yoffset = (font1_height - font2_height) / 2;
10058   int num_elements_text_len = strlen(num_elements_text) * font1_width;
10059   int num_similar_text_len = strlen(num_similar_text) * font1_width;
10060   int properties_text_len = strlen(properties_text) * font1_width;
10061   int xpos = ED_ELEMENT_SETTINGS_X(0);
10062   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
10063   int i, x, y;
10064
10065   if (setup.editor.show_element_token)
10066   {
10067     int font3_nr = FONT_TEXT_3;
10068     int font3_height = getFontHeight(font3_nr);
10069
10070     DrawTextF(xpos, ypos, font3_nr,
10071               "[%s]", element_info[properties_element].token_name);
10072
10073     ypos += 2 * font3_height;
10074   }
10075
10076   // ----- print number of elements / percentage of this element in level
10077
10078   for (y = 0; y < lev_fieldy; y++)
10079   {
10080     for (x = 0; x < lev_fieldx; x++)
10081     {
10082       if (Tile[x][y] == properties_element)
10083       {
10084         num_elements_in_level++;
10085       }
10086       else if (IS_MM_WALL(Tile[x][y]) &&
10087                map_mm_wall_element(Tile[x][y]) == properties_element)
10088       {
10089         num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
10090       }
10091     }
10092   }
10093
10094   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
10095
10096   DrawTextS(xpos, ypos, font1_nr, num_elements_text);
10097
10098   if (num_hires_tiles_in_level > 0)
10099     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
10100               "%d wall tiles", num_hires_tiles_in_level);
10101   else if (num_elements_in_level > 0)
10102     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
10103               "%d (%.2f %%)", num_elements_in_level, percentage);
10104   else
10105     DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
10106               none_text);
10107
10108   // ----- print number of similar elements / percentage of them in level
10109
10110   for (y = 0; y < lev_fieldy; y++)
10111   {
10112     for (x = 0; x < lev_fieldx; x++)
10113     {
10114       if (strEqual(element_info[Tile[x][y]].class_name,
10115                    element_info[properties_element].class_name))
10116       {
10117         num_similar_in_level++;
10118       }
10119     }
10120   }
10121
10122   if (num_similar_in_level != num_elements_in_level)
10123   {
10124     ypos += 1 * MAX(font1_height, font2_height);
10125
10126     percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
10127
10128     DrawTextS(xpos, ypos, font1_nr, num_similar_text);
10129
10130     if (num_similar_in_level > 0)
10131       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
10132                 "%d (%.2f %%)", num_similar_in_level, percentage);
10133     else
10134       DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
10135                 none_text);
10136   }
10137
10138   ypos += 2 * MAX(font1_height, font2_height);
10139
10140   // ----- print standard properties of this element
10141
10142   DrawTextS(xpos, ypos, font1_nr, properties_text);
10143
10144   ypos += line1_height;
10145
10146   for (i = 0; properties[i].value != -1; i++)
10147   {
10148     if (!HAS_PROPERTY(properties_element, properties[i].value))
10149       continue;
10150
10151     DrawTextS(xpos, ypos, font2_nr, properties[i].text);
10152
10153     ypos += font2_height;
10154
10155     num_standard_properties++;
10156   }
10157
10158   if (num_standard_properties == 0)
10159   {
10160     DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
10161               font2_nr, none_text);
10162
10163     ypos -= (line1_height - font1_height);
10164   }
10165
10166   ypos += MAX(font1_height, font2_height);
10167
10168   // ----- print special description of this element
10169
10170   PrintInfoText(description_text, font1_nr, xpos, ypos);
10171
10172   ypos += line1_height;
10173
10174   if (PrintElementDescriptionFromFile(filename, font2_nr, xpos, ypos) == 0)
10175     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
10176 }
10177
10178 #define TEXT_COLLECTING         "Score for collecting"
10179 #define TEXT_SMASHING           "Score for smashing"
10180 #define TEXT_SLURPING           "Score for slurping robot"
10181 #define TEXT_CRACKING           "Score for cracking"
10182 #define TEXT_AMOEBA_SPEED       "Speed of amoeba growth"
10183 #define TEXT_DURATION           "Duration when activated"
10184 #define TEXT_DELAY_ON           "Delay before activating"
10185 #define TEXT_DELAY_OFF          "Delay before deactivating"
10186 #define TEXT_DELAY_CHANGING     "Delay before changing"
10187 #define TEXT_DELAY_EXPLODING    "Delay before exploding"
10188 #define TEXT_DELAY_MOVING       "Delay before moving"
10189 #define TEXT_BALL_DELAY         "Element generation delay"
10190 #define TEXT_MOVE_SPEED         "Speed of android moving"
10191 #define TEXT_CLONE_SPEED        "Speed of android cloning"
10192 #define TEXT_GAME_OF_LIFE_1     "Min neighbours to survive"
10193 #define TEXT_GAME_OF_LIFE_2     "Max neighbours to survive"
10194 #define TEXT_GAME_OF_LIFE_3     "Min neighbours to create"
10195 #define TEXT_GAME_OF_LIFE_4     "Max neighbours to create"
10196 #define TEXT_TIME_BONUS         "Extra time to solve level"
10197
10198 static struct
10199 {
10200   int element;
10201   int *value;
10202   char *text;
10203 } elements_with_counter[] =
10204 {
10205   { EL_EMERALD,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
10206   { EL_BD_DIAMOND,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
10207   { EL_EMERALD_YELLOW,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
10208   { EL_EMERALD_RED,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
10209   { EL_EMERALD_PURPLE,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
10210   { EL_SP_INFOTRON,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
10211   { EL_DIAMOND,         &level.score[SC_DIAMOND],       TEXT_COLLECTING },
10212   { EL_CRYSTAL,         &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
10213   { EL_PEARL,           &level.score[SC_PEARL],         TEXT_COLLECTING },
10214   { EL_BUG,             &level.score[SC_BUG],           TEXT_SMASHING   },
10215   { EL_BUG_RIGHT,       &level.score[SC_BUG],           TEXT_SMASHING   },
10216   { EL_BUG_UP,          &level.score[SC_BUG],           TEXT_SMASHING   },
10217   { EL_BUG_LEFT,        &level.score[SC_BUG],           TEXT_SMASHING   },
10218   { EL_BUG_DOWN,        &level.score[SC_BUG],           TEXT_SMASHING   },
10219   { EL_BD_BUTTERFLY,    &level.score[SC_BUG],           TEXT_SMASHING   },
10220   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],         TEXT_SMASHING   },
10221   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],         TEXT_SMASHING   },
10222   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],         TEXT_SMASHING   },
10223   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],         TEXT_SMASHING   },
10224   { EL_SP_ELECTRON,     &level.score[SC_BUG],           TEXT_SMASHING   },
10225   { EL_SPACESHIP,       &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10226   { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10227   { EL_SPACESHIP_UP,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10228   { EL_SPACESHIP_LEFT,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10229   { EL_SPACESHIP_DOWN,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10230   { EL_BD_FIREFLY,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10231   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10232   { EL_BD_FIREFLY_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10233   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10234   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10235   { EL_SP_SNIKSNAK,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
10236   { EL_YAMYAM,          &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10237   { EL_YAMYAM_LEFT,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10238   { EL_YAMYAM_RIGHT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10239   { EL_YAMYAM_UP,       &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10240   { EL_YAMYAM_DOWN,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10241   { EL_DARK_YAMYAM,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
10242   { EL_ROBOT,           &level.score[SC_ROBOT],         TEXT_SMASHING   },
10243   { EL_PACMAN,          &level.score[SC_PACMAN],        TEXT_SMASHING   },
10244   { EL_PACMAN_RIGHT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
10245   { EL_PACMAN_UP,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
10246   { EL_PACMAN_LEFT,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
10247   { EL_PACMAN_DOWN,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
10248   { EL_NUT,             &level.score[SC_NUT],           TEXT_CRACKING   },
10249   { EL_DYNAMITE,        &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
10250   { EL_EM_DYNAMITE,     &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
10251   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE], TEXT_COLLECTING },
10252   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE], TEXT_COLLECTING },
10253   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE], TEXT_COLLECTING },
10254   { EL_SHIELD_NORMAL,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
10255   { EL_SHIELD_DEADLY,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
10256   { EL_EXTRA_TIME,      &level.extra_time_score,        TEXT_COLLECTING },
10257   { EL_KEY_1,           &level.score[SC_KEY],           TEXT_COLLECTING },
10258   { EL_KEY_2,           &level.score[SC_KEY],           TEXT_COLLECTING },
10259   { EL_KEY_3,           &level.score[SC_KEY],           TEXT_COLLECTING },
10260   { EL_KEY_4,           &level.score[SC_KEY],           TEXT_COLLECTING },
10261   { EL_EM_KEY_1,        &level.score[SC_KEY],           TEXT_COLLECTING },
10262   { EL_EM_KEY_2,        &level.score[SC_KEY],           TEXT_COLLECTING },
10263   { EL_EM_KEY_3,        &level.score[SC_KEY],           TEXT_COLLECTING },
10264   { EL_EM_KEY_4,        &level.score[SC_KEY],           TEXT_COLLECTING },
10265   { EL_EMC_KEY_5,       &level.score[SC_KEY],           TEXT_COLLECTING },
10266   { EL_EMC_KEY_6,       &level.score[SC_KEY],           TEXT_COLLECTING },
10267   { EL_EMC_KEY_7,       &level.score[SC_KEY],           TEXT_COLLECTING },
10268   { EL_EMC_KEY_8,       &level.score[SC_KEY],           TEXT_COLLECTING },
10269   { EL_DC_KEY_WHITE,    &level.score[SC_KEY],           TEXT_COLLECTING },
10270   { EL_MM_KETTLE,       &level.score[SC_EMERALD],       TEXT_COLLECTING },
10271   { EL_DF_CELL,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
10272   { EL_MM_KEY,          &level.score[SC_KEY],           TEXT_COLLECTING },
10273   { EL_MM_LIGHTBALL,    &level.score[SC_ELEM_BONUS],    TEXT_COLLECTING },
10274   { EL_MM_PACMAN,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
10275   { EL_MM_PACMAN_RIGHT, &level.score[SC_PACMAN],        TEXT_SMASHING   },
10276   { EL_MM_PACMAN_UP,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
10277   { EL_MM_PACMAN_LEFT,  &level.score[SC_PACMAN],        TEXT_SMASHING   },
10278   { EL_MM_PACMAN_DOWN,  &level.score[SC_PACMAN],        TEXT_SMASHING   },
10279   { EL_AMOEBA_WET,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
10280   { EL_AMOEBA_DRY,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
10281   { EL_AMOEBA_FULL,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
10282   { EL_BD_AMOEBA,       &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
10283   { EL_EMC_DRIPPER,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
10284   { EL_MAGIC_WALL,      &level.time_magic_wall,         TEXT_DURATION   },
10285   { EL_BD_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
10286   { EL_DC_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
10287   { EL_ROBOT_WHEEL,     &level.time_wheel,              TEXT_DURATION   },
10288
10289   { EL_TIMEGATE_SWITCH,   &level.time_timegate,         TEXT_DURATION   },
10290   { EL_DC_TIMEGATE_SWITCH,&level.time_timegate,         TEXT_DURATION   },
10291   { EL_LIGHT_SWITCH,    &level.time_light,              TEXT_DURATION   },
10292   { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,          TEXT_DURATION   },
10293   { EL_SHIELD_NORMAL,   &level.shield_normal_time,      TEXT_DURATION   },
10294   { EL_SHIELD_DEADLY,   &level.shield_deadly_time,      TEXT_DURATION   },
10295   { EL_EXTRA_TIME,      &level.extra_time,              TEXT_TIME_BONUS },
10296   { EL_TIME_ORB_FULL,   &level.time_orb_time,           TEXT_TIME_BONUS },
10297   { EL_GAME_OF_LIFE,    &level.game_of_life[0],         TEXT_GAME_OF_LIFE_1 },
10298   { EL_GAME_OF_LIFE,    &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
10299   { EL_GAME_OF_LIFE,    &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
10300   { EL_GAME_OF_LIFE,    &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
10301   { EL_BIOMAZE,         &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
10302   { EL_BIOMAZE,         &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
10303   { EL_BIOMAZE,         &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
10304   { EL_BIOMAZE,         &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
10305
10306   { EL_EMC_ANDROID,     &level.android_move_time,       TEXT_MOVE_SPEED },
10307   { EL_EMC_ANDROID,     &level.android_clone_time,      TEXT_CLONE_SPEED },
10308   { EL_EMC_MAGIC_BALL,  &level.ball_time,               TEXT_BALL_DELAY },
10309   { EL_EMC_LENSES,      &level.lenses_score,            TEXT_COLLECTING },
10310   { EL_EMC_MAGNIFIER,   &level.magnify_score,           TEXT_COLLECTING },
10311   { EL_SPRING,          &level.slurp_score,             TEXT_SLURPING   },
10312   { EL_SPRING_LEFT,     &level.slurp_score,             TEXT_SLURPING   },
10313   { EL_SPRING_RIGHT,    &level.slurp_score,             TEXT_SLURPING   },
10314   { EL_EMC_LENSES,      &level.lenses_time,             TEXT_DURATION   },
10315   { EL_EMC_MAGNIFIER,   &level.magnify_time,            TEXT_DURATION   },
10316   { EL_MM_FUSE_ACTIVE,  &level.mm_time_fuse,            TEXT_DELAY_OFF  },
10317   { EL_MM_BOMB,         &level.mm_time_bomb,            TEXT_DELAY_EXPLODING },
10318   { EL_MM_GRAY_BALL,    &level.mm_time_ball,            TEXT_DELAY_CHANGING },
10319   { EL_MM_STEEL_BLOCK,  &level.mm_time_block,           TEXT_DELAY_MOVING },
10320   { EL_MM_WOODEN_BLOCK, &level.mm_time_block,           TEXT_DELAY_MOVING },
10321
10322   { -1,                 NULL,                           NULL            }
10323 };
10324
10325 static boolean checkPropertiesConfig(int element)
10326 {
10327   int i;
10328
10329   if (IS_GEM(element) ||
10330       IS_CUSTOM_ELEMENT(element) ||
10331       IS_GROUP_ELEMENT(element) ||
10332       IS_EMPTY_ELEMENT(element) ||
10333       IS_BALLOON_ELEMENT(element) ||
10334       IS_ENVELOPE(element) ||
10335       IS_MM_ENVELOPE(element) ||
10336       IS_MM_MCDUFFIN(element) ||
10337       IS_DF_LASER(element) ||
10338       IS_PLAYER_ELEMENT(element) ||
10339       HAS_EDITOR_CONTENT(element) ||
10340       CAN_GROW(element) ||
10341       COULD_MOVE_INTO_ACID(element) ||
10342       MAYBE_DONT_COLLIDE_WITH(element) ||
10343       element == EL_BD_PLAYER ||
10344       element == EL_SOKOBAN_OBJECT ||
10345       element == EL_SOKOBAN_FIELD_EMPTY ||
10346       element == EL_SOKOBAN_FIELD_FULL)
10347     return TRUE;
10348   else
10349     for (i = 0; elements_with_counter[i].element != -1; i++)
10350       if (elements_with_counter[i].element == element)
10351         return TRUE;
10352
10353   return FALSE;
10354 }
10355
10356 static void SetAutomaticNumberOfGemsNeeded(void)
10357 {
10358   int x, y;
10359
10360   if (!level.auto_count_gems)
10361     return;
10362
10363   level.gems_needed = 0;
10364
10365   for (x = 0; x < lev_fieldx; x++)
10366   {
10367     for (y = 0; y < lev_fieldy; y++)
10368     {
10369       int element = Tile[x][y];
10370
10371       switch (element)
10372       {
10373         case EL_EMERALD:
10374         case EL_EMERALD_YELLOW:
10375         case EL_EMERALD_RED:
10376         case EL_EMERALD_PURPLE:
10377         case EL_BD_DIAMOND:
10378         case EL_WALL_EMERALD:
10379         case EL_WALL_EMERALD_YELLOW:
10380         case EL_WALL_EMERALD_RED:
10381         case EL_WALL_EMERALD_PURPLE:
10382         case EL_WALL_BD_DIAMOND:
10383         case EL_NUT:
10384         case EL_SP_INFOTRON:
10385         case EL_MM_KETTLE:
10386         case EL_DF_CELL:
10387           level.gems_needed++;
10388           break;
10389
10390         case EL_DIAMOND:
10391         case EL_WALL_DIAMOND:
10392           level.gems_needed += 3;
10393           break;
10394
10395         case EL_PEARL:
10396         case EL_WALL_PEARL:
10397           level.gems_needed += 5;
10398           break;
10399
10400         case EL_CRYSTAL:
10401         case EL_WALL_CRYSTAL:
10402           level.gems_needed += 8;
10403           break;
10404
10405         default:
10406           break;
10407       }
10408     }
10409   }
10410
10411   ModifyEditorCounterValue(ED_COUNTER_ID_LEVEL_GEMSLIMIT, level.gems_needed);
10412 }
10413
10414 static void DrawPropertiesConfig(void)
10415 {
10416   boolean draw_footer_line = FALSE;
10417   int max_num_element_counters = 4;
10418   int num_element_counters = 0;
10419   int i;
10420
10421   if (!checkPropertiesConfig(properties_element))
10422   {
10423     int xpos = ED_ELEMENT_SETTINGS_X(0);
10424     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
10425
10426     PrintInfoText("No configuration options available.",
10427                   FONT_TEXT_1, xpos, ypos);
10428
10429     return;
10430   }
10431
10432   // check if there are elements where a value can be chosen for
10433   for (i = 0; elements_with_counter[i].element != -1; i++)
10434   {
10435     if (elements_with_counter[i].element == properties_element)
10436     {
10437       int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
10438
10439       counterbutton_info[counter_id].y =
10440         ED_ELEMENT_SETTINGS_YPOS(
10441                 (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
10442                 (CAN_GROW(properties_element)                ? 1 : 0) +
10443                 (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
10444                 (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
10445                 (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
10446                 num_element_counters);
10447
10448       counterbutton_info[counter_id].value = elements_with_counter[i].value;
10449       counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
10450
10451       if (properties_element == EL_GAME_OF_LIFE ||
10452           properties_element == EL_BIOMAZE)
10453       {
10454         counterbutton_info[counter_id].min_value = 0;   // min neighbours
10455         counterbutton_info[counter_id].max_value = 8;   // max neighbours
10456       }
10457       else
10458       {
10459         // !!! CHANGE THIS FOR CERTAIN ELEMENTS !!!
10460         counterbutton_info[counter_id].min_value = MIN_SCORE;
10461         counterbutton_info[counter_id].max_value = MAX_SCORE;
10462       }
10463
10464       MapCounterButtons(counter_id);
10465
10466       num_element_counters++;
10467       if (num_element_counters >= max_num_element_counters)
10468         break;
10469     }
10470   }
10471
10472   if (HAS_EDITOR_CONTENT(properties_element))
10473   {
10474     // draw stickybutton gadget
10475     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
10476
10477     if (IS_AMOEBOID(properties_element))
10478       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
10479     else if (properties_element == EL_YAMYAM ||
10480              properties_element == EL_YAMYAM_LEFT ||
10481              properties_element == EL_YAMYAM_RIGHT ||
10482              properties_element == EL_YAMYAM_UP ||
10483              properties_element == EL_YAMYAM_DOWN)
10484       DrawYamYamContentAreas();
10485     else if (properties_element == EL_EMC_MAGIC_BALL)
10486     {
10487       DrawMagicBallContentAreas();
10488
10489       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
10490       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
10491     }
10492     else if (properties_element == EL_EMC_ANDROID)
10493       DrawAndroidElementArea();
10494     else if (properties_element == EL_MM_GRAY_BALL)
10495     {
10496       MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
10497       MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
10498       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
10499       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
10500
10501       DrawMMBallContentArea();
10502     }
10503   }
10504
10505   if (IS_PLAYER_ELEMENT(properties_element))
10506   {
10507     int player_nr = GET_PLAYER_NR(properties_element);
10508
10509     // these properties can be set for every player individually
10510
10511     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
10512     {
10513       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
10514         &level.start_element[player_nr];
10515       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
10516         &level.artwork_element[player_nr];
10517       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
10518         &level.explosion_element[player_nr];
10519
10520       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
10521         &level.use_start_element[player_nr];
10522       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
10523         &level.use_artwork_element[player_nr];
10524       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
10525         &level.use_explosion_element[player_nr];
10526       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
10527         &level.initial_player_gravity[player_nr];
10528
10529       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
10530         &level.initial_player_stepsize[player_nr];
10531
10532       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
10533       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
10534                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
10535                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
10536       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
10537       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
10538       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
10539       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
10540       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
10541       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
10542       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
10543       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
10544       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
10545       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
10546       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER);
10547
10548       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
10549       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
10550       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
10551
10552       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
10553     }
10554     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
10555     {
10556       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
10557         &level.initial_inventory_content[player_nr][0];
10558
10559       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
10560         &level.initial_inventory_size[player_nr];
10561
10562       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
10563         &level.use_initial_inventory[player_nr];
10564
10565       // draw checkbutton gadgets
10566       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
10567       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
10568       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
10569
10570       // draw counter gadgets
10571       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
10572
10573       // draw drawing area gadgets
10574       DrawPlayerInitialInventoryArea(properties_element);
10575     }
10576   }
10577
10578   if (properties_element == EL_BD_PLAYER)
10579     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
10580
10581   if (IS_GEM(properties_element))
10582     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
10583
10584   if (properties_element == EL_EM_DYNAMITE)
10585     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
10586
10587   if (COULD_MOVE_INTO_ACID(properties_element) &&
10588       !IS_PLAYER_ELEMENT(properties_element) &&
10589       (!IS_CUSTOM_ELEMENT(properties_element) ||
10590        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
10591   {
10592     // set position for checkbutton for "can move into acid"
10593     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
10594       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
10595     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
10596       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
10597                                IS_BALLOON_ELEMENT(properties_element) ||
10598                                HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
10599
10600     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
10601   }
10602
10603   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
10604     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
10605
10606   if (properties_element == EL_SPRING ||
10607       properties_element == EL_SPRING_LEFT ||
10608       properties_element == EL_SPRING_RIGHT)
10609     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
10610
10611   if (properties_element == EL_TIME_ORB_FULL)
10612     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
10613
10614   if (properties_element == EL_GAME_OF_LIFE ||
10615       properties_element == EL_BIOMAZE)
10616     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
10617
10618   if (CAN_GROW(properties_element))
10619   {
10620     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
10621       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
10622
10623     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
10624   }
10625
10626   if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
10627     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
10628
10629   if (properties_element == EL_SOKOBAN_OBJECT)
10630     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
10631
10632   if (properties_element == EL_SOKOBAN_OBJECT ||
10633       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
10634       properties_element == EL_SOKOBAN_FIELD_FULL)
10635   {
10636     checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
10637       ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
10638                                0 : 1);
10639
10640     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
10641   }
10642
10643   if (IS_BALLOON_ELEMENT(properties_element))
10644     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
10645
10646   if (IS_ENVELOPE(properties_element) ||
10647       IS_MM_ENVELOPE(properties_element))
10648   {
10649     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
10650     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
10651     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
10652     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
10653     int envelope_nr = ENVELOPE_NR(properties_element);
10654
10655     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
10656     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
10657
10658     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
10659     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
10660
10661     // display counter to choose size of envelope text area
10662     MapCounterButtons(counter1_id);
10663     MapCounterButtons(counter2_id);
10664
10665     // display checkbuttons to choose auto-wrap and alignment properties
10666     MapCheckbuttonGadget(button1_id);
10667     MapCheckbuttonGadget(button2_id);
10668
10669     DrawEnvelopeTextArea(envelope_nr);
10670   }
10671
10672   if (IS_MM_MCDUFFIN(properties_element))
10673   {
10674     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_RED);
10675     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_GREEN);
10676     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_MM_LASER_BLUE);
10677   }
10678
10679   if (IS_DF_LASER(properties_element))
10680   {
10681     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_RED);
10682     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_GREEN);
10683     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DF_LASER_BLUE);
10684   }
10685
10686   if (IS_CUSTOM_ELEMENT(properties_element))
10687   {
10688     // draw stickybutton gadget
10689     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
10690
10691     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
10692     {
10693       // draw checkbutton gadgets
10694       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
10695            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
10696         MapCheckbuttonGadget(i);
10697
10698       // draw counter gadgets
10699       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
10700            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
10701         MapCounterButtons(i);
10702
10703       // draw selectbox gadgets
10704       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
10705            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
10706         MapSelectboxGadget(i);
10707
10708       // draw textbutton gadgets
10709       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
10710
10711       // draw text input gadgets
10712       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
10713
10714       // draw drawing area gadgets
10715       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
10716
10717       draw_footer_line = TRUE;
10718     }
10719     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
10720     {
10721       // draw checkbutton gadgets
10722       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
10723            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
10724         MapCheckbuttonGadget(i);
10725
10726       // draw counter gadgets
10727       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
10728            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
10729         MapCounterButtons(i);
10730
10731       // draw selectbox gadgets
10732       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
10733            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
10734         MapSelectboxGadget(i);
10735
10736       // draw drawing area gadgets
10737       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
10738       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
10739       DrawCustomContentArea();
10740     }
10741   }
10742   else if (IS_GROUP_ELEMENT(properties_element))
10743   {
10744     // draw stickybutton gadget
10745     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
10746
10747     // draw checkbutton gadgets
10748     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
10749     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
10750
10751     // draw counter gadgets
10752     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
10753
10754     // draw selectbox gadgets
10755     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
10756
10757     // draw textbutton gadgets
10758     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
10759
10760     // draw drawing area gadgets
10761     DrawGroupElementArea();
10762
10763     // draw text input gadgets
10764     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
10765
10766     // draw drawing area gadgets
10767     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
10768
10769     draw_footer_line = TRUE;
10770   }
10771   else if (IS_EMPTY_ELEMENT(properties_element))
10772   {
10773     // draw stickybutton gadget
10774     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
10775
10776     // draw checkbutton gadgets
10777     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
10778     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
10779
10780     // draw textbutton gadgets
10781     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
10782
10783     // draw drawing area gadgets
10784     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
10785
10786     draw_footer_line = TRUE;
10787   }
10788
10789   // draw little footer border line above CE/GE use/save template gadgets
10790   if (draw_footer_line)
10791   {
10792     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
10793     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
10794     int gd_x = gd->x + gd_gi1->border.width / 2;
10795     int gd_y = gd->y + gd_gi1->height - 1;
10796     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
10797
10798     if (tab_color != BLACK_PIXEL)               // black => transparent
10799       FillRectangle(drawto,
10800                     SX + ED_ELEMENT_SETTINGS_X(0),
10801                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
10802                     ED_TAB_BAR_HEIGHT,
10803                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
10804   }
10805 }
10806
10807 static void DrawPropertiesChangeDrawingAreas(void)
10808 {
10809   if (IS_CUSTOM_ELEMENT(properties_element))
10810   {
10811     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
10812     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
10813     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
10814
10815     DrawCustomChangeContentArea();
10816   }
10817
10818   redraw_mask |= REDRAW_FIELD;
10819 }
10820
10821 static void DrawPropertiesChange(void)
10822 {
10823   int i;
10824
10825   // needed to initially set selectbox options for special action options
10826   setSelectboxSpecialActionOptions();
10827
10828   // draw stickybutton gadget
10829   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
10830
10831   // draw checkbutton gadgets
10832   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
10833        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
10834     MapCheckbuttonGadget(i);
10835
10836   // draw counter gadgets
10837   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
10838        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
10839     MapCounterButtons(i);
10840
10841   // draw selectbox gadgets
10842   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
10843        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
10844     MapSelectboxGadget(i);
10845
10846   // draw textbutton gadgets
10847   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
10848        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
10849     MapTextbuttonGadget(i);
10850
10851   // draw graphicbutton gadgets
10852   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
10853        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
10854     MapGraphicbuttonGadget(i);
10855
10856   // draw drawing area gadgets
10857   DrawPropertiesChangeDrawingAreas();
10858 }
10859
10860 static void DrawEditorElementAnimation(int x, int y)
10861 {
10862   int graphic = el2img(properties_element);
10863   int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
10864                custom_element.ce_value_fixed_initial :
10865                ANIM_MODE(graphic) == ANIM_CE_SCORE ?
10866                custom_element.collect_score_initial : FrameCounter);
10867
10868   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
10869 }
10870
10871 static void DrawEditorElementName(int x, int y, int font_nr)
10872 {
10873   char *element_name = getElementInfoText(properties_element);
10874   int font_width = getFontWidth(font_nr);
10875   int font_height = getFontHeight(font_nr);
10876   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
10877   int max_chars_per_line = max_text_width / font_width;
10878
10879   if (strlen(element_name) <= max_chars_per_line)
10880     DrawTextS(x, y, font_nr, element_name);
10881   else
10882   {
10883     char buffer[max_chars_per_line + 1];
10884     int next_pos = max_chars_per_line;
10885
10886     strncpy(buffer, element_name, max_chars_per_line);
10887     buffer[max_chars_per_line] = '\0';
10888
10889     if (element_name[max_chars_per_line] == ' ')
10890       next_pos++;
10891     else
10892     {
10893       int i;
10894
10895       for (i = max_chars_per_line - 1; i >= 0; i--)
10896         if (buffer[i] == ' ')
10897           break;
10898
10899       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
10900       {
10901         buffer[i] = '\0';
10902         next_pos = i + 1;
10903       }
10904     }
10905
10906     DrawTextS(x, y - font_height / 2, font_nr, buffer);
10907
10908     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
10909     buffer[max_chars_per_line] = '\0';
10910
10911     DrawTextS(x, y + font_height / 2, font_nr, buffer);
10912   }
10913 }
10914
10915 static void DrawPropertiesWindow(void)
10916 {
10917   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
10918   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
10919   int border_size = gd->border_size;
10920   int font_nr = FONT_TEXT_1;
10921   int font_height = getFontHeight(font_nr);
10922   int xoffset = TILEX + element_border + 3 * border_size;
10923   int yoffset = (TILEY - font_height) / 2;
10924   int x1 = editor.settings.element_graphic.x + element_border;
10925   int y1 = editor.settings.element_graphic.y + element_border;
10926   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
10927             editor.settings.element_name.x);
10928   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
10929             editor.settings.element_name.y);
10930   char *text = "Element Settings";
10931   int font2_nr = FONT_TITLE_1;
10932   struct MenuPosInfo *pos = &editor.settings.headline;
10933   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
10934   int sy = SY + pos->y;
10935
10936   stick_element_properties_window = FALSE;
10937
10938   // make sure that previous properties edit mode exists for this element
10939   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
10940       !IS_CUSTOM_ELEMENT(properties_element))
10941     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
10942
10943   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
10944       !IS_PLAYER_ELEMENT(properties_element) &&
10945       !IS_CUSTOM_ELEMENT(properties_element))
10946     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
10947
10948   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
10949       (IS_PLAYER_ELEMENT(properties_element) ||
10950        IS_CUSTOM_ELEMENT(properties_element)))
10951     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
10952
10953   CopyElementPropertiesToEditor(properties_element);
10954
10955   UnmapLevelEditorFieldGadgets();
10956   UnmapLevelEditorToolboxDrawingGadgets();
10957   UnmapLevelEditorToolboxCustomGadgets();
10958
10959   MapLevelEditorToolboxCustomGadgetsIfNeeded();
10960
10961   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
10962   ClearField();
10963
10964   DrawText(sx, sy, text, font2_nr);
10965
10966   FrameCounter = 0;     // restart animation frame counter
10967
10968   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
10969   DrawEditorElementAnimation(SX + x1, SY + y1);
10970   DrawEditorElementName(x2, y2, font_nr);
10971
10972   DrawPropertiesTabulatorGadgets();
10973
10974   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
10975     DrawPropertiesInfo();
10976   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
10977     DrawPropertiesChange();
10978   else  // (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2])
10979     DrawPropertiesConfig();
10980 }
10981
10982 static void DrawPaletteWindow(void)
10983 {
10984   int i;
10985
10986   UnmapLevelEditorFieldGadgets();
10987
10988   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
10989   ClearField();
10990
10991   // map buttons to select elements
10992   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
10993     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
10994   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
10995   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
10996   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
10997 }
10998
10999 static void UpdateCustomElementGraphicGadgets(void)
11000 {
11001   int i;
11002
11003   InitElementPropertiesGfxElement();
11004
11005   ModifyEditorElementList();
11006   RedrawDrawingElements();
11007
11008   // force redraw of all mapped drawing area gadgets
11009   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
11010   {
11011     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
11012
11013     if (gi->mapped)
11014       MapDrawingArea(i);
11015   }
11016 }
11017
11018 static int getOpenDirectionFromTube(int element)
11019 {
11020   switch (element)
11021   {
11022     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
11023     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
11024     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
11025     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
11026     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
11027     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
11028     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
11029     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
11030     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
11031     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
11032     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
11033   }
11034
11035   return MV_NONE;
11036 }
11037
11038 static int getTubeFromOpenDirection(int direction)
11039 {
11040   switch (direction)
11041   {
11042     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
11043     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
11044     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
11045     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
11046     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
11047     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
11048     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
11049     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
11050     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
11051     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
11052     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
11053
11054     // if only one direction, fall back to simple tube with that direction
11055     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
11056     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
11057     case (MV_UP):                       return EL_TUBE_VERTICAL;
11058     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
11059   }
11060
11061   return EL_EMPTY;
11062 }
11063
11064 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
11065 {
11066   int element_new = getTubeFromOpenDirection(direction);
11067
11068   return (element_new != EL_EMPTY ? element_new : element_old);
11069 }
11070
11071 static int getOpenDirectionFromBelt(int element)
11072 {
11073   int belt_dir = getBeltDirFromBeltElement(element);
11074
11075   return (belt_dir == MV_LEFT ? MV_RIGHT :
11076           belt_dir == MV_RIGHT ? MV_LEFT :
11077           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
11078 }
11079
11080 static int getBeltFromNrAndOpenDirection(int nr, int direction)
11081 {
11082   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
11083                   direction == MV_RIGHT ? MV_LEFT :
11084                   direction == MV_HORIZONTAL ? MV_NONE : direction);
11085
11086   if (direction == MV_NONE)
11087     return EL_EMPTY;
11088
11089   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
11090 }
11091
11092 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
11093                                                  int element_old)
11094 {
11095   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
11096
11097   return (element_new != EL_EMPTY ? element_new : element_old);
11098 }
11099
11100 static int getOpenDirectionFromPool(int element)
11101 {
11102   switch (element)
11103   {
11104     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
11105     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
11106     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
11107     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
11108     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
11109     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
11110   }
11111
11112   return MV_NONE;
11113 }
11114
11115 static int getPoolFromOpenDirection(int direction)
11116 {
11117   switch (direction)
11118   {
11119     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
11120     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
11121     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
11122     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
11123     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
11124     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
11125   }
11126
11127   return EL_EMPTY;
11128 }
11129
11130 static int getPoolFromOpenDirectionExt(int direction, int help_element)
11131 {
11132   int element = getPoolFromOpenDirection(direction);
11133   int help_direction = getOpenDirectionFromPool(help_element);
11134
11135   if (element == EL_EMPTY)
11136   {
11137     int help_direction_vertical = help_direction & MV_VERTICAL;
11138
11139     element = getPoolFromOpenDirection(direction | help_direction_vertical);
11140   }
11141
11142   if (element == EL_EMPTY)
11143   {
11144     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
11145
11146     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
11147   }
11148
11149   return element;
11150 }
11151
11152 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
11153 {
11154   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
11155
11156   return (element_new != EL_EMPTY ? element_new : element_old);
11157 }
11158
11159 static int getOpenDirectionFromPillar(int element)
11160 {
11161   switch (element)
11162   {
11163     case EL_EMC_WALL_1:                 return (MV_DOWN);
11164     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
11165     case EL_EMC_WALL_3:                 return (MV_UP);
11166   }
11167
11168   return MV_NONE;
11169 }
11170
11171 static int getPillarFromOpenDirection(int direction)
11172 {
11173   switch (direction)
11174   {
11175     case (MV_DOWN):                     return EL_EMC_WALL_1;
11176     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
11177     case (MV_UP):                       return EL_EMC_WALL_3;
11178   }
11179
11180   return EL_EMPTY;
11181 }
11182
11183 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
11184 {
11185   int element_new = getPillarFromOpenDirection(direction);
11186
11187   return (element_new != EL_EMPTY ? element_new : element_old);
11188 }
11189
11190 static int getOpenDirectionFromSteel2(int element)
11191 {
11192   switch (element)
11193   {
11194     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
11195     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
11196     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
11197     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
11198     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
11199     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
11200     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
11201     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
11202   }
11203
11204   return MV_NONE;
11205 }
11206
11207 static int getSteel2FromOpenDirection(int direction)
11208 {
11209   switch (direction)
11210   {
11211     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
11212     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
11213     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
11214     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
11215     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
11216     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
11217     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
11218     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
11219   }
11220
11221   return EL_EMPTY;
11222 }
11223
11224 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
11225 {
11226   int element_new = getSteel2FromOpenDirection(direction);
11227
11228   return (element_new != EL_EMPTY ? element_new : element_old);
11229 }
11230
11231 static int getOpenDirectionFromChip(int element)
11232 {
11233   switch (element)
11234   {
11235     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
11236     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
11237     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
11238     case EL_SP_CHIP_TOP:                return (MV_DOWN);
11239     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
11240   }
11241
11242   return MV_NONE;
11243 }
11244
11245 static int getChipFromOpenDirection(int direction)
11246 {
11247   switch (direction)
11248   {
11249     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
11250     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
11251     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
11252     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
11253     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
11254   }
11255
11256   return EL_EMPTY;
11257 }
11258
11259 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
11260 {
11261   int element_new = getChipFromOpenDirection(direction);
11262
11263   return (element_new != EL_EMPTY ? element_new : element_old);
11264 }
11265
11266 static int getClosedTube(int x, int y)
11267 {
11268   struct XY *xy = xy_directions;
11269   int element_old = IntelliDrawBuffer[x][y];
11270   int direction_old = getOpenDirectionFromTube(element_old);
11271   int direction_new = MV_NONE;
11272   int i;
11273
11274   for (i = 0; i < NUM_DIRECTIONS; i++)
11275   {
11276     int xx = x + xy[i].x;
11277     int yy = y + xy[i].y;
11278     int dir = MV_DIR_FROM_BIT(i);
11279     int dir_opposite = MV_DIR_OPPOSITE(dir);
11280
11281     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
11282         (direction_old & dir) &&
11283         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11284       direction_new |= dir;
11285   }
11286
11287   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
11288 }
11289
11290 static int getClosedBelt(int x, int y)
11291 {
11292   struct XY *xy = xy_directions;
11293   int element_old = IntelliDrawBuffer[x][y];
11294   int nr = getBeltNrFromBeltElement(element_old);
11295   int direction_old = getOpenDirectionFromBelt(element_old);
11296   int direction_new = MV_NONE;
11297   int i;
11298
11299   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
11300   {
11301     int xx = x + xy[i].x;
11302     int yy = y + xy[i].y;
11303     int dir = MV_DIR_FROM_BIT(i);
11304     int dir_opposite = MV_DIR_OPPOSITE(dir);
11305
11306     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
11307         (direction_old & dir) &&
11308         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11309       direction_new |= dir;
11310   }
11311
11312   return getBeltFromNrAndOpenDirection(nr, direction_new);
11313 }
11314
11315 static int getClosedPool(int x, int y)
11316 {
11317   struct XY *xy = xy_directions;
11318   int element_old = IntelliDrawBuffer[x][y];
11319   int direction_old = getOpenDirectionFromPool(element_old);
11320   int direction_new = MV_NONE;
11321   int i;
11322
11323   for (i = 0; i < NUM_DIRECTIONS; i++)
11324   {
11325     int xx = x + xy[i].x;
11326     int yy = y + xy[i].y;
11327     int dir = MV_DIR_FROM_BIT(i);
11328     int dir_opposite = MV_DIR_OPPOSITE(dir);
11329
11330     if (IN_LEV_FIELD(xx, yy) &&
11331         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
11332         (direction_old & dir) &&
11333         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11334       direction_new |= dir;
11335   }
11336
11337   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
11338 }
11339
11340 static int getClosedPillar(int x, int y)
11341 {
11342   struct XY *xy = xy_directions;
11343   int element_old = IntelliDrawBuffer[x][y];
11344   int direction_old = getOpenDirectionFromPillar(element_old);
11345   int direction_new = MV_NONE;
11346   int i;
11347
11348   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
11349   {
11350     int xx = x + xy[i].x;
11351     int yy = y + xy[i].y;
11352     int dir = MV_DIR_FROM_BIT(i);
11353     int dir_opposite = MV_DIR_OPPOSITE(dir);
11354
11355     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
11356         (direction_old & dir) &&
11357         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11358       direction_new |= dir;
11359   }
11360
11361   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
11362 }
11363
11364 static int getClosedSteel2(int x, int y)
11365 {
11366   struct XY *xy = xy_directions;
11367   int element_old = IntelliDrawBuffer[x][y];
11368   int direction_old = getOpenDirectionFromSteel2(element_old);
11369   int direction_new = MV_NONE;
11370   int i;
11371
11372   for (i = 0; i < NUM_DIRECTIONS; i++)
11373   {
11374     int xx = x + xy[i].x;
11375     int yy = y + xy[i].y;
11376     int dir = MV_DIR_FROM_BIT(i);
11377     int dir_opposite = MV_DIR_OPPOSITE(dir);
11378
11379     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
11380         (direction_old & dir) &&
11381         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11382       direction_new |= dir;
11383   }
11384
11385   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
11386 }
11387
11388 static int getClosedChip(int x, int y)
11389 {
11390   struct XY *xy = xy_directions;
11391   int element_old = IntelliDrawBuffer[x][y];
11392   int direction_old = getOpenDirectionFromChip(element_old);
11393   int direction_new = MV_NONE;
11394   int i;
11395
11396   for (i = 0; i < NUM_DIRECTIONS; i++)
11397   {
11398     int xx = x + xy[i].x;
11399     int yy = y + xy[i].y;
11400     int dir = MV_DIR_FROM_BIT(i);
11401     int dir_opposite = MV_DIR_OPPOSITE(dir);
11402
11403     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
11404         (direction_old & dir) &&
11405         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
11406       direction_new |= dir;
11407   }
11408
11409   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
11410 }
11411
11412 static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
11413                                 boolean change_level)
11414 {
11415   int sx = x - level_xpos;
11416   int sy = y - level_ypos;
11417   int old_element = Tile[x][y];
11418   int new_element = element;
11419   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
11420   boolean draw_masked = FALSE;
11421
11422   if (IS_MM_WALL_EDITOR(element))
11423   {
11424     element = map_mm_wall_element_editor(element) | new_bitmask;
11425
11426     if (IS_MM_WALL(old_element))
11427       element |= MM_WALL_BITS(old_element);
11428
11429     if (!change_level)
11430       draw_masked = TRUE;
11431   }
11432   else if (IS_MM_WALL(old_element) && element == EL_EMPTY)
11433   {
11434     int element_changed = old_element & ~new_bitmask;
11435
11436     if (MM_WALL_BITS(element_changed) != 0)
11437       element = element_changed;
11438   }
11439
11440   IntelliDrawBuffer[x][y] = element;
11441
11442   if (change_level)
11443     Tile[x][y] = element;
11444
11445   if (IN_ED_FIELD(sx, sy))
11446   {
11447     if (IS_MM_WALL(old_element) && new_element == EL_EMPTY)
11448       DrawSizedWallParts_MM(sx, sy, EL_EMPTY, ed_tilesize, FALSE, new_bitmask);
11449     else if (draw_masked)
11450       DrawEditorElementThruMask(sx, sy, element);
11451     else
11452       DrawEditorElement(sx, sy, element);
11453   }
11454 }
11455
11456 static void SetElementSimple(int x, int y, int element, boolean change_level)
11457 {
11458   SetElementSimpleExt(x, y, 0, 0, element, change_level);
11459 }
11460
11461 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
11462                                            int x2, int y2, int *element2,
11463                                            int (*close_function)(int, int),
11464                                            boolean change_level)
11465 {
11466   // set neighbour elements to newly determined connections
11467   SetElementSimple(x1, y1, *element1, change_level);
11468   SetElementSimple(x2, y2, *element2, change_level);
11469
11470   // remove all open connections of neighbour elements
11471   *element1 = close_function(x1, y1);
11472   *element2 = close_function(x2, y2);
11473
11474   // set neighbour elements to new, minimized connections
11475   SetElementSimple(x1, y1, *element1, change_level);
11476   SetElementSimple(x2, y2, *element2, change_level);
11477 }
11478
11479 static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
11480                                   boolean change_level, int button)
11481 {
11482   struct XY *xy = xy_directions;
11483   static int last_x = -1;
11484   static int last_y = -1;
11485
11486   if (new_element == EL_UNDEFINED)
11487   {
11488     last_x = -1;
11489     last_y = -1;
11490
11491     return;
11492   }
11493
11494   int old_element = IntelliDrawBuffer[x][y];
11495
11496   if (IS_TUBE(new_element))
11497   {
11498     int last_element_new = EL_UNDEFINED;
11499     int direction = MV_NONE;
11500     int i;
11501
11502     // if old element is of same kind, keep all existing directions
11503     if (IS_TUBE(old_element))
11504       direction |= getOpenDirectionFromTube(old_element);
11505
11506     for (i = 0; i < NUM_DIRECTIONS; i++)
11507     {
11508       int xx = x + xy[i].x;
11509       int yy = y + xy[i].y;
11510
11511       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11512           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
11513       {
11514         int dir = MV_DIR_FROM_BIT(i);
11515         int dir_opposite = MV_DIR_OPPOSITE(dir);
11516         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11517         int last_direction_old = getOpenDirectionFromTube(last_element_old);
11518         int last_direction_new = last_direction_old | dir_opposite;
11519
11520         last_element_new = getTubeFromOpenDirection(last_direction_new);
11521
11522         direction |= dir;
11523       }
11524     }
11525
11526     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
11527
11528     if (last_element_new != EL_UNDEFINED)
11529       MergeAndCloseNeighbourElements(x, y, &new_element,
11530                                      last_x, last_y, &last_element_new,
11531                                      getClosedTube, change_level);
11532   }
11533   else if (IS_BELT(new_element))
11534   {
11535     int belt_nr = getBeltNrFromBeltElement(new_element);
11536     int last_element_new = EL_UNDEFINED;
11537     int direction = MV_NONE;
11538     int i;
11539
11540     // if old element is of same kind, keep all existing directions
11541     if (IS_BELT(old_element))
11542       direction |= getOpenDirectionFromBelt(old_element);
11543
11544     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
11545     {
11546       int xx = x + xy[i].x;
11547       int yy = y + xy[i].y;
11548
11549       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11550           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
11551       {
11552         int dir = MV_DIR_FROM_BIT(i);
11553         int dir_opposite = MV_DIR_OPPOSITE(dir);
11554         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11555         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
11556         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
11557         int last_direction_new = last_direction_old | dir_opposite;
11558
11559         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
11560                                                          last_direction_new);
11561         direction |= dir;
11562       }
11563     }
11564
11565     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
11566                                                         new_element);
11567     if (last_element_new != EL_UNDEFINED)
11568       MergeAndCloseNeighbourElements(x, y, &new_element,
11569                                      last_x, last_y, &last_element_new,
11570                                      getClosedBelt, change_level);
11571   }
11572   else if (IS_ACID_POOL_OR_ACID(new_element))
11573   {
11574     int last_element_new = EL_UNDEFINED;
11575     int direction = MV_NONE;
11576     int i;
11577
11578     // if old element is of same kind, keep all existing directions
11579     if (IS_ACID_POOL_OR_ACID(old_element))
11580       direction |= getOpenDirectionFromPool(old_element);
11581
11582     for (i = 0; i < NUM_DIRECTIONS; i++)
11583     {
11584       int xx = x + xy[i].x;
11585       int yy = y + xy[i].y;
11586
11587       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11588           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
11589       {
11590         int dir = MV_DIR_FROM_BIT(i);
11591         int dir_opposite = MV_DIR_OPPOSITE(dir);
11592         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11593         int last_direction_old = getOpenDirectionFromPool(last_element_old);
11594         int last_direction_new = last_direction_old | dir_opposite;
11595
11596         last_element_new = getPoolFromOpenDirection(last_direction_new);
11597
11598         direction |= dir;
11599       }
11600     }
11601
11602     // special corrections needed for intuitively correct acid pool drawing
11603     if (last_element_new == EL_EMPTY)
11604       last_element_new = new_element;
11605     else if (last_element_new != EL_UNDEFINED)
11606       new_element = last_element_new;
11607
11608     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
11609
11610     if (last_element_new != EL_UNDEFINED)
11611       MergeAndCloseNeighbourElements(x, y, &new_element,
11612                                      last_x, last_y, &last_element_new,
11613                                      getClosedPool, change_level);
11614   }
11615   else if (IS_EMC_PILLAR(new_element))
11616   {
11617     int last_element_new = EL_UNDEFINED;
11618     int direction = MV_NONE;
11619     int i;
11620
11621     // if old element is of same kind, keep all existing directions
11622     if (IS_EMC_PILLAR(old_element))
11623       direction |= getOpenDirectionFromPillar(old_element);
11624
11625     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
11626     {
11627       int xx = x + xy[i].x;
11628       int yy = y + xy[i].y;
11629
11630       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11631           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
11632       {
11633         int dir = MV_DIR_FROM_BIT(i);
11634         int dir_opposite = MV_DIR_OPPOSITE(dir);
11635         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11636         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
11637         int last_direction_new = last_direction_old | dir_opposite;
11638
11639         last_element_new = getPillarFromOpenDirection(last_direction_new);
11640
11641         direction |= dir;
11642       }
11643     }
11644
11645     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
11646
11647     if (last_element_new != EL_UNDEFINED)
11648       MergeAndCloseNeighbourElements(x, y, &new_element,
11649                                      last_x, last_y, &last_element_new,
11650                                      getClosedPillar, change_level);
11651   }
11652   else if (IS_DC_STEELWALL_2(new_element))
11653   {
11654     int last_element_new = EL_UNDEFINED;
11655     int direction = MV_NONE;
11656     int i;
11657
11658     // if old element is of same kind, keep all existing directions
11659     if (IS_DC_STEELWALL_2(old_element))
11660       direction |= getOpenDirectionFromSteel2(old_element);
11661
11662     for (i = 0; i < NUM_DIRECTIONS; i++)
11663     {
11664       int xx = x + xy[i].x;
11665       int yy = y + xy[i].y;
11666
11667       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11668           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
11669       {
11670         int dir = MV_DIR_FROM_BIT(i);
11671         int dir_opposite = MV_DIR_OPPOSITE(dir);
11672         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11673         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
11674         int last_direction_new = last_direction_old | dir_opposite;
11675
11676         last_element_new = getSteel2FromOpenDirection(last_direction_new);
11677
11678         direction |= dir;
11679       }
11680     }
11681
11682     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
11683
11684     if (last_element_new != EL_UNDEFINED)
11685       MergeAndCloseNeighbourElements(x, y, &new_element,
11686                                      last_x, last_y, &last_element_new,
11687                                      getClosedSteel2, change_level);
11688   }
11689   else if (IS_SP_CHIP(new_element))
11690   {
11691     int last_element_new = EL_UNDEFINED;
11692     int direction = MV_NONE;
11693     int i;
11694
11695     // (do not keep existing directions, regardless of kind of old element)
11696
11697     for (i = 0; i < NUM_DIRECTIONS; i++)
11698     {
11699       int xx = x + xy[i].x;
11700       int yy = y + xy[i].y;
11701
11702       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11703           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
11704       {
11705         int dir = MV_DIR_FROM_BIT(i);
11706         int dir_opposite = MV_DIR_OPPOSITE(dir);
11707         int last_element_old = IntelliDrawBuffer[last_x][last_y];
11708         int last_direction_old = getOpenDirectionFromChip(last_element_old);
11709         int last_direction_new = last_direction_old | dir_opposite;
11710
11711         if (last_direction_old == MV_NONE)
11712         {
11713           last_element_new = getChipFromOpenDirection(last_direction_new);
11714           direction |= dir;
11715         }
11716         else if (last_direction_old & (dir | dir_opposite))
11717         {
11718           direction |= MV_DIR_OPPOSITE(last_direction_old);
11719         }
11720         else
11721         {
11722           direction |= MV_DIR_OPPOSITE(dir);
11723         }
11724       }
11725     }
11726
11727     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
11728
11729     if (last_element_new != EL_UNDEFINED)
11730       MergeAndCloseNeighbourElements(x, y, &new_element,
11731                                      last_x, last_y, &last_element_new,
11732                                      getClosedChip, change_level);
11733   }
11734   else if (IS_SP_HARDWARE_BASE(new_element))
11735   {
11736     int nr = GetSimpleRandom(6);
11737
11738     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
11739                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
11740                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
11741                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
11742                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
11743   }
11744   else if (new_element == EL_SP_HARDWARE_GREEN ||
11745            new_element == EL_SP_HARDWARE_BLUE ||
11746            new_element == EL_SP_HARDWARE_RED)
11747   {
11748     int nr = GetSimpleRandom(3);
11749
11750     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
11751                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
11752   }
11753   else if (IS_GROUP_ELEMENT(new_element))
11754   {
11755     boolean connected_drawing = FALSE;
11756     int i;
11757
11758     for (i = 0; i < NUM_DIRECTIONS; i++)
11759     {
11760       int xx = x + xy[i].x;
11761       int yy = y + xy[i].y;
11762
11763       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
11764           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
11765         connected_drawing = TRUE;
11766     }
11767
11768     if (!connected_drawing)
11769       ResolveGroupElement(new_element);
11770
11771     new_element = GetElementFromGroupElement(new_element);
11772   }
11773   else if (IS_BELT_SWITCH(old_element))
11774   {
11775     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
11776     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
11777
11778     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
11779                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
11780
11781     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
11782   }
11783   else
11784   {
11785     static int swappable_elements[][2] =
11786     {
11787       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
11788       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
11789       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
11790       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
11791       { EL_EMERALD,                     EL_WALL_EMERALD                 },
11792       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
11793       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
11794       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
11795       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
11796       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
11797       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
11798       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
11799       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
11800       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
11801       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
11802       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
11803       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
11804       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
11805       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
11806       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
11807       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
11808       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
11809       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
11810       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
11811       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
11812       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
11813       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
11814       { EL_PEARL,                       EL_WALL_PEARL                   },
11815       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
11816       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
11817       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
11818       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
11819       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
11820       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
11821       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
11822       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
11823       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
11824       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
11825       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
11826       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
11827       { EL_MM_EXIT_CLOSED,              EL_MM_EXIT_OPEN                 },
11828       { EL_MM_FUSE,                     EL_MM_FUSE_ACTIVE               },
11829       { EL_MM_LIGHTBULB,                EL_MM_LIGHTBULB_ACTIVE          },
11830       { EL_MM_FUEL_EMPTY,               EL_MM_FUEL_FULL                 },
11831
11832       { -1,                             -1                              },
11833     };
11834     static int rotatable_elements_4[][4] =
11835     {
11836       {
11837         EL_BUG_UP,
11838         EL_BUG_RIGHT,
11839         EL_BUG_DOWN,
11840         EL_BUG_LEFT
11841       },
11842       {
11843         EL_SPACESHIP_UP,
11844         EL_SPACESHIP_RIGHT,
11845         EL_SPACESHIP_DOWN,
11846         EL_SPACESHIP_LEFT
11847       },
11848       {
11849         EL_BD_BUTTERFLY_UP,
11850         EL_BD_BUTTERFLY_RIGHT,
11851         EL_BD_BUTTERFLY_DOWN,
11852         EL_BD_BUTTERFLY_LEFT
11853       },
11854       {
11855         EL_BD_FIREFLY_UP,
11856         EL_BD_FIREFLY_RIGHT,
11857         EL_BD_FIREFLY_DOWN,
11858         EL_BD_FIREFLY_LEFT
11859       },
11860       {
11861         EL_PACMAN_UP,
11862         EL_PACMAN_RIGHT,
11863         EL_PACMAN_DOWN,
11864         EL_PACMAN_LEFT
11865       },
11866       {
11867         EL_YAMYAM_UP,
11868         EL_YAMYAM_RIGHT,
11869         EL_YAMYAM_DOWN,
11870         EL_YAMYAM_LEFT
11871       },
11872       {
11873         EL_ARROW_UP,
11874         EL_ARROW_RIGHT,
11875         EL_ARROW_DOWN,
11876         EL_ARROW_LEFT
11877       },
11878       {
11879         EL_SP_PORT_UP,
11880         EL_SP_PORT_RIGHT,
11881         EL_SP_PORT_DOWN,
11882         EL_SP_PORT_LEFT
11883       },
11884       {
11885         EL_SP_GRAVITY_PORT_UP,
11886         EL_SP_GRAVITY_PORT_RIGHT,
11887         EL_SP_GRAVITY_PORT_DOWN,
11888         EL_SP_GRAVITY_PORT_LEFT
11889       },
11890       {
11891         EL_SP_GRAVITY_ON_PORT_UP,
11892         EL_SP_GRAVITY_ON_PORT_RIGHT,
11893         EL_SP_GRAVITY_ON_PORT_DOWN,
11894         EL_SP_GRAVITY_ON_PORT_LEFT
11895       },
11896       {
11897         EL_SP_GRAVITY_OFF_PORT_UP,
11898         EL_SP_GRAVITY_OFF_PORT_RIGHT,
11899         EL_SP_GRAVITY_OFF_PORT_DOWN,
11900         EL_SP_GRAVITY_OFF_PORT_LEFT
11901       },
11902       {
11903         EL_MOLE_UP,
11904         EL_MOLE_RIGHT,
11905         EL_MOLE_DOWN,
11906         EL_MOLE_LEFT
11907       },
11908       {
11909         EL_BALLOON_SWITCH_UP,
11910         EL_BALLOON_SWITCH_RIGHT,
11911         EL_BALLOON_SWITCH_DOWN,
11912         EL_BALLOON_SWITCH_LEFT
11913       },
11914       {
11915         EL_MM_MCDUFFIN_UP,
11916         EL_MM_MCDUFFIN_RIGHT,
11917         EL_MM_MCDUFFIN_DOWN,
11918         EL_MM_MCDUFFIN_LEFT
11919       },
11920       {
11921         EL_MM_MIRROR_FIXED_1,
11922         EL_MM_MIRROR_FIXED_4,
11923         EL_MM_MIRROR_FIXED_3,
11924         EL_MM_MIRROR_FIXED_2
11925       },
11926       {
11927         EL_MM_STEEL_GRID_FIXED_1,
11928         EL_MM_STEEL_GRID_FIXED_4,
11929         EL_MM_STEEL_GRID_FIXED_2,
11930         EL_MM_STEEL_GRID_FIXED_3
11931       },
11932       {
11933         EL_MM_WOODEN_GRID_FIXED_1,
11934         EL_MM_WOODEN_GRID_FIXED_4,
11935         EL_MM_WOODEN_GRID_FIXED_2,
11936         EL_MM_WOODEN_GRID_FIXED_3
11937       },
11938       {
11939         EL_MM_POLARIZER_CROSS_1,
11940         EL_MM_POLARIZER_CROSS_4,
11941         EL_MM_POLARIZER_CROSS_3,
11942         EL_MM_POLARIZER_CROSS_2
11943       },
11944       {
11945         EL_MM_PACMAN_UP,
11946         EL_MM_PACMAN_RIGHT,
11947         EL_MM_PACMAN_DOWN,
11948         EL_MM_PACMAN_LEFT
11949       },
11950       {
11951         EL_DF_LASER_UP,
11952         EL_DF_LASER_RIGHT,
11953         EL_DF_LASER_DOWN,
11954         EL_DF_LASER_LEFT
11955       },
11956       {
11957         EL_DF_RECEIVER_UP,
11958         EL_DF_RECEIVER_RIGHT,
11959         EL_DF_RECEIVER_DOWN,
11960         EL_DF_RECEIVER_LEFT
11961       },
11962       {
11963         EL_DF_SLOPE_1,
11964         EL_DF_SLOPE_4,
11965         EL_DF_SLOPE_3,
11966         EL_DF_SLOPE_2
11967       },
11968
11969       {
11970         -1,
11971       },
11972     };
11973     static int rotatable_elements_8[][8] =
11974     {
11975       {
11976         EL_DF_STEEL_GRID_FIXED_1,
11977         EL_DF_STEEL_GRID_FIXED_8,
11978         EL_DF_STEEL_GRID_FIXED_7,
11979         EL_DF_STEEL_GRID_FIXED_6,
11980         EL_DF_STEEL_GRID_FIXED_5,
11981         EL_DF_STEEL_GRID_FIXED_4,
11982         EL_DF_STEEL_GRID_FIXED_3,
11983         EL_DF_STEEL_GRID_FIXED_2
11984       },
11985       {
11986         EL_DF_WOODEN_GRID_FIXED_1,
11987         EL_DF_WOODEN_GRID_FIXED_8,
11988         EL_DF_WOODEN_GRID_FIXED_7,
11989         EL_DF_WOODEN_GRID_FIXED_6,
11990         EL_DF_WOODEN_GRID_FIXED_5,
11991         EL_DF_WOODEN_GRID_FIXED_4,
11992         EL_DF_WOODEN_GRID_FIXED_3,
11993         EL_DF_WOODEN_GRID_FIXED_2
11994       },
11995       {
11996         EL_DF_STEEL_GRID_ROTATING_1,
11997         EL_DF_STEEL_GRID_ROTATING_8,
11998         EL_DF_STEEL_GRID_ROTATING_7,
11999         EL_DF_STEEL_GRID_ROTATING_6,
12000         EL_DF_STEEL_GRID_ROTATING_5,
12001         EL_DF_STEEL_GRID_ROTATING_4,
12002         EL_DF_STEEL_GRID_ROTATING_3,
12003         EL_DF_STEEL_GRID_ROTATING_2
12004       },
12005       {
12006         EL_DF_WOODEN_GRID_ROTATING_1,
12007         EL_DF_WOODEN_GRID_ROTATING_8,
12008         EL_DF_WOODEN_GRID_ROTATING_7,
12009         EL_DF_WOODEN_GRID_ROTATING_6,
12010         EL_DF_WOODEN_GRID_ROTATING_5,
12011         EL_DF_WOODEN_GRID_ROTATING_4,
12012         EL_DF_WOODEN_GRID_ROTATING_3,
12013         EL_DF_WOODEN_GRID_ROTATING_2
12014       },
12015
12016       {
12017         -1,
12018       },
12019     };
12020     static int rotatable_elements_16[][16] =
12021     {
12022       {
12023         EL_MM_MIRROR_1,
12024         EL_MM_MIRROR_16,
12025         EL_MM_MIRROR_15,
12026         EL_MM_MIRROR_14,
12027         EL_MM_MIRROR_13,
12028         EL_MM_MIRROR_12,
12029         EL_MM_MIRROR_11,
12030         EL_MM_MIRROR_10,
12031         EL_MM_MIRROR_9,
12032         EL_MM_MIRROR_8,
12033         EL_MM_MIRROR_7,
12034         EL_MM_MIRROR_6,
12035         EL_MM_MIRROR_5,
12036         EL_MM_MIRROR_4,
12037         EL_MM_MIRROR_3,
12038         EL_MM_MIRROR_2
12039       },
12040       {
12041         EL_MM_TELEPORTER_5,
12042         EL_MM_TELEPORTER_4,
12043         EL_MM_TELEPORTER_3,
12044         EL_MM_TELEPORTER_2,
12045         EL_MM_TELEPORTER_1,
12046         EL_MM_TELEPORTER_16,
12047         EL_MM_TELEPORTER_15,
12048         EL_MM_TELEPORTER_14,
12049         EL_MM_TELEPORTER_13,
12050         EL_MM_TELEPORTER_12,
12051         EL_MM_TELEPORTER_11,
12052         EL_MM_TELEPORTER_10,
12053         EL_MM_TELEPORTER_9,
12054         EL_MM_TELEPORTER_8,
12055         EL_MM_TELEPORTER_7,
12056         EL_MM_TELEPORTER_6
12057       },
12058       {
12059         EL_MM_TELEPORTER_RED_5,
12060         EL_MM_TELEPORTER_RED_4,
12061         EL_MM_TELEPORTER_RED_3,
12062         EL_MM_TELEPORTER_RED_2,
12063         EL_MM_TELEPORTER_RED_1,
12064         EL_MM_TELEPORTER_RED_16,
12065         EL_MM_TELEPORTER_RED_15,
12066         EL_MM_TELEPORTER_RED_14,
12067         EL_MM_TELEPORTER_RED_13,
12068         EL_MM_TELEPORTER_RED_12,
12069         EL_MM_TELEPORTER_RED_11,
12070         EL_MM_TELEPORTER_RED_10,
12071         EL_MM_TELEPORTER_RED_9,
12072         EL_MM_TELEPORTER_RED_8,
12073         EL_MM_TELEPORTER_RED_7,
12074         EL_MM_TELEPORTER_RED_6
12075       },
12076       {
12077         EL_MM_TELEPORTER_YELLOW_5,
12078         EL_MM_TELEPORTER_YELLOW_4,
12079         EL_MM_TELEPORTER_YELLOW_3,
12080         EL_MM_TELEPORTER_YELLOW_2,
12081         EL_MM_TELEPORTER_YELLOW_1,
12082         EL_MM_TELEPORTER_YELLOW_16,
12083         EL_MM_TELEPORTER_YELLOW_15,
12084         EL_MM_TELEPORTER_YELLOW_14,
12085         EL_MM_TELEPORTER_YELLOW_13,
12086         EL_MM_TELEPORTER_YELLOW_12,
12087         EL_MM_TELEPORTER_YELLOW_11,
12088         EL_MM_TELEPORTER_YELLOW_10,
12089         EL_MM_TELEPORTER_YELLOW_9,
12090         EL_MM_TELEPORTER_YELLOW_8,
12091         EL_MM_TELEPORTER_YELLOW_7,
12092         EL_MM_TELEPORTER_YELLOW_6
12093       },
12094       {
12095         EL_MM_TELEPORTER_GREEN_5,
12096         EL_MM_TELEPORTER_GREEN_4,
12097         EL_MM_TELEPORTER_GREEN_3,
12098         EL_MM_TELEPORTER_GREEN_2,
12099         EL_MM_TELEPORTER_GREEN_1,
12100         EL_MM_TELEPORTER_GREEN_16,
12101         EL_MM_TELEPORTER_GREEN_15,
12102         EL_MM_TELEPORTER_GREEN_14,
12103         EL_MM_TELEPORTER_GREEN_13,
12104         EL_MM_TELEPORTER_GREEN_12,
12105         EL_MM_TELEPORTER_GREEN_11,
12106         EL_MM_TELEPORTER_GREEN_10,
12107         EL_MM_TELEPORTER_GREEN_9,
12108         EL_MM_TELEPORTER_GREEN_8,
12109         EL_MM_TELEPORTER_GREEN_7,
12110         EL_MM_TELEPORTER_GREEN_6
12111       },
12112       {
12113         EL_MM_TELEPORTER_BLUE_5,
12114         EL_MM_TELEPORTER_BLUE_4,
12115         EL_MM_TELEPORTER_BLUE_3,
12116         EL_MM_TELEPORTER_BLUE_2,
12117         EL_MM_TELEPORTER_BLUE_1,
12118         EL_MM_TELEPORTER_BLUE_16,
12119         EL_MM_TELEPORTER_BLUE_15,
12120         EL_MM_TELEPORTER_BLUE_14,
12121         EL_MM_TELEPORTER_BLUE_13,
12122         EL_MM_TELEPORTER_BLUE_12,
12123         EL_MM_TELEPORTER_BLUE_11,
12124         EL_MM_TELEPORTER_BLUE_10,
12125         EL_MM_TELEPORTER_BLUE_9,
12126         EL_MM_TELEPORTER_BLUE_8,
12127         EL_MM_TELEPORTER_BLUE_7,
12128         EL_MM_TELEPORTER_BLUE_6
12129       },
12130       {
12131         EL_MM_POLARIZER_1,
12132         EL_MM_POLARIZER_16,
12133         EL_MM_POLARIZER_15,
12134         EL_MM_POLARIZER_14,
12135         EL_MM_POLARIZER_13,
12136         EL_MM_POLARIZER_12,
12137         EL_MM_POLARIZER_11,
12138         EL_MM_POLARIZER_10,
12139         EL_MM_POLARIZER_9,
12140         EL_MM_POLARIZER_8,
12141         EL_MM_POLARIZER_7,
12142         EL_MM_POLARIZER_6,
12143         EL_MM_POLARIZER_5,
12144         EL_MM_POLARIZER_4,
12145         EL_MM_POLARIZER_3,
12146         EL_MM_POLARIZER_2
12147       },
12148       {
12149         EL_DF_MIRROR_1,
12150         EL_DF_MIRROR_16,
12151         EL_DF_MIRROR_15,
12152         EL_DF_MIRROR_14,
12153         EL_DF_MIRROR_13,
12154         EL_DF_MIRROR_12,
12155         EL_DF_MIRROR_11,
12156         EL_DF_MIRROR_10,
12157         EL_DF_MIRROR_9,
12158         EL_DF_MIRROR_8,
12159         EL_DF_MIRROR_7,
12160         EL_DF_MIRROR_6,
12161         EL_DF_MIRROR_5,
12162         EL_DF_MIRROR_4,
12163         EL_DF_MIRROR_3,
12164         EL_DF_MIRROR_2
12165       },
12166       {
12167         EL_DF_MIRROR_ROTATING_1,
12168         EL_DF_MIRROR_ROTATING_16,
12169         EL_DF_MIRROR_ROTATING_15,
12170         EL_DF_MIRROR_ROTATING_14,
12171         EL_DF_MIRROR_ROTATING_13,
12172         EL_DF_MIRROR_ROTATING_12,
12173         EL_DF_MIRROR_ROTATING_11,
12174         EL_DF_MIRROR_ROTATING_10,
12175         EL_DF_MIRROR_ROTATING_9,
12176         EL_DF_MIRROR_ROTATING_8,
12177         EL_DF_MIRROR_ROTATING_7,
12178         EL_DF_MIRROR_ROTATING_6,
12179         EL_DF_MIRROR_ROTATING_5,
12180         EL_DF_MIRROR_ROTATING_4,
12181         EL_DF_MIRROR_ROTATING_3,
12182         EL_DF_MIRROR_ROTATING_2
12183       },
12184       {
12185         EL_DF_MIRROR_FIXED_1,
12186         EL_DF_MIRROR_FIXED_16,
12187         EL_DF_MIRROR_FIXED_15,
12188         EL_DF_MIRROR_FIXED_14,
12189         EL_DF_MIRROR_FIXED_13,
12190         EL_DF_MIRROR_FIXED_12,
12191         EL_DF_MIRROR_FIXED_11,
12192         EL_DF_MIRROR_FIXED_10,
12193         EL_DF_MIRROR_FIXED_9,
12194         EL_DF_MIRROR_FIXED_8,
12195         EL_DF_MIRROR_FIXED_7,
12196         EL_DF_MIRROR_FIXED_6,
12197         EL_DF_MIRROR_FIXED_5,
12198         EL_DF_MIRROR_FIXED_4,
12199         EL_DF_MIRROR_FIXED_3,
12200         EL_DF_MIRROR_FIXED_2
12201       },
12202
12203       {
12204         -1,
12205       },
12206     };
12207     int i, j;
12208
12209     for (i = 0; swappable_elements[i][0] != -1; i++)
12210     {
12211       int element1 = swappable_elements[i][0];
12212       int element2 = swappable_elements[i][1];
12213
12214       if (old_element == element1 || old_element == element2)
12215         new_element = (old_element == element1 ? element2 : element1);
12216     }
12217
12218     for (i = 0; rotatable_elements_4[i][0] != -1; i++)
12219     {
12220       for (j = 0; j < 4; j++)
12221       {
12222         int element = rotatable_elements_4[i][j];
12223
12224         if (old_element == element)
12225           new_element = (button == 1 ? rotatable_elements_4[i][(j + 3) % 4] :
12226                          button == 2 ? rotatable_elements_4[i][0]           :
12227                          button == 3 ? rotatable_elements_4[i][(j + 1) % 4] :
12228                          old_element);
12229       }
12230     }
12231
12232     for (i = 0; rotatable_elements_8[i][0] != -1; i++)
12233     {
12234       for (j = 0; j < 8; j++)
12235       {
12236         int element = rotatable_elements_8[i][j];
12237
12238         if (old_element == element)
12239           new_element = (button == 1 ? rotatable_elements_8[i][(j + 7) % 8] :
12240                          button == 2 ? rotatable_elements_8[i][0]           :
12241                          button == 3 ? rotatable_elements_8[i][(j + 1) % 8] :
12242                          old_element);
12243       }
12244     }
12245
12246     for (i = 0; rotatable_elements_16[i][0] != -1; i++)
12247     {
12248       for (j = 0; j < 16; j++)
12249       {
12250         int element = rotatable_elements_16[i][j];
12251
12252         if (old_element == element)
12253           new_element = (button == 1 ? rotatable_elements_16[i][(j + 15) % 16] :
12254                          button == 2 ? rotatable_elements_16[i][0]             :
12255                          button == 3 ? rotatable_elements_16[i][(j + 1)  % 16] :
12256                          old_element);
12257       }
12258     }
12259
12260     if (old_element != new_element)
12261     {
12262       int max_infotext_len = getMaxInfoTextLength();
12263       char infotext[MAX_OUTPUT_LINESIZE + 1];
12264
12265       strncpy(infotext, getElementInfoText(new_element), max_infotext_len);
12266       infotext[max_infotext_len] = '\0';
12267
12268       ClearEditorGadgetInfoText();
12269
12270       DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT,
12271                 infotext);
12272     }
12273   }
12274
12275   if (IS_MM_WALL_EDITOR(new_element))
12276     SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
12277   else
12278     SetElementSimple(x, y, new_element, change_level);
12279
12280   last_x = x;
12281   last_y = y;
12282 }
12283
12284 static void ResetIntelliDraw(void)
12285 {
12286   int x, y;
12287
12288   for (x = 0; x < lev_fieldx; x++)
12289     for (y = 0; y < lev_fieldy; y++)
12290       IntelliDrawBuffer[x][y] = Tile[x][y];
12291
12292   SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
12293 }
12294
12295 static boolean draw_mode_hires = FALSE;
12296
12297 static boolean isHiresTileElement(int element)
12298 {
12299   return (IS_MM_WALL(element)        || element == EL_EMPTY);
12300 }
12301
12302 static boolean isHiresDrawElement(int element)
12303 {
12304   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
12305 }
12306
12307 static int numHiresTiles(int element)
12308 {
12309   if (IS_MM_WALL(element))
12310     return get_number_of_bits(MM_WALL_BITS(element));
12311
12312   return 1;
12313 }
12314
12315 static void SetDrawModeHiRes(int element)
12316 {
12317   draw_mode_hires =
12318     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
12319      isHiresDrawElement(element));
12320 }
12321
12322 static boolean getDrawModeHiRes(void)
12323 {
12324   return draw_mode_hires;
12325 }
12326
12327 static int getLoResScreenPos(int pos)
12328 {
12329   return (getDrawModeHiRes() ? pos / 2 : pos);
12330 }
12331
12332 static int getLoResScreenMod(int pos)
12333 {
12334   return (getDrawModeHiRes() ? pos % 2 : 0);
12335 }
12336
12337 static void SetElementExt(int x, int y, int dx, int dy, int element,
12338                           boolean change_level, int button)
12339 {
12340   if (element < 0)
12341     SetElementSimple(x, y, Tile[x][y], change_level);
12342   else if (GetKeyModState() & KMOD_Shift)
12343     SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
12344   else
12345     SetElementSimpleExt(x, y, dx, dy, element, change_level);
12346 }
12347
12348 static void SetElement(int x, int y, int element)
12349 {
12350   SetElementExt(x, y, 0, 0, element, TRUE, -1);
12351 }
12352
12353 static void SetElementButton(int x, int y, int dx, int dy, int element,
12354                              int button)
12355 {
12356   SetElementExt(x, y, dx, dy, element, TRUE, button);
12357 }
12358
12359 static void SetElementHiRes(int sx2, int sy2, int element, boolean change_level)
12360 {
12361   int lx = getLoResScreenPos(sx2) + level_xpos;
12362   int ly = getLoResScreenPos(sy2) + level_ypos;
12363   int dx = getLoResScreenMod(sx2);
12364   int dy = getLoResScreenMod(sy2);
12365
12366   SetElementExt(lx, ly, dx, dy, element, change_level, -1);
12367 }
12368
12369 static void SetLevelElementHiRes(int lx2, int ly2, int element)
12370 {
12371   int lx = lx2 / 2;
12372   int ly = ly2 / 2;
12373   int dx = lx2 % 2;
12374   int dy = ly2 % 2;
12375
12376   SetElementExt(lx, ly, dx, dy, element, TRUE, -1);
12377 }
12378
12379 static int getLevelElementHiRes(int lx2, int ly2)
12380 {
12381   int lx = lx2 / 2;
12382   int ly = ly2 / 2;
12383   int dx = lx2 % 2;
12384   int dy = ly2 % 2;
12385   int element = Tile[lx][ly];
12386   unsigned int bitmask = (dx + 1) << (dy * 2);
12387
12388   if (IS_MM_WALL(element))
12389   {
12390     if (element & bitmask)
12391       return map_mm_wall_element(element);
12392     else
12393       return EL_EMPTY;
12394   }
12395
12396   return element;
12397 }
12398
12399 static void DrawLineElement(int x, int y, int element, boolean change_level)
12400 {
12401   SetElementHiRes(x, y, element, change_level);
12402 }
12403
12404 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
12405                      int element, boolean change_level)
12406 {
12407   int xsize = ABS(to_x - from_x);
12408   int ysize = ABS(to_y - from_y);
12409   int dx = (to_x < from_x ? -1 : +1);
12410   int dy = (to_y < from_y ? -1 : +1);
12411   int i;
12412
12413   if (from_y == to_y)                   // horizontal line
12414   {
12415     for (i = 0; i <= xsize; i++)
12416       DrawLineElement(from_x + i * dx, from_y, element, change_level);
12417   }
12418   else if (from_x == to_x)              // vertical line
12419   {
12420     for (i = 0; i <= ysize; i++)
12421       DrawLineElement(from_x, from_y + i * dy, element, change_level);
12422   }
12423   else                                  // diagonal line
12424   {
12425     if (ysize < xsize)                  // a < 1
12426     {
12427       float a = (float)ysize / (float)xsize;
12428
12429       for (i = 0; i <= xsize; i++)
12430       {
12431         int x = dx * i;
12432         int y = dy * (int)(a * i + 0.5);
12433
12434         DrawLineElement(from_x + x, from_y + y, element, change_level);
12435       }
12436     }
12437     else                                // a >= 1
12438     {
12439       float a = (float)xsize / (float)ysize;
12440
12441       for (i = 0; i <= ysize; i++)
12442       {
12443         int x = dx * (int)(a * i + 0.5);
12444         int y = dy * i;
12445
12446         DrawLineElement(from_x + x, from_y + y, element, change_level);
12447       }
12448     }
12449   }
12450 }
12451
12452 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
12453                     int element, boolean change_level)
12454 {
12455   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
12456   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
12457   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
12458   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
12459 }
12460
12461 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
12462                           int element, boolean change_level)
12463 {
12464   int y;
12465
12466   if (from_y > to_y)
12467     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
12468
12469   for (y = from_y; y <= to_y; y++)
12470     DrawLine(from_x, y, to_x, y, element, change_level);
12471 }
12472
12473 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
12474                        int element, boolean change_level)
12475 {
12476   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
12477   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
12478   int len_x = ABS(to_x - from_x);
12479   int len_y = ABS(to_y - from_y);
12480   int radius, x, y;
12481
12482   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
12483
12484   // not optimal (some points get drawn twice) but simple,
12485   // and fast enough for the few points we are drawing
12486
12487   for (x = 0; x <= radius; x++)
12488   {
12489     int sx, sy, sx2, sy2, lx, ly;
12490
12491     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
12492
12493     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
12494     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
12495     sx = getLoResScreenPos(sx2);
12496     sy = getLoResScreenPos(sy2);
12497     lx = sx + level_xpos;
12498     ly = sy + level_ypos;
12499
12500     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
12501       DrawLineElement(sx2, sy2, element, change_level);
12502   }
12503
12504   for (y = 0; y <= radius; y++)
12505   {
12506     int sx, sy, sx2, sy2, lx, ly;
12507
12508     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
12509
12510     sx2 = from_x + x * (from_x < to_x2 ? +1 : -1);
12511     sy2 = from_y + y * (from_y < to_y2 ? +1 : -1);
12512     sx = getLoResScreenPos(sx2);
12513     sy = getLoResScreenPos(sy2);
12514     lx = sx + level_xpos;
12515     ly = sy + level_ypos;
12516
12517     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
12518       DrawLineElement(sx2, sy2, element, change_level);
12519   }
12520 }
12521
12522 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
12523                     int element, boolean change_level)
12524 {
12525   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
12526   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
12527
12528   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
12529 }
12530
12531 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
12532
12533 #if DRAW_CIRCLES_BUTTON_AVAILABLE
12534 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
12535                        int element, boolean change_level)
12536 {
12537   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
12538   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
12539   int mirror_to_x2 = from_x - (to_x2 - from_x);
12540   int mirror_to_y2 = from_y - (to_y2 - from_y);
12541
12542   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
12543   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
12544   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
12545   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
12546 }
12547 #endif
12548
12549 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
12550 {
12551   int from_sx, from_sy;
12552   int to_sx, to_sy;
12553
12554   if (from_x > to_x)
12555     swap_numbers(&from_x, &to_x);
12556
12557   if (from_y > to_y)
12558     swap_numbers(&from_y, &to_y);
12559
12560   from_sx = SX + from_x * ed_tilesize;
12561   from_sy = SY + from_y * ed_tilesize;
12562   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
12563   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
12564
12565   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
12566   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
12567   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
12568   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
12569
12570   if (from_x == to_x && from_y == to_y)
12571     MarkTileDirty(from_x/2, from_y/2);
12572   else
12573     redraw_mask |= REDRAW_FIELD;
12574 }
12575
12576 static void DrawAreaBox(int from_x, int from_y, int to_x, int to_y,
12577                         int element, boolean change_level)
12578 {
12579   DrawBox(from_x, from_y, to_x, to_y, element, change_level);
12580 }
12581
12582 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
12583                        int element, boolean change_level)
12584 {
12585   if (element == -1 || change_level)
12586     DrawAreaBox(from_x, from_y, to_x, to_y, -1, FALSE);
12587   else
12588     DrawAreaBorder(from_x, from_y, to_x, to_y);
12589 }
12590
12591 // values for CopyBrushExt()
12592 #define CB_AREA_TO_BRUSH                0
12593 #define CB_BRUSH_TO_CURSOR              1
12594 #define CB_BRUSH_TO_LEVEL               2
12595 #define CB_DELETE_OLD_CURSOR            3
12596 #define CB_DUMP_BRUSH                   4
12597 #define CB_DUMP_BRUSH_SMALL             5
12598 #define CB_CLIPBOARD_TO_BRUSH           6
12599 #define CB_BRUSH_TO_CLIPBOARD           7
12600 #define CB_BRUSH_TO_CLIPBOARD_SMALL     8
12601 #define CB_UPDATE_BRUSH_POSITION        9
12602 #define CB_FLIP_BRUSH_X                 10
12603 #define CB_FLIP_BRUSH_Y                 11
12604 #define CB_FLIP_BRUSH_XY                12
12605
12606 #define MAX_CB_PART_SIZE        10
12607 #define MAX_CB_LINE_SIZE        (MAX_LEV_FIELDX + 1)    // text plus newline
12608 #define MAX_CB_NUM_LINES        (MAX_LEV_FIELDY)
12609 #define MAX_CB_TEXT_SIZE        (MAX_CB_LINE_SIZE *     \
12610                                  MAX_CB_NUM_LINES *     \
12611                                  MAX_CB_PART_SIZE)
12612
12613 static int getFlippedTileExt(int map[], int element)
12614 {
12615   int i;
12616
12617   for (i = 0; map[i] != -1; i++)
12618     if (map[i] == element)
12619       return map[i ^ 1];        // get flipped element by flipping LSB of index
12620
12621   return element;
12622 }
12623
12624 static int getFlippedTileX(int element)
12625 {
12626   int map[] =
12627   {
12628     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_RIGHT,
12629     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_RIGHT,
12630     EL_BUG_LEFT,                        EL_BUG_RIGHT,
12631     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_RIGHT,
12632     EL_PACMAN_LEFT,                     EL_PACMAN_RIGHT,
12633     EL_ARROW_LEFT,                      EL_ARROW_RIGHT,
12634     EL_MOLE_LEFT,                       EL_MOLE_RIGHT,
12635     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_RIGHT,
12636     EL_YAMYAM_LEFT,                     EL_YAMYAM_RIGHT,
12637     EL_SP_PORT_LEFT,                    EL_SP_PORT_RIGHT,
12638     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_RIGHT,
12639     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_RIGHT,
12640     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_RIGHT,
12641     EL_CONVEYOR_BELT_1_LEFT,            EL_CONVEYOR_BELT_1_RIGHT,
12642     EL_CONVEYOR_BELT_2_LEFT,            EL_CONVEYOR_BELT_2_RIGHT,
12643     EL_CONVEYOR_BELT_3_LEFT,            EL_CONVEYOR_BELT_3_RIGHT,
12644     EL_CONVEYOR_BELT_4_LEFT,            EL_CONVEYOR_BELT_4_RIGHT,
12645     EL_SPRING_LEFT,                     EL_SPRING_RIGHT,
12646     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_RIGHT,
12647     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_VERTICAL_RIGHT,
12648     EL_TUBE_LEFT_UP,                    EL_TUBE_RIGHT_UP,
12649     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_DOWN,
12650     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_RIGHT,
12651     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_TOPRIGHT,
12652     EL_DC_STEELWALL_1_BOTTOMLEFT,       EL_DC_STEELWALL_1_BOTTOMRIGHT,
12653     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_TOPRIGHT_2,
12654     EL_DC_STEELWALL_1_BOTTOMLEFT_2,     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
12655     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_RIGHT,
12656     EL_ACID_POOL_TOPLEFT,               EL_ACID_POOL_TOPRIGHT,
12657     EL_ACID_POOL_BOTTOMLEFT,            EL_ACID_POOL_BOTTOMRIGHT,
12658
12659     -1
12660   };
12661
12662   return getFlippedTileExt(map, element);
12663 }
12664
12665 static int getFlippedTileY(int element)
12666 {
12667   int map[] =
12668   {
12669     EL_BD_BUTTERFLY_UP,                 EL_BD_BUTTERFLY_DOWN,
12670     EL_BD_FIREFLY_UP,                   EL_BD_FIREFLY_DOWN,
12671     EL_BUG_UP,                          EL_BUG_DOWN,
12672     EL_SPACESHIP_UP,                    EL_SPACESHIP_DOWN,
12673     EL_PACMAN_UP,                       EL_PACMAN_DOWN,
12674     EL_ARROW_UP,                        EL_ARROW_DOWN,
12675     EL_MOLE_UP,                         EL_MOLE_DOWN,
12676     EL_BALLOON_SWITCH_UP,               EL_BALLOON_SWITCH_DOWN,
12677     EL_YAMYAM_UP,                       EL_YAMYAM_DOWN,
12678     EL_SP_PORT_UP,                      EL_SP_PORT_DOWN,
12679     EL_SP_GRAVITY_PORT_UP,              EL_SP_GRAVITY_PORT_DOWN,
12680     EL_SP_GRAVITY_ON_PORT_UP,           EL_SP_GRAVITY_ON_PORT_DOWN,
12681     EL_SP_GRAVITY_OFF_PORT_UP,          EL_SP_GRAVITY_OFF_PORT_DOWN,
12682     EL_SP_CHIP_TOP,                     EL_SP_CHIP_BOTTOM,
12683     EL_TUBE_HORIZONTAL_UP,              EL_TUBE_HORIZONTAL_DOWN,
12684     EL_TUBE_LEFT_UP,                    EL_TUBE_LEFT_DOWN,
12685     EL_TUBE_RIGHT_UP,                   EL_TUBE_RIGHT_DOWN,
12686     EL_DC_STEELWALL_1_TOP,              EL_DC_STEELWALL_1_BOTTOM,
12687     EL_DC_STEELWALL_1_TOPLEFT,          EL_DC_STEELWALL_1_BOTTOMLEFT,
12688     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMRIGHT,
12689     EL_DC_STEELWALL_1_TOPLEFT_2,        EL_DC_STEELWALL_1_BOTTOMLEFT_2,
12690     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
12691     EL_DC_STEELWALL_2_TOP,              EL_DC_STEELWALL_2_BOTTOM,
12692     EL_EMC_WALL_1,                      EL_EMC_WALL_3,
12693
12694     -1
12695   };
12696
12697   return getFlippedTileExt(map, element);
12698 }
12699
12700 static int getFlippedTileXY(int element)
12701 {
12702   int map[] =
12703   {
12704     EL_BD_BUTTERFLY_LEFT,               EL_BD_BUTTERFLY_UP,
12705     EL_BD_BUTTERFLY_RIGHT,              EL_BD_BUTTERFLY_DOWN,
12706     EL_BD_FIREFLY_LEFT,                 EL_BD_FIREFLY_UP,
12707     EL_BD_FIREFLY_RIGHT,                EL_BD_FIREFLY_DOWN,
12708     EL_BUG_LEFT,                        EL_BUG_UP,
12709     EL_BUG_RIGHT,                       EL_BUG_DOWN,
12710     EL_SPACESHIP_LEFT,                  EL_SPACESHIP_UP,
12711     EL_SPACESHIP_RIGHT,                 EL_SPACESHIP_DOWN,
12712     EL_PACMAN_LEFT,                     EL_PACMAN_UP,
12713     EL_PACMAN_RIGHT,                    EL_PACMAN_DOWN,
12714     EL_ARROW_LEFT,                      EL_ARROW_UP,
12715     EL_ARROW_RIGHT,                     EL_ARROW_DOWN,
12716     EL_MOLE_LEFT,                       EL_MOLE_UP,
12717     EL_MOLE_RIGHT,                      EL_MOLE_DOWN,
12718     EL_BALLOON_SWITCH_LEFT,             EL_BALLOON_SWITCH_UP,
12719     EL_BALLOON_SWITCH_RIGHT,            EL_BALLOON_SWITCH_DOWN,
12720     EL_YAMYAM_LEFT,                     EL_YAMYAM_UP,
12721     EL_YAMYAM_RIGHT,                    EL_YAMYAM_DOWN,
12722     EL_SP_PORT_LEFT,                    EL_SP_PORT_UP,
12723     EL_SP_PORT_RIGHT,                   EL_SP_PORT_DOWN,
12724     EL_SP_GRAVITY_PORT_LEFT,            EL_SP_GRAVITY_PORT_UP,
12725     EL_SP_GRAVITY_PORT_RIGHT,           EL_SP_GRAVITY_PORT_DOWN,
12726     EL_SP_GRAVITY_ON_PORT_LEFT,         EL_SP_GRAVITY_ON_PORT_UP,
12727     EL_SP_GRAVITY_ON_PORT_RIGHT,        EL_SP_GRAVITY_ON_PORT_DOWN,
12728     EL_SP_GRAVITY_OFF_PORT_LEFT,        EL_SP_GRAVITY_OFF_PORT_UP,
12729     EL_SP_GRAVITY_OFF_PORT_RIGHT,       EL_SP_GRAVITY_OFF_PORT_DOWN,
12730     EL_SP_CHIP_LEFT,                    EL_SP_CHIP_TOP,
12731     EL_SP_CHIP_RIGHT,                   EL_SP_CHIP_BOTTOM,
12732     EL_TUBE_VERTICAL,                   EL_TUBE_HORIZONTAL,
12733     EL_TUBE_VERTICAL_LEFT,              EL_TUBE_HORIZONTAL_UP,
12734     EL_TUBE_VERTICAL_RIGHT,             EL_TUBE_HORIZONTAL_DOWN,
12735     EL_TUBE_LEFT_DOWN,                  EL_TUBE_RIGHT_UP,
12736     EL_DC_STEELWALL_1_LEFT,             EL_DC_STEELWALL_1_TOP,
12737     EL_DC_STEELWALL_1_RIGHT,            EL_DC_STEELWALL_1_BOTTOM,
12738     EL_DC_STEELWALL_1_HORIZONTAL,       EL_DC_STEELWALL_1_VERTICAL,
12739     EL_DC_STEELWALL_1_TOPRIGHT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
12740     EL_DC_STEELWALL_1_TOPRIGHT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
12741     EL_DC_STEELWALL_2_LEFT,             EL_DC_STEELWALL_2_TOP,
12742     EL_DC_STEELWALL_2_RIGHT,            EL_DC_STEELWALL_2_BOTTOM,
12743     EL_DC_STEELWALL_2_HORIZONTAL,       EL_DC_STEELWALL_2_VERTICAL,
12744     EL_EXPANDABLE_WALL_HORIZONTAL,      EL_EXPANDABLE_WALL_VERTICAL,
12745     EL_EXPANDABLE_STEELWALL_HORIZONTAL, EL_EXPANDABLE_STEELWALL_VERTICAL,
12746
12747     -1
12748   };
12749
12750   return getFlippedTileExt(map, element);
12751 }
12752
12753 static int getFlippedTile(int element, int mode)
12754 {
12755   if (IS_MM_ELEMENT(element))
12756   {
12757     // get MM game element
12758     element = map_element_RND_to_MM(element);
12759
12760     // get flipped game element
12761     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
12762                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
12763                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
12764                element);
12765
12766     // get RND game element again
12767     element = map_element_MM_to_RND(element);
12768   }
12769   else
12770   {
12771     // get flipped game element
12772     element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
12773                mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
12774                mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
12775                element);
12776   }
12777
12778   return element;
12779 }
12780
12781 static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
12782 {
12783   // flip tiles
12784   short tile1_flipped = getFlippedTile(*tile1, mode);
12785   short tile2_flipped = getFlippedTile(*tile2, mode);
12786
12787   // swap tiles
12788   *tile1 = tile2_flipped;
12789   *tile2 = tile1_flipped;
12790 }
12791
12792 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
12793 {
12794   DrawLineElement(sx, sy, element, change_level);
12795 }
12796
12797 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
12798                          int button, int mode)
12799 {
12800   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
12801   static int brush_width, brush_height;
12802   static int last_cursor_x = -1, last_cursor_y = -1;
12803   static boolean delete_old_brush = FALSE;
12804   int new_element = BUTTON_ELEMENT(button);
12805   int x, y;
12806
12807   if (mode == CB_DUMP_BRUSH ||
12808       mode == CB_DUMP_BRUSH_SMALL ||
12809       mode == CB_BRUSH_TO_CLIPBOARD ||
12810       mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
12811   {
12812     if (edit_mode != ED_MODE_DRAWING)
12813       return;
12814
12815     char part[MAX_CB_PART_SIZE + 1] = "";
12816     char text[MAX_CB_TEXT_SIZE + 1] = "";
12817     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
12818     int height = (draw_with_brush ? brush_height : lev_fieldy);
12819     char *format = "%s%03d";
12820
12821     for (y = 0; y < height; y++)
12822       for (x = 0; x < width; x++)
12823         if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
12824           format = "%s%04d";
12825
12826     for (y = 0; y < height; y++)
12827     {
12828       for (x = 0; x < width; x++)
12829       {
12830         int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
12831         char *prefix = (mode == CB_DUMP_BRUSH ||
12832                         mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
12833
12834         if (element >= NUM_FILE_ELEMENTS)
12835           element = EL_UNKNOWN;
12836
12837         // copy brush to level sketch text buffer for the R'n'D forum:
12838         // - large tiles: `xxx or `xxxx (0x60 ASCII)
12839         // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
12840         snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
12841         strcat(text, part);
12842       }
12843
12844       strcat(text, "\n");
12845     }
12846
12847     if (mode == CB_BRUSH_TO_CLIPBOARD ||
12848         mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
12849       SDL_SetClipboardText(text);
12850     else
12851       Print("%s", text);        // print brush data to console and log file
12852
12853     return;
12854   }
12855
12856   if (mode == CB_CLIPBOARD_TO_BRUSH)
12857   {
12858     if (edit_mode != ED_MODE_DRAWING)
12859       return;
12860
12861     if (!SDL_HasClipboardText())
12862     {
12863       Request("Clipboard is empty!", REQ_CONFIRM);
12864
12865       return;
12866     }
12867
12868     boolean copy_to_brush = (draw_with_brush ||
12869                              drawing_function == GADGET_ID_GRAB_BRUSH);
12870
12871     // this will delete the old brush, if already drawing with a brush
12872     if (copy_to_brush)
12873       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], MB_LEFTBUTTON);
12874
12875     // initialization is required for "odd" (incomplete) clipboard content
12876     for (x = 0; x < MAX_LEV_FIELDX; x++)
12877       for (y = 0; y < MAX_LEV_FIELDY; y++)
12878         brush_buffer[x][y] = EL_EMPTY;
12879
12880     brush_width  = 0;
12881     brush_height = 0;
12882     x = 0;
12883     y = 0;
12884
12885     char *clipboard_text = SDL_GetClipboardText();
12886     char *ptr = clipboard_text;
12887     boolean allow_new_row = FALSE;
12888     boolean stop = FALSE;
12889
12890     while (*ptr && !stop)
12891     {
12892       boolean prefix_found = FALSE;
12893       boolean start_new_row = FALSE;
12894
12895       // level sketch element number prefixes (may be multi-byte characters)
12896       char *prefix_list[] = { "`", "¸" };
12897       int i;
12898
12899       for (i = 0; i < ARRAY_SIZE(prefix_list); i++)
12900       {
12901         char *prefix = prefix_list[i];
12902
12903         // check if string is large enough for prefix
12904         if (strlen(ptr) < strlen(prefix))
12905         {
12906           stop = TRUE;
12907
12908           break;
12909         }
12910
12911         // check if string starts with prefix
12912         if (strPrefix(ptr, prefix))
12913         {
12914           ptr += strlen(prefix);
12915
12916           prefix_found = TRUE;
12917
12918           break;
12919         }
12920       }
12921
12922       // check if prefix found and followed by (at least) three digits
12923       if (prefix_found &&
12924           strlen(ptr) >= 3 &&
12925           ptr[0] >= '0' && ptr[0] <= '9' &&
12926           ptr[1] >= '0' && ptr[1] <= '9' &&
12927           ptr[2] >= '0' && ptr[2] <= '9')
12928       {
12929         int element = ((ptr[0] - '0') * 100 +
12930                        (ptr[1] - '0') * 10 +
12931                        (ptr[2] - '0'));
12932
12933         ptr += 3;
12934
12935         // level sketch element number might consist of four digits
12936         if (ptr[0] >= '0' && ptr[0] <= '9')
12937         {
12938           element = element * 10 + (ptr[0] - '0');
12939           ptr++;
12940         }
12941
12942         // remap some (historic, now obsolete) elements
12943         element = getMappedElement(element);
12944
12945         if (element >= NUM_FILE_ELEMENTS)
12946           element = EL_UNKNOWN;
12947
12948         brush_buffer[x][y] = element;
12949
12950         brush_width  = MAX(x + 1, brush_width);
12951         brush_height = MAX(y + 1, brush_height);
12952
12953         x++;
12954
12955         if (x >= MAX_LEV_FIELDX)
12956           start_new_row = TRUE;
12957
12958         allow_new_row = TRUE;
12959       }
12960       else
12961       {
12962         if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
12963           start_new_row = TRUE;
12964
12965         ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
12966       }
12967
12968       if (start_new_row)
12969       {
12970         x = 0;
12971         y++;
12972
12973         if (y >= MAX_LEV_FIELDY)
12974           stop = TRUE;
12975
12976         allow_new_row = FALSE;
12977       }
12978     }
12979
12980     SDL_free(clipboard_text);
12981
12982     if (brush_width == 0 || brush_height == 0)
12983     {
12984       Request("No level sketch found in clipboard!", REQ_CONFIRM);
12985
12986       return;
12987     }
12988
12989     if (copy_to_brush)
12990     {
12991       struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_DRAWING_LEVEL];
12992       int mx, my;
12993
12994       SDL_GetMouseState(&mx, &my);
12995
12996       // if inside drawing area, activate and draw brush at last mouse position
12997       if (mx >= gi->x && mx < gi->x + gi->width &&
12998           my >= gi->y && my < gi->y + gi->height)
12999         CopyBrushToCursor(last_cursor_x, last_cursor_y);
13000
13001       draw_with_brush = TRUE;
13002     }
13003     else
13004     {
13005       char request[100];
13006
13007       sprintf(request, "Replace level with %dx%d level sketch from clipboard?",
13008               brush_width, brush_height);
13009
13010       if (!Request(request, REQ_ASK))
13011         return;
13012
13013       for (x = 0; x < MAX_LEV_FIELDX; x++)
13014         for (y = 0; y < MAX_LEV_FIELDY; y++)
13015           Tile[x][y] = brush_buffer[x][y];
13016
13017       lev_fieldx = level.fieldx = brush_width;
13018       lev_fieldy = level.fieldy = brush_height;
13019
13020       boolean use_bd_engine = TRUE;
13021       boolean use_em_engine = TRUE;
13022       boolean use_sp_engine = TRUE;
13023       boolean use_mm_engine = TRUE;
13024
13025       for (x = 0; x < MAX_LEV_FIELDX; x++)
13026       {
13027         for (y = 0; y < MAX_LEV_FIELDY; y++)
13028         {
13029           int element = Tile[x][y];
13030
13031           if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
13032             use_bd_engine = FALSE;
13033
13034           if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
13035             use_em_engine = FALSE;
13036
13037           if (!IS_SP_ELEMENT(element))
13038             use_sp_engine = FALSE;
13039
13040           if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
13041             use_mm_engine = FALSE;
13042         }
13043       }
13044
13045       level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
13046                                 use_em_engine ? GAME_ENGINE_TYPE_EM :
13047                                 use_sp_engine ? GAME_ENGINE_TYPE_SP :
13048                                 use_mm_engine ? GAME_ENGINE_TYPE_MM :
13049                                 GAME_ENGINE_TYPE_RND);
13050
13051       // update element selection list
13052       ReinitializeElementList();
13053       ModifyEditorElementList();
13054
13055       SetBorderElement();
13056
13057       DrawEditModeWindow();
13058       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13059     }
13060
13061     return;
13062   }
13063
13064   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
13065     return;
13066
13067   if (mode == CB_AREA_TO_BRUSH)
13068   {
13069     int from_lx, from_ly;
13070
13071     if (from_x > to_x)
13072       swap_numbers(&from_x, &to_x);
13073
13074     if (from_y > to_y)
13075       swap_numbers(&from_y, &to_y);
13076
13077     brush_width = to_x - from_x + 1;
13078     brush_height = to_y - from_y + 1;
13079
13080     from_lx = from_x + level_xpos;
13081     from_ly = from_y + level_ypos;
13082
13083     for (y = 0; y < brush_height; y++)
13084     {
13085       for (x = 0; x < brush_width; x++)
13086       {
13087         brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
13088
13089         if (button != 1)
13090           DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
13091       }
13092     }
13093
13094     if (button != 1)
13095       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13096
13097     delete_old_brush = FALSE;
13098   }
13099   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
13100            mode == CB_BRUSH_TO_LEVEL)
13101   {
13102     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
13103     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
13104     int cursor_from_x = cursor_x - brush_width / 2;
13105     int cursor_from_y = cursor_y - brush_height / 2;
13106     int border_from_x = cursor_x, border_from_y = cursor_y;
13107     int border_to_x = cursor_x, border_to_y = cursor_y;
13108
13109     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
13110       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
13111
13112     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
13113         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
13114     {
13115       delete_old_brush = FALSE;
13116
13117       return;
13118     }
13119
13120     for (y = 0; y < brush_height; y++)
13121     {
13122       for (x = 0; x < brush_width; x++)
13123       {
13124         int sx = cursor_from_x + x;
13125         int sy = cursor_from_y + y;
13126         int lx = sx + level_xpos;
13127         int ly = sy + level_ypos;
13128         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
13129         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
13130                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
13131                        brush_buffer[x][y] : new_element);
13132
13133         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
13134         {
13135           if (sx < border_from_x)
13136             border_from_x = sx;
13137           else if (sx > border_to_x)
13138             border_to_x = sx;
13139           if (sy < border_from_y)
13140             border_from_y = sy;
13141           else if (sy > border_to_y)
13142             border_to_y = sy;
13143
13144           DrawBrushElement(sx, sy, element, change_level);
13145         }
13146       }
13147     }
13148
13149     if (mode != CB_DELETE_OLD_CURSOR)
13150       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
13151
13152     last_cursor_x = cursor_x;
13153     last_cursor_y = cursor_y;
13154
13155     delete_old_brush = TRUE;
13156   }
13157   else if (mode == CB_FLIP_BRUSH_X)
13158   {
13159     for (y = 0; y < brush_height; y++)
13160       for (x = 0; x < (brush_width + 1) / 2; x++)
13161         SwapFlippedTiles(&brush_buffer[x][y],
13162                          &brush_buffer[brush_width - x - 1][y], mode);
13163
13164     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
13165   }
13166   else if (mode == CB_FLIP_BRUSH_Y)
13167   {
13168     for (y = 0; y < (brush_height + 1) / 2; y++)
13169       for (x = 0; x < brush_width; x++)
13170         SwapFlippedTiles(&brush_buffer[x][y],
13171                          &brush_buffer[x][brush_height - y - 1], mode);
13172
13173     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
13174   }
13175   else if (mode == CB_FLIP_BRUSH_XY)
13176   {
13177     CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
13178
13179     for (y = 0; y < MAX(brush_width, brush_height); y++)
13180       for (x = 0; x <= y; x++)
13181         SwapFlippedTiles(&brush_buffer[x][y],
13182                          &brush_buffer[y][x], mode);
13183
13184     swap_numbers(&brush_width, &brush_height);
13185
13186     CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
13187   }
13188
13189   if (mode == CB_UPDATE_BRUSH_POSITION)
13190   {
13191     last_cursor_x = from_x;
13192     last_cursor_y = from_y;
13193   }
13194 }
13195
13196 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
13197                             int button)
13198 {
13199   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
13200 }
13201
13202 static void CopyBrushToLevel(int x, int y, int button)
13203 {
13204   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
13205 }
13206
13207 static void CopyBrushToCursor(int x, int y)
13208 {
13209   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
13210 }
13211
13212 static void UpdateBrushPosition(int x, int y)
13213 {
13214   CopyBrushExt(x, y, 0, 0, 0, CB_UPDATE_BRUSH_POSITION);
13215 }
13216
13217 static void DeleteBrushFromCursor(void)
13218 {
13219   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
13220 }
13221
13222 static void FlipBrushX(void)
13223 {
13224   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
13225 }
13226
13227 static void FlipBrushY(void)
13228 {
13229   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
13230 }
13231
13232 static void RotateBrush(void)
13233 {
13234   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
13235   CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
13236 }
13237
13238 void DumpBrush(void)
13239 {
13240   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
13241 }
13242
13243 void DumpBrush_Small(void)
13244 {
13245   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
13246 }
13247
13248 void CopyClipboardToBrush(void)
13249 {
13250   CopyBrushExt(0, 0, 0, 0, 0, CB_CLIPBOARD_TO_BRUSH);
13251 }
13252
13253 void CopyBrushToClipboard(void)
13254 {
13255   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD);
13256 }
13257
13258 void CopyBrushToClipboard_Small(void)
13259 {
13260   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
13261 }
13262
13263 void UndoLevelEditorOperation(void)
13264 {
13265   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
13266 }
13267
13268 void RedoLevelEditorOperation(void)
13269 {
13270   ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
13271 }
13272
13273 static void FloodFill(int from_x, int from_y, int fill_element)
13274 {
13275   FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
13276 }
13277
13278 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
13279 {
13280   int from_x = from_sx2 + 2 * level_xpos;
13281   int from_y = from_sy2 + 2 * level_ypos;
13282   int max_fillx = lev_fieldx * 2;
13283   int max_filly = lev_fieldy * 2;
13284   short Fill[max_fillx][max_filly];
13285   int x, y;
13286
13287   for (x = 0; x < max_fillx; x++)
13288     for (y = 0; y < max_filly; y++)
13289       Fill[x][y] = getLevelElementHiRes(x, y);
13290
13291   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
13292                     Fill, max_fillx, max_filly);
13293
13294   for (x = 0; x < max_fillx; x++)
13295     for (y = 0; y < max_filly; y++)
13296       if (Fill[x][y] == fill_element)
13297         SetLevelElementHiRes(x, y, Fill[x][y]);
13298 }
13299
13300 // values for DrawLevelText() modes
13301 #define TEXT_INIT               0
13302 #define TEXT_SETCURSOR          1
13303 #define TEXT_WRITECHAR          2
13304 #define TEXT_BACKSPACE          3
13305 #define TEXT_NEWLINE            4
13306 #define TEXT_END                5
13307 #define TEXT_QUERY_TYPING       6
13308
13309 static int DrawLevelText(int sx, int sy, char letter, int mode)
13310 {
13311   static short delete_buffer[MAX_LEV_FIELDX];
13312   static int start_sx;
13313   static int last_sx, last_sy;
13314   static boolean typing = FALSE;
13315   int letter_element;
13316   int lx = 0, ly = 0;
13317
13318   // map lower case letters to upper case and convert special characters
13319   if (letter >= 'a' && letter <= 'z')
13320     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
13321   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
13322     letter_element = EL_CHAR_AUMLAUT;
13323   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
13324     letter_element = EL_CHAR_OUMLAUT;
13325   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
13326     letter_element = EL_CHAR_UUMLAUT;
13327   else if (letter == '^')
13328     letter_element = EL_CHAR_COPYRIGHT;
13329   else
13330     letter_element = EL_CHAR_ASCII0 + letter;
13331
13332   if (mode != TEXT_INIT)
13333   {
13334     if (!typing)
13335       return FALSE;
13336
13337     if (mode != TEXT_SETCURSOR)
13338     {
13339       sx = last_sx;
13340       sy = last_sy;
13341     }
13342
13343     lx = last_sx + level_xpos;
13344     ly = last_sy + level_ypos;
13345   }
13346
13347   switch (mode)
13348   {
13349     case TEXT_INIT:
13350       if (typing)
13351         DrawLevelText(0, 0, 0, TEXT_END);
13352
13353       typing = TRUE;
13354       start_sx = sx;
13355       last_sx = sx;
13356       last_sy = sy;
13357       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
13358       break;
13359
13360     case TEXT_SETCURSOR:
13361       DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
13362       DrawAreaBorder(sx, sy, sx, sy);
13363       StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
13364                      ed_tilesize, ed_tilesize);
13365       last_sx = sx;
13366       last_sy = sy;
13367       break;
13368
13369     case TEXT_WRITECHAR:
13370       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
13371       {
13372         if (new_element1 >= EL_STEEL_CHAR_START &&
13373             new_element1 <= EL_STEEL_CHAR_END)
13374           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
13375
13376         delete_buffer[sx - start_sx] = Tile[lx][ly];
13377         Tile[lx][ly] = letter_element;
13378
13379         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
13380           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
13381         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
13382           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
13383         else
13384           DrawLevelText(0, 0, 0, TEXT_END);
13385
13386         level.changed = TRUE;
13387       }
13388       break;
13389
13390     case TEXT_BACKSPACE:
13391       if (sx > start_sx)
13392       {
13393         Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
13394         DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
13395         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
13396       }
13397       break;
13398
13399     case TEXT_NEWLINE:
13400       if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
13401         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
13402       else
13403         DrawLevelText(0, 0, 0, TEXT_END);
13404       break;
13405
13406     case TEXT_END:
13407       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13408       DrawEditorElement(sx, sy, Tile[lx][ly]);
13409       StopTextInput();
13410       typing = FALSE;
13411       break;
13412
13413     case TEXT_QUERY_TYPING:
13414       break;
13415
13416     default:
13417       break;
13418   }
13419
13420   return typing;
13421 }
13422
13423 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
13424                           int element, boolean change_level)
13425 {
13426   int lx = sx + level_xpos;
13427   int ly = sy + level_ypos;
13428
13429   if (element == -1)
13430     DrawEditorElement(sx, sy, Tile[lx][ly]);
13431   else
13432     DrawAreaBorder(sx, sy, sx, sy);
13433 }
13434
13435 static void CheckLevelBorderElement(boolean redraw_playfield)
13436 {
13437   int last_border_element = BorderElement;
13438
13439   SetBorderElement();
13440
13441   if (redraw_playfield && BorderElement != last_border_element)
13442     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
13443 }
13444
13445 static void CopyLevelToUndoBuffer(int mode)
13446 {
13447   static boolean accumulated_undo = FALSE;
13448   boolean new_undo_buffer_position = TRUE;
13449   int x, y;
13450
13451   if (undo_buffer_steps == 0)
13452     accumulated_undo = FALSE;
13453
13454   switch (mode)
13455   {
13456     case UNDO_IMMEDIATE:
13457       accumulated_undo = FALSE;
13458       break;
13459
13460     case UNDO_ACCUMULATE:
13461       if (accumulated_undo)
13462         new_undo_buffer_position = FALSE;
13463       accumulated_undo = TRUE;
13464       break;
13465
13466     default:
13467       break;
13468   }
13469
13470   if (new_undo_buffer_position)
13471   {
13472     // advance position in undo buffer ring
13473     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
13474
13475     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
13476       undo_buffer_steps++;
13477   }
13478
13479   // always reset redo buffer when storing level change into undo buffer
13480   redo_buffer_steps = 0;
13481
13482   for (x = 0; x < lev_fieldx; x++)
13483     for (y = 0; y < lev_fieldy; y++)
13484       UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
13485
13486   // check if drawing operation forces change of border style
13487   CheckLevelBorderElement(TRUE);
13488
13489   level.changed = TRUE;
13490 }
13491
13492 static void RandomPlacement(int new_element)
13493 {
13494   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
13495   int num_free_positions = 0;
13496   int num_percentage, num_elements;
13497   int x, y;
13498
13499   ResetIntelliDraw();
13500
13501   // determine number of free positions for randomly placing the new element
13502   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
13503   {
13504     free_position[x][y] =
13505       (random_placement_background_restricted ?
13506        Tile[x][y] == random_placement_background_element :
13507        Tile[x][y] != new_element);
13508
13509     if (free_position[x][y])
13510       num_free_positions++;
13511   }
13512
13513   // determine number of new elements to place there
13514   num_percentage = num_free_positions * random_placement_value / 100;
13515   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
13516                   num_percentage : random_placement_value);
13517
13518   // if less free positions than elements to place, fill all these positions
13519   if (num_free_positions < num_elements)
13520   {
13521     for (x = 0; x < lev_fieldx; x++)
13522       for (y = 0; y < lev_fieldy; y++)
13523         if (free_position[x][y])
13524           SetElement(x, y, new_element);
13525   }
13526   else
13527   {
13528     while (num_elements > 0)
13529     {
13530       x = GetSimpleRandom(lev_fieldx);
13531       y = GetSimpleRandom(lev_fieldy);
13532
13533       // don't place element at the same position twice
13534       if (free_position[x][y])
13535       {
13536         free_position[x][y] = FALSE;
13537         SetElement(x, y, new_element);
13538         num_elements--;
13539       }
13540     }
13541   }
13542
13543   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
13544   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13545 }
13546
13547 static void WrapLevel(int dx, int dy)
13548 {
13549   int wrap_dx = lev_fieldx - dx;
13550   int wrap_dy = lev_fieldy - dy;
13551   int x, y;
13552
13553   for (x = 0; x < lev_fieldx; x++)
13554     for (y = 0; y < lev_fieldy; y++)
13555       TileBackup[x][y] = Tile[x][y];
13556
13557   for (x = 0; x < lev_fieldx; x++)
13558     for (y = 0; y < lev_fieldy; y++)
13559       Tile[x][y] =
13560         TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
13561
13562   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
13563   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
13564 }
13565
13566 static void DrawAreaElementHighlight(boolean highlighted,
13567                                      boolean highlighted_similar)
13568 {
13569   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
13570
13571   if (!highlighted)
13572     return;
13573
13574   int x, y;
13575
13576   for (x = 0; x < ed_fieldx; x++)
13577   {
13578     for (y = 0; y < ed_fieldy; y++)
13579     {
13580       boolean highlight = FALSE;
13581       int lx = x + level_xpos;
13582       int ly = y + level_ypos;
13583
13584       if (!IN_LEV_FIELD(lx, ly))
13585         continue;
13586
13587       // check if element is the same
13588       if (Tile[lx][ly] == new_element1)
13589         highlight = TRUE;
13590
13591       // check if element is similar
13592       if (highlighted_similar &&
13593           strEqual(element_info[Tile[lx][ly]].class_name,
13594                    element_info[new_element1].class_name))
13595         highlight = TRUE;
13596
13597       // check if element is matching MM style wall
13598       if (IS_MM_WALL(Tile[lx][ly]) &&
13599           map_mm_wall_element(Tile[lx][ly]) == new_element1)
13600         highlight = TRUE;
13601
13602       if (!highlight)
13603         continue;
13604
13605       if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
13606       {
13607         int i;
13608
13609         for (i = 0; i < 4; i++)
13610         {
13611           if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
13612             continue;
13613
13614           int xx = x * 2 + (i % 2);
13615           int yy = y * 2 + (i / 2);
13616           int sx = SX + xx * ed_tilesize / 2;
13617           int sy = SY + yy * ed_tilesize / 2;
13618           int from_sx = sx;
13619           int from_sy = sy;
13620           int to_sx = sx + ed_tilesize / 2 - 1;
13621           int to_sy = sy + ed_tilesize / 2 - 1;
13622
13623           DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
13624           DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
13625           DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
13626           DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
13627         }
13628       }
13629       else
13630       {
13631         int sx = SX + x * ed_tilesize;
13632         int sy = SY + y * ed_tilesize;
13633         int from_sx = sx;
13634         int from_sy = sy;
13635         int to_sx = sx + ed_tilesize - 1;
13636         int to_sy = sy + ed_tilesize - 1;
13637
13638         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
13639         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
13640         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
13641         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
13642       }
13643     }
13644   }
13645 }
13646
13647 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
13648 {
13649   char *template_filename_old = getLocalLevelTemplateFilename();
13650   char *template_filename_new =
13651     getPath2(getUserLevelDir(levelset_subdir), LEVELTEMPLATE_FILENAME);
13652
13653   if (copyFile(template_filename_old, template_filename_new) != 0)
13654     Request("Cannot copy level template!", REQ_CONFIRM);
13655
13656   free(template_filename_new);
13657 }
13658
13659 static void HandleDrawingAreas(struct GadgetInfo *gi)
13660 {
13661   static boolean started_inside_drawing_area = FALSE;
13662   static int last_sx = -1;
13663   static int last_sy = -1;
13664   static int last_sx2 = -1;
13665   static int last_sy2 = -1;
13666   int id = gi->custom_id;
13667   int type_id = gi->custom_type_id;
13668   boolean button_press_event;
13669   boolean button_release_event;
13670   boolean inside_drawing_area = !gi->event.off_borders;
13671   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
13672   int actual_drawing_function;
13673   int button = gi->event.button;
13674   int new_element = BUTTON_ELEMENT(button);
13675   int sx = gi->event.x, sy = gi->event.y;
13676   int min_sx = 0, min_sy = 0;
13677   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
13678   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
13679   int mini_item_xsize = item_xsize / 2, mini_item_ysize = item_ysize / 2;
13680   int sx2 = gi->event.mx / mini_item_xsize;
13681   int sy2 = gi->event.my / mini_item_ysize;
13682   int dx = sx2 % 2;
13683   int dy = sy2 % 2;
13684   int lx = 0, ly = 0;
13685   int x, y;
13686
13687   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
13688   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
13689
13690   // make sure to stay inside drawing area boundaries
13691   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
13692   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
13693
13694   if (draw_level)
13695   {
13696     int min_lx = 0, min_ly = 0;
13697     int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
13698
13699     // get positions inside level field
13700     lx = sx + level_xpos;
13701     ly = sy + level_ypos;
13702
13703     if (!IN_LEV_FIELD(lx, ly))
13704       inside_drawing_area = FALSE;
13705
13706     // make sure to stay inside level field boundaries
13707     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
13708     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
13709
13710     // correct drawing area positions accordingly
13711     sx = lx - level_xpos;
13712     sy = ly - level_ypos;
13713   }
13714
13715   // also correct MM wall-sized (double) drawing area positions accordingly
13716   if (sx2 / 2 < sx || sx2 / 2 > sx)
13717   {
13718     dx = (sx2 / 2 < sx ? 0 : 1);
13719     sx2 = sx * 2 + dx;
13720   }
13721   if (sy2 / 2 < sy || sy2 / 2 > sy)
13722   {
13723     dy = (sy2 / 2 < sy ? 0 : 1);
13724     sy2 = sy * 2 + dy;
13725   }
13726
13727   if (!button_press_event && !button_release_event)
13728   {
13729     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
13730     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
13731                              isHiresTileElement(old_element) &&
13732                              isHiresDrawElement(new_element));
13733
13734     // prevent handling events for every pixel position when moving mouse
13735     if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
13736         (sx2 == last_sx2 && sy2 == last_sy2))
13737       return;
13738   }
13739
13740   last_sx = sx;
13741   last_sy = sy;
13742   last_sx2 = sx2;
13743   last_sy2 = sy2;
13744
13745   if (button_press_event)
13746     started_inside_drawing_area = inside_drawing_area;
13747
13748   if (!started_inside_drawing_area)
13749     return;
13750
13751   if (!IS_VALID_BUTTON(button))
13752     return;
13753
13754   // handle info callback for each invocation of action callback
13755   gi->callback_info(gi);
13756
13757   // automatically switch to 'single item' drawing mode, if needed
13758   actual_drawing_function =
13759     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
13760      drawing_function : GADGET_ID_SINGLE_ITEMS);
13761
13762   // clicking into drawing area with pressed Control key picks element
13763   if (GetKeyModState() & KMOD_Control)
13764   {
13765     last_drawing_function = drawing_function;
13766     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
13767   }
13768
13769   if (GetKeyModState() & KMOD_Shift)
13770   {
13771     if (button_press_event || button_release_event)
13772       ResetIntelliDraw();
13773   }
13774
13775   SetDrawModeHiRes(-1);         // reset to normal draw mode
13776
13777   switch (actual_drawing_function)
13778   {
13779     case GADGET_ID_SINGLE_ITEMS:
13780       if (draw_level)
13781       {
13782         if (button_release_event)
13783         {
13784           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13785
13786           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
13787               !inside_drawing_area)
13788             DeleteBrushFromCursor();
13789
13790           break;
13791         }
13792
13793         if (draw_with_brush)
13794         {
13795           CopyBrushToLevel(sx, sy, button);
13796         }
13797         else
13798         {
13799           SetDrawModeHiRes(new_element);
13800
13801           if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
13802           {
13803             // remove player at old position
13804             for (y = 0; y < lev_fieldy; y++)
13805             {
13806               for (x = 0; x < lev_fieldx; x++)
13807               {
13808                 int old_element = Tile[x][y];
13809
13810                 if (IS_PLAYER_ELEMENT(old_element) &&
13811                     IS_PLAYER_ELEMENT(new_element))
13812                 {
13813                   int replaced_with_element =
13814                     (old_element == EL_SOKOBAN_FIELD_PLAYER &&
13815                      new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
13816
13817                      old_element == EL_SOKOBAN_FIELD_PLAYER &&
13818                      new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
13819
13820                      new_element == EL_SOKOBAN_FIELD_PLAYER &&
13821                      old_element == EL_PLAYER_1 ? EL_EMPTY :
13822
13823                      new_element >= EL_PLAYER_1 &&
13824                      new_element <= EL_PLAYER_4 &&
13825                      new_element == old_element ? EL_EMPTY :
13826
13827                      old_element);
13828
13829                   SetElement(x, y, replaced_with_element);
13830                 }
13831                 else if (IS_MM_MCDUFFIN(old_element) &&
13832                          IS_MM_MCDUFFIN(new_element))
13833                 {
13834                   // remove McDuffin at old position
13835                   SetElement(x, y, EL_EMPTY);
13836                 }
13837               }
13838             }
13839           }
13840
13841           SetElementButton(lx, ly, dx, dy, new_element, button);
13842         }
13843       }
13844       else if (!button_release_event)
13845       {
13846         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
13847
13848         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
13849           DrawMiniGraphicExt(drawto,
13850                              gi->x + sx * MINI_TILEX,
13851                              gi->y + sy * MINI_TILEY,
13852                              el2edimg(new_element));
13853         else
13854           DrawFixedGraphicExt(drawto,
13855                               gi->x + sx * TILEX,
13856                               gi->y + sy * TILEY,
13857                               el2edimg(new_element), 0);
13858
13859         if (id == GADGET_ID_CUSTOM_GRAPHIC)
13860           new_element = GFX_ELEMENT(new_element);
13861
13862         drawingarea_info[type_id].value[pos] = new_element;
13863
13864         CopyElementPropertiesToGame(properties_element);
13865
13866         if (id == GADGET_ID_CUSTOM_GRAPHIC)
13867         {
13868           UpdateCustomElementGraphicGadgets();
13869
13870           FrameCounter = 0;     // restart animation frame counter
13871         }
13872       }
13873       break;
13874
13875     case GADGET_ID_CONNECTED_ITEMS:
13876       {
13877         static int last_sx = -1;
13878         static int last_sy = -1;
13879
13880         if (button_release_event)
13881           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13882
13883         SetDrawModeHiRes(new_element);
13884
13885         if (getDrawModeHiRes())
13886         {
13887           sx = sx2;
13888           sy = sy2;
13889         }
13890
13891         if (!button_press_event)
13892           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
13893
13894         last_sx = sx;
13895         last_sy = sy;
13896       }
13897       break;
13898
13899     case GADGET_ID_LINE:
13900     case GADGET_ID_ARC:
13901     case GADGET_ID_RECTANGLE:
13902     case GADGET_ID_FILLED_BOX:
13903       SetDrawModeHiRes(new_element);
13904
13905       if (getDrawModeHiRes())
13906       {
13907         sx = sx2;
13908         sy = sy2;
13909       }
13910       // FALLTHROUGH
13911     case GADGET_ID_GRAB_BRUSH:
13912     case GADGET_ID_TEXT:
13913       {
13914         static int last_sx = -1;
13915         static int last_sy = -1;
13916         static int start_sx = -1;
13917         static int start_sy = -1;
13918         void (*draw_func)(int, int, int, int, int, boolean);
13919
13920         if (drawing_function == GADGET_ID_LINE)
13921           draw_func = DrawLine;
13922         else if (drawing_function == GADGET_ID_ARC)
13923           draw_func = DrawArc;
13924         else if (drawing_function == GADGET_ID_RECTANGLE)
13925           draw_func = DrawBox;
13926         else if (drawing_function == GADGET_ID_FILLED_BOX)
13927           draw_func = DrawFilledBox;
13928         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
13929           draw_func = SelectArea;
13930         else // (drawing_function == GADGET_ID_TEXT)
13931           draw_func = SetTextCursor;
13932
13933         if (button_press_event)
13934         {
13935           draw_func(sx, sy, sx, sy, new_element, FALSE);
13936           start_sx = last_sx = sx;
13937           start_sy = last_sy = sy;
13938
13939           if (drawing_function == GADGET_ID_TEXT)
13940             DrawLevelText(0, 0, 0, TEXT_END);
13941         }
13942         else if (button_release_event)
13943         {
13944           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
13945           if (drawing_function == GADGET_ID_GRAB_BRUSH)
13946           {
13947             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
13948             CopyBrushToCursor(sx, sy);
13949             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
13950                           MB_LEFTBUTTON);
13951             draw_with_brush = TRUE;
13952           }
13953           else if (drawing_function == GADGET_ID_TEXT)
13954             DrawLevelText(sx, sy, 0, TEXT_INIT);
13955           else
13956             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13957         }
13958         else if (last_sx != sx || last_sy != sy)
13959         {
13960           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
13961           if (IS_MM_WALL_EDITOR(new_element))   // clear wall background
13962             draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
13963           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
13964           last_sx = sx;
13965           last_sy = sy;
13966         }
13967       }
13968       break;
13969
13970     case GADGET_ID_FLOOD_FILL:
13971       if (button_press_event && Tile[lx][ly] != new_element)
13972       {
13973         if (IS_MM_WALL_EDITOR(new_element))
13974           FloodFillWall_MM(sx2, sy2, new_element);
13975         else
13976           FloodFill(lx, ly, new_element);
13977
13978         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
13979         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
13980       }
13981       break;
13982
13983     case GADGET_ID_PICK_ELEMENT:
13984       if (button_release_event)
13985         ClickOnGadget(level_editor_gadget[last_drawing_function],
13986                       MB_LEFTBUTTON);
13987       else if (draw_level)
13988         PickDrawingElement(button, Tile[lx][ly]);
13989       else
13990       {
13991         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
13992
13993         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
13994       }
13995
13996     default:
13997       break;
13998   }
13999
14000   // do not mark level as modified for certain non-level-changing gadgets
14001   if ((type_id >= ED_DRAWING_ID_EDITOR_FIRST &&
14002        type_id <= ED_DRAWING_ID_EDITOR_LAST) ||
14003       actual_drawing_function == GADGET_ID_GRAB_BRUSH ||
14004       actual_drawing_function == GADGET_ID_PICK_ELEMENT)
14005     return;
14006
14007   level.changed = TRUE;
14008 }
14009
14010 static void HandleCounterButtons(struct GadgetInfo *gi)
14011 {
14012   int gadget_id = gi->custom_id;
14013   int counter_id = gi->custom_type_id;
14014   int button = gi->event.button;
14015   int *counter_value = counterbutton_info[counter_id].value;
14016   int step = BUTTON_STEPSIZE(button) *
14017     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
14018
14019   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
14020   {
14021     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
14022     boolean released = (gi->event.type == GD_EVENT_RELEASED);
14023     boolean level_changed = LevelChanged();
14024
14025     if ((level_changed && pressed) || (!level_changed && released))
14026       return;
14027
14028     if (level_changed && !Request("Level has changed! Discard changes?",
14029                                   REQ_ASK))
14030     {
14031       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
14032         ModifyEditorCounterValue(counter_id, *counter_value);
14033
14034       return;
14035     }
14036   }
14037
14038   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
14039     *counter_value = gi->textinput.number_value;
14040   else
14041     ModifyEditorCounterValue(counter_id, *counter_value + step);
14042
14043   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
14044   {
14045     int last_game_engine_type = level.game_engine_type;
14046
14047     LoadLevel(level_nr);
14048     LoadScore(level_nr);
14049
14050     SaveLevelSetup_SeriesInfo();
14051
14052     TapeErase();
14053
14054     ResetUndoBuffer();
14055     DrawEditModeWindow();
14056
14057     if (level.game_engine_type != last_game_engine_type)
14058     {
14059       // update element selection list
14060       ReinitializeElementList();
14061       ModifyEditorElementList();
14062     }
14063
14064     return;
14065   }
14066
14067   switch (counter_id)
14068   {
14069     case ED_COUNTER_ID_YAMYAM_CONTENT:
14070       DrawYamYamContentAreas();
14071       break;
14072
14073     case ED_COUNTER_ID_BALL_CONTENT:
14074       DrawMagicBallContentAreas();
14075       break;
14076
14077     case ED_COUNTER_ID_ANDROID_CONTENT:
14078       DrawAndroidElementArea();
14079       break;
14080
14081     case ED_COUNTER_ID_GROUP_CONTENT:
14082       DrawGroupElementArea();
14083       CopyGroupElementPropertiesToGame(properties_element);
14084       break;
14085
14086     case ED_COUNTER_ID_INVENTORY_SIZE:
14087       DrawPlayerInitialInventoryArea(properties_element);
14088       break;
14089
14090     case ED_COUNTER_ID_MM_BALL_CONTENT:
14091       DrawMMBallContentArea();
14092       break;
14093
14094     case ED_COUNTER_ID_ENVELOPE_XSIZE:
14095     case ED_COUNTER_ID_ENVELOPE_YSIZE:
14096       DrawEnvelopeTextArea(-1);
14097       break;
14098
14099     case ED_COUNTER_ID_LEVEL_XSIZE:
14100     case ED_COUNTER_ID_LEVEL_YSIZE:
14101       lev_fieldx = level.fieldx;
14102       lev_fieldy = level.fieldy;
14103
14104       // check if resizing of level results in change of border border
14105       SetBorderElement();
14106
14107       break;
14108
14109     default:
14110       break;
14111   }
14112
14113   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
14114        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
14115       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
14116        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
14117     CopyElementPropertiesToGame(properties_element);
14118
14119   // do not mark level as modified for certain non-level-changing gadgets
14120   if ((counter_id >= ED_COUNTER_ID_LEVELSET_FIRST &&
14121        counter_id <= ED_COUNTER_ID_LEVELSET_LAST) ||
14122       (counter_id >= ED_COUNTER_ID_EDITOR_FIRST &&
14123        counter_id <= ED_COUNTER_ID_EDITOR_LAST))
14124     return;
14125
14126   level.changed = TRUE;
14127 }
14128
14129 static void HandleTextInputGadgets(struct GadgetInfo *gi)
14130 {
14131   int type_id = gi->custom_type_id;
14132
14133   strcpy(textinput_info[type_id].value, gi->textinput.value);
14134
14135   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
14136   {
14137     CopyElementPropertiesToGame(properties_element);
14138
14139     ModifyEditorElementList();  // update changed button info text
14140   }
14141
14142   // do not mark level as modified for certain non-level-changing gadgets
14143   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
14144       type_id <= ED_TEXTINPUT_ID_LEVELSET_LAST)
14145     return;
14146
14147   level.changed = TRUE;
14148 }
14149
14150 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
14151 {
14152   int type_id = gi->custom_type_id;
14153
14154   strncpy(textarea_info[type_id].value, gi->textarea.value,
14155           MAX_ENVELOPE_TEXT_LEN);
14156   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
14157
14158   level.changed = TRUE;
14159 }
14160
14161 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
14162 {
14163   int type_id = gi->custom_type_id;
14164   int value_old = *selectbox_info[type_id].value;
14165   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
14166
14167   *selectbox_info[type_id].value = value_new;
14168
14169   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
14170   {
14171     DrawLevelConfigWindow();
14172   }
14173   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
14174   {
14175     element_info[properties_element].current_change_page = gi->selectbox.index;
14176
14177     DrawPropertiesWindow();
14178   }
14179   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
14180             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
14181            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
14182             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
14183            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
14184   {
14185     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
14186     {
14187       // when changing action type, also check action mode and action arg
14188       if (value_old != value_new)
14189         setSelectboxSpecialActionVariablesIfNeeded();
14190
14191       DrawPropertiesChange();
14192     }
14193
14194     CopyElementPropertiesToGame(properties_element);
14195   }
14196   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
14197   {
14198     // update element selection list
14199     ReinitializeElementList();
14200     ModifyEditorElementList();
14201   }
14202
14203   // do not mark level as modified for certain non-level-changing gadgets
14204   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
14205       type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
14206     return;
14207
14208   level.changed = TRUE;
14209 }
14210
14211 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
14212 {
14213   int type_id = gi->custom_type_id;
14214   int i;
14215
14216   if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
14217       type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
14218   {
14219     edit_mode_levelconfig = gi->custom_type_id;
14220
14221     DrawLevelConfigWindow();
14222   }
14223   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
14224            type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
14225   {
14226     edit_mode_properties = gi->custom_type_id;
14227
14228     DrawPropertiesWindow();
14229   }
14230   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1 ||
14231            type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2)
14232   {
14233     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
14234
14235     // backup original "level.field" (needed to track playfield changes)
14236     CopyPlayfield(level.field, TileBackup);
14237
14238     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
14239     CopyPlayfield(Tile, level.field);
14240
14241     if (new_template ||
14242         Request("Save this template and kill the old?", REQ_ASK))
14243       SaveLevelTemplate();
14244
14245     if (new_template)
14246       Request("Template saved!", REQ_CONFIRM);
14247
14248     // restore original "level.field" (needed to track playfield changes)
14249     CopyPlayfield(TileBackup, level.field);
14250   }
14251   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
14252   {
14253     char *levelset_subdir = getLevelSubdirFromSaveMode(levelset_save_mode);
14254
14255     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
14256         leveldir_current->readonly)
14257     {
14258       Request("This level set is read-only!", REQ_CONFIRM);
14259
14260       return;
14261     }
14262
14263     if (strEqual(levelset_name, ""))
14264     {
14265       Request("Please enter level set title!", REQ_CONFIRM);
14266
14267       return;
14268     }
14269
14270     if (strEqual(levelset_author, ""))
14271     {
14272       Request("Please enter level set author!", REQ_CONFIRM);
14273
14274       return;
14275     }
14276
14277     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE)
14278     {
14279       if (UpdateUserLevelSet(levelset_subdir,
14280                              levelset_name,
14281                              levelset_author,
14282                              levelset_num_levels))
14283       {
14284         Request("Level set updated!", REQ_CONFIRM);
14285       }
14286       else
14287       {
14288         Request("Updating level set failed!", REQ_CONFIRM);
14289       }
14290     }
14291     else if (levelset_save_mode == LEVELSET_SAVE_MODE_CREATE)
14292     {
14293       if (level.changed && !Request("Level has changed! Discard changes?",
14294                                      REQ_ASK))
14295         return;
14296
14297       if (CreateUserLevelSet(levelset_subdir,
14298                              levelset_name,
14299                              levelset_author,
14300                              levelset_num_levels,
14301                              levelset_use_levelset_artwork))
14302       {
14303         if (levelset_copy_level_template)
14304           CopyLevelTemplateToUserLevelSet(levelset_subdir);
14305
14306         Request("New level set created!", REQ_CONFIRM);
14307
14308         AddUserLevelSetToLevelInfo(levelset_subdir);
14309         ChangeEditorToLevelSet(levelset_subdir);
14310       }
14311       else
14312       {
14313         Request("Creating new level set failed!", REQ_CONFIRM);
14314       }
14315     }
14316   }
14317   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
14318            custom_element.num_change_pages < MAX_CHANGE_PAGES)
14319   {
14320     struct ElementInfo *ei = &element_info[properties_element];
14321
14322     // when modifying custom element, ask for copying level template
14323     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
14324       return;
14325
14326     setElementChangePages(ei, ei->num_change_pages + 1);
14327
14328     // set new change page to be new current change page
14329     ei->current_change_page = ei->num_change_pages - 1;
14330     ei->change = &ei->change_page[ei->current_change_page];
14331
14332     setElementChangeInfoToDefaults(ei->change);
14333
14334     DrawPropertiesWindow();
14335
14336     level.changed = TRUE;
14337   }
14338   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
14339            custom_element.num_change_pages > MIN_CHANGE_PAGES)
14340   {
14341     struct ElementInfo *ei = &element_info[properties_element];
14342
14343     // when modifying custom element, ask for copying level template
14344     if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
14345       return;
14346
14347     // copy all change pages after change page to be deleted
14348     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
14349       ei->change_page[i] = ei->change_page[i + 1];
14350
14351     setElementChangePages(ei, ei->num_change_pages - 1);
14352
14353     DrawPropertiesWindow();
14354
14355     level.changed = TRUE;
14356   }
14357 }
14358
14359 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
14360 {
14361   int type_id = gi->custom_type_id;
14362
14363   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
14364       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
14365   {
14366     struct ElementInfo *ei = &element_info[properties_element];
14367     int step = BUTTON_STEPSIZE(gi->event.button);
14368
14369     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
14370     ei->current_change_page += step;
14371
14372     if (ei->current_change_page < 0)
14373       ei->current_change_page = 0;
14374     else if (ei->current_change_page >= ei->num_change_pages)
14375       ei->current_change_page = ei->num_change_pages - 1;
14376
14377     DrawPropertiesWindow();
14378   }
14379   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
14380            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
14381   {
14382     struct ElementInfo *ei = &element_info[properties_element];
14383     int current_change_page = ei->current_change_page;
14384
14385     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
14386     {
14387       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
14388         ei->change_page[current_change_page];
14389     }
14390     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
14391     {
14392       // when modifying custom element, ask for copying level template
14393       if (level.use_custom_template && !AskToCopyAndModifyLevelTemplate())
14394         return;
14395
14396       ei->change_page[current_change_page] =
14397         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
14398
14399       level.changed = TRUE;
14400     }
14401
14402     DrawPropertiesWindow();
14403   }
14404 }
14405
14406 static void HandleRadiobuttons(struct GadgetInfo *gi)
14407 {
14408   int type_id = gi->custom_type_id;
14409
14410   *radiobutton_info[type_id].value =
14411     radiobutton_info[type_id].checked_value;
14412
14413   // do not mark level as modified for certain non-level-changing gadgets
14414   if (type_id >= ED_RADIOBUTTON_ID_EDITOR_FIRST &&
14415       type_id <= ED_RADIOBUTTON_ID_EDITOR_LAST)
14416     return;
14417
14418   level.changed = TRUE;
14419 }
14420
14421 static void HandleCheckbuttons(struct GadgetInfo *gi)
14422 {
14423   int type_id = gi->custom_type_id;
14424
14425   *checkbutton_info[type_id].value ^= TRUE;
14426
14427   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
14428       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
14429       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
14430       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
14431          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
14432         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
14433          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
14434        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1))
14435   {
14436     CopyElementPropertiesToGame(properties_element);
14437   }
14438
14439   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
14440   {
14441     UpdateCustomElementGraphicGadgets();
14442   }
14443   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1 ||
14444            type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2)
14445   {
14446     boolean template_related_changes_found = FALSE;
14447     int i;
14448
14449     // check if any custom, group or empty elements have been changed
14450     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
14451       if ((IS_CUSTOM_ELEMENT(i) ||
14452            IS_GROUP_ELEMENT(i) ||
14453            IS_EMPTY_ELEMENT(i)) &&
14454           element_info[i].modified_settings)
14455         template_related_changes_found = TRUE;
14456
14457     if (level.use_custom_template &&
14458         !fileExists(getGlobalLevelTemplateFilename()))
14459     {
14460       Request("No level template found!", REQ_CONFIRM);
14461
14462       level.use_custom_template = FALSE;
14463
14464       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
14465
14466       return;
14467     }
14468
14469     if (level.use_custom_template &&
14470         template_related_changes_found &&
14471         !Request("Discard changes and use level template?", REQ_ASK))
14472     {
14473       level.use_custom_template = FALSE;
14474
14475       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
14476
14477       return;
14478     }
14479
14480     if (!level.use_custom_template &&
14481         Request("Copy settings from level template?", REQ_ASK))
14482     {
14483       return;
14484     }
14485
14486     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
14487
14488     DrawEditModeWindow();
14489   }
14490   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3)
14491   {
14492     if (setup.editor.use_template_for_new_levels &&
14493         !fileExists(getGlobalLevelTemplateFilename()))
14494     {
14495       Request("No level template found!", REQ_CONFIRM);
14496
14497       return;
14498     }
14499
14500     if (setup.editor.use_template_for_new_levels &&
14501         level.changed &&
14502         !Request("Discard level and load template?", REQ_ASK))
14503     {
14504       return;
14505     }
14506
14507     if (!setup.editor.use_template_for_new_levels &&
14508         level.changed &&
14509         !Request("Discard level and use empty level?", REQ_ASK))
14510     {
14511       return;
14512     }
14513
14514     LoadLevel(level_nr);
14515     LoadScore(level_nr);
14516
14517     TapeErase();
14518
14519     ResetUndoBuffer();
14520     DrawEditModeWindow();
14521   }
14522   else if (type_id == ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS)
14523   {
14524     SetAutomaticNumberOfGemsNeeded();
14525   }
14526
14527   // do not mark level as modified for certain non-level-changing gadgets
14528   if ((type_id >= ED_CHECKBUTTON_ID_LEVELSET_FIRST &&
14529        type_id <= ED_CHECKBUTTON_ID_LEVELSET_LAST) ||
14530       (type_id >= ED_CHECKBUTTON_ID_EDITOR_FIRST &&
14531        type_id <= ED_CHECKBUTTON_ID_EDITOR_LAST &&
14532        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2) ||
14533       type_id == ED_CHECKBUTTON_ID_STICK_ELEMENT)
14534     return;
14535
14536   level.changed = TRUE;
14537 }
14538
14539 static void HandleControlButtons(struct GadgetInfo *gi)
14540 {
14541   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
14542   static int last_edit_mode = ED_MODE_DRAWING;
14543   static int last_custom_copy_mode = -1;
14544   static int last_button = 0;
14545   int id = gi->custom_id;
14546   int button = gi->event.button;
14547   int step = BUTTON_STEPSIZE(button);
14548   int new_element = BUTTON_ELEMENT(button);
14549   int last_properties_element = properties_element;
14550   int x, y;
14551
14552   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
14553     DrawLevelText(0, 0, 0, TEXT_END);
14554
14555   if (id < ED_NUM_CTRL1_BUTTONS &&
14556       id != GADGET_ID_SINGLE_ITEMS &&
14557       id != GADGET_ID_PICK_ELEMENT &&
14558       edit_mode != ED_MODE_DRAWING &&
14559       drawing_function != GADGET_ID_PICK_ELEMENT &&
14560       !(GetKeyModState() & KMOD_Control))
14561     ChangeEditModeWindow(ED_MODE_DRAWING);
14562
14563   // element copy mode active, but no element button pressed => deactivate
14564   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
14565     last_custom_copy_mode = -1;
14566
14567   // when showing palette on element buttons, change element of button used
14568   if (editor.palette.show_on_element_buttons &&
14569       id >= GADGET_ID_ELEMENT_LEFT && id <= GADGET_ID_ELEMENT_RIGHT)
14570   {
14571     last_button = id - GADGET_ID_ELEMENT_LEFT + 1;
14572
14573     id = GADGET_ID_PALETTE;
14574   }
14575
14576   switch (id)
14577   {
14578     case GADGET_ID_SCROLL_LEFT:
14579       if (level_xpos >= 0)
14580       {
14581         if (lev_fieldx < ed_fieldx - 2)
14582           break;
14583
14584         level_xpos -= step;
14585         if (level_xpos < -1)
14586           level_xpos = -1;
14587         if (button == 1)
14588           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
14589         else
14590           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14591
14592         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
14593                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
14594       }
14595       break;
14596
14597     case GADGET_ID_SCROLL_RIGHT:
14598       if (level_xpos <= lev_fieldx - ed_fieldx)
14599       {
14600         if (lev_fieldx < ed_fieldx - 2)
14601           break;
14602
14603         level_xpos += step;
14604         if (level_xpos > lev_fieldx - ed_fieldx + 1)
14605           level_xpos = lev_fieldx - ed_fieldx + 1;
14606         if (button == 1)
14607           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
14608         else
14609           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14610
14611         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
14612                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
14613       }
14614       break;
14615
14616     case GADGET_ID_SCROLL_UP:
14617       if (level_ypos >= 0)
14618       {
14619         if (lev_fieldy < ed_fieldy - 2)
14620           break;
14621
14622         level_ypos -= step;
14623         if (level_ypos < -1)
14624           level_ypos = -1;
14625         if (button == 1)
14626           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
14627         else
14628           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14629
14630         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
14631                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
14632       }
14633       break;
14634
14635     case GADGET_ID_SCROLL_DOWN:
14636       if (level_ypos <= lev_fieldy - ed_fieldy)
14637       {
14638         if (lev_fieldy < ed_fieldy - 2)
14639           break;
14640
14641         level_ypos += step;
14642         if (level_ypos > lev_fieldy - ed_fieldy + 1)
14643           level_ypos = lev_fieldy - ed_fieldy + 1;
14644         if (button == 1)
14645           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
14646         else
14647           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14648
14649         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
14650                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
14651       }
14652       break;
14653
14654     case GADGET_ID_SCROLL_HORIZONTAL:
14655       level_xpos = gi->event.item_position - 1;
14656
14657       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14658       BackToFront();
14659
14660       break;
14661
14662     case GADGET_ID_SCROLL_VERTICAL:
14663       level_ypos = gi->event.item_position - 1;
14664
14665       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14666       BackToFront();
14667
14668       break;
14669
14670     case GADGET_ID_SCROLL_LIST_UP:
14671     case GADGET_ID_SCROLL_LIST_DOWN:
14672     case GADGET_ID_SCROLL_LIST_VERTICAL:
14673       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
14674         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
14675       else
14676       {
14677         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
14678         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
14679
14680         if (element_shift < 0)
14681           element_shift = 0;
14682         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
14683           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
14684
14685         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
14686                      GDI_SCROLLBAR_ITEM_POSITION,
14687                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
14688       }
14689
14690       ModifyEditorElementList();
14691
14692       break;
14693
14694     case GADGET_ID_PROPERTIES:
14695       // always switch off element properties when they are already displayed
14696       last_properties_element = new_element;
14697     case GADGET_ID_ELEMENT_LEFT:
14698     case GADGET_ID_ELEMENT_MIDDLE:
14699     case GADGET_ID_ELEMENT_RIGHT:
14700       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
14701                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
14702                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
14703                             new_element);
14704
14705       if (edit_mode != ED_MODE_PROPERTIES)
14706       {
14707         last_edit_mode = edit_mode;
14708
14709         ChangeEditModeWindow(ED_MODE_PROPERTIES);
14710
14711         last_level_drawing_function = drawing_function;
14712         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
14713                       MB_LEFTBUTTON);
14714       }
14715       else if (properties_element != last_properties_element)
14716       {
14717         DrawEditModeWindow();
14718       }
14719       else
14720       {
14721         ChangeEditModeWindow(ED_MODE_DRAWING);
14722
14723         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
14724                       MB_LEFTBUTTON);
14725       }
14726       break;
14727
14728     case GADGET_ID_PALETTE:
14729       if (edit_mode != ED_MODE_PALETTE)
14730       {
14731         last_edit_mode = edit_mode;
14732
14733         ChangeEditModeWindow(ED_MODE_PALETTE);
14734       }
14735       else
14736       {
14737         ChangeEditModeWindow(last_edit_mode);
14738       }
14739       break;
14740
14741     case GADGET_ID_WRAP_LEFT:
14742       WrapLevel(-step, 0);
14743       break;
14744
14745     case GADGET_ID_WRAP_RIGHT:
14746       WrapLevel(step, 0);
14747       break;
14748
14749     case GADGET_ID_WRAP_UP:
14750       WrapLevel(0, -step);
14751       break;
14752
14753     case GADGET_ID_WRAP_DOWN:
14754       WrapLevel(0, step);
14755       break;
14756
14757     case GADGET_ID_SINGLE_ITEMS:
14758     case GADGET_ID_CONNECTED_ITEMS:
14759     case GADGET_ID_LINE:
14760     case GADGET_ID_ARC:
14761     case GADGET_ID_TEXT:
14762     case GADGET_ID_RECTANGLE:
14763     case GADGET_ID_FILLED_BOX:
14764     case GADGET_ID_FLOOD_FILL:
14765     case GADGET_ID_GRAB_BRUSH:
14766     case GADGET_ID_PICK_ELEMENT:
14767       if (drawing_function != GADGET_ID_PICK_ELEMENT)
14768         last_drawing_function = drawing_function;
14769       drawing_function = id;
14770       draw_with_brush = FALSE;
14771       break;
14772
14773     case GADGET_ID_RANDOM_PLACEMENT:
14774       RandomPlacement(new_element);
14775       break;
14776
14777     case GADGET_ID_ZOOM:
14778       // zoom level editor tile size in or out (or reset to default size)
14779       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
14780                      button == 2 ? ed_tilesize_default :
14781                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
14782
14783       // when using touch device, cycle through all zoom tilesizes
14784       if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
14785         ed_tilesize = MICRO_TILESIZE;
14786
14787       // limit zoom level by upper and lower bound
14788       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
14789
14790       InitZoomLevelSettings(ed_tilesize);
14791
14792       if (edit_mode == ED_MODE_DRAWING)
14793       {
14794         DrawDrawingWindow();
14795
14796         // redraw zoom gadget info text
14797         PrintEditorGadgetInfoText(level_editor_gadget[id]);
14798       }
14799
14800       // save current editor zoom tilesize
14801       SaveSetup_AutoSetup();
14802
14803       break;
14804
14805     case GADGET_ID_CUSTOM_COPY_FROM:
14806     case GADGET_ID_CUSTOM_COPY_TO:
14807     case GADGET_ID_CUSTOM_EXCHANGE:
14808       last_custom_copy_mode = id;
14809       last_drawing_function = drawing_function;
14810       break;
14811
14812     case GADGET_ID_CUSTOM_COPY:
14813       CopyCustomElement(properties_element, -1, id);
14814       break;
14815
14816     case GADGET_ID_CUSTOM_PASTE:
14817       CopyCustomElement(-1, properties_element, id);
14818       break;
14819
14820     case GADGET_ID_UNDO:
14821       if (button < 0)   // keep button value (even if modifier keys are pressed)
14822         button = -button;
14823       else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
14824         button = 3;
14825
14826       if (button == 1 && undo_buffer_steps == 0)
14827       {
14828         Request("Undo buffer empty!", REQ_CONFIRM);
14829
14830         break;
14831       }
14832       else if (button == 2)
14833       {
14834         break;
14835       }
14836       else if (button == 3 && redo_buffer_steps == 0)
14837       {
14838         Request("Redo buffer empty!", REQ_CONFIRM);
14839
14840         break;
14841       }
14842
14843       if (edit_mode != ED_MODE_DRAWING)
14844         ChangeEditModeWindow(ED_MODE_DRAWING);
14845
14846       if (button == 1)
14847       {
14848         // undo
14849
14850         undo_buffer_position =
14851           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
14852
14853         undo_buffer_steps--;
14854         redo_buffer_steps++;
14855       }
14856       else
14857       {
14858         // redo
14859
14860         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
14861
14862         undo_buffer_steps++;
14863         redo_buffer_steps--;
14864       }
14865
14866       for (x = 0; x < lev_fieldx; x++)
14867         for (y = 0; y < lev_fieldy; y++)
14868           Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
14869
14870       // check if undo operation forces change of border style
14871       CheckLevelBorderElement(FALSE);
14872
14873       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14874
14875       break;
14876
14877     case GADGET_ID_CONF:
14878       if (edit_mode != ED_MODE_LEVELCONFIG)
14879       {
14880         last_edit_mode = edit_mode;
14881
14882         ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
14883       }
14884       else
14885       {
14886         ChangeEditModeWindow(ED_MODE_DRAWING);
14887       }
14888       break;
14889
14890     case GADGET_ID_CLEAR:
14891       if (edit_mode != ED_MODE_DRAWING)
14892         ChangeEditModeWindow(ED_MODE_DRAWING);
14893
14894       for (x = 0; x < MAX_LEV_FIELDX; x++)
14895         for (y = 0; y < MAX_LEV_FIELDY; y++)
14896           Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
14897
14898       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
14899
14900       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
14901       break;
14902
14903     case GADGET_ID_SAVE:
14904     {
14905       // saving read-only levels into personal level set modifies global vars
14906       // "leveldir_current" and "level_nr"; restore them after saving level
14907       LevelDirTree *leveldir_former = leveldir_current;
14908       int level_nr_former = level_nr;
14909       char *level_filename;
14910       boolean new_level;
14911
14912       if (leveldir_current->readonly &&
14913           !PrepareSavingIntoPersonalLevelSet())
14914         break;
14915
14916       level_filename = getDefaultLevelFilename(level_nr);
14917       new_level = !fileExists(level_filename);
14918
14919       if (new_level ||
14920           Request("Save this level and kill the old?", REQ_ASK))
14921       {
14922         if (leveldir_former->readonly)
14923           ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
14924
14925         SetAutomaticNumberOfGemsNeeded();
14926
14927         CopyPlayfield(Tile, level.field);
14928         SaveLevel(level_nr);
14929
14930         level.changed = FALSE;
14931
14932         if (new_level)
14933         {
14934           char level_saved_msg[64];
14935
14936           if (leveldir_former->readonly)
14937             sprintf(level_saved_msg,
14938                     "Level saved as level %d into personal level set!",
14939                     level_nr);
14940           else
14941             strcpy(level_saved_msg, "Level saved!");
14942
14943           Request(level_saved_msg, REQ_CONFIRM);
14944         }
14945       }
14946
14947       // "cd" back to copied-from levelset (in case of saved read-only level)
14948       leveldir_current = leveldir_former;
14949       level_nr = level_nr_former;
14950
14951       break;
14952     }
14953
14954     case GADGET_ID_TEST:
14955       if (LevelChanged())
14956         level.game_version = GAME_VERSION_ACTUAL;
14957
14958       CopyPlayfield(level.field, TileBackup);
14959       CopyPlayfield(Tile, level.field);
14960
14961       CopyNativeLevel_RND_to_Native(&level);
14962
14963       UnmapLevelEditorGadgets();
14964       UndrawSpecialEditorDoor();
14965
14966       CloseDoor(DOOR_CLOSE_ALL);
14967
14968       // needed before playing if editor playfield area has different size
14969       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
14970
14971       // redraw_mask = REDRAW_ALL;
14972
14973       level_editor_test_game = TRUE;
14974
14975       StartGameActions(FALSE, setup.autorecord, level.random_seed);
14976
14977       break;
14978
14979     case GADGET_ID_EXIT:
14980       RequestExitLevelEditor(TRUE, FALSE);  // if level has changed, ask user
14981       break;
14982
14983     default:
14984       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
14985           id <= GADGET_ID_ELEMENTLIST_LAST)
14986       {
14987         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
14988
14989         new_element = editor_elements[element_position + element_shift];
14990
14991         if (IS_EDITOR_CASCADE(new_element))
14992         {
14993           int i;
14994
14995           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
14996           {
14997             int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
14998             boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
14999
15000             if (*cascade_element == new_element)
15001             {
15002               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
15003               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
15004
15005               // update element selection list
15006               ReinitializeElementList();
15007               ModifyEditorElementList();
15008
15009               // update cascading gadget info text
15010               PrintEditorGadgetInfoText(level_editor_gadget[id]);
15011
15012               // save current editor cascading state
15013               SaveSetup_EditorCascade();
15014
15015               break;
15016             }
15017           }
15018
15019           break;
15020         }
15021
15022         if (last_custom_copy_mode != -1)
15023         {
15024           if (CopyCustomElement(properties_element, new_element,
15025                                 last_custom_copy_mode))
15026           {
15027             ClickOnGadget(level_editor_gadget[last_drawing_function],
15028                           MB_LEFTBUTTON);
15029
15030             last_custom_copy_mode = -1;
15031           }
15032
15033           break;
15034         }
15035
15036         // change element of button used to show palette
15037         if (editor.palette.show_on_element_buttons)
15038           button = last_button;
15039
15040         PickDrawingElement(button, new_element);
15041
15042         if (!stick_element_properties_window &&
15043             drawing_function != GADGET_ID_PICK_ELEMENT &&
15044             !(GetKeyModState() & KMOD_Control))
15045         {
15046           properties_element = new_element;
15047           if (edit_mode == ED_MODE_PROPERTIES)
15048             DrawPropertiesWindow();
15049         }
15050
15051         if (drawing_function == GADGET_ID_PICK_ELEMENT)
15052           ClickOnGadget(level_editor_gadget[last_drawing_function],
15053                         MB_LEFTBUTTON);
15054
15055         if (!use_permanent_palette)
15056           ChangeEditModeWindow(last_edit_mode);
15057       }
15058 #ifdef DEBUG
15059       else if (gi->event.type == GD_EVENT_PRESSED)
15060         Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
15061       else if (gi->event.type == GD_EVENT_RELEASED)
15062         Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
15063       else if (gi->event.type == GD_EVENT_MOVING)
15064         Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
15065       else
15066         Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
15067 #endif
15068       break;
15069   }
15070 }
15071
15072 void HandleLevelEditorKeyInput(Key key)
15073 {
15074   char letter = getCharFromKey(key);
15075
15076   if (drawing_function == GADGET_ID_TEXT &&
15077       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
15078   {
15079     if (letter)
15080       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
15081     else if (key == KSYM_Delete || key == KSYM_BackSpace)
15082       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
15083     else if (key == KSYM_Return)
15084       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
15085     else if (key == KSYM_Escape)
15086       DrawLevelText(0, 0, 0, TEXT_END);
15087
15088     return;
15089   }
15090
15091   int id = GADGET_ID_NONE;
15092   int new_element_shift = element_shift;
15093   int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
15094   int button = MB_LEFTBUTTON;
15095   int i;
15096
15097   switch (key)
15098   {
15099     case KSYM_Left:
15100       id = GADGET_ID_SCROLL_LEFT;
15101       break;
15102     case KSYM_Right:
15103       id = GADGET_ID_SCROLL_RIGHT;
15104       break;
15105     case KSYM_Up:
15106       id = GADGET_ID_SCROLL_UP;
15107       break;
15108     case KSYM_Down:
15109       id = GADGET_ID_SCROLL_DOWN;
15110       break;
15111
15112     case KSYM_Page_Up:
15113     case KSYM_Page_Down:
15114       step *= (key == KSYM_Page_Up ? -1 : +1);
15115       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
15116
15117       if (element_shift < 0)
15118         element_shift = 0;
15119       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
15120         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
15121
15122       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
15123                    GDI_SCROLLBAR_ITEM_POSITION,
15124                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
15125
15126       ModifyEditorElementList();
15127
15128       break;
15129
15130     case KSYM_Home:
15131     case KSYM_End:
15132       element_shift = (key == KSYM_Home ? 0 :
15133                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
15134
15135       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
15136                    GDI_SCROLLBAR_ITEM_POSITION,
15137                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
15138
15139       ModifyEditorElementList();
15140
15141       break;
15142
15143     case KSYM_Insert:
15144     case KSYM_Delete:
15145
15146       // this is needed to prevent interference with running "True X-Mouse"
15147       if (GetKeyModStateFromEvents() & KMOD_Control)
15148         break;
15149
15150       // check for last or next editor cascade block in element list
15151       for (i = 0; i < num_editor_elements; i++)
15152       {
15153         if ((key == KSYM_Insert && i == element_shift) ||
15154             (key == KSYM_Delete && new_element_shift > element_shift))
15155           break;
15156
15157         // jump to next cascade block (or to start of element list)
15158         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
15159           new_element_shift = i;
15160       }
15161
15162       if (i < num_editor_elements)
15163         element_shift = new_element_shift;
15164
15165       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
15166         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
15167
15168       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
15169                    GDI_SCROLLBAR_ITEM_POSITION,
15170                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
15171
15172       ModifyEditorElementList();
15173
15174       break;
15175
15176     case KSYM_Escape:
15177       if (edit_mode == ED_MODE_DRAWING)
15178         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
15179       else if (edit_mode == ED_MODE_LEVELCONFIG)
15180         HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
15181       else if (edit_mode == ED_MODE_PROPERTIES)
15182         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
15183       else if (edit_mode == ED_MODE_PALETTE)
15184         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
15185       else              // should never happen
15186         ChangeEditModeWindow(ED_MODE_DRAWING);
15187
15188       break;
15189
15190     default:
15191       break;
15192   }
15193
15194   if (id != GADGET_ID_NONE)
15195     ClickOnGadget(level_editor_gadget[id], button);
15196   else if (letter == '1' || letter == '?')
15197     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
15198   else if (letter == '2')
15199     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
15200   else if (letter == '3')
15201     ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
15202   else if (letter == '.')
15203     ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
15204   else if (letter == 'U')
15205     ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
15206   else if (letter == '-' || key == KSYM_KP_Subtract)
15207     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
15208   else if (letter == '0' || key == KSYM_KP_0)
15209     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
15210   else if (letter == '+' || key == KSYM_KP_Add ||
15211            letter == '=')       // ("Shift-=" is "+" on US keyboards)
15212     ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
15213   else if (key == KSYM_Return ||
15214            key == KSYM_space ||
15215            key == setup.shortcut.toggle_pause)
15216     ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
15217   else
15218     for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
15219       if (letter && letter == controlbutton_info[i].shortcut)
15220         if (!anyTextGadgetActive())
15221           ClickOnGadget(level_editor_gadget[i], button);
15222
15223   if (draw_with_brush)
15224   {
15225     if (letter == 'x')
15226       FlipBrushX();
15227     else if (letter == 'y')
15228       FlipBrushY();
15229     else if (letter == 'z')
15230       RotateBrush();
15231   }
15232 }
15233
15234 static void HandleLevelEditorIdle_Properties(void)
15235 {
15236   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
15237   int x = editor.settings.element_graphic.x + element_border;
15238   int y = editor.settings.element_graphic.y + element_border;
15239   static DelayCounter action_delay = { 0 };
15240   int i;
15241
15242   action_delay.value = GameFrameDelay;
15243
15244   if (!DelayReached(&action_delay))
15245     return;
15246
15247   for (i = 0; i < ED_NUM_SELECTBOX; i++)
15248   {
15249     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
15250
15251     if (gi->mapped && gi->active && gi->selectbox.open)
15252       return;
15253   }
15254
15255   DrawEditorElementAnimation(SX + x, SY + y);
15256
15257   redraw_mask |= REDRAW_FIELD;
15258
15259   FrameCounter++;       // increase animation frame counter
15260 }
15261
15262 static void HandleLevelEditorIdle_Drawing(void)
15263 {
15264   static boolean last_highlighted = FALSE;
15265   static boolean last_highlighted_similar = FALSE;
15266   boolean highlighted = (GetKeyModState() & KMOD_Alt);
15267   boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
15268
15269   if (highlighted != last_highlighted ||
15270       (highlighted && highlighted_similar != last_highlighted_similar))
15271   {
15272     DrawAreaElementHighlight(highlighted, highlighted_similar);
15273
15274     redraw_mask |= REDRAW_FIELD;
15275   }
15276
15277   last_highlighted = highlighted;
15278   last_highlighted_similar = highlighted_similar;
15279 }
15280
15281 void HandleLevelEditorIdle(void)
15282 {
15283   if (edit_mode == ED_MODE_PROPERTIES)
15284     HandleLevelEditorIdle_Properties();
15285   else if (edit_mode == ED_MODE_DRAWING)
15286     HandleLevelEditorIdle_Drawing();
15287 }
15288
15289 static void ClearEditorGadgetInfoText(void)
15290 {
15291   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
15292 }
15293
15294 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
15295 {
15296   char infotext[MAX_OUTPUT_LINESIZE + 1];
15297   int max_infotext_len = getMaxInfoTextLength();
15298
15299   if (gi == NULL || strlen(gi->info_text) == 0)
15300     return;
15301
15302   strncpy(infotext, gi->info_text, max_infotext_len);
15303   infotext[max_infotext_len] = '\0';
15304
15305   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
15306   {
15307     int key = controlbutton_info[gi->custom_id].shortcut;
15308
15309     if (key)
15310     {
15311       char shortcut[MAX_OUTPUT_LINESIZE + 1];
15312
15313       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
15314         sprintf(shortcut, " ('.' or '%c')", key);
15315       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
15316         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
15317       else if (gi->custom_id == GADGET_ID_TEST)
15318         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
15319       else if (gi->custom_id == GADGET_ID_UNDO)
15320         sprintf(shortcut, " ('%c/Shift-U')", key);
15321       else if (gi->custom_id == GADGET_ID_ZOOM)
15322         sprintf(shortcut, " ('%c', '0', '-')", key);
15323       else
15324         sprintf(shortcut, " ('%s%c')",
15325                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
15326
15327       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
15328         strcat(infotext, shortcut);
15329     }
15330   }
15331
15332   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
15333 }
15334
15335 void HandleEditorGadgetInfoText(void *ptr)
15336 {
15337   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
15338
15339   if (game_status != GAME_MODE_EDITOR)
15340     return;
15341
15342   ClearEditorGadgetInfoText();
15343
15344   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
15345     return;
15346
15347   // misuse this function to delete brush cursor, if needed
15348   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
15349     DeleteBrushFromCursor();
15350
15351   PrintEditorGadgetInfoText(gi);
15352 }
15353
15354 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
15355 {
15356   int id = gi->custom_id;
15357   int type_id = gi->custom_type_id;
15358   int sx = gi->event.x;
15359   int sy = gi->event.y;
15360   int lx = sx + level_xpos;
15361   int ly = sy + level_ypos;
15362   int min_sx = 0, min_sy = 0;
15363   int max_sx = gi->drawing.area_xsize - 1;
15364   int max_sy = gi->drawing.area_ysize - 1;
15365   int actual_drawing_function = drawing_function;
15366   int max_infotext_len = getMaxInfoTextLength();
15367   char infotext[MAX_OUTPUT_LINESIZE + 1];
15368
15369   infotext[0] = '\0';           // start with empty info text
15370
15371   // pressed Control key: simulate picking element
15372   if (GetKeyModState() & KMOD_Control)
15373     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
15374
15375   ClearEditorGadgetInfoText();
15376
15377   if (gi->event.type == GD_EVENT_INFO_LEAVING)
15378     return;
15379
15380   // make sure to stay inside drawing area boundaries
15381   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
15382   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
15383
15384   if (id == GADGET_ID_DRAWING_LEVEL)
15385   {
15386     if (button_status)
15387     {
15388       int min_lx = 0, min_ly = 0;
15389       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
15390
15391       // get positions inside level field
15392       lx = sx + level_xpos;
15393       ly = sy + level_ypos;
15394
15395       // make sure to stay inside level field boundaries
15396       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
15397       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
15398
15399       // correct drawing area positions accordingly
15400       sx = lx - level_xpos;
15401       sy = ly - level_ypos;
15402     }
15403
15404     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
15405     {
15406       if (button_status)        // if (gi->state == GD_BUTTON_PRESSED)
15407       {
15408         static int start_lx = 0;
15409         static int start_ly = 0;
15410         char *text;
15411
15412         if (gi->event.type == GD_EVENT_PRESSED)
15413         {
15414           start_lx = lx;
15415           start_ly = ly;
15416         }
15417
15418         switch (actual_drawing_function)
15419         {
15420           case GADGET_ID_SINGLE_ITEMS:
15421             text = "Drawing single items";
15422             break;
15423           case GADGET_ID_CONNECTED_ITEMS:
15424             text = "Drawing connected items";
15425             break;
15426           case GADGET_ID_LINE:
15427             text = "Drawing line";
15428             break;
15429           case GADGET_ID_ARC:
15430             text = "Drawing arc";
15431             break;
15432           case GADGET_ID_TEXT:
15433             text = "Setting text cursor";
15434             break;
15435           case GADGET_ID_RECTANGLE:
15436             text = "Drawing rectangle";
15437             break;
15438           case GADGET_ID_FILLED_BOX:
15439             text = "Drawing filled box";
15440             break;
15441           case GADGET_ID_FLOOD_FILL:
15442             text = "Flood fill";
15443             break;
15444           case GADGET_ID_GRAB_BRUSH:
15445             text = "Grabbing brush";
15446             break;
15447           case GADGET_ID_PICK_ELEMENT:
15448             text = "Picking element";
15449             break;
15450
15451           default:
15452             text = "Drawing position";
15453             break;
15454         }
15455
15456         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15457           sprintf(infotext, "%s: %d, %d", text, lx, ly);
15458         else
15459           sprintf(infotext, "%s: %d, %d", text,
15460                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
15461       }
15462       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15463         strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
15464       else
15465         sprintf(infotext, "Level position: %d, %d", lx, ly);
15466     }
15467
15468     // misuse this function to draw brush cursor, if needed
15469     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
15470     {
15471       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
15472         CopyBrushToCursor(sx, sy);
15473       else
15474         DeleteBrushFromCursor();
15475     }
15476
15477     if (!draw_with_brush)
15478       UpdateBrushPosition(sx, sy);
15479   }
15480   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
15481   {
15482     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
15483     int element = drawingarea_info[type_id].value[pos];
15484
15485     strncpy(infotext, getElementInfoText(element), max_infotext_len);
15486   }
15487   else
15488   {
15489     if (id == GADGET_ID_CUSTOM_CONTENT)
15490       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
15491     else if (id == GADGET_ID_GROUP_CONTENT)
15492       sprintf(infotext, "group element position: %d", sx + 1);
15493     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
15494              id <= GADGET_ID_YAMYAM_CONTENT_7)
15495       sprintf(infotext, "content area %d position: %d, %d",
15496               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
15497     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
15498              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
15499       sprintf(infotext, "content area %d position: %d, %d",
15500               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
15501     else if (id == GADGET_ID_ANDROID_CONTENT)
15502       sprintf(infotext, "android element position: %d", sx + 1);
15503     else if (drawingarea_info[type_id].infotext != NULL)
15504       strcpy(infotext, drawingarea_info[type_id].infotext);
15505   }
15506
15507   infotext[max_infotext_len] = '\0';
15508
15509   if (strlen(infotext) > 0)
15510     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
15511 }
15512
15513 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
15514                             boolean quick_quit)
15515 {
15516   if (!ask_if_level_has_changed ||
15517       !LevelChanged() ||
15518       Request("Level has changed! Exit without saving?",
15519               REQ_ASK | REQ_STAY_OPEN))
15520   {
15521     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
15522     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
15523
15524     // draw normal door
15525     UndrawSpecialEditorDoor();
15526
15527     // use door animation if door 1 viewport is unchanged and contains toolbox
15528     if (useEditorDoorAnimation())
15529       CloseDoor(DOOR_CLOSE_1 | DOOR_FORCE_ANIM);
15530
15531     // close editor doors if viewport definition is the same as in main menu
15532     if (vp_door_1->x      == DX     &&
15533         vp_door_1->y      == DY     &&
15534         vp_door_1->width  == DXSIZE &&
15535         vp_door_1->height == DYSIZE &&
15536         vp_door_2->x      == VX     &&
15537         vp_door_2->y      == VY     &&
15538         vp_door_2->width  == VXSIZE &&
15539         vp_door_2->height == VYSIZE)
15540       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
15541     else
15542       SetDoorState(DOOR_CLOSE_ALL);
15543
15544     BackToFront();
15545
15546     if (quick_quit)
15547       FadeSkipNextFadeIn();
15548
15549     SetGameStatus(GAME_MODE_MAIN);
15550
15551     DrawMainMenu();
15552   }
15553   else
15554   {
15555     if (!global.use_envelope_request)
15556     {
15557       CloseDoor(DOOR_CLOSE_1);
15558       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
15559     }
15560   }
15561 }