added separate buttons for element properties of drawing elements
[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 //                  http://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   -----------------------------------------------------------------------------
30   screen and artwork graphic pixel position definitions
31   -----------------------------------------------------------------------------
32 */
33
34 /* values for the control window */
35 #define ED_CTRL1_BUTTONS_HORIZ          4       /* toolbox */
36 #define ED_CTRL1_BUTTONS_VERT           4
37 #define ED_CTRL2_BUTTONS_HORIZ          3       /* level */
38 #define ED_CTRL2_BUTTONS_VERT           2
39 #define ED_CTRL3_BUTTONS_HORIZ          3       /* CE and GE */
40 #define ED_CTRL3_BUTTONS_VERT           1
41 #define ED_CTRL4_BUTTONS_HORIZ          2       /* CE and GE */
42 #define ED_CTRL4_BUTTONS_VERT           1
43 #define ED_CTRL5_BUTTONS_HORIZ          1       /* properties */
44 #define ED_CTRL5_BUTTONS_VERT           1
45 #define ED_CTRL6_BUTTONS_HORIZ          3       /* properties */
46 #define ED_CTRL6_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_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
55 #define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
56 #define ED_NUM_CTRL1_4_BUTTONS (ED_NUM_CTRL1_3_BUTTONS + ED_NUM_CTRL4_BUTTONS)
57 #define ED_NUM_CTRL1_5_BUTTONS (ED_NUM_CTRL1_4_BUTTONS + ED_NUM_CTRL5_BUTTONS)
58 #define ED_NUM_CTRL1_6_BUTTONS (ED_NUM_CTRL1_5_BUTTONS + ED_NUM_CTRL6_BUTTONS)
59 #define ED_NUM_CTRL_BUTTONS    ED_NUM_CTRL1_6_BUTTONS
60
61 /* values for the element list */
62 #define ED_ELEMENTLIST_XPOS             (editor.palette.x)
63 #define ED_ELEMENTLIST_YPOS             (editor.palette.y)
64 #define ED_ELEMENTLIST_XSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
65 #define ED_ELEMENTLIST_YSIZE            (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
66 #define ED_ELEMENTLIST_BUTTONS_HORIZ    (editor.palette.cols)
67 #define ED_ELEMENTLIST_BUTTONS_VERT     (editor.palette.rows)
68 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
69                                          ED_ELEMENTLIST_BUTTONS_VERT)
70
71 /* standard distances */
72 #define ED_GADGET_NORMAL_DISTANCE       (editor.gadget.normal_spacing)
73 #define ED_GADGET_SMALL_DISTANCE        (editor.gadget.small_spacing)
74 #define ED_GADGET_TINY_DISTANCE         (editor.gadget.tiny_spacing)
75 #define ED_GADGET_LINE_DISTANCE         (editor.gadget.line_spacing)
76 #define ED_GADGET_TEXT_DISTANCE         (editor.gadget.text_spacing)
77 #define ED_TAB_BAR_HEIGHT               (editor.gadget.separator_line.height)
78 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE +      \
79                                          ED_DRAWINGAREA_BORDER_SIZE)
80 #define ED_GADGET_SPACE_DISTANCE        (getFontWidth(FONT_TEXT_1))
81
82 /* values for drawingarea gadgets */
83 #define IMG_BORDER_1                    IMG_EDITOR_ELEMENT_BORDER
84 #define IMG_BORDER_2                    IMG_EDITOR_ELEMENT_BORDER_INPUT
85 #define ED_ELEMENT_BORDER               (graphic_info[IMG_BORDER_1].border_size)
86 #define ED_DRAWINGAREA_BORDER_SIZE      (graphic_info[IMG_BORDER_2].border_size)
87 #define ED_DRAWINGAREA_TILE_SIZE        (editor.drawingarea.tile_size)
88
89 /* values for checkbutton gadgets */
90 #define ED_CHECKBUTTON_XSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].width)
91 #define ED_CHECKBUTTON_YSIZE         (graphic_info[IMG_EDITOR_CHECKBOX].height)
92
93 #define ED_TABBUTTON_XSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].width)
94 #define ED_TABBUTTON_YSIZE           (graphic_info[IMG_EDITOR_TABBUTTON].height)
95
96 #define ED_LEVEL_SETTINGS_TABS_X        (editor.settings.tabs.x)
97 #define ED_LEVEL_SETTINGS_TABS_Y        (editor.settings.tabs.y)
98 #define ED_ELEMENT_SETTINGS_TABS_X      (editor.settings.tabs.x)
99 #define ED_ELEMENT_SETTINGS_TABS_Y      (editor.settings.tabs.y +       \
100                                          editor.settings.tabs.yoffset2)
101
102 #define ED_SETTINGS_TABS_XOFFSET        (editor.settings.tabs.draw_xoffset)
103 #define ED_SETTINGS_TABS_YOFFSET        (editor.settings.tabs.draw_yoffset)
104
105 #define ED_LEVEL_SETTINGS_XSTART        (ED_LEVEL_SETTINGS_TABS_X +     \
106                                          ED_SETTINGS_TABS_XOFFSET)
107 #define ED_LEVEL_SETTINGS_YSTART        (ED_LEVEL_SETTINGS_TABS_Y +     \
108                                          ED_TABBUTTON_YSIZE +           \
109                                          ED_GADGET_TINY_DISTANCE +      \
110                                          ED_TAB_BAR_HEIGHT +            \
111                                          ED_SETTINGS_TABS_YOFFSET +     \
112                                          getFontHeight(FONT_TEXT_1) +   \
113                                          ED_GADGET_TEXT_DISTANCE)
114 #define ED_ELEMENT_SETTINGS_XSTART      (ED_ELEMENT_SETTINGS_TABS_X +   \
115                                          ED_SETTINGS_TABS_XOFFSET)
116 #define ED_ELEMENT_SETTINGS_YSTART      (ED_ELEMENT_SETTINGS_TABS_Y +   \
117                                          ED_TABBUTTON_YSIZE +           \
118                                          ED_GADGET_TINY_DISTANCE +      \
119                                          ED_TAB_BAR_HEIGHT +            \
120                                          ED_SETTINGS_TABS_YOFFSET)
121
122 #define ED_SETTINGS_XOFFSET             (ED_CHECKBUTTON_XSIZE +         \
123                                          ED_GADGET_TEXT_DISTANCE)
124 #define ED_SETTINGS_YOFFSET             (ED_CHECKBUTTON_YSIZE +         \
125                                          ED_GADGET_LINE_DISTANCE)
126
127 #define ED_POS_LEVEL_SETTINGS_RANGE     (10000)
128 #define ED_POS_LEVEL_SETTINGS_FIRST     (1 * ED_POS_LEVEL_SETTINGS_RANGE)
129 #define ED_POS_LEVEL_SETTINGS_LAST      (2 * ED_POS_LEVEL_SETTINGS_RANGE - 1)
130 #define ED_POS_ELEMENT_SETTINGS_FIRST   (2 * ED_POS_LEVEL_SETTINGS_RANGE)
131 #define ED_POS_ELEMENT_SETTINGS_LAST    (3 * ED_POS_LEVEL_SETTINGS_RANGE - 1)
132
133 #define ED_LEVEL_SETTINGS_XPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
134 #define ED_LEVEL_SETTINGS_YPOS(n)       (ED_POS_LEVEL_SETTINGS_FIRST + (n))
135
136 #define ED_ELEMENT_SETTINGS_XPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
137 #define ED_ELEMENT_SETTINGS_YPOS(n)     (ED_POS_ELEMENT_SETTINGS_FIRST + (n))
138
139 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
140                                        (n) <= ED_POS_LEVEL_SETTINGS_LAST)
141 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
142                                        (n) <= ED_POS_ELEMENT_SETTINGS_LAST)
143
144 #define ED_LEVEL_SETTINGS_LINE(n)       ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
145 #define ED_ELEMENT_SETTINGS_LINE(n)     ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
146
147 #define ED_LEVEL_SETTINGS_X(n)          (ED_LEVEL_SETTINGS_XSTART +     \
148                                          (n) * ED_SETTINGS_XOFFSET)
149 #define ED_LEVEL_SETTINGS_Y(n)          (ED_LEVEL_SETTINGS_YSTART +     \
150                                          (n) * ED_SETTINGS_YOFFSET)
151
152 #define ED_ELEMENT_SETTINGS_X(n)        (ED_ELEMENT_SETTINGS_XSTART +   \
153                                          (n) * ED_SETTINGS_XOFFSET)
154 #define ED_ELEMENT_SETTINGS_Y(n)        (ED_ELEMENT_SETTINGS_YSTART +   \
155                                          (n) * ED_SETTINGS_YOFFSET)
156
157 #define ED_POS_TO_LEVEL_SETTINGS_X(n)   \
158   (ED_LEVEL_SETTINGS_X(ED_LEVEL_SETTINGS_LINE(n)))
159 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)   \
160   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
161
162 #define ED_POS_TO_ELEMENT_SETTINGS_X(n) \
163   (ED_ELEMENT_SETTINGS_X(ED_ELEMENT_SETTINGS_LINE(n)))
164 #define ED_POS_TO_ELEMENT_SETTINGS_Y(n) \
165   (ED_ELEMENT_SETTINGS_Y(ED_ELEMENT_SETTINGS_LINE(n)))
166
167 #define ED_SETTINGS_X(n)                (IS_POS_LEVEL_SETTINGS(n) ?     \
168                                          ED_POS_TO_LEVEL_SETTINGS_X(n) : \
169                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
170                                          ED_POS_TO_ELEMENT_SETTINGS_X(n) : (n))
171 #define ED_SETTINGS_Y(n)                (IS_POS_LEVEL_SETTINGS(n) ?     \
172                                          ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
173                                          IS_POS_ELEMENT_SETTINGS(n) ?   \
174                                          ED_POS_TO_ELEMENT_SETTINGS_Y(n) : (n))
175
176 #define ED_TAB_SETTINGS_X(n)            (IS_POS_LEVEL_SETTINGS(n) ?     \
177                                          ED_LEVEL_SETTINGS_TABS_X :     \
178                                          ED_ELEMENT_SETTINGS_TABS_X)
179 #define ED_TAB_SETTINGS_Y(n)            (IS_POS_LEVEL_SETTINGS(n) ?     \
180                                          ED_LEVEL_SETTINGS_TABS_Y :     \
181                                          ED_ELEMENT_SETTINGS_TABS_Y)
182
183 #define ED_SETTINGS_XOFF(n)             (5 * ((n) % 4) *                \
184                                          ED_DRAWINGAREA_TILE_SIZE)
185 #define ED_SETTINGS_YOFF(n)             (5 * ((n) / 4) *                \
186                                          ED_DRAWINGAREA_TILE_SIZE)
187
188 #define ED_AREA_XOFFSET_1(n)            ((n) != 0 ?                     \
189                                          ED_DRAWINGAREA_BORDER_SIZE : 0)
190 #define ED_AREA_YOFFSET_1(n)            ((n) != 0 ?                     \
191                                          (ED_CHECKBUTTON_YSIZE -        \
192                                           ED_DRAWINGAREA_TILE_SIZE) / 2 : 0)
193
194 #define ED_AREA_XOFFSET_2(n)      (0)
195 #define ED_AREA_YOFFSET_2(n)      ((n) == 3 ?                   \
196                                    ((n) - 1) * ED_DRAWINGAREA_TILE_SIZE / 2 : 0)
197
198 #define ED_AREA_SETTINGS_X(i)      (ED_SETTINGS_X((i).x) +              \
199                                     ED_SETTINGS_XOFF((i).xoffset) +     \
200                                     ED_AREA_XOFFSET_1((i).x) -          \
201                                     ED_AREA_XOFFSET_2((i).area_xsize))
202 #define ED_AREA_SETTINGS_Y(i)      (ED_SETTINGS_Y((i).y) +              \
203                                     ED_SETTINGS_YOFF((i).yoffset) +     \
204                                     ED_AREA_YOFFSET_1((i).y) -          \
205                                     ED_AREA_YOFFSET_2((i).area_ysize))
206
207 /* values for element content drawing areas */
208 #define ED_AREA_1X1_LSETTINGS_XPOS(n)   ED_LEVEL_SETTINGS_XPOS(n)
209 #define ED_AREA_1X1_LSETTINGS_YPOS(n)   ED_LEVEL_SETTINGS_YPOS(n)
210 #define ED_AREA_1X1_LSETTINGS_XOFF      (0)
211 #define ED_AREA_1X1_LSETTINGS_YOFF      (0)
212
213 #define ED_AREA_1X1_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
214 #define ED_AREA_1X1_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
215 #define ED_AREA_1X1_SETTINGS_XOFF       (0)
216 #define ED_AREA_1X1_SETTINGS_YOFF       (0)
217
218 #define ED_AREA_3X3_SETTINGS_XPOS(n)    ED_ELEMENT_SETTINGS_XPOS(n)
219 #define ED_AREA_3X3_SETTINGS_YPOS(n)    ED_ELEMENT_SETTINGS_YPOS(n)
220 #define ED_AREA_3X3_SETTINGS_XOFF       (0)
221 #define ED_AREA_3X3_SETTINGS_YOFF       (0)
222
223 /* element content */
224 #define ED_AREA_ELEMENT_CONTENT_XOFF(n) (n)
225 #define ED_AREA_ELEMENT_CONTENT_YOFF(n) (n)
226
227 /* yamyam content */
228 #define ED_XPOS_YAM                     0
229 #define ED_YPOS_YAM                     5
230 #define ED_AREA_YAMYAM_CONTENT_XPOS     ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_YAM)
231 #define ED_AREA_YAMYAM_CONTENT_YPOS     ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_YAM)
232 #define ED_AREA_YAMYAM_CONTENT_XOFF(n)  ED_AREA_ELEMENT_CONTENT_XOFF(n)
233 #define ED_AREA_YAMYAM_CONTENT_YOFF(n)  ED_AREA_ELEMENT_CONTENT_YOFF(n)
234 #define ED_AREA_YAMYAM_CONTENT_X(n)     (ED_ELEMENT_SETTINGS_X(ED_XPOS_YAM) + \
235                                          ED_SETTINGS_XOFF(n))
236 #define ED_AREA_YAMYAM_CONTENT_Y(n)     (ED_ELEMENT_SETTINGS_Y(ED_YPOS_YAM) + \
237                                          ED_SETTINGS_YOFF(n) +          \
238                                          ED_AREA_YOFFSET_1(ED_YPOS_YAM) - \
239                                          ED_AREA_YOFFSET_2(3))
240
241 /* magic ball content */
242 #define ED_XPOS_BALL                    0
243 #define ED_YPOS_BALL                    6
244 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS ED_ELEMENT_SETTINGS_XPOS(ED_XPOS_BALL)
245 #define ED_AREA_MAGIC_BALL_CONTENT_YPOS ED_ELEMENT_SETTINGS_YPOS(ED_YPOS_BALL)
246 #define ED_AREA_MAGIC_BALL_CONTENT_XOFF(n) ED_AREA_ELEMENT_CONTENT_XOFF(n)
247 #define ED_AREA_MAGIC_BALL_CONTENT_YOFF(n) ED_AREA_ELEMENT_CONTENT_YOFF(n)
248 #define ED_AREA_MAGIC_BALL_CONTENT_X(n) (ED_ELEMENT_SETTINGS_X(ED_XPOS_BALL) + \
249                                          ED_SETTINGS_XOFF(n))
250 #define ED_AREA_MAGIC_BALL_CONTENT_Y(n) (ED_ELEMENT_SETTINGS_Y(ED_YPOS_BALL) + \
251                                          ED_SETTINGS_YOFF(n) +          \
252                                          ED_AREA_YOFFSET_1(ED_YPOS_BALL) - \
253                                          ED_AREA_YOFFSET_2(3))
254
255 /* values for scrolling gadgets for drawing area */
256 #define ED_SCROLLBUTTON_XSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].width)
257 #define ED_SCROLLBUTTON_YSIZE           (graphic_info[IMG_EDITOR_PLAYFIELD_SCROLLBAR].height)
258
259 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
260 #define ED_SCROLL_UP_YPOS               (0)
261 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
262 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
263 #define ED_SCROLL_LEFT_XPOS             (0)
264 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
265 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
266 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
267 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS +          \
268                                          ED_SCROLLBUTTON_XSIZE)
269 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
270 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
271 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
272 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
273 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS +            \
274                                          ED_SCROLLBUTTON_YSIZE)
275 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
276 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
277
278 /* values for scrolling gadgets for element list */
279 #define ED_SCROLLBUTTON2_XSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].width)
280 #define ED_SCROLLBUTTON2_YSIZE          (graphic_info[IMG_EDITOR_PALETTE_SCROLL_UP].height)
281
282 #define ED_SCROLL2_UP_XPOS              (ED_ELEMENTLIST_XPOS +          \
283                                          ED_ELEMENTLIST_BUTTONS_HORIZ * \
284                                          ED_ELEMENTLIST_XSIZE)
285 #define ED_SCROLL2_UP_YPOS              ED_ELEMENTLIST_YPOS
286 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
287 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS +           \
288                                          ED_ELEMENTLIST_BUTTONS_VERT *  \
289                                          ED_ELEMENTLIST_YSIZE -         \
290                                          ED_SCROLLBUTTON2_YSIZE)
291 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
292 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS +           \
293                                          ED_SCROLLBUTTON2_YSIZE)
294 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
295 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT *  \
296                                          ED_ELEMENTLIST_YSIZE -         \
297                                          2 * ED_SCROLLBUTTON2_YSIZE)
298
299 /* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */
300 #define INFOTEXT_FONT           FONT_TEXT_2
301 #define INFOTEXT_XSIZE          SXSIZE
302 #define INFOTEXT_YSIZE          getFontHeight(INFOTEXT_FONT)
303 #define INFOTEXT_YSIZE_FULL     (INFOTEXT_YSIZE + ED_GADGET_SMALL_DISTANCE)
304 #define INFOTEXT_XPOS           SX
305 #define INFOTEXT_YPOS           (SY + SYSIZE - INFOTEXT_YSIZE)
306
307
308 /*
309   -----------------------------------------------------------------------------
310   editor gadget definitions
311   -----------------------------------------------------------------------------
312 */
313
314 /* drawing toolbox buttons */
315 #define GADGET_ID_NONE                  -1
316 #define GADGET_ID_TOOLBOX_FIRST         0
317
318 #define GADGET_ID_SINGLE_ITEMS          (GADGET_ID_TOOLBOX_FIRST + 0)
319 #define GADGET_ID_CONNECTED_ITEMS       (GADGET_ID_TOOLBOX_FIRST + 1)
320 #define GADGET_ID_LINE                  (GADGET_ID_TOOLBOX_FIRST + 2)
321 #define GADGET_ID_ARC                   (GADGET_ID_TOOLBOX_FIRST + 3)
322 #define GADGET_ID_RECTANGLE             (GADGET_ID_TOOLBOX_FIRST + 4)
323 #define GADGET_ID_FILLED_BOX            (GADGET_ID_TOOLBOX_FIRST + 5)
324 #define GADGET_ID_WRAP_UP               (GADGET_ID_TOOLBOX_FIRST + 6)
325 #define GADGET_ID_TEXT                  (GADGET_ID_TOOLBOX_FIRST + 7)
326 #define GADGET_ID_FLOOD_FILL            (GADGET_ID_TOOLBOX_FIRST + 8)
327 #define GADGET_ID_WRAP_LEFT             (GADGET_ID_TOOLBOX_FIRST + 9)
328 #define GADGET_ID_ZOOM                  (GADGET_ID_TOOLBOX_FIRST + 10)
329 #define GADGET_ID_WRAP_RIGHT            (GADGET_ID_TOOLBOX_FIRST + 11)
330 #define GADGET_ID_RANDOM_PLACEMENT      (GADGET_ID_TOOLBOX_FIRST + 12)
331 #define GADGET_ID_GRAB_BRUSH            (GADGET_ID_TOOLBOX_FIRST + 13)
332 #define GADGET_ID_WRAP_DOWN             (GADGET_ID_TOOLBOX_FIRST + 14)
333 #define GADGET_ID_PICK_ELEMENT          (GADGET_ID_TOOLBOX_FIRST + 15)
334
335 #define GADGET_ID_UNDO                  (GADGET_ID_TOOLBOX_FIRST + 16)
336 #define GADGET_ID_INFO                  (GADGET_ID_TOOLBOX_FIRST + 17)
337 #define GADGET_ID_SAVE                  (GADGET_ID_TOOLBOX_FIRST + 18)
338 #define GADGET_ID_CLEAR                 (GADGET_ID_TOOLBOX_FIRST + 19)
339 #define GADGET_ID_TEST                  (GADGET_ID_TOOLBOX_FIRST + 20)
340 #define GADGET_ID_EXIT                  (GADGET_ID_TOOLBOX_FIRST + 21)
341
342 #define GADGET_ID_CUSTOM_COPY_FROM      (GADGET_ID_TOOLBOX_FIRST + 22)
343 #define GADGET_ID_CUSTOM_COPY_TO        (GADGET_ID_TOOLBOX_FIRST + 23)
344 #define GADGET_ID_CUSTOM_EXCHANGE       (GADGET_ID_TOOLBOX_FIRST + 24)
345 #define GADGET_ID_CUSTOM_COPY           (GADGET_ID_TOOLBOX_FIRST + 25)
346 #define GADGET_ID_CUSTOM_PASTE          (GADGET_ID_TOOLBOX_FIRST + 26)
347
348 #define GADGET_ID_PROPERTIES            (GADGET_ID_TOOLBOX_FIRST + 27)
349 #define GADGET_ID_ELEMENT_LEFT          (GADGET_ID_TOOLBOX_FIRST + 28)
350 #define GADGET_ID_ELEMENT_MIDDLE        (GADGET_ID_TOOLBOX_FIRST + 29)
351 #define GADGET_ID_ELEMENT_RIGHT         (GADGET_ID_TOOLBOX_FIRST + 30)
352
353
354 /* counter gadget identifiers */
355 #define GADGET_ID_COUNTER_FIRST         (GADGET_ID_TOOLBOX_FIRST + 31)
356
357 #define GADGET_ID_SELECT_LEVEL_DOWN     (GADGET_ID_COUNTER_FIRST + 0)
358 #define GADGET_ID_SELECT_LEVEL_TEXT     (GADGET_ID_COUNTER_FIRST + 1)
359 #define GADGET_ID_SELECT_LEVEL_UP       (GADGET_ID_COUNTER_FIRST + 2)
360 #define GADGET_ID_LEVEL_XSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 3)
361 #define GADGET_ID_LEVEL_XSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 4)
362 #define GADGET_ID_LEVEL_XSIZE_UP        (GADGET_ID_COUNTER_FIRST + 5)
363 #define GADGET_ID_LEVEL_YSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 6)
364 #define GADGET_ID_LEVEL_YSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 7)
365 #define GADGET_ID_LEVEL_YSIZE_UP        (GADGET_ID_COUNTER_FIRST + 8)
366 #define GADGET_ID_LEVEL_RANDOM_DOWN     (GADGET_ID_COUNTER_FIRST + 9)
367 #define GADGET_ID_LEVEL_RANDOM_TEXT     (GADGET_ID_COUNTER_FIRST + 10)
368 #define GADGET_ID_LEVEL_RANDOM_UP       (GADGET_ID_COUNTER_FIRST + 11)
369 #define GADGET_ID_LEVEL_GEMSLIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 12)
370 #define GADGET_ID_LEVEL_GEMSLIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 13)
371 #define GADGET_ID_LEVEL_GEMSLIMIT_UP    (GADGET_ID_COUNTER_FIRST + 14)
372 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 15)
373 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 16)
374 #define GADGET_ID_LEVEL_TIMELIMIT_UP    (GADGET_ID_COUNTER_FIRST + 17)
375 #define GADGET_ID_LEVEL_TIMESCORE_DOWN  (GADGET_ID_COUNTER_FIRST + 18)
376 #define GADGET_ID_LEVEL_TIMESCORE_TEXT  (GADGET_ID_COUNTER_FIRST + 19)
377 #define GADGET_ID_LEVEL_TIMESCORE_UP    (GADGET_ID_COUNTER_FIRST + 20)
378 #define GADGET_ID_LEVEL_RANDOM_SEED_DOWN (GADGET_ID_COUNTER_FIRST + 21)
379 #define GADGET_ID_LEVEL_RANDOM_SEED_TEXT (GADGET_ID_COUNTER_FIRST + 22)
380 #define GADGET_ID_LEVEL_RANDOM_SEED_UP  (GADGET_ID_COUNTER_FIRST + 23)
381 #define GADGET_ID_ELEMENT_VALUE1_DOWN   (GADGET_ID_COUNTER_FIRST + 24)
382 #define GADGET_ID_ELEMENT_VALUE1_TEXT   (GADGET_ID_COUNTER_FIRST + 25)
383 #define GADGET_ID_ELEMENT_VALUE1_UP     (GADGET_ID_COUNTER_FIRST + 26)
384 #define GADGET_ID_ELEMENT_VALUE2_DOWN   (GADGET_ID_COUNTER_FIRST + 27)
385 #define GADGET_ID_ELEMENT_VALUE2_TEXT   (GADGET_ID_COUNTER_FIRST + 28)
386 #define GADGET_ID_ELEMENT_VALUE2_UP     (GADGET_ID_COUNTER_FIRST + 29)
387 #define GADGET_ID_ELEMENT_VALUE3_DOWN   (GADGET_ID_COUNTER_FIRST + 30)
388 #define GADGET_ID_ELEMENT_VALUE3_TEXT   (GADGET_ID_COUNTER_FIRST + 31)
389 #define GADGET_ID_ELEMENT_VALUE3_UP     (GADGET_ID_COUNTER_FIRST + 32)
390 #define GADGET_ID_ELEMENT_VALUE4_DOWN   (GADGET_ID_COUNTER_FIRST + 33)
391 #define GADGET_ID_ELEMENT_VALUE4_TEXT   (GADGET_ID_COUNTER_FIRST + 34)
392 #define GADGET_ID_ELEMENT_VALUE4_UP     (GADGET_ID_COUNTER_FIRST + 35)
393 #define GADGET_ID_YAMYAM_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 36)
394 #define GADGET_ID_YAMYAM_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 37)
395 #define GADGET_ID_YAMYAM_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 38)
396 #define GADGET_ID_BALL_CONTENT_DOWN     (GADGET_ID_COUNTER_FIRST + 39)
397 #define GADGET_ID_BALL_CONTENT_TEXT     (GADGET_ID_COUNTER_FIRST + 40)
398 #define GADGET_ID_BALL_CONTENT_UP       (GADGET_ID_COUNTER_FIRST + 41)
399 #define GADGET_ID_ANDROID_CONTENT_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
400 #define GADGET_ID_ANDROID_CONTENT_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
401 #define GADGET_ID_ANDROID_CONTENT_UP    (GADGET_ID_COUNTER_FIRST + 44)
402 #define GADGET_ID_ENVELOPE_XSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 45)
403 #define GADGET_ID_ENVELOPE_XSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 46)
404 #define GADGET_ID_ENVELOPE_XSIZE_UP     (GADGET_ID_COUNTER_FIRST + 47)
405 #define GADGET_ID_ENVELOPE_YSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 48)
406 #define GADGET_ID_ENVELOPE_YSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 49)
407 #define GADGET_ID_ENVELOPE_YSIZE_UP     (GADGET_ID_COUNTER_FIRST + 50)
408 #define GADGET_ID_INVENTORY_SIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 51)
409 #define GADGET_ID_INVENTORY_SIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 52)
410 #define GADGET_ID_INVENTORY_SIZE_UP     (GADGET_ID_COUNTER_FIRST + 53)
411 #define GADGET_ID_CUSTOM_SCORE_DOWN     (GADGET_ID_COUNTER_FIRST + 54)
412 #define GADGET_ID_CUSTOM_SCORE_TEXT     (GADGET_ID_COUNTER_FIRST + 55)
413 #define GADGET_ID_CUSTOM_SCORE_UP       (GADGET_ID_COUNTER_FIRST + 56)
414 #define GADGET_ID_CUSTOM_GEMCOUNT_DOWN  (GADGET_ID_COUNTER_FIRST + 57)
415 #define GADGET_ID_CUSTOM_GEMCOUNT_TEXT  (GADGET_ID_COUNTER_FIRST + 58)
416 #define GADGET_ID_CUSTOM_GEMCOUNT_UP    (GADGET_ID_COUNTER_FIRST + 59)
417 #define GADGET_ID_CUSTOM_VALUE_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 60)
418 #define GADGET_ID_CUSTOM_VALUE_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 61)
419 #define GADGET_ID_CUSTOM_VALUE_FIX_UP   (GADGET_ID_COUNTER_FIRST + 62)
420 #define GADGET_ID_CUSTOM_VALUE_RND_DOWN (GADGET_ID_COUNTER_FIRST + 63)
421 #define GADGET_ID_CUSTOM_VALUE_RND_TEXT (GADGET_ID_COUNTER_FIRST + 64)
422 #define GADGET_ID_CUSTOM_VALUE_RND_UP   (GADGET_ID_COUNTER_FIRST + 65)
423 #define GADGET_ID_PUSH_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 66)
424 #define GADGET_ID_PUSH_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 67)
425 #define GADGET_ID_PUSH_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 68)
426 #define GADGET_ID_PUSH_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 69)
427 #define GADGET_ID_PUSH_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 70)
428 #define GADGET_ID_PUSH_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 71)
429 #define GADGET_ID_DROP_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 72)
430 #define GADGET_ID_DROP_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 73)
431 #define GADGET_ID_DROP_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 74)
432 #define GADGET_ID_DROP_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 75)
433 #define GADGET_ID_DROP_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 76)
434 #define GADGET_ID_DROP_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 77)
435 #define GADGET_ID_MOVE_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 78)
436 #define GADGET_ID_MOVE_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 79)
437 #define GADGET_ID_MOVE_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 80)
438 #define GADGET_ID_MOVE_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 81)
439 #define GADGET_ID_MOVE_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 82)
440 #define GADGET_ID_MOVE_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 83)
441 #define GADGET_ID_EXPLOSION_DELAY_DOWN  (GADGET_ID_COUNTER_FIRST + 84)
442 #define GADGET_ID_EXPLOSION_DELAY_TEXT  (GADGET_ID_COUNTER_FIRST + 85)
443 #define GADGET_ID_EXPLOSION_DELAY_UP    (GADGET_ID_COUNTER_FIRST + 86)
444 #define GADGET_ID_IGNITION_DELAY_DOWN   (GADGET_ID_COUNTER_FIRST + 87)
445 #define GADGET_ID_IGNITION_DELAY_TEXT   (GADGET_ID_COUNTER_FIRST + 88)
446 #define GADGET_ID_IGNITION_DELAY_UP     (GADGET_ID_COUNTER_FIRST + 89)
447 #define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 90)
448 #define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 91)
449 #define GADGET_ID_CHANGE_DELAY_FIX_UP   (GADGET_ID_COUNTER_FIRST + 92)
450 #define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 93)
451 #define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 94)
452 #define GADGET_ID_CHANGE_DELAY_RND_UP   (GADGET_ID_COUNTER_FIRST + 95)
453 #define GADGET_ID_CHANGE_CONT_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 96)
454 #define GADGET_ID_CHANGE_CONT_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 97)
455 #define GADGET_ID_CHANGE_CONT_RND_UP    (GADGET_ID_COUNTER_FIRST + 98)
456 #define GADGET_ID_GROUP_CONTENT_DOWN    (GADGET_ID_COUNTER_FIRST + 99)
457 #define GADGET_ID_GROUP_CONTENT_TEXT    (GADGET_ID_COUNTER_FIRST + 100)
458 #define GADGET_ID_GROUP_CONTENT_UP      (GADGET_ID_COUNTER_FIRST + 101)
459
460 /* drawing area identifiers */
461 #define GADGET_ID_DRAWING_AREA_FIRST    (GADGET_ID_COUNTER_FIRST + 102)
462
463 #define GADGET_ID_DRAWING_LEVEL         (GADGET_ID_DRAWING_AREA_FIRST + 0)
464 #define GADGET_ID_YAMYAM_CONTENT_0      (GADGET_ID_DRAWING_AREA_FIRST + 1)
465 #define GADGET_ID_YAMYAM_CONTENT_1      (GADGET_ID_DRAWING_AREA_FIRST + 2)
466 #define GADGET_ID_YAMYAM_CONTENT_2      (GADGET_ID_DRAWING_AREA_FIRST + 3)
467 #define GADGET_ID_YAMYAM_CONTENT_3      (GADGET_ID_DRAWING_AREA_FIRST + 4)
468 #define GADGET_ID_YAMYAM_CONTENT_4      (GADGET_ID_DRAWING_AREA_FIRST + 5)
469 #define GADGET_ID_YAMYAM_CONTENT_5      (GADGET_ID_DRAWING_AREA_FIRST + 6)
470 #define GADGET_ID_YAMYAM_CONTENT_6      (GADGET_ID_DRAWING_AREA_FIRST + 7)
471 #define GADGET_ID_YAMYAM_CONTENT_7      (GADGET_ID_DRAWING_AREA_FIRST + 8)
472 #define GADGET_ID_MAGIC_BALL_CONTENT_0  (GADGET_ID_DRAWING_AREA_FIRST + 9)
473 #define GADGET_ID_MAGIC_BALL_CONTENT_1  (GADGET_ID_DRAWING_AREA_FIRST + 10)
474 #define GADGET_ID_MAGIC_BALL_CONTENT_2  (GADGET_ID_DRAWING_AREA_FIRST + 11)
475 #define GADGET_ID_MAGIC_BALL_CONTENT_3  (GADGET_ID_DRAWING_AREA_FIRST + 12)
476 #define GADGET_ID_MAGIC_BALL_CONTENT_4  (GADGET_ID_DRAWING_AREA_FIRST + 13)
477 #define GADGET_ID_MAGIC_BALL_CONTENT_5  (GADGET_ID_DRAWING_AREA_FIRST + 14)
478 #define GADGET_ID_MAGIC_BALL_CONTENT_6  (GADGET_ID_DRAWING_AREA_FIRST + 15)
479 #define GADGET_ID_MAGIC_BALL_CONTENT_7  (GADGET_ID_DRAWING_AREA_FIRST + 16)
480 #define GADGET_ID_ANDROID_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 17)
481 #define GADGET_ID_AMOEBA_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 18)
482 #define GADGET_ID_START_ELEMENT         (GADGET_ID_DRAWING_AREA_FIRST + 19)
483 #define GADGET_ID_ARTWORK_ELEMENT       (GADGET_ID_DRAWING_AREA_FIRST + 20)
484 #define GADGET_ID_EXPLOSION_ELEMENT     (GADGET_ID_DRAWING_AREA_FIRST + 21)
485 #define GADGET_ID_INVENTORY_CONTENT     (GADGET_ID_DRAWING_AREA_FIRST + 22)
486 #define GADGET_ID_CUSTOM_GRAPHIC        (GADGET_ID_DRAWING_AREA_FIRST + 23)
487 #define GADGET_ID_CUSTOM_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 24)
488 #define GADGET_ID_CUSTOM_MOVE_ENTER     (GADGET_ID_DRAWING_AREA_FIRST + 25)
489 #define GADGET_ID_CUSTOM_MOVE_LEAVE     (GADGET_ID_DRAWING_AREA_FIRST + 26)
490 #define GADGET_ID_CUSTOM_CHANGE_TARGET  (GADGET_ID_DRAWING_AREA_FIRST + 27)
491 #define GADGET_ID_CUSTOM_CHANGE_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 28)
492 #define GADGET_ID_CUSTOM_CHANGE_TRIGGER (GADGET_ID_DRAWING_AREA_FIRST + 29)
493 #define GADGET_ID_CUSTOM_CHANGE_ACTION  (GADGET_ID_DRAWING_AREA_FIRST + 30)
494 #define GADGET_ID_GROUP_CONTENT         (GADGET_ID_DRAWING_AREA_FIRST + 31)
495 #define GADGET_ID_RANDOM_BACKGROUND     (GADGET_ID_DRAWING_AREA_FIRST + 32)
496
497 /* text input identifiers */
498 #define GADGET_ID_TEXT_INPUT_FIRST      (GADGET_ID_DRAWING_AREA_FIRST + 33)
499
500 #define GADGET_ID_LEVEL_NAME            (GADGET_ID_TEXT_INPUT_FIRST + 0)
501 #define GADGET_ID_LEVEL_AUTHOR          (GADGET_ID_TEXT_INPUT_FIRST + 1)
502 #define GADGET_ID_ELEMENT_NAME          (GADGET_ID_TEXT_INPUT_FIRST + 2)
503
504 /* text area identifiers */
505 #define GADGET_ID_TEXT_AREA_FIRST       (GADGET_ID_TEXT_INPUT_FIRST + 3)
506
507 #define GADGET_ID_ENVELOPE_INFO         (GADGET_ID_TEXT_AREA_FIRST + 0)
508
509 /* selectbox identifiers */
510 #define GADGET_ID_SELECTBOX_FIRST       (GADGET_ID_TEXT_AREA_FIRST + 1)
511
512 #define GADGET_ID_TIME_OR_STEPS         (GADGET_ID_SELECTBOX_FIRST + 0)
513 #define GADGET_ID_GAME_ENGINE_TYPE      (GADGET_ID_SELECTBOX_FIRST + 1)
514 #define GADGET_ID_WIND_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 2)
515 #define GADGET_ID_PLAYER_SPEED          (GADGET_ID_SELECTBOX_FIRST + 3)
516 #define GADGET_ID_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 4)
517 #define GADGET_ID_CUSTOM_EXPLOSION_TYPE (GADGET_ID_SELECTBOX_FIRST + 5)
518 #define GADGET_ID_CUSTOM_DEADLINESS     (GADGET_ID_SELECTBOX_FIRST + 6)
519 #define GADGET_ID_CUSTOM_MOVE_PATTERN   (GADGET_ID_SELECTBOX_FIRST + 7)
520 #define GADGET_ID_CUSTOM_MOVE_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 8)
521 #define GADGET_ID_CUSTOM_MOVE_STEPSIZE  (GADGET_ID_SELECTBOX_FIRST + 9)
522 #define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 10)
523 #define GADGET_ID_CUSTOM_SMASH_TARGETS  (GADGET_ID_SELECTBOX_FIRST + 11)
524 #define GADGET_ID_CUSTOM_SLIPPERY_TYPE  (GADGET_ID_SELECTBOX_FIRST + 12)
525 #define GADGET_ID_CUSTOM_ACCESS_TYPE    (GADGET_ID_SELECTBOX_FIRST + 13)
526 #define GADGET_ID_CUSTOM_ACCESS_LAYER   (GADGET_ID_SELECTBOX_FIRST + 14)
527 #define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 15)
528 #define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 16)
529 #define GADGET_ID_CHANGE_TIME_UNITS     (GADGET_ID_SELECTBOX_FIRST + 17)
530 #define GADGET_ID_CHANGE_DIRECT_ACTION  (GADGET_ID_SELECTBOX_FIRST + 18)
531 #define GADGET_ID_CHANGE_OTHER_ACTION   (GADGET_ID_SELECTBOX_FIRST + 19)
532 #define GADGET_ID_CHANGE_SIDE           (GADGET_ID_SELECTBOX_FIRST + 20)
533 #define GADGET_ID_CHANGE_PLAYER         (GADGET_ID_SELECTBOX_FIRST + 21)
534 #define GADGET_ID_CHANGE_PAGE           (GADGET_ID_SELECTBOX_FIRST + 22)
535 #define GADGET_ID_CHANGE_REPLACE_WHEN   (GADGET_ID_SELECTBOX_FIRST + 23)
536 #define GADGET_ID_ACTION_TYPE           (GADGET_ID_SELECTBOX_FIRST + 24)
537 #define GADGET_ID_ACTION_MODE           (GADGET_ID_SELECTBOX_FIRST + 25)
538 #define GADGET_ID_ACTION_ARG            (GADGET_ID_SELECTBOX_FIRST + 26)
539 #define GADGET_ID_SELECT_CHANGE_PAGE    (GADGET_ID_SELECTBOX_FIRST + 27)
540 #define GADGET_ID_GROUP_CHOICE_MODE     (GADGET_ID_SELECTBOX_FIRST + 28)
541
542 /* textbutton identifiers */
543 #define GADGET_ID_TEXTBUTTON_FIRST      (GADGET_ID_SELECTBOX_FIRST + 29)
544
545 #define GADGET_ID_LEVELINFO_LEVEL       (GADGET_ID_TEXTBUTTON_FIRST + 0)
546 #define GADGET_ID_LEVELINFO_EDITOR      (GADGET_ID_TEXTBUTTON_FIRST + 1)
547 #define GADGET_ID_PROPERTIES_INFO       (GADGET_ID_TEXTBUTTON_FIRST + 2)
548 #define GADGET_ID_PROPERTIES_CONFIG     (GADGET_ID_TEXTBUTTON_FIRST + 3)
549 #define GADGET_ID_PROPERTIES_CONFIG_1   (GADGET_ID_TEXTBUTTON_FIRST + 4)
550 #define GADGET_ID_PROPERTIES_CONFIG_2   (GADGET_ID_TEXTBUTTON_FIRST + 5)
551 #define GADGET_ID_PROPERTIES_CHANGE     (GADGET_ID_TEXTBUTTON_FIRST + 6)
552 #define GADGET_ID_SAVE_AS_TEMPLATE      (GADGET_ID_TEXTBUTTON_FIRST + 7)
553 #define GADGET_ID_ADD_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 8)
554 #define GADGET_ID_DEL_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 9)
555
556 /* graphicbutton identifiers */
557 #define GADGET_ID_GRAPHICBUTTON_FIRST   (GADGET_ID_TEXTBUTTON_FIRST + 10)
558
559 #define GADGET_ID_PREV_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 0)
560 #define GADGET_ID_NEXT_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 1)
561 #define GADGET_ID_COPY_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 2)
562 #define GADGET_ID_PASTE_CHANGE_PAGE     (GADGET_ID_GRAPHICBUTTON_FIRST + 3)
563
564 /* gadgets for scrolling of drawing area */
565 #define GADGET_ID_SCROLLING_FIRST       (GADGET_ID_GRAPHICBUTTON_FIRST + 4)
566
567 #define GADGET_ID_SCROLL_UP             (GADGET_ID_SCROLLING_FIRST + 0)
568 #define GADGET_ID_SCROLL_DOWN           (GADGET_ID_SCROLLING_FIRST + 1)
569 #define GADGET_ID_SCROLL_LEFT           (GADGET_ID_SCROLLING_FIRST + 2)
570 #define GADGET_ID_SCROLL_RIGHT          (GADGET_ID_SCROLLING_FIRST + 3)
571 #define GADGET_ID_SCROLL_HORIZONTAL     (GADGET_ID_SCROLLING_FIRST + 4)
572 #define GADGET_ID_SCROLL_VERTICAL       (GADGET_ID_SCROLLING_FIRST + 5)
573
574 /* gadgets for scrolling element list */
575 #define GADGET_ID_SCROLLING_LIST_FIRST  (GADGET_ID_SCROLLING_FIRST + 6)
576
577 #define GADGET_ID_SCROLL_LIST_UP        (GADGET_ID_SCROLLING_LIST_FIRST + 0)
578 #define GADGET_ID_SCROLL_LIST_DOWN      (GADGET_ID_SCROLLING_LIST_FIRST + 1)
579 #define GADGET_ID_SCROLL_LIST_VERTICAL  (GADGET_ID_SCROLLING_LIST_FIRST + 2)
580
581 /* checkbuttons/radiobuttons for level/element properties */
582 #define GADGET_ID_CHECKBUTTON_FIRST     (GADGET_ID_SCROLLING_LIST_FIRST + 3)
583
584 #define GADGET_ID_RANDOM_PERCENTAGE     (GADGET_ID_CHECKBUTTON_FIRST + 0)
585 #define GADGET_ID_RANDOM_QUANTITY       (GADGET_ID_CHECKBUTTON_FIRST + 1)
586 #define GADGET_ID_RANDOM_RESTRICTED     (GADGET_ID_CHECKBUTTON_FIRST + 2)
587 #define GADGET_ID_STICK_ELEMENT         (GADGET_ID_CHECKBUTTON_FIRST + 3)
588 #define GADGET_ID_EM_SLIPPERY_GEMS      (GADGET_ID_CHECKBUTTON_FIRST + 4)
589 #define GADGET_ID_EM_EXPLODES_BY_FIRE   (GADGET_ID_CHECKBUTTON_FIRST + 5)
590 #define GADGET_ID_USE_SPRING_BUG        (GADGET_ID_CHECKBUTTON_FIRST + 6)
591 #define GADGET_ID_USE_TIME_ORB_BUG      (GADGET_ID_CHECKBUTTON_FIRST + 7)
592 #define GADGET_ID_RANDOM_BALL_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 8)
593 #define GADGET_ID_INITIAL_BALL_STATE    (GADGET_ID_CHECKBUTTON_FIRST + 9)
594 #define GADGET_ID_GROW_INTO_DIGGABLE    (GADGET_ID_CHECKBUTTON_FIRST + 10)
595 #define GADGET_ID_AUTO_EXIT_SOKOBAN     (GADGET_ID_CHECKBUTTON_FIRST + 11)
596 #define GADGET_ID_CONTINUOUS_SNAPPING   (GADGET_ID_CHECKBUTTON_FIRST + 12)
597 #define GADGET_ID_BLOCK_SNAP_FIELD      (GADGET_ID_CHECKBUTTON_FIRST + 13)
598 #define GADGET_ID_BLOCK_LAST_FIELD      (GADGET_ID_CHECKBUTTON_FIRST + 14)
599 #define GADGET_ID_SP_BLOCK_LAST_FIELD   (GADGET_ID_CHECKBUTTON_FIRST + 15)
600 #define GADGET_ID_INSTANT_RELOCATION    (GADGET_ID_CHECKBUTTON_FIRST + 16)
601 #define GADGET_ID_SHIFTED_RELOCATION    (GADGET_ID_CHECKBUTTON_FIRST + 17)
602 #define GADGET_ID_LAZY_RELOCATION       (GADGET_ID_CHECKBUTTON_FIRST + 18)
603 #define GADGET_ID_USE_START_ELEMENT     (GADGET_ID_CHECKBUTTON_FIRST + 19)
604 #define GADGET_ID_USE_ARTWORK_ELEMENT   (GADGET_ID_CHECKBUTTON_FIRST + 20)
605 #define GADGET_ID_USE_EXPLOSION_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 21)
606 #define GADGET_ID_INITIAL_GRAVITY       (GADGET_ID_CHECKBUTTON_FIRST + 22)
607 #define GADGET_ID_USE_INITIAL_INVENTORY (GADGET_ID_CHECKBUTTON_FIRST + 23)
608 #define GADGET_ID_CAN_PASS_TO_WALKABLE  (GADGET_ID_CHECKBUTTON_FIRST + 24)
609 #define GADGET_ID_CAN_FALL_INTO_ACID    (GADGET_ID_CHECKBUTTON_FIRST + 25)
610 #define GADGET_ID_CAN_MOVE_INTO_ACID    (GADGET_ID_CHECKBUTTON_FIRST + 26)
611 #define GADGET_ID_DONT_COLLIDE_WITH     (GADGET_ID_CHECKBUTTON_FIRST + 27)
612 #define GADGET_ID_ENVELOPE_AUTOWRAP     (GADGET_ID_CHECKBUTTON_FIRST + 28)
613 #define GADGET_ID_ENVELOPE_CENTERED     (GADGET_ID_CHECKBUTTON_FIRST + 29)
614 #define GADGET_ID_CUSTOM_INDESTRUCTIBLE (GADGET_ID_CHECKBUTTON_FIRST + 30)
615 #define GADGET_ID_CUSTOM_CAN_EXPLODE    (GADGET_ID_CHECKBUTTON_FIRST + 31)
616 #define GADGET_ID_CUSTOM_EXPLODE_FIRE   (GADGET_ID_CHECKBUTTON_FIRST + 32)
617 #define GADGET_ID_CUSTOM_EXPLODE_SMASH  (GADGET_ID_CHECKBUTTON_FIRST + 33)
618 #define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 34)
619 #define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 35)
620 #define GADGET_ID_CUSTOM_DEADLY         (GADGET_ID_CHECKBUTTON_FIRST + 36)
621 #define GADGET_ID_CUSTOM_CAN_MOVE       (GADGET_ID_CHECKBUTTON_FIRST + 37)
622 #define GADGET_ID_CUSTOM_CAN_FALL       (GADGET_ID_CHECKBUTTON_FIRST + 38)
623 #define GADGET_ID_CUSTOM_CAN_SMASH      (GADGET_ID_CHECKBUTTON_FIRST + 39)
624 #define GADGET_ID_CUSTOM_SLIPPERY       (GADGET_ID_CHECKBUTTON_FIRST + 40)
625 #define GADGET_ID_CUSTOM_ACCESSIBLE     (GADGET_ID_CHECKBUTTON_FIRST + 41)
626 #define GADGET_ID_CUSTOM_GRAV_REACHABLE (GADGET_ID_CHECKBUTTON_FIRST + 42)
627 #define GADGET_ID_CUSTOM_USE_LAST_VALUE (GADGET_ID_CHECKBUTTON_FIRST + 43)
628 #define GADGET_ID_CUSTOM_USE_GRAPHIC    (GADGET_ID_CHECKBUTTON_FIRST + 44)
629 #define GADGET_ID_CUSTOM_USE_TEMPLATE   (GADGET_ID_CHECKBUTTON_FIRST + 45)
630 #define GADGET_ID_CUSTOM_CAN_CHANGE     (GADGET_ID_CHECKBUTTON_FIRST + 46)
631 #define GADGET_ID_CHANGE_USE_CONTENT    (GADGET_ID_CHECKBUTTON_FIRST + 47)
632 #define GADGET_ID_CHANGE_USE_EXPLOSION  (GADGET_ID_CHECKBUTTON_FIRST + 48)
633 #define GADGET_ID_CHANGE_ONLY_COMPLETE  (GADGET_ID_CHECKBUTTON_FIRST + 49)
634 #define GADGET_ID_CHANGE_USE_RANDOM     (GADGET_ID_CHECKBUTTON_FIRST + 50)
635 #define GADGET_ID_CHANGE_HAS_ACTION     (GADGET_ID_CHECKBUTTON_FIRST + 51)
636 #define GADGET_ID_CHANGE_DELAY          (GADGET_ID_CHECKBUTTON_FIRST + 52)
637 #define GADGET_ID_CHANGE_BY_DIRECT_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 53)
638 #define GADGET_ID_CHANGE_BY_OTHER_ACT   (GADGET_ID_CHECKBUTTON_FIRST + 54)
639
640 /* gadgets for buttons in element list */
641 #define GADGET_ID_ELEMENTLIST_FIRST     (GADGET_ID_CHECKBUTTON_FIRST + 55)
642 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
643                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
644
645 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
646
647 /* radio button numbers */
648 #define RADIO_NR_NONE                   0
649 #define RADIO_NR_DRAWING_TOOLBOX        1
650 #define RADIO_NR_RANDOM_ELEMENTS        2
651
652 /* values for counter gadgets */
653 #define ED_COUNTER_ID_SELECT_LEVEL      0
654 #define ED_COUNTER_ID_LEVEL_XSIZE       1
655 #define ED_COUNTER_ID_LEVEL_YSIZE       2
656 #define ED_COUNTER_ID_LEVEL_GEMSLIMIT   3
657 #define ED_COUNTER_ID_LEVEL_TIMELIMIT   4
658 #define ED_COUNTER_ID_LEVEL_TIMESCORE   5
659 #define ED_COUNTER_ID_LEVEL_RANDOM_SEED 6
660 #define ED_COUNTER_ID_LEVEL_RANDOM      7
661 #define ED_COUNTER_ID_ELEMENT_VALUE1    8
662 #define ED_COUNTER_ID_ELEMENT_VALUE2    9
663 #define ED_COUNTER_ID_ELEMENT_VALUE3    10
664 #define ED_COUNTER_ID_ELEMENT_VALUE4    11
665 #define ED_COUNTER_ID_YAMYAM_CONTENT    12
666 #define ED_COUNTER_ID_BALL_CONTENT      13
667 #define ED_COUNTER_ID_ANDROID_CONTENT   14
668 #define ED_COUNTER_ID_ENVELOPE_XSIZE    15
669 #define ED_COUNTER_ID_ENVELOPE_YSIZE    16
670 #define ED_COUNTER_ID_INVENTORY_SIZE    17
671 #define ED_COUNTER_ID_CUSTOM_SCORE      18
672 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT   19
673 #define ED_COUNTER_ID_CUSTOM_VALUE_FIX  20
674 #define ED_COUNTER_ID_CUSTOM_VALUE_RND  21
675 #define ED_COUNTER_ID_PUSH_DELAY_FIX    22
676 #define ED_COUNTER_ID_PUSH_DELAY_RND    23
677 #define ED_COUNTER_ID_DROP_DELAY_FIX    24
678 #define ED_COUNTER_ID_DROP_DELAY_RND    25
679 #define ED_COUNTER_ID_MOVE_DELAY_FIX    26
680 #define ED_COUNTER_ID_MOVE_DELAY_RND    27
681 #define ED_COUNTER_ID_EXPLOSION_DELAY   28
682 #define ED_COUNTER_ID_IGNITION_DELAY    29
683 #define ED_COUNTER_ID_GROUP_CONTENT     30
684 #define ED_COUNTER_ID_CHANGE_DELAY_FIX  31
685 #define ED_COUNTER_ID_CHANGE_DELAY_RND  32
686 #define ED_COUNTER_ID_CHANGE_CONT_RND   33
687
688 #define ED_NUM_COUNTERBUTTONS           34
689
690 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
691 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM_SEED
692 #define ED_COUNTER_ID_EDITOR_FIRST      ED_COUNTER_ID_LEVEL_RANDOM
693 #define ED_COUNTER_ID_EDITOR_LAST       ED_COUNTER_ID_LEVEL_RANDOM
694
695 #define ED_COUNTER_ID_CUSTOM1_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
696 #define ED_COUNTER_ID_CUSTOM1_LAST      ED_COUNTER_ID_DROP_DELAY_RND
697 #define ED_COUNTER_ID_CUSTOM2_FIRST     ED_COUNTER_ID_MOVE_DELAY_FIX
698 #define ED_COUNTER_ID_CUSTOM2_LAST      ED_COUNTER_ID_IGNITION_DELAY
699 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM1_FIRST
700 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_CUSTOM2_LAST
701
702 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
703 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
704
705 /* values for scrollbutton gadgets */
706 #define ED_SCROLLBUTTON_ID_AREA_UP      0
707 #define ED_SCROLLBUTTON_ID_AREA_DOWN    1
708 #define ED_SCROLLBUTTON_ID_AREA_LEFT    2
709 #define ED_SCROLLBUTTON_ID_AREA_RIGHT   3
710 #define ED_SCROLLBUTTON_ID_LIST_UP      4
711 #define ED_SCROLLBUTTON_ID_LIST_DOWN    5
712
713 #define ED_NUM_SCROLLBUTTONS            6
714
715 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
716 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
717
718 /* values for scrollbar gadgets */
719 #define ED_SCROLLBAR_ID_AREA_HORIZONTAL 0
720 #define ED_SCROLLBAR_ID_AREA_VERTICAL   1
721 #define ED_SCROLLBAR_ID_LIST_VERTICAL   2
722
723 #define ED_NUM_SCROLLBARS               3
724
725 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
726 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
727
728 /* values for text input gadgets */
729 #define ED_TEXTINPUT_ID_LEVEL_NAME      0
730 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR    1
731 #define ED_TEXTINPUT_ID_ELEMENT_NAME    2
732
733 #define ED_NUM_TEXTINPUT                3
734
735 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
736 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
737
738 /* values for text area gadgets */
739 #define ED_TEXTAREA_ID_ENVELOPE_INFO    0
740
741 #define ED_NUM_TEXTAREAS                        1
742
743 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
744 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
745
746 /* values for selectbox gadgets */
747 #define ED_SELECTBOX_ID_TIME_OR_STEPS           0
748 #define ED_SELECTBOX_ID_GAME_ENGINE_TYPE        1
749 #define ED_SELECTBOX_ID_WIND_DIRECTION          2
750 #define ED_SELECTBOX_ID_PLAYER_SPEED            3
751 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE      4
752 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER     5
753 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED 6
754 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION 7
755 #define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION   8
756 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN     9
757 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION   10      
758 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE    11
759 #define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE  12
760 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS    13
761 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE    14
762 #define ED_SELECTBOX_ID_CUSTOM_DEADLINESS       15
763 #define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE   16
764 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS       17
765 #define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION    18
766 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION     19
767 #define ED_SELECTBOX_ID_CHANGE_SIDE             20
768 #define ED_SELECTBOX_ID_CHANGE_PLAYER           21
769 #define ED_SELECTBOX_ID_CHANGE_PAGE             22
770 #define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN     23
771 #define ED_SELECTBOX_ID_ACTION_TYPE             24
772 #define ED_SELECTBOX_ID_ACTION_MODE             25
773 #define ED_SELECTBOX_ID_ACTION_ARG              26
774 #define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE      27
775 #define ED_SELECTBOX_ID_GROUP_CHOICE_MODE       28
776
777 #define ED_NUM_SELECTBOX                        29
778
779 #define ED_SELECTBOX_ID_LEVEL_FIRST     ED_SELECTBOX_ID_TIME_OR_STEPS
780 #define ED_SELECTBOX_ID_LEVEL_LAST      ED_SELECTBOX_ID_WIND_DIRECTION
781
782 #define ED_SELECTBOX_ID_CUSTOM1_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
783 #define ED_SELECTBOX_ID_CUSTOM1_LAST    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
784 #define ED_SELECTBOX_ID_CUSTOM2_FIRST   ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
785 #define ED_SELECTBOX_ID_CUSTOM2_LAST    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
786 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM1_FIRST
787 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM2_LAST
788
789 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
790 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
791
792 /* values for textbutton gadgets */
793 #define ED_TEXTBUTTON_ID_LEVELINFO_LEVEL        0
794 #define ED_TEXTBUTTON_ID_LEVELINFO_EDITOR       1
795 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO        2
796 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG      3
797 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1    4
798 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2    5
799 #define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE      6
800 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE       7
801 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE        8
802 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE        9
803
804 #define ED_NUM_TEXTBUTTONS                      10
805
806 #define ED_TEXTBUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
807 #define ED_TEXTBUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
808
809 #define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
810 #define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
811
812 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
813 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
814
815 /* values for graphicbutton gadgets */
816 #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE    0
817 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE    1
818 #define ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE    2
819 #define ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE   3
820
821 #define ED_NUM_GRAPHICBUTTONS                   4
822
823 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
824 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
825
826 /* values for checkbutton gadgets */
827 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED     0
828 #define ED_CHECKBUTTON_ID_STICK_ELEMENT         1
829 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS      2
830 #define ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE   3
831 #define ED_CHECKBUTTON_ID_USE_SPRING_BUG        4
832 #define ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG      5
833 #define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT   6
834 #define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE    7
835 #define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE    8
836 #define ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN     9
837 #define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING   10
838 #define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD      11
839 #define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD      12
840 #define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD   13
841 #define ED_CHECKBUTTON_ID_INSTANT_RELOCATION    14
842 #define ED_CHECKBUTTON_ID_SHIFTED_RELOCATION    15
843 #define ED_CHECKBUTTON_ID_LAZY_RELOCATION       16
844 #define ED_CHECKBUTTON_ID_USE_START_ELEMENT     17
845 #define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT   18
846 #define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT 19
847 #define ED_CHECKBUTTON_ID_INITIAL_GRAVITY       20
848 #define ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY 21
849 #define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE  22
850 #define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID    23
851 #define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID    24
852 #define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH     25
853 #define ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP     26
854 #define ED_CHECKBUTTON_ID_ENVELOPE_CENTERED     27
855 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC    28
856 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE   29
857 #define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE     30
858 #define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE 31
859 #define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE 32
860 #define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 33
861 #define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE 34
862 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE       35
863 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL       36
864 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH      37
865 #define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY       38
866 #define ED_CHECKBUTTON_ID_CUSTOM_DEADLY         39
867 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE    40
868 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE   41
869 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH  42
870 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 43
871 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE     44
872 #define ED_CHECKBUTTON_ID_CHANGE_DELAY          45
873 #define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT  46
874 #define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT   47
875 #define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION  48
876 #define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT    49
877 #define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE  50
878 #define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM     51
879 #define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION     52
880
881 #define ED_NUM_CHECKBUTTONS                     53
882
883 #define ED_CHECKBUTTON_ID_EDITOR_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
884 #define ED_CHECKBUTTON_ID_EDITOR_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
885
886 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
887 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST  ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
888 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
889 #define ED_CHECKBUTTON_ID_CUSTOM2_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
890 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM1_FIRST
891 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM2_LAST
892
893 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
894 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
895
896 /* values for radiobutton gadgets */
897 #define ED_RADIOBUTTON_ID_PERCENTAGE    0
898 #define ED_RADIOBUTTON_ID_QUANTITY      1
899
900 #define ED_NUM_RADIOBUTTONS             2
901
902 #define ED_RADIOBUTTON_ID_EDITOR_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
903 #define ED_RADIOBUTTON_ID_EDITOR_LAST   ED_RADIOBUTTON_ID_QUANTITY
904
905 /* values for drawing area gadgets */
906 #define ED_DRAWING_ID_DRAWING_LEVEL             0
907 #define ED_DRAWING_ID_YAMYAM_CONTENT_0          1
908 #define ED_DRAWING_ID_YAMYAM_CONTENT_1          2
909 #define ED_DRAWING_ID_YAMYAM_CONTENT_2          3
910 #define ED_DRAWING_ID_YAMYAM_CONTENT_3          4
911 #define ED_DRAWING_ID_YAMYAM_CONTENT_4          5
912 #define ED_DRAWING_ID_YAMYAM_CONTENT_5          6
913 #define ED_DRAWING_ID_YAMYAM_CONTENT_6          7
914 #define ED_DRAWING_ID_YAMYAM_CONTENT_7          8
915 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_0      9
916 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_1      10
917 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_2      11
918 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_3      12
919 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_4      13
920 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_5      14
921 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_6      15
922 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_7      16
923 #define ED_DRAWING_ID_ANDROID_CONTENT           17
924 #define ED_DRAWING_ID_AMOEBA_CONTENT            18
925 #define ED_DRAWING_ID_START_ELEMENT             19
926 #define ED_DRAWING_ID_ARTWORK_ELEMENT           20
927 #define ED_DRAWING_ID_EXPLOSION_ELEMENT         21
928 #define ED_DRAWING_ID_INVENTORY_CONTENT         22
929 #define ED_DRAWING_ID_CUSTOM_GRAPHIC            23
930 #define ED_DRAWING_ID_CUSTOM_CONTENT            24
931 #define ED_DRAWING_ID_CUSTOM_MOVE_ENTER         25
932 #define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE         26
933 #define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET      27
934 #define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT     28
935 #define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER     29
936 #define ED_DRAWING_ID_CUSTOM_CHANGE_ACTION      30
937 #define ED_DRAWING_ID_GROUP_CONTENT             31
938 #define ED_DRAWING_ID_RANDOM_BACKGROUND         32
939
940 #define ED_NUM_DRAWING_AREAS                    33
941
942
943 /*
944   -----------------------------------------------------------------------------
945   some internally used definitions
946   -----------------------------------------------------------------------------
947 */
948
949 /* values for CopyLevelToUndoBuffer() */
950 #define UNDO_IMMEDIATE                  0
951 #define UNDO_ACCUMULATE                 1
952
953 /* values for scrollbars */
954 #define ED_SCROLL_NO                    0
955 #define ED_SCROLL_LEFT                  1
956 #define ED_SCROLL_RIGHT                 2
957 #define ED_SCROLL_UP                    4
958 #define ED_SCROLL_DOWN                  8
959
960 /* screens in the level editor */
961 #define ED_MODE_DRAWING                 0
962 #define ED_MODE_INFO                    1
963 #define ED_MODE_PROPERTIES              2
964
965 /* sub-screens in the global settings section */
966 #define ED_MODE_LEVELINFO_LEVEL         ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
967 #define ED_MODE_LEVELINFO_EDITOR        ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
968
969 /* sub-screens in the element properties section */
970 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
971 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
972 #define ED_MODE_PROPERTIES_CONFIG_1     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
973 #define ED_MODE_PROPERTIES_CONFIG_2     ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
974 #define ED_MODE_PROPERTIES_CHANGE       ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
975
976 /* how many steps can be cancelled */
977 #define NUM_UNDO_STEPS                  (64 + 1)
978
979 /* values for elements with score for certain actions */
980 #define MIN_SCORE                       0
981 #define MAX_SCORE                       999
982
983 /* values for elements with count for collecting */
984 #define MIN_COLLECT_COUNT               0
985 #define MAX_COLLECT_COUNT               999
986
987 /* values for random placement */
988 #define RANDOM_USE_PERCENTAGE           0
989 #define RANDOM_USE_QUANTITY             1
990
991 /* default value for element tile size in drawing area */
992 #define DEFAULT_EDITOR_TILESIZE         MINI_TILESIZE
993
994
995 /*
996   -----------------------------------------------------------------------------
997   some internally used data structure definitions
998   -----------------------------------------------------------------------------
999 */
1000
1001 static struct
1002 {
1003   int graphic;
1004   int gadget_id;
1005   struct XYTileSize *pos;
1006   int gadget_type;
1007   char *infotext;
1008   char shortcut;
1009 } controlbutton_info[ED_NUM_CTRL_BUTTONS] =
1010 {
1011   /* note: some additional characters are already reserved for "cheat mode"
1012      shortcuts (":XYZ" style) -- for details, see "events.c" */
1013
1014   /* ---------- toolbox control buttons ------------------------------------ */
1015
1016   {
1017     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,          GADGET_ID_SINGLE_ITEMS,
1018     &editor.button.draw_single,                 GD_TYPE_RADIO_BUTTON,
1019     "draw single items",                        's'
1020   },
1021   {
1022     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,       GADGET_ID_CONNECTED_ITEMS,
1023     &editor.button.draw_connected,              GD_TYPE_RADIO_BUTTON,
1024     "draw connected items",                     'd'
1025   },
1026   {
1027     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,            GADGET_ID_LINE,
1028     &editor.button.draw_line,                   GD_TYPE_RADIO_BUTTON,
1029     "draw lines",                               'l'
1030   },
1031   {
1032     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,             GADGET_ID_ARC,
1033     &editor.button.draw_arc,                    GD_TYPE_RADIO_BUTTON,
1034     "draw arcs",                                'a'
1035   },
1036   {
1037     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,       GADGET_ID_RECTANGLE,
1038     &editor.button.draw_rectangle,              GD_TYPE_RADIO_BUTTON,
1039     "draw outline rectangles",                  'r'
1040   },
1041   {
1042     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,      GADGET_ID_FILLED_BOX,
1043     &editor.button.draw_filled_box,             GD_TYPE_RADIO_BUTTON,
1044     "draw filled rectangles",                   'R'
1045   },
1046   {
1047     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,            GADGET_ID_WRAP_UP,
1048     &editor.button.rotate_up,                   GD_TYPE_NORMAL_BUTTON,
1049     "wrap (rotate) level up",                   0
1050   },
1051   {
1052     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,            GADGET_ID_TEXT,
1053     &editor.button.draw_text,                   GD_TYPE_RADIO_BUTTON,
1054     "enter text elements",                      't'
1055   },
1056   {
1057     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,           GADGET_ID_FLOOD_FILL,
1058     &editor.button.flood_fill,                  GD_TYPE_RADIO_BUTTON,
1059     "flood fill",                               'f'
1060   },
1061   {
1062     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,          GADGET_ID_WRAP_LEFT,
1063     &editor.button.rotate_left,                 GD_TYPE_NORMAL_BUTTON,
1064     "wrap (rotate) level left",                 0
1065   },
1066   {
1067     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,           GADGET_ID_ZOOM,
1068     &editor.button.zoom_level,                  GD_TYPE_NORMAL_BUTTON,
1069     "zoom level tile size",                     '+'
1070   },
1071   {
1072     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,         GADGET_ID_WRAP_RIGHT,
1073     &editor.button.rotate_right,                GD_TYPE_NORMAL_BUTTON,
1074     "wrap (rotate) level right",                0
1075   },
1076   {
1077     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,          GADGET_ID_RANDOM_PLACEMENT,
1078     &editor.button.draw_random,                 GD_TYPE_NORMAL_BUTTON,
1079     "random element placement",                 0
1080   },
1081   {
1082     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,           GADGET_ID_GRAB_BRUSH,
1083     &editor.button.grab_brush,                  GD_TYPE_RADIO_BUTTON,
1084     "grab brush",                               'b'
1085   },
1086   {
1087     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,          GADGET_ID_WRAP_DOWN,
1088     &editor.button.rotate_down,                 GD_TYPE_NORMAL_BUTTON,
1089     "wrap (rotate) level down",                 0
1090   },
1091   {
1092     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,         GADGET_ID_PICK_ELEMENT,
1093     &editor.button.pick_element,                GD_TYPE_RADIO_BUTTON,
1094     "pick drawing element",                     ','
1095   },
1096
1097   /* ---------- level control buttons -------------------------------------- */
1098
1099   {
1100     IMG_GFX_EDITOR_BUTTON_UNDO,                 GADGET_ID_UNDO,
1101     &editor.button.undo,                        GD_TYPE_NORMAL_BUTTON,
1102     "undo/redo last operation",                 'u'
1103   },
1104   {
1105     IMG_GFX_EDITOR_BUTTON_CONF,                 GADGET_ID_INFO,
1106     &editor.button.conf,                        GD_TYPE_NORMAL_BUTTON,
1107     "properties of level",                      'I'
1108   },
1109   {
1110     IMG_GFX_EDITOR_BUTTON_SAVE,                 GADGET_ID_SAVE,
1111     &editor.button.save,                        GD_TYPE_NORMAL_BUTTON,
1112     "save level",                               'S'
1113   },
1114   {
1115     IMG_GFX_EDITOR_BUTTON_CLEAR,                GADGET_ID_CLEAR,
1116     &editor.button.clear,                       GD_TYPE_NORMAL_BUTTON,
1117     "clear level",                              'C'
1118   },
1119   {
1120     IMG_GFX_EDITOR_BUTTON_TEST,                 GADGET_ID_TEST,
1121     &editor.button.test,                        GD_TYPE_NORMAL_BUTTON,
1122     "test level",                               'T'
1123   },
1124   {
1125     IMG_GFX_EDITOR_BUTTON_EXIT,                 GADGET_ID_EXIT,
1126     &editor.button.exit,                        GD_TYPE_NORMAL_BUTTON,
1127     "exit level editor",                        'E'
1128   },
1129
1130   /* ---------- CE and GE control buttons ---------------------------------- */
1131
1132   {
1133     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,         GADGET_ID_CUSTOM_COPY_FROM,
1134     &editor.button.ce_copy_from,                GD_TYPE_RADIO_BUTTON,
1135     "copy settings from other element",         0
1136   },
1137   {
1138     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,           GADGET_ID_CUSTOM_COPY_TO,
1139     &editor.button.ce_copy_to,                  GD_TYPE_RADIO_BUTTON,
1140     "copy settings to other element",           0
1141   },
1142   {
1143     IMG_GFX_EDITOR_BUTTON_CE_SWAP,              GADGET_ID_CUSTOM_EXCHANGE,
1144     &editor.button.ce_swap,                     GD_TYPE_RADIO_BUTTON,
1145     "exchange element with other element",      0
1146   },
1147   {
1148     IMG_GFX_EDITOR_BUTTON_CE_COPY,              GADGET_ID_CUSTOM_COPY,
1149     &editor.button.ce_copy,                     GD_TYPE_NORMAL_BUTTON,
1150     "copy settings from this element",          0
1151   },
1152   {
1153     IMG_GFX_EDITOR_BUTTON_CE_PASTE,             GADGET_ID_CUSTOM_PASTE,
1154     &editor.button.ce_paste,                    GD_TYPE_NORMAL_BUTTON,
1155     "paste settings to this element",           0
1156   },
1157
1158   /* ---------- palette control buttons ------------------------------------ */
1159
1160   {
1161     IMG_GFX_EDITOR_BUTTON_PROPERTIES,           GADGET_ID_PROPERTIES,
1162     &editor.button.properties,                  GD_TYPE_NORMAL_BUTTON,
1163     "properties of drawing element",            'p'
1164   },
1165   {
1166     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,         GADGET_ID_ELEMENT_LEFT,
1167     &editor.button.element_left,                GD_TYPE_NORMAL_BUTTON,
1168     "properties of drawing element 1",          '1'
1169   },
1170   {
1171     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,       GADGET_ID_ELEMENT_MIDDLE,
1172     &editor.button.element_middle,              GD_TYPE_NORMAL_BUTTON,
1173     "properties of drawing element 2",          '2'
1174   },
1175   {
1176     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,        GADGET_ID_ELEMENT_RIGHT,
1177     &editor.button.element_right,               GD_TYPE_NORMAL_BUTTON,
1178     "properties of drawing element 3",          '3'
1179   }
1180 };
1181
1182 static int random_placement_value = 10;
1183 static int random_placement_method = RANDOM_USE_QUANTITY;
1184 static int random_placement_background_element = EL_SAND;
1185 static boolean random_placement_background_restricted = FALSE;
1186 static boolean stick_element_properties_window = FALSE;
1187 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
1188 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
1189 static struct ElementChangeInfo custom_element_change;
1190 static struct ElementGroupInfo group_element_info;
1191 static struct ElementInfo custom_element;
1192
1193 static struct
1194 {
1195   int x, y;
1196   int min_value, max_value;
1197   int gadget_id_down, gadget_id_up;
1198   int gadget_id_text;
1199   int gadget_id_align;
1200   int *value;
1201   char *text_above, *text_left, *text_right;
1202 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
1203 {
1204   /* ---------- current level number --------------------------------------- */
1205
1206   {
1207     -1, -1,     /* these values are not constant, but can change at runtime */
1208     1,                                  100,
1209     GADGET_ID_SELECT_LEVEL_DOWN,        GADGET_ID_SELECT_LEVEL_UP,
1210     GADGET_ID_SELECT_LEVEL_TEXT,        GADGET_ID_NONE,
1211     &level_nr,
1212     NULL,                               NULL, NULL
1213   },
1214
1215   /* ---------- level and editor settings ---------------------------------- */
1216
1217   {
1218     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(4),
1219     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
1220     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
1221     GADGET_ID_LEVEL_XSIZE_TEXT,         GADGET_ID_NONE,
1222     &level.fieldx,
1223     "playfield size:",                  NULL, "width",
1224   },
1225   {
1226     -1,                                 ED_LEVEL_SETTINGS_YPOS(4),
1227     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
1228     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
1229     GADGET_ID_LEVEL_YSIZE_TEXT,         GADGET_ID_LEVEL_XSIZE_UP,
1230     &level.fieldy,
1231     NULL,                               " ", "height",
1232   },
1233   {
1234     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(5),
1235     0,                                  999,
1236     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,     GADGET_ID_LEVEL_GEMSLIMIT_UP,
1237     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,     GADGET_ID_NONE,
1238     &level.gems_needed,
1239     NULL,                               "number of gems to collect:", NULL
1240   },
1241   {
1242     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(7),
1243     0,                                  9999,
1244     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
1245     GADGET_ID_LEVEL_TIMELIMIT_TEXT,     GADGET_ID_NONE,
1246     &level.time,
1247     "time or step limit to solve level:", NULL, NULL
1248   },
1249   {
1250     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(9),
1251     0,                                  999,
1252     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
1253     GADGET_ID_LEVEL_TIMESCORE_TEXT,     GADGET_ID_NONE,
1254     &level.score[SC_TIME_BONUS],
1255     "score for each second/step left:", NULL, NULL
1256   },
1257   {
1258     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(12),
1259     0,                                  9999,
1260     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,   GADGET_ID_LEVEL_RANDOM_SEED_UP,
1261     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,   GADGET_ID_NONE,
1262     &level.random_seed,
1263     NULL,                               "random seed:", "(0 => random)"
1264   },
1265   {
1266     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1267     1,                                  100,
1268     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
1269     GADGET_ID_LEVEL_RANDOM_TEXT,        GADGET_ID_NONE,
1270     &random_placement_value,
1271     "random element placement:",        NULL, "in"
1272   },
1273
1274   /* ---------- element settings: configure (various elements) ------------- */
1275
1276   {
1277     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1278     MIN_SCORE,                          MAX_SCORE,
1279     GADGET_ID_ELEMENT_VALUE1_DOWN,      GADGET_ID_ELEMENT_VALUE1_UP,
1280     GADGET_ID_ELEMENT_VALUE1_TEXT,      GADGET_ID_NONE,
1281     NULL,                               /* will be set when used */
1282     NULL,                               NULL, NULL
1283   },
1284   {
1285     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
1286     MIN_SCORE,                          MAX_SCORE,
1287     GADGET_ID_ELEMENT_VALUE2_DOWN,      GADGET_ID_ELEMENT_VALUE2_UP,
1288     GADGET_ID_ELEMENT_VALUE2_TEXT,      GADGET_ID_NONE,
1289     NULL,                               /* will be set when used */
1290     NULL,                               NULL, NULL
1291   },
1292   {
1293     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1294     MIN_SCORE,                          MAX_SCORE,
1295     GADGET_ID_ELEMENT_VALUE3_DOWN,      GADGET_ID_ELEMENT_VALUE3_UP,
1296     GADGET_ID_ELEMENT_VALUE3_TEXT,      GADGET_ID_NONE,
1297     NULL,                               /* will be set when used */
1298     NULL,                               NULL, NULL
1299   },
1300   {
1301     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1302     MIN_SCORE,                          MAX_SCORE,
1303     GADGET_ID_ELEMENT_VALUE4_DOWN,      GADGET_ID_ELEMENT_VALUE4_UP,
1304     GADGET_ID_ELEMENT_VALUE4_TEXT,      GADGET_ID_NONE,
1305     NULL,                               /* will be set when used */
1306     NULL,                               NULL, NULL
1307   },
1308   {
1309     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1310     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1311     GADGET_ID_YAMYAM_CONTENT_DOWN,      GADGET_ID_YAMYAM_CONTENT_UP,
1312     GADGET_ID_YAMYAM_CONTENT_TEXT,      GADGET_ID_NONE,
1313     &level.num_yamyam_contents,
1314     NULL,                               NULL, "number of content areas"
1315   },
1316   {
1317     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1318     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
1319     GADGET_ID_BALL_CONTENT_DOWN,        GADGET_ID_BALL_CONTENT_UP,
1320     GADGET_ID_BALL_CONTENT_TEXT,        GADGET_ID_NONE,
1321     &level.num_ball_contents,
1322     NULL,                               NULL, "number of content areas"
1323   },
1324   {
1325     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
1326     MIN_ANDROID_ELEMENTS,               MAX_ANDROID_ELEMENTS,
1327     GADGET_ID_ANDROID_CONTENT_DOWN,     GADGET_ID_ANDROID_CONTENT_UP,
1328     GADGET_ID_ANDROID_CONTENT_TEXT,     GADGET_ID_NONE,
1329     &level.num_android_clone_elements,
1330     NULL,                               NULL, "number of clonable elements"
1331   },
1332   {
1333     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
1334     MIN_ENVELOPE_XSIZE,                 MAX_ENVELOPE_XSIZE,
1335     GADGET_ID_ENVELOPE_XSIZE_DOWN,      GADGET_ID_ENVELOPE_XSIZE_UP,
1336     GADGET_ID_ENVELOPE_XSIZE_TEXT,      GADGET_ID_NONE,
1337     NULL,                               /* will be set when used */
1338     NULL,                               NULL, "width",
1339   },
1340   {
1341     -1,                                 ED_ELEMENT_SETTINGS_YPOS(0),
1342     MIN_ENVELOPE_YSIZE,                 MAX_ENVELOPE_YSIZE,
1343     GADGET_ID_ENVELOPE_YSIZE_DOWN,      GADGET_ID_ENVELOPE_YSIZE_UP,
1344     GADGET_ID_ENVELOPE_YSIZE_TEXT,      GADGET_ID_ENVELOPE_XSIZE_UP,
1345     NULL,                               /* will be set when used */
1346     NULL,                               " ", "height",
1347   },
1348   {
1349     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
1350     MIN_INITIAL_INVENTORY_SIZE,         MAX_INITIAL_INVENTORY_SIZE,
1351     GADGET_ID_INVENTORY_SIZE_DOWN,      GADGET_ID_INVENTORY_SIZE_UP,
1352     GADGET_ID_INVENTORY_SIZE_TEXT,      GADGET_ID_NONE,
1353     &level.initial_inventory_size[0],
1354     NULL,                               NULL, "number of inventory elements"
1355   },
1356
1357   /* ---------- element settings: configure 1 (custom elements) ------------ */
1358
1359   {
1360     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1361     MIN_SCORE,                          MAX_SCORE,
1362     GADGET_ID_CUSTOM_SCORE_DOWN,        GADGET_ID_CUSTOM_SCORE_UP,
1363     GADGET_ID_CUSTOM_SCORE_TEXT,        GADGET_ID_NONE,
1364     &custom_element.collect_score_initial,
1365     NULL,                               "CE score", " "
1366   },
1367   {
1368     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1369     MIN_COLLECT_COUNT,                  MAX_COLLECT_COUNT,
1370     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,     GADGET_ID_CUSTOM_GEMCOUNT_UP,
1371     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,     GADGET_ID_CUSTOM_SCORE_UP,
1372     &custom_element.collect_count_initial,
1373     NULL,                               "CE count", NULL
1374   },
1375   {
1376     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1377     0,                                  9999,
1378     GADGET_ID_CUSTOM_VALUE_FIX_DOWN,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1379     GADGET_ID_CUSTOM_VALUE_FIX_TEXT,    GADGET_ID_NONE,
1380     &custom_element.ce_value_fixed_initial,
1381     NULL,                               "CE value", NULL
1382   },
1383   {
1384     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
1385     0,                                  9999,
1386     GADGET_ID_CUSTOM_VALUE_RND_DOWN,    GADGET_ID_CUSTOM_VALUE_RND_UP,
1387     GADGET_ID_CUSTOM_VALUE_RND_TEXT,    GADGET_ID_CUSTOM_VALUE_FIX_UP,
1388     &custom_element.ce_value_random_initial,
1389     NULL,                               "+random", NULL
1390   },
1391   {
1392     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(6),
1393     0,                                  999,
1394     GADGET_ID_PUSH_DELAY_FIX_DOWN,      GADGET_ID_PUSH_DELAY_FIX_UP,
1395     GADGET_ID_PUSH_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1396     &custom_element.push_delay_fixed,
1397     NULL,                               "push delay", NULL
1398   },
1399   {
1400     -1,                                 ED_ELEMENT_SETTINGS_YPOS(6),
1401     0,                                  999,
1402     GADGET_ID_PUSH_DELAY_RND_DOWN,      GADGET_ID_PUSH_DELAY_RND_UP,
1403     GADGET_ID_PUSH_DELAY_RND_TEXT,      GADGET_ID_PUSH_DELAY_FIX_UP,
1404     &custom_element.push_delay_random,
1405     NULL,                               "+random", NULL
1406   },
1407   {
1408     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(7),
1409     0,                                  999,
1410     GADGET_ID_DROP_DELAY_FIX_DOWN,      GADGET_ID_DROP_DELAY_FIX_UP,
1411     GADGET_ID_DROP_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1412     &custom_element.drop_delay_fixed,
1413     NULL,                               "drop delay", NULL
1414   },
1415   {
1416     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
1417     0,                                  999,
1418     GADGET_ID_DROP_DELAY_RND_DOWN,      GADGET_ID_DROP_DELAY_RND_UP,
1419     GADGET_ID_DROP_DELAY_RND_TEXT,      GADGET_ID_DROP_DELAY_FIX_UP,
1420     &custom_element.drop_delay_random,
1421     NULL,                               "+random", NULL
1422   },
1423
1424   /* ---------- element settings: configure 2 (custom elements) ------------ */
1425
1426   {
1427     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
1428     0,                                  999,
1429     GADGET_ID_MOVE_DELAY_FIX_DOWN,      GADGET_ID_MOVE_DELAY_FIX_UP,
1430     GADGET_ID_MOVE_DELAY_FIX_TEXT,      GADGET_ID_NONE,
1431     &custom_element.move_delay_fixed,
1432     NULL,                               "move delay", NULL
1433   },
1434   {
1435     -1,                                 ED_ELEMENT_SETTINGS_YPOS(5),
1436     0,                                  999,
1437     GADGET_ID_MOVE_DELAY_RND_DOWN,      GADGET_ID_MOVE_DELAY_RND_UP,
1438     GADGET_ID_MOVE_DELAY_RND_TEXT,      GADGET_ID_MOVE_DELAY_FIX_UP,
1439     &custom_element.move_delay_random,
1440     NULL,                               "+random", NULL
1441   },
1442   {
1443     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(12),
1444     0,                                  999,
1445     GADGET_ID_EXPLOSION_DELAY_DOWN,     GADGET_ID_EXPLOSION_DELAY_UP,
1446     GADGET_ID_EXPLOSION_DELAY_TEXT,     GADGET_ID_NONE,
1447     &custom_element.explosion_delay,
1448     NULL,                               "explosion delay", NULL
1449   },
1450   {
1451     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
1452     0,                                  999,
1453     GADGET_ID_IGNITION_DELAY_DOWN,      GADGET_ID_IGNITION_DELAY_UP,
1454     GADGET_ID_IGNITION_DELAY_TEXT,      GADGET_ID_NONE,
1455     &custom_element.ignition_delay,
1456     NULL,                               "ignition delay", "(by fire)"
1457   },
1458
1459   /* ---------- element settings: configure (group elements) --------------- */
1460
1461   {
1462     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1463     MIN_ELEMENTS_IN_GROUP,              MAX_ELEMENTS_IN_GROUP,
1464     GADGET_ID_GROUP_CONTENT_DOWN,       GADGET_ID_GROUP_CONTENT_UP,
1465     GADGET_ID_GROUP_CONTENT_TEXT,       GADGET_ID_NONE,
1466     &group_element_info.num_elements,
1467     NULL,                               NULL, "number of elements in group"
1468   },
1469
1470   /* ---------- element settings: advanced (custom elements) --------------- */
1471
1472   {
1473     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(2),
1474     0,                                  999,
1475     GADGET_ID_CHANGE_DELAY_FIX_DOWN,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1476     GADGET_ID_CHANGE_DELAY_FIX_TEXT,    GADGET_ID_NONE,
1477     &custom_element_change.delay_fixed,
1478     NULL,                               "CE delay", NULL,
1479   },
1480   {
1481     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
1482     0,                                  999,
1483     GADGET_ID_CHANGE_DELAY_RND_DOWN,    GADGET_ID_CHANGE_DELAY_RND_UP,
1484     GADGET_ID_CHANGE_DELAY_RND_TEXT,    GADGET_ID_CHANGE_DELAY_FIX_UP,
1485     &custom_element_change.delay_random,
1486     NULL,                               "+random", NULL
1487   },
1488   {
1489     ED_ELEMENT_SETTINGS_XPOS(3),        ED_ELEMENT_SETTINGS_YPOS(12),
1490     0,                                  100,
1491     GADGET_ID_CHANGE_CONT_RND_DOWN,     GADGET_ID_CHANGE_CONT_RND_UP,
1492     GADGET_ID_CHANGE_CONT_RND_TEXT,     GADGET_ID_NONE,
1493     &custom_element_change.random_percentage,
1494     NULL,                               "use random replace:", "%"
1495   },
1496 };
1497
1498 static struct
1499 {
1500   int x, y;
1501   int gadget_id;
1502   int size;
1503   char *value;
1504   char *text_above, *infotext;
1505 } textinput_info[ED_NUM_TEXTINPUT] =
1506 {
1507   {
1508     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
1509     GADGET_ID_LEVEL_NAME,
1510     MAX_LEVEL_NAME_LEN,
1511     level.name,
1512     "Title:", "Title"
1513   },
1514   {
1515     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(2),
1516     GADGET_ID_LEVEL_AUTHOR,
1517     MAX_LEVEL_AUTHOR_LEN,
1518     level.author,
1519     "Author:", "Author"
1520   },
1521   {
1522     -1, -1,     /* these values are not constant, but can change at runtime */
1523     GADGET_ID_ELEMENT_NAME,
1524     MAX_ELEMENT_NAME_LEN - 2,           /* currently 2 chars less editable */
1525     custom_element.description,
1526     NULL, "Element name"
1527   }
1528 };
1529
1530 static struct
1531 {
1532   int x, y;
1533   int gadget_id;
1534   int xsize, ysize;
1535   char *value;
1536   char *text_above, *infotext;
1537 } textarea_info[ED_NUM_TEXTAREAS] =
1538 {
1539   {
1540     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
1541     GADGET_ID_ENVELOPE_INFO,
1542     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
1543     NULL,
1544     "Envelope Content:", "Envelope Content"
1545   }
1546 };
1547
1548 static struct ValueTextInfo options_time_or_steps[] =
1549 {
1550   { 0,                          "seconds"                       },
1551   { 1,                          "steps"                         },
1552
1553   { -1,                         NULL                            }
1554 };
1555
1556 static struct ValueTextInfo options_game_engine_type[] =
1557 {
1558   { GAME_ENGINE_TYPE_RND,       "Rocks'n'Diamonds"              },
1559   { GAME_ENGINE_TYPE_EM,        "Emerald Mine"                  },
1560   { GAME_ENGINE_TYPE_SP,        "Supaplex"                      },
1561
1562   { -1,                         NULL                            }
1563 };
1564
1565 static struct ValueTextInfo options_wind_direction[] =
1566 {
1567   { MV_START_NONE,              "none"                          },
1568   { MV_START_LEFT,              "left"                          },
1569   { MV_START_RIGHT,             "right"                         },
1570   { MV_START_UP,                "up"                            },
1571   { MV_START_DOWN,              "down"                          },
1572
1573   { -1,                         NULL                            }
1574 };
1575
1576 static struct ValueTextInfo options_player_speed[] =
1577 {
1578   { 0,                          "frozen"                        },
1579   { 1,                          "very slow"                     },
1580   { 2,                          "slow"                          },
1581   { 4,                          "normal"                        },
1582   { 8,                          "fast"                          },
1583   { 16,                         "very fast"                     },
1584   { 32,                         "ultrafast"                     },
1585
1586   { -1,                         NULL                            }
1587 };
1588
1589 static struct ValueTextInfo options_access_type[] =
1590 {
1591   { EP_WALKABLE,                "walkable"                      },
1592   { EP_PASSABLE,                "passable"                      },
1593
1594   { -1,                         NULL                            }
1595 };
1596
1597 static struct ValueTextInfo options_access_layer[] =
1598 {
1599   { EP_ACCESSIBLE_OVER,         "over"                          },
1600   { EP_ACCESSIBLE_INSIDE,       "inside"                        },
1601   { EP_ACCESSIBLE_UNDER,        "under"                         },
1602
1603   { -1,                         NULL                            }
1604 };
1605
1606 static struct ValueTextInfo options_access_protected[] =
1607 {
1608   { 0,                          "unprotected"                   },
1609   { 1,                          "protected"                     },
1610
1611   { -1,                         NULL                            }
1612 };
1613
1614 static struct ValueTextInfo options_access_direction[] =
1615 {
1616   { MV_NO_DIRECTION,            "no direction"                  },
1617   { MV_LEFT,                    "left"                          },
1618   { MV_RIGHT,                   "right"                         },
1619   { MV_UP,                      "up"                            },
1620   { MV_DOWN,                    "down"                          },
1621   { MV_LEFT  | MV_UP,           "left + up"                     },
1622   { MV_LEFT  | MV_DOWN,         "left + down"                   },
1623   { MV_RIGHT | MV_UP,           "right + up"                    },
1624   { MV_RIGHT | MV_DOWN,         "right + down"                  },
1625   { MV_HORIZONTAL,              "horizontal"                    },
1626   { MV_VERTICAL,                "vertical"                      },
1627   { MV_HORIZONTAL | MV_UP,      "horizontal + up"               },
1628   { MV_HORIZONTAL | MV_DOWN,    "horizontal + down"             },
1629   { MV_VERTICAL   | MV_LEFT,    "vertical + left"               },
1630   { MV_VERTICAL   | MV_RIGHT,   "vertical + right"              },
1631   { MV_ALL_DIRECTIONS,          "all directions"                },
1632
1633   { -1,                         NULL                            }
1634 };
1635
1636 static struct ValueTextInfo options_walk_to_action[] =
1637 {
1638   { EP_DIGGABLE,                "diggable"                      },
1639   { EP_COLLECTIBLE_ONLY,        "collectible"                   },
1640   { EP_DROPPABLE,               "collectible & droppable"       },
1641   { EP_THROWABLE,               "collectible & throwable"       },
1642   { EP_PUSHABLE,                "pushable"                      },
1643
1644   { -1,                         NULL                            }
1645 };
1646
1647 static struct ValueTextInfo options_move_pattern[] =
1648 {
1649   { MV_LEFT,                    "left"                          },
1650   { MV_RIGHT,                   "right"                         },
1651   { MV_UP,                      "up"                            },
1652   { MV_DOWN,                    "down"                          },
1653   { MV_HORIZONTAL,              "horizontal"                    },
1654   { MV_VERTICAL,                "vertical"                      },
1655   { MV_ALL_DIRECTIONS,          "all directions"                },
1656   { MV_WIND_DIRECTION,          "wind direction"                },
1657   { MV_TOWARDS_PLAYER,          "towards player"                },
1658   { MV_AWAY_FROM_PLAYER,        "away from player"              },
1659   { MV_ALONG_LEFT_SIDE,         "along left side"               },
1660   { MV_ALONG_RIGHT_SIDE,        "along right side"              },
1661   { MV_TURNING_LEFT,            "turning left"                  },
1662   { MV_TURNING_RIGHT,           "turning right"                 },
1663   { MV_TURNING_LEFT_RIGHT,      "turning left, right"           },
1664   { MV_TURNING_RIGHT_LEFT,      "turning right, left"           },
1665   { MV_TURNING_RANDOM,          "turning random"                },
1666   { MV_MAZE_RUNNER,             "maze runner style"             },
1667   { MV_MAZE_HUNTER,             "maze hunter style"             },
1668   { MV_WHEN_PUSHED,             "when pushed"                   },
1669   { MV_WHEN_DROPPED,            "when dropped/thrown"           },
1670
1671   { -1,                         NULL                            }
1672 };
1673
1674 static struct ValueTextInfo options_move_direction[] =
1675 {
1676   { MV_START_AUTOMATIC,         "automatic"                     },
1677   { MV_START_LEFT,              "left"                          },
1678   { MV_START_RIGHT,             "right"                         },
1679   { MV_START_UP,                "up"                            },
1680   { MV_START_DOWN,              "down"                          },
1681   { MV_START_RANDOM,            "random"                        },
1682   { MV_START_PREVIOUS,          "previous"                      },
1683
1684   { -1,                         NULL                            }
1685 };
1686
1687 static struct ValueTextInfo options_move_stepsize[] =
1688 {
1689   { 0,                          "not moving"                    },
1690   { 1,                          "very slow"                     },
1691   { 2,                          "slow"                          },
1692   { 4,                          "normal"                        },
1693   { 8,                          "fast"                          },
1694   { 16,                         "very fast"                     },
1695   { 32,                         "even faster"                   },
1696
1697   { -1,                         NULL                            }
1698 };
1699
1700 static struct ValueTextInfo options_move_leave_type[] =
1701 {
1702   { LEAVE_TYPE_UNLIMITED,       "leave behind"                  },
1703   { LEAVE_TYPE_LIMITED,         "change it to"                  },
1704
1705   { -1,                         NULL                            }
1706 };
1707
1708 static struct ValueTextInfo options_smash_targets[] =
1709 {
1710   { EP_CAN_SMASH_PLAYER,        "player"                        },
1711 #if 0
1712   { EP_CAN_SMASH_ENEMIES,       "enemies"                       },
1713 #endif
1714   { EP_CAN_SMASH_EVERYTHING,    "everything"                    },
1715
1716   { -1,                         NULL                            }
1717 };
1718
1719 static struct ValueTextInfo options_slippery_type[] =
1720 {
1721   { SLIPPERY_ANY_RANDOM,        "random"                        },
1722   { SLIPPERY_ANY_LEFT_RIGHT,    "left, right"                   },
1723   { SLIPPERY_ANY_RIGHT_LEFT,    "right, left"                   },
1724   { SLIPPERY_ONLY_LEFT,         "only left"                     },
1725   { SLIPPERY_ONLY_RIGHT,        "only right"                    },
1726
1727   { -1,                         NULL                            }
1728 };
1729
1730 static struct ValueTextInfo options_deadliness[] =
1731 {
1732   { EP_DONT_RUN_INTO,           "running into"                  },
1733   { EP_DONT_COLLIDE_WITH,       "colliding with"                },
1734   { EP_DONT_GET_HIT_BY,         "getting hit by"                },
1735   { EP_DONT_TOUCH,              "touching"                      },
1736
1737   { -1,                         NULL                            }
1738 };
1739
1740 static struct ValueTextInfo options_explosion_type[] =
1741 {
1742   { EXPLODES_3X3,               "3x3"                           },
1743   { EXPLODES_CROSS,             "3+3"                           },
1744   { EXPLODES_1X1,               "1x1"                           },
1745
1746   { -1,                         NULL                            }
1747 };
1748
1749 static struct ValueTextInfo options_time_units[] =
1750 {
1751   { 1,                          "frames"                        },
1752   { FRAMES_PER_SECOND,          "seconds"                       },
1753
1754   { -1,                         NULL                            }
1755 };
1756
1757 static struct ValueTextInfo options_change_direct_action[] =
1758 {
1759   { CE_TOUCHED_BY_PLAYER,       "touched by player"             },
1760   { CE_PRESSED_BY_PLAYER,       "pressed by player"             },
1761   { CE_SWITCHED_BY_PLAYER,      "switched by player"            },
1762   { CE_SNAPPED_BY_PLAYER,       "snapped by player"             },
1763   { CE_PUSHED_BY_PLAYER,        "pushed by player"              },
1764   { CE_ENTERED_BY_PLAYER,       "entered by player"             },
1765   { CE_LEFT_BY_PLAYER,          "left by player"                },
1766   { CE_DROPPED_BY_PLAYER,       "dropped/thrown by player"      },
1767   { CE_SWITCHED,                "switched"                      },
1768   { CE_HITTING_SOMETHING,       "hitting something"             },
1769   { CE_HIT_BY_SOMETHING,        "hit by something"              },
1770 #if 0
1771   { CE_BLOCKED,                 "blocked"                       },
1772 #endif
1773   { CE_IMPACT,                  "impact (on something)"         },
1774   { CE_SMASHED,                 "smashed (from above)"          },
1775 #if 0
1776   { CE_VALUE_CHANGES,           "CE value changes"              },
1777   { CE_SCORE_CHANGES,           "CE score changes"              },
1778 #endif
1779   { CE_VALUE_GETS_ZERO,         "CE value gets 0"               },
1780   { CE_SCORE_GETS_ZERO,         "CE score gets 0"               },
1781
1782   { -1,                         NULL                            }
1783 };
1784
1785 static struct ValueTextInfo options_change_other_action[] =
1786 {
1787   { CE_PLAYER_TOUCHES_X,        "player touches"                },
1788   { CE_PLAYER_PRESSES_X,        "player presses"                },
1789   { CE_PLAYER_SWITCHES_X,       "player switches"               },
1790   { CE_PLAYER_SNAPS_X,          "player snaps"                  },
1791   { CE_PLAYER_PUSHES_X,         "player pushes"                 },
1792   { CE_PLAYER_ENTERS_X,         "player enters"                 },
1793   { CE_PLAYER_LEAVES_X,         "player leaves"                 },
1794   { CE_PLAYER_DIGS_X,           "player digs"                   },
1795   { CE_PLAYER_COLLECTS_X,       "player collects"               },
1796   { CE_PLAYER_DROPS_X,          "player drops/throws"           },
1797   { CE_TOUCHING_X,              "touching"                      },
1798   { CE_HITTING_X,               "hitting"                       },
1799   { CE_DIGGING_X,               "digging"                       },
1800   { CE_HIT_BY_X,                "hit by"                        },
1801   { CE_SWITCH_OF_X,             "switch of"                     },
1802   { CE_CHANGE_OF_X,             "change by page of"             },
1803   { CE_EXPLOSION_OF_X,          "explosion of"                  },
1804   { CE_MOVE_OF_X,               "move of"                       },
1805   { CE_CREATION_OF_X,           "creation of"                   },
1806   { CE_VALUE_CHANGES_OF_X,      "CE value changes of"           },
1807   { CE_SCORE_CHANGES_OF_X,      "CE score changes of"           },
1808   { CE_VALUE_GETS_ZERO_OF_X,    "CE value gets 0 of"            },
1809   { CE_SCORE_GETS_ZERO_OF_X,    "CE score gets 0 of"            },
1810
1811   { -1,                         NULL                            }
1812 };
1813
1814 static struct ValueTextInfo options_change_trigger_side[] =
1815 {
1816   { CH_SIDE_LEFT,               "left"                          },
1817   { CH_SIDE_RIGHT,              "right"                         },
1818   { CH_SIDE_TOP,                "top"                           },
1819   { CH_SIDE_BOTTOM,             "bottom"                        },
1820   { CH_SIDE_LEFT_RIGHT,         "left/right"                    },
1821   { CH_SIDE_TOP_BOTTOM,         "top/bottom"                    },
1822   { CH_SIDE_ANY,                "any"                           },
1823
1824   { -1,                         NULL                            }
1825 };
1826
1827 static struct ValueTextInfo options_change_trigger_player[] =
1828 {
1829   { CH_PLAYER_1,                "1"                             },
1830   { CH_PLAYER_2,                "2"                             },
1831   { CH_PLAYER_3,                "3"                             },
1832   { CH_PLAYER_4,                "4"                             },
1833   { CH_PLAYER_ANY,              "any"                           },
1834
1835   { -1,                         NULL                            }
1836 };
1837
1838 static struct ValueTextInfo options_change_trigger_page[] =
1839 {
1840   { (1 << 0),                   "1"                             },
1841   { (1 << 1),                   "2"                             },
1842   { (1 << 2),                   "3"                             },
1843   { (1 << 3),                   "4"                             },
1844   { (1 << 4),                   "5"                             },
1845   { (1 << 5),                   "6"                             },
1846   { (1 << 6),                   "7"                             },
1847   { (1 << 7),                   "8"                             },
1848   { (1 << 8),                   "9"                             },
1849   { (1 << 9),                   "10"                            },
1850   { (1 << 10),                  "11"                            },
1851   { (1 << 11),                  "12"                            },
1852   { (1 << 12),                  "13"                            },
1853   { (1 << 13),                  "14"                            },
1854   { (1 << 14),                  "15"                            },
1855   { (1 << 15),                  "16"                            },
1856   { (1 << 16),                  "17"                            },
1857   { (1 << 17),                  "18"                            },
1858   { (1 << 18),                  "19"                            },
1859   { (1 << 19),                  "20"                            },
1860   { (1 << 20),                  "21"                            },
1861   { (1 << 21),                  "22"                            },
1862   { (1 << 22),                  "23"                            },
1863   { (1 << 23),                  "24"                            },
1864   { (1 << 24),                  "25"                            },
1865   { (1 << 25),                  "26"                            },
1866   { (1 << 26),                  "27"                            },
1867   { (1 << 27),                  "28"                            },
1868   { (1 << 28),                  "29"                            },
1869   { (1 << 29),                  "30"                            },
1870   { (1 << 30),                  "31"                            },
1871   { (1 << 31),                  "32"                            },
1872   { CH_PAGE_ANY,                "any"                           },
1873
1874   { -1,                         NULL                            }
1875 };
1876
1877 static struct ValueTextInfo options_change_replace_when[] =
1878 {
1879   { CP_WHEN_EMPTY,              "empty"                         },
1880   { CP_WHEN_WALKABLE,           "walkable"                      },
1881   { CP_WHEN_DIGGABLE,           "diggable"                      },
1882   { CP_WHEN_COLLECTIBLE,        "collectible"                   },
1883   { CP_WHEN_REMOVABLE,          "removable"                     },
1884   { CP_WHEN_DESTRUCTIBLE,       "destructible"                  },
1885
1886   { -1,                         NULL                            }
1887 };
1888
1889 static struct ValueTextInfo options_action_type[] =
1890 {
1891   { CA_NO_ACTION,               "no action"                     },
1892   { CA_UNDEFINED,               " "                             },
1893   { CA_HEADLINE_LEVEL_ACTIONS,  "[level]"                       },
1894   { CA_RESTART_LEVEL,           "restart level"                 },
1895   { CA_SHOW_ENVELOPE,           "show envelope"                 },
1896   { CA_SET_LEVEL_TIME,          "set time"                      },
1897   { CA_SET_LEVEL_SCORE,         "set score"                     },
1898   { CA_SET_LEVEL_GEMS,          "set gems"                      },
1899   { CA_SET_LEVEL_WIND,          "set wind dir."                 },
1900   { CA_SET_LEVEL_RANDOM_SEED,   "set rand. seed"                },
1901   { CA_UNDEFINED,               " "                             },
1902   { CA_HEADLINE_PLAYER_ACTIONS, "[player]"                      },
1903   { CA_MOVE_PLAYER,             "move player"                   },
1904   { CA_EXIT_PLAYER,             "exit player"                   },
1905   { CA_KILL_PLAYER,             "kill player"                   },
1906   { CA_SET_PLAYER_KEYS,         "set keys"                      },
1907   { CA_SET_PLAYER_SPEED,        "set speed"                     },
1908   { CA_SET_PLAYER_SHIELD,       "set shield"                    },
1909   { CA_SET_PLAYER_GRAVITY,      "set gravity"                   },
1910   { CA_SET_PLAYER_ARTWORK,      "set artwork"                   },
1911   { CA_SET_PLAYER_INVENTORY,    "set inventory"                 },
1912   { CA_UNDEFINED,               " "                             },
1913   { CA_HEADLINE_CE_ACTIONS,     "[CE]"                          },
1914   { CA_SET_CE_VALUE,            "set CE value"                  },
1915   { CA_SET_CE_SCORE,            "set CE score"                  },
1916   { CA_SET_CE_ARTWORK,          "set CE artwork"                },
1917   { CA_UNDEFINED,               " "                             },
1918   { CA_HEADLINE_ENGINE_ACTIONS, "[engine]"                      },
1919   { CA_SET_ENGINE_SCAN_MODE,    "set scan mode"                 },
1920
1921   { -1,                         NULL                            }
1922 };
1923
1924 static struct ValueTextInfo options_action_mode_none[] =
1925 {
1926   { CA_MODE_UNDEFINED,          " "                             },
1927
1928   { -1,                         NULL                            }
1929 };
1930
1931 static struct ValueTextInfo options_action_mode_assign[] =
1932 {
1933   { CA_MODE_SET,                "="                             },
1934
1935   { -1,                         NULL                            }
1936 };
1937
1938 static struct ValueTextInfo options_action_mode_add_remove[] =
1939 {
1940   { CA_MODE_ADD,                "+"                             },
1941   { CA_MODE_SUBTRACT,           "-"                             },
1942
1943   { -1,                         NULL                            }
1944 };
1945
1946 static struct ValueTextInfo options_action_mode_calculate[] =
1947 {
1948   { CA_MODE_SET,                "="                             },
1949   { CA_MODE_ADD,                "+"                             },
1950   { CA_MODE_SUBTRACT,           "-"                             },
1951   { CA_MODE_MULTIPLY,           "*"                             },
1952   { CA_MODE_DIVIDE,             "/"                             },
1953   { CA_MODE_MODULO,             "%"                             },
1954
1955   { -1,                         NULL                            }
1956 };
1957
1958 static struct ValueTextInfo options_action_arg_none[] =
1959 {
1960   { CA_ARG_UNDEFINED,           "         "                     },
1961
1962   { -1,                         NULL                            }
1963 };
1964
1965 static struct ValueTextInfo options_action_arg_player[] =
1966 {
1967   { CA_ARG_PLAYER_HEADLINE,     "[player]"                      },
1968   { CA_ARG_PLAYER_1,            "1"                             },
1969   { CA_ARG_PLAYER_2,            "2"                             },
1970   { CA_ARG_PLAYER_3,            "3"                             },
1971   { CA_ARG_PLAYER_4,            "4"                             },
1972   { CA_ARG_PLAYER_ANY,          "any"                           },
1973   { CA_ARG_PLAYER_TRIGGER,      "trigger"                       },
1974   { CA_ARG_PLAYER_ACTION,       "action ->"                     },
1975
1976   { -1,                         NULL                            }
1977 };
1978
1979 static struct ValueTextInfo options_action_arg_number[] =
1980 {
1981   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
1982   { CA_ARG_0,                   "0"                             },
1983   { CA_ARG_1,                   "1"                             },
1984   { CA_ARG_2,                   "2"                             },
1985   { CA_ARG_3,                   "3"                             },
1986   { CA_ARG_4,                   "4"                             },
1987   { CA_ARG_5,                   "5"                             },
1988   { CA_ARG_10,                  "10"                            },
1989   { CA_ARG_100,                 "100"                           },
1990   { CA_ARG_1000,                "1000"                          },
1991   { CA_ARG_UNDEFINED,           " "                             },
1992   { CA_ARG_NUMBER_MIN,          "min"                           },
1993   { CA_ARG_NUMBER_MAX,          "max"                           },
1994   { CA_ARG_UNDEFINED,           " "                             },
1995   { CA_ARG_NUMBER_RESET,        "reset"                         },
1996   { CA_ARG_UNDEFINED,           " "                             },
1997   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
1998   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
1999   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2000   { CA_ARG_UNDEFINED,           " "                             },
2001   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2002   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2003   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2004   { CA_ARG_UNDEFINED,           " "                             },
2005   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2006   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2007   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2008   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2009   { CA_ARG_UNDEFINED,           " "                             },
2010   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2011   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2012   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2013   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2014
2015   { -1,                         NULL                            }
2016 };
2017
2018 static struct ValueTextInfo options_action_arg_value[] =
2019 {
2020   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2021   { CA_ARG_0,                   "0"                             },
2022   { CA_ARG_1,                   "1"                             },
2023   { CA_ARG_2,                   "2"                             },
2024   { CA_ARG_3,                   "3"                             },
2025   { CA_ARG_4,                   "4"                             },
2026   { CA_ARG_5,                   "5"                             },
2027   { CA_ARG_10,                  "10"                            },
2028   { CA_ARG_100,                 "100"                           },
2029   { CA_ARG_1000,                "1000"                          },
2030   { CA_ARG_UNDEFINED,           " "                             },
2031   { CA_ARG_NUMBER_MIN,          "min"                           },
2032   { CA_ARG_NUMBER_MAX,          "max"                           },
2033   { CA_ARG_UNDEFINED,           " "                             },
2034   { CA_ARG_NUMBER_RESET,        "reset"                         },
2035   { CA_ARG_UNDEFINED,           " "                             },
2036   { CA_ARG_NUMBER_CE_VALUE,     "CE value"                      },
2037   { CA_ARG_NUMBER_CE_SCORE,     "CE score"                      },
2038   { CA_ARG_NUMBER_CE_DELAY,     "CE delay"                      },
2039   { CA_ARG_UNDEFINED,           " "                             },
2040   { CA_ARG_NUMBER_LEVEL_TIME,   "time"                          },
2041   { CA_ARG_NUMBER_LEVEL_GEMS,   "gems"                          },
2042   { CA_ARG_NUMBER_LEVEL_SCORE,  "score"                         },
2043   { CA_ARG_UNDEFINED,           " "                             },
2044   { CA_ARG_ELEMENT_CV_HEADLINE, "[CE value]"                    },
2045   { CA_ARG_ELEMENT_CV_TARGET,   "target"                        },
2046   { CA_ARG_ELEMENT_CV_TRIGGER,  "trigger"                       },
2047   { CA_ARG_ELEMENT_CV_ACTION,   "action ->"                     },
2048   { CA_ARG_UNDEFINED,           " "                             },
2049   { CA_ARG_ELEMENT_CS_HEADLINE, "[CE score]"                    },
2050   { CA_ARG_ELEMENT_CS_TARGET,   "target"                        },
2051   { CA_ARG_ELEMENT_CS_TRIGGER,  "trigger"                       },
2052   { CA_ARG_ELEMENT_CS_ACTION,   "action ->"                     },
2053   { CA_ARG_UNDEFINED,           " "                             },
2054   { CA_ARG_ELEMENT_NR_HEADLINE, "[element]"                     },
2055   { CA_ARG_ELEMENT_NR_TARGET,   "target"                        },
2056   { CA_ARG_ELEMENT_NR_TRIGGER,  "trigger"                       },
2057   { CA_ARG_ELEMENT_NR_ACTION,   "action ->"                     },
2058
2059   { -1,                         NULL                            }
2060 };
2061
2062 static struct ValueTextInfo options_action_arg_envelope[] =
2063 {
2064   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2065   { CA_ARG_1,                   "1"                             },
2066   { CA_ARG_2,                   "2"                             },
2067   { CA_ARG_3,                   "3"                             },
2068   { CA_ARG_4,                   "4"                             },
2069   { CA_ARG_UNDEFINED,           " "                             },
2070   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2071   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2072   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2073   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2074
2075   { -1,                         NULL                            }
2076 };
2077
2078 static struct ValueTextInfo options_action_arg_key[] =
2079 {
2080   { CA_ARG_NUMBER_HEADLINE,     "[number]"                      },
2081   { CA_ARG_1,                   "1"                             },
2082   { CA_ARG_2,                   "2"                             },
2083   { CA_ARG_3,                   "3"                             },
2084   { CA_ARG_4,                   "4"                             },
2085   { CA_ARG_5,                   "5"                             },
2086   { CA_ARG_6,                   "6"                             },
2087   { CA_ARG_7,                   "7"                             },
2088   { CA_ARG_8,                   "8"                             },
2089   { CA_ARG_UNDEFINED,           " "                             },
2090   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2091   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2092   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2093   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2094
2095   { -1,                         NULL                            }
2096 };
2097
2098 static struct ValueTextInfo options_action_arg_speed[] =
2099 {
2100   { CA_ARG_SPEED_HEADLINE,      "[speed]"                       },
2101   { CA_ARG_SPEED_NOT_MOVING,    "frozen"                        },
2102   { CA_ARG_SPEED_VERY_SLOW,     "very slow"                     },
2103   { CA_ARG_SPEED_SLOW,          "slow"                          },
2104   { CA_ARG_SPEED_NORMAL,        "normal"                        },
2105   { CA_ARG_SPEED_FAST,          "fast"                          },
2106   { CA_ARG_SPEED_VERY_FAST,     "very fast"                     },
2107   { CA_ARG_SPEED_EVEN_FASTER,   "ultrafast"                     },
2108   { CA_ARG_UNDEFINED,           " "                             },
2109   { CA_ARG_SPEED_SLOWER,        "slower"                        },
2110   { CA_ARG_SPEED_FASTER,        "faster"                        },
2111   { CA_ARG_UNDEFINED,           " "                             },
2112   { CA_ARG_SPEED_RESET,         "reset"                         },
2113
2114   { -1,                         NULL                            }
2115 };
2116
2117 static struct ValueTextInfo options_action_arg_shield[] =
2118 {
2119   { CA_ARG_SHIELD_HEADLINE,     "[shield]"                      },
2120   { CA_ARG_SHIELD_OFF,          "off"                           },
2121   { CA_ARG_SHIELD_NORMAL,       "normal"                        },
2122   { CA_ARG_SHIELD_DEADLY,       "deadly"                        },
2123
2124   { -1,                         NULL                            }
2125 };
2126
2127 static struct ValueTextInfo options_action_arg_artwork[] =
2128 {
2129   { CA_ARG_ELEMENT_HEADLINE,    "[element]"                     },
2130   { CA_ARG_ELEMENT_TARGET,      "target"                        },
2131   { CA_ARG_ELEMENT_TRIGGER,     "trigger"                       },
2132   { CA_ARG_ELEMENT_ACTION,      "action ->"                     },
2133   { CA_ARG_UNDEFINED,           " "                             },
2134   { CA_ARG_ELEMENT_RESET,       "reset"                         },
2135
2136   { -1,                         NULL                            }
2137 };
2138
2139 static struct ValueTextInfo options_action_arg_gravity[] =
2140 {
2141   { CA_ARG_GRAVITY_HEADLINE,    "[gravity]"                     },
2142   { CA_ARG_GRAVITY_ON,          "on"                            },
2143   { CA_ARG_GRAVITY_OFF,         "off"                           },
2144   { CA_ARG_GRAVITY_TOGGLE,      "toggle"                        },
2145
2146   { -1,                         NULL                            }
2147 };
2148
2149 static struct ValueTextInfo options_action_arg_direction[] =
2150 {
2151   { CA_ARG_DIRECTION_HEADLINE,  "[dir.]"                        },
2152   { CA_ARG_DIRECTION_NONE,      "none"                          },
2153   { CA_ARG_DIRECTION_LEFT,      "left"                          },
2154   { CA_ARG_DIRECTION_RIGHT,     "right"                         },
2155   { CA_ARG_DIRECTION_UP,        "up"                            },
2156   { CA_ARG_DIRECTION_DOWN,      "down"                          },
2157   { CA_ARG_DIRECTION_TRIGGER,   "trigger"                       },
2158   { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                   },
2159
2160   { -1,                         NULL                            }
2161 };
2162
2163 static struct ValueTextInfo options_action_arg_scan_mode[] =
2164 {
2165   { CA_ARG_SCAN_MODE_HEADLINE,  "[mode]"                        },
2166   { CA_ARG_SCAN_MODE_NORMAL,    "normal"                        },
2167   { CA_ARG_SCAN_MODE_REVERSE,   "reverse"                       },
2168
2169   { -1,                         NULL                            }
2170 };
2171
2172 static struct ValueTextInfo options_action_arg_inventory[] =
2173 {
2174   { CA_ARG_INVENTORY_HEADLINE,  "[add]"                         },
2175   { CA_ARG_ELEMENT_TARGET,      "+ target"                      },
2176   { CA_ARG_ELEMENT_TRIGGER,     "+ trigger"                     },
2177   { CA_ARG_ELEMENT_ACTION,      "+ action"                      },
2178   { CA_ARG_UNDEFINED,           " "                             },
2179   { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]"                     },
2180   { CA_ARG_INVENTORY_RM_TARGET, "- target"                      },
2181   { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger"                     },
2182   { CA_ARG_INVENTORY_RM_ACTION, "- action"                      },
2183   { CA_ARG_INVENTORY_RM_FIRST,  "- first"                       },
2184   { CA_ARG_INVENTORY_RM_LAST,   "- last"                        },
2185   { CA_ARG_INVENTORY_RM_ALL,    "- all"                         },
2186   { CA_ARG_UNDEFINED,           " "                             },
2187   { CA_ARG_INVENTORY_RESET,     "reset"                         },
2188
2189   { -1,                         NULL                            }
2190 };
2191
2192 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
2193 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
2194 {
2195   { -1,                         NULL                            }
2196 };
2197
2198 static struct ValueTextInfo options_group_choice_mode[] =
2199 {
2200   { ANIM_RANDOM,                "random"                        },
2201   { ANIM_LOOP,                  "loop"                          },
2202   { ANIM_LINEAR,                "linear"                        },
2203   { ANIM_PINGPONG,              "pingpong"                      },
2204   { ANIM_PINGPONG2,             "pingpong 2"                    },
2205
2206   { -1,                         NULL                            }
2207 };
2208
2209 static struct ValueTextInfo *action_arg_modes[] =
2210 {
2211   options_action_mode_none,
2212   options_action_mode_assign,
2213   options_action_mode_add_remove,
2214   options_action_mode_calculate,
2215 };
2216
2217 static struct
2218 {
2219   int value;
2220   int mode;
2221   struct ValueTextInfo *options;
2222 }
2223 action_arg_options[] =
2224 {
2225   { CA_NO_ACTION,               0,      options_action_arg_none,        },
2226   { CA_EXIT_PLAYER,             0,      options_action_arg_player,      },
2227   { CA_KILL_PLAYER,             0,      options_action_arg_player,      },
2228   { CA_MOVE_PLAYER,             0,      options_action_arg_direction,   },
2229   { CA_RESTART_LEVEL,           0,      options_action_arg_none,        },
2230   { CA_SHOW_ENVELOPE,           0,      options_action_arg_envelope,    },
2231   { CA_SET_LEVEL_TIME,          3,      options_action_arg_number,      },
2232   { CA_SET_LEVEL_GEMS,          3,      options_action_arg_number,      },
2233   { CA_SET_LEVEL_SCORE,         3,      options_action_arg_number,      },
2234   { CA_SET_LEVEL_WIND,          1,      options_action_arg_direction,   },
2235   { CA_SET_LEVEL_RANDOM_SEED,   1,      options_action_arg_number,      },
2236   { CA_SET_PLAYER_KEYS,         2,      options_action_arg_key,         },
2237   { CA_SET_PLAYER_SPEED,        1,      options_action_arg_speed,       },
2238   { CA_SET_PLAYER_SHIELD,       1,      options_action_arg_shield,      },
2239   { CA_SET_PLAYER_GRAVITY,      1,      options_action_arg_gravity,     },
2240   { CA_SET_PLAYER_ARTWORK,      1,      options_action_arg_artwork,     },
2241   { CA_SET_PLAYER_INVENTORY,    0,      options_action_arg_inventory,   },
2242   { CA_SET_CE_VALUE,            3,      options_action_arg_value,       },
2243   { CA_SET_CE_SCORE,            3,      options_action_arg_value,       },
2244   { CA_SET_CE_ARTWORK,          1,      options_action_arg_artwork,     },
2245   { CA_SET_ENGINE_SCAN_MODE,    1,      options_action_arg_scan_mode,   },
2246
2247   { -1,                         FALSE,  NULL                            }
2248 };
2249
2250 static struct
2251 {
2252   int x, y;
2253   int gadget_id;
2254   int gadget_id_align;
2255   int size;     /* char size of selectbox or '-1' (dynamically determined) */
2256   struct ValueTextInfo *options;
2257   int *value;
2258   char *text_left, *text_right, *infotext;
2259 } selectbox_info[ED_NUM_SELECTBOX] =
2260 {
2261   /* ---------- level and editor settings ---------------------------------- */
2262
2263   {
2264     -1,                                 ED_LEVEL_SETTINGS_YPOS(7),
2265     GADGET_ID_TIME_OR_STEPS,            GADGET_ID_LEVEL_TIMELIMIT_UP,
2266     -1,
2267     options_time_or_steps,
2268     &level.use_step_counter,
2269     NULL, "(0 => no limit)",            "time or step limit"
2270   },
2271   {
2272     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(11),
2273     GADGET_ID_GAME_ENGINE_TYPE,         GADGET_ID_NONE,
2274     -1,
2275     options_game_engine_type,
2276     &level.game_engine_type,
2277     "game engine:", NULL,               "game engine"
2278   },
2279   {
2280     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(10),
2281     GADGET_ID_WIND_DIRECTION,           GADGET_ID_NONE,
2282     -1,
2283     options_wind_direction,
2284     &level.wind_direction_initial,
2285     "initial wind direction:", NULL,    "initial wind direction"
2286   },
2287
2288   /* ---------- element settings: configure (several elements) ------------- */
2289
2290   {
2291     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
2292     GADGET_ID_PLAYER_SPEED,             GADGET_ID_NONE,
2293     -1,
2294     options_player_speed,
2295     &level.initial_player_stepsize[0],
2296     "initial player speed:", NULL,      "initial player speed"
2297   },
2298
2299   /* ---------- element settings: configure 1 (custom elements) ------------ */
2300
2301   {
2302     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2303     GADGET_ID_CUSTOM_ACCESS_TYPE,       GADGET_ID_NONE,
2304     -1,
2305     options_access_type,
2306     &custom_element.access_type,
2307     NULL, NULL,                         "type of access to this field"
2308   },
2309   {
2310     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2311     GADGET_ID_CUSTOM_ACCESS_LAYER,      GADGET_ID_CUSTOM_ACCESS_TYPE,
2312     -1,
2313     options_access_layer,
2314     &custom_element.access_layer,
2315     NULL, NULL,                         "layer of access for this field"
2316   },
2317   {
2318     -1,                                 ED_ELEMENT_SETTINGS_YPOS(2),
2319     GADGET_ID_CUSTOM_ACCESS_PROTECTED,  GADGET_ID_CUSTOM_ACCESS_LAYER,
2320     -1,
2321     options_access_protected,
2322     &custom_element.access_protected,
2323     NULL, NULL,                         "protected access for this field"
2324   },
2325   {
2326     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2327     GADGET_ID_CUSTOM_ACCESS_DIRECTION,  GADGET_ID_NONE,
2328     -1,
2329     options_access_direction,
2330     &custom_element.access_direction,
2331     "from", NULL,                       "access direction for this field"
2332   },
2333   {
2334     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2335     GADGET_ID_CUSTOM_WALK_TO_ACTION,    GADGET_ID_NONE,
2336     -1,
2337     options_walk_to_action,
2338     &custom_element.walk_to_action,
2339     NULL, NULL,                         "diggable/collectible/pushable"
2340   },
2341
2342   /* ---------- element settings: configure 2 (custom elements) ------------ */
2343
2344   {
2345     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(1),
2346     GADGET_ID_CUSTOM_MOVE_PATTERN,      GADGET_ID_NONE,
2347     -1,
2348     options_move_pattern,
2349     &custom_element.move_pattern,
2350     "can move", NULL,                   "element move pattern"
2351   },
2352   {
2353     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
2354     GADGET_ID_CUSTOM_MOVE_DIRECTION,    GADGET_ID_NONE,
2355     -1,
2356     options_move_direction,
2357     &custom_element.move_direction_initial,
2358     "starts moving", NULL,              "initial element move direction"
2359   },
2360   {
2361     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
2362     GADGET_ID_CUSTOM_MOVE_STEPSIZE,     GADGET_ID_NONE,
2363     -1,
2364     options_move_stepsize,
2365     &custom_element.move_stepsize,
2366     "move/fall speed", NULL,            "speed of element movement"
2367   },
2368   {
2369     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(3),
2370     GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,   GADGET_ID_NONE,
2371     -1,
2372     options_move_leave_type,
2373     &custom_element.move_leave_type,
2374     // left text with leading spaces to place gadget next to "can dig" gadget
2375     // (needed because drawing area gadgets created after selectbox gadgets)
2376     // "can dig:    can", ":",          "leave behind or change element"
2377     "            can", ":",             "leave behind or change element"
2378   },
2379   {
2380     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
2381     GADGET_ID_CUSTOM_SMASH_TARGETS,     GADGET_ID_CUSTOM_CAN_SMASH,
2382     -1,
2383     options_smash_targets,
2384     &custom_element.smash_targets,
2385     "can smash", NULL,                  "elements that can be smashed"
2386   },
2387   {
2388     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
2389     GADGET_ID_CUSTOM_SLIPPERY_TYPE,     GADGET_ID_NONE,
2390     -1,
2391     options_slippery_type,
2392     &custom_element.slippery_type,
2393     "slippery", NULL,                   "where other elements fall down"
2394   },
2395   {
2396     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
2397     GADGET_ID_CUSTOM_DEADLINESS,        GADGET_ID_NONE,
2398     -1,
2399     options_deadliness,
2400     &custom_element.deadliness,
2401     "deadly when", NULL,                "deadliness of element"
2402   },
2403   {
2404     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(10),
2405     GADGET_ID_CUSTOM_EXPLOSION_TYPE,    GADGET_ID_NONE,
2406     -1,
2407     options_explosion_type,
2408     &custom_element.explosion_type,
2409     "can explode", NULL,                "explosion type"
2410   },
2411
2412   /* ---------- element settings: advanced (custom elements) --------------- */
2413
2414   {
2415     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(3),
2416     GADGET_ID_CHANGE_TIME_UNITS,        GADGET_ID_NONE,
2417     -1,
2418     options_time_units,
2419     &custom_element_change.delay_frames,
2420     "delay time given in", NULL,        "delay time units for change"
2421   },
2422   {
2423     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(4),
2424     GADGET_ID_CHANGE_DIRECT_ACTION,     GADGET_ID_NONE,
2425     -1,
2426     options_change_direct_action,
2427     &custom_element_change.direct_action,
2428     NULL, NULL,                         "type of direct action"
2429   },
2430   {
2431     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(5),
2432     GADGET_ID_CHANGE_OTHER_ACTION,      GADGET_ID_NONE,
2433     -1,
2434     options_change_other_action,
2435     &custom_element_change.other_action,
2436     NULL, "element:",                   "type of other element action"
2437   },
2438   {
2439     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(6),
2440     GADGET_ID_CHANGE_SIDE,              GADGET_ID_NONE,
2441     -1,
2442     options_change_trigger_side,
2443     &custom_element_change.trigger_side,
2444     "at", "side",                       "element side triggering change"
2445   },
2446   {
2447     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2448     GADGET_ID_CHANGE_PLAYER,            GADGET_ID_NONE,
2449     -1,
2450     options_change_trigger_player,
2451     &custom_element_change.trigger_player,
2452     "player:", " ",                     "player that causes change"
2453   },
2454   {
2455     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(7),
2456     GADGET_ID_CHANGE_PAGE,              GADGET_ID_CHANGE_PLAYER,
2457     -1,
2458     options_change_trigger_page,
2459     &custom_element_change.trigger_page,
2460     "page:", NULL,                      "change page that causes change"
2461   },
2462   {
2463     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(10),
2464     GADGET_ID_CHANGE_REPLACE_WHEN,      GADGET_ID_NONE,
2465     -1,
2466     options_change_replace_when,
2467     &custom_element_change.replace_when,
2468     "replace when", NULL,               "which elements can be replaced"
2469   },
2470   {
2471     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(13),
2472     GADGET_ID_ACTION_TYPE,              GADGET_ID_NONE,
2473     -1,
2474     options_action_type,
2475     &custom_element_change.action_type,
2476     NULL, NULL,                         "action on specified condition"
2477   },
2478   {
2479     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2480     GADGET_ID_ACTION_MODE,              GADGET_ID_ACTION_TYPE,
2481     -1,
2482     options_action_mode_none,
2483     &custom_element_change.action_mode,
2484     NULL, NULL,                         "action operator"
2485   },
2486   {
2487     -1,                                 ED_ELEMENT_SETTINGS_YPOS(13),
2488     GADGET_ID_ACTION_ARG,               GADGET_ID_ACTION_MODE,
2489     -1,
2490     options_action_arg_none,
2491     &custom_element_change.action_arg,
2492     NULL, NULL,                         "action parameter"
2493   },
2494   {
2495     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(14),
2496     GADGET_ID_SELECT_CHANGE_PAGE,       GADGET_ID_NONE,
2497     3,
2498     options_change_page,
2499     &custom_element.current_change_page,
2500     NULL, NULL,                         "element change page"
2501   },
2502
2503   /* ---------- element settings: configure (group elements) --------------- */
2504
2505   {
2506     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2507     GADGET_ID_GROUP_CHOICE_MODE,        GADGET_ID_NONE,
2508     -1,
2509     options_group_choice_mode,
2510     &group_element_info.choice_mode,
2511     "choice type:", NULL,               "type of group element choice"
2512   },
2513 };
2514
2515 static struct
2516 {
2517   int x, y;
2518   int gadget_id;
2519   int gadget_id_align;
2520   int size;
2521   char *text;
2522   char *text_left, *text_right, *infotext;
2523 } textbutton_info[ED_NUM_TEXTBUTTONS] =
2524 {
2525   {
2526     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(0),
2527     GADGET_ID_LEVELINFO_LEVEL,          GADGET_ID_NONE,
2528     8,                                  "Level",                        
2529     NULL, NULL,                         "Configure level properties"
2530   },
2531   {
2532     -1,                                 -1,
2533     GADGET_ID_LEVELINFO_EDITOR,         GADGET_ID_LEVELINFO_LEVEL,
2534     8,                                  "Editor",                       
2535     NULL, NULL,                         "Configure editor properties"
2536   },
2537   {
2538     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2539     GADGET_ID_PROPERTIES_INFO,          GADGET_ID_NONE,
2540     8,                                  "Info",                 
2541     NULL, NULL,                         "Show information about element"
2542   },
2543   {
2544     -1,                                 -1,
2545     GADGET_ID_PROPERTIES_CONFIG,        GADGET_ID_PROPERTIES_INFO,
2546     8,                                  "Config",
2547     NULL, NULL,                         "Configure element properties"
2548   },
2549   {
2550     -1,                                 -1,
2551     GADGET_ID_PROPERTIES_CONFIG_1,      GADGET_ID_PROPERTIES_INFO,
2552     8,                                  "Config 1",
2553     NULL, NULL,                         "Configure element properties, part 1"
2554   },
2555   {
2556     -1,                                 -1,
2557     GADGET_ID_PROPERTIES_CONFIG_2,      GADGET_ID_PROPERTIES_CONFIG_1,
2558     8,                                  "Config 2",
2559     NULL, NULL,                         "Configure element properties, part 2"
2560   },
2561   {
2562     -1,                                 -1,
2563     GADGET_ID_PROPERTIES_CHANGE,        GADGET_ID_PROPERTIES_CONFIG_2,
2564     8,                                  "Change",
2565     NULL, NULL,                         "Configure custom element change pages"
2566   },
2567   {
2568     -1,                                 -1,
2569     GADGET_ID_SAVE_AS_TEMPLATE,         GADGET_ID_CUSTOM_USE_TEMPLATE,
2570     -1,                                 "Save",
2571     " ", "As Template",                 "Save current settings as new template"
2572   },
2573   {
2574     -1,                                 -1,
2575     GADGET_ID_ADD_CHANGE_PAGE,          GADGET_ID_PASTE_CHANGE_PAGE,
2576     -1,                                 "New",
2577     NULL, NULL,                         "Add new change page"
2578   },
2579   {
2580     -1,                                 -1,
2581     GADGET_ID_DEL_CHANGE_PAGE,          GADGET_ID_ADD_CHANGE_PAGE,
2582     -1,                                 "Delete",
2583     NULL, NULL,                         "Delete current change page"
2584   },
2585 };
2586
2587 static struct
2588 {
2589   int graphic;
2590   int x, y;
2591   int gadget_id;
2592   int gadget_id_align;
2593   char *text_left, *text_right, *infotext;
2594 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
2595 {
2596   {
2597     IMG_EDITOR_COUNTER_DOWN,
2598     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
2599     GADGET_ID_PREV_CHANGE_PAGE,         GADGET_ID_NONE,
2600     NULL, NULL,                         "select previous change page"
2601   },
2602   {
2603     IMG_EDITOR_COUNTER_UP,
2604     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2605     GADGET_ID_NEXT_CHANGE_PAGE,         GADGET_ID_SELECT_CHANGE_PAGE,
2606     NULL, "change page",                "select next change page"
2607   },
2608   {
2609     IMG_GFX_EDITOR_BUTTON_CP_COPY,
2610     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2611     GADGET_ID_COPY_CHANGE_PAGE,         GADGET_ID_NEXT_CHANGE_PAGE,
2612     " ", NULL,                          "copy settings from this change page"
2613   },
2614   {
2615     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
2616     -1,                                 ED_ELEMENT_SETTINGS_YPOS(14),
2617     GADGET_ID_PASTE_CHANGE_PAGE,        GADGET_ID_COPY_CHANGE_PAGE,
2618     NULL, NULL,                         "paste settings to this change page"
2619   },
2620 };
2621
2622 static struct
2623 {
2624   int x, y;
2625 } scrollbutton_pos[ED_NUM_SCROLLBUTTONS];
2626
2627 static struct
2628 {
2629   int graphic;
2630   int gadget_id;
2631   char *infotext;
2632 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
2633 {
2634   {
2635     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
2636     GADGET_ID_SCROLL_UP,
2637     "scroll level editing area up"
2638   },
2639   {
2640     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
2641     GADGET_ID_SCROLL_DOWN,
2642     "scroll level editing area down"
2643   },
2644   {
2645     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
2646     GADGET_ID_SCROLL_LEFT,
2647     "scroll level editing area left"
2648   },
2649   {
2650     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
2651     GADGET_ID_SCROLL_RIGHT,
2652     "scroll level editing area right"
2653   },
2654   {
2655     IMG_EDITOR_PALETTE_SCROLL_UP,
2656     GADGET_ID_SCROLL_LIST_UP,
2657     "scroll element list up ('Page Up')"
2658   },
2659   {
2660     IMG_EDITOR_PALETTE_SCROLL_DOWN,
2661     GADGET_ID_SCROLL_LIST_DOWN,
2662     "scroll element list down ('Page Down')"
2663   },
2664 };
2665
2666 static struct
2667 {
2668   int x, y;
2669   int width, height;
2670   int wheel_x, wheel_y;
2671   int wheel_width, wheel_height;
2672 } scrollbar_pos[ED_NUM_SCROLLBARS];
2673
2674 static struct
2675 {
2676   int graphic;
2677   int type;
2678   int gadget_id;
2679   char *infotext;
2680 } scrollbar_info[ED_NUM_SCROLLBARS] =
2681 {
2682   {
2683     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
2684     GD_TYPE_SCROLLBAR_HORIZONTAL,
2685     GADGET_ID_SCROLL_HORIZONTAL,
2686     "scroll level editing area horizontally"
2687   },
2688   {
2689     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
2690     GD_TYPE_SCROLLBAR_VERTICAL,
2691     GADGET_ID_SCROLL_VERTICAL,
2692     "scroll level editing area vertically"
2693   },
2694   {
2695     IMG_EDITOR_PALETTE_SCROLLBAR,
2696     GD_TYPE_SCROLLBAR_VERTICAL,
2697     GADGET_ID_SCROLL_LIST_VERTICAL,
2698     "scroll element list vertically"
2699   }
2700 };
2701
2702
2703 static struct
2704 {
2705   int x, y;
2706   int gadget_id;
2707   int gadget_id_align;
2708   int radio_button_nr;
2709   int *value;
2710   int checked_value;
2711   char *text_left, *text_right, *infotext;
2712 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
2713 {
2714   {
2715     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
2716     GADGET_ID_RANDOM_PERCENTAGE,        GADGET_ID_LEVEL_RANDOM_UP,
2717     RADIO_NR_RANDOM_ELEMENTS,
2718     &random_placement_method,           RANDOM_USE_PERCENTAGE,
2719     " ", "percentage",                  "use percentage for random elements"
2720   },
2721   {
2722     -1,                                 ED_LEVEL_SETTINGS_YPOS(0),
2723     GADGET_ID_RANDOM_QUANTITY,          GADGET_ID_RANDOM_PERCENTAGE,
2724     RADIO_NR_RANDOM_ELEMENTS,
2725     &random_placement_method,           RANDOM_USE_QUANTITY,
2726     " ", "quantity",                    "use quantity for random elements"
2727   }
2728 };
2729
2730 static struct
2731 {
2732   int x, y;
2733   int gadget_id;
2734   int gadget_id_align;
2735   boolean *value;
2736   char *text_left, *text_right, *infotext;
2737 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
2738 {
2739   /* ---------- level and editor settings ---------------------------------- */
2740
2741   {
2742     ED_LEVEL_SETTINGS_XPOS(0),          ED_LEVEL_SETTINGS_YPOS(1),
2743     GADGET_ID_RANDOM_RESTRICTED,        GADGET_ID_NONE,
2744     &random_placement_background_restricted,
2745     NULL,
2746     "restrict random placement to:",    "set random placement restriction"
2747   },
2748
2749   /* ---------- element settings: configure (various elements) ------------- */
2750
2751   {
2752     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2753     GADGET_ID_STICK_ELEMENT,            GADGET_ID_NONE,
2754     &stick_element_properties_window,
2755     NULL,
2756     "stick this screen to edit content","stick this screen to edit content"
2757   },
2758   {
2759     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2760     GADGET_ID_EM_SLIPPERY_GEMS,         GADGET_ID_NONE,
2761     &level.em_slippery_gems,
2762     NULL,
2763     "slip down from certain flat walls","use EM/DC style slipping behaviour"
2764   },
2765   {
2766     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2767     GADGET_ID_EM_EXPLODES_BY_FIRE,      GADGET_ID_NONE,
2768     &level.em_explodes_by_fire,
2769     NULL,
2770     "explodes with chain reaction",     "use R'n'D style explosion behaviour"
2771   },
2772   {
2773     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2774     GADGET_ID_USE_SPRING_BUG,           GADGET_ID_NONE,
2775     &level.use_spring_bug,
2776     NULL,
2777     "use spring pushing bug",           "use odd spring pushing behaviour"
2778   },
2779   {
2780     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2781     GADGET_ID_USE_TIME_ORB_BUG,         GADGET_ID_NONE,
2782     &level.use_time_orb_bug,
2783     NULL,
2784     "use time orb bug",                 "use odd time orb behaviour"
2785   },
2786   {
2787     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2788     GADGET_ID_RANDOM_BALL_CONTENT,      GADGET_ID_NONE,
2789     &level.ball_random,
2790     NULL,
2791     "create single random element",     "only create one element from content"
2792   },
2793   {
2794     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2795     GADGET_ID_INITIAL_BALL_STATE,       GADGET_ID_NONE,
2796     &level.ball_state_initial,
2797     NULL,
2798     "magic ball initially activated",   "activate magic ball after level start"
2799   },
2800   {
2801     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2802     GADGET_ID_GROW_INTO_DIGGABLE,       GADGET_ID_NONE,
2803     &level.grow_into_diggable,
2804     NULL,
2805     "can grow into anything diggable",  "grow into more than just sand"
2806   },
2807   {
2808     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2809     GADGET_ID_AUTO_EXIT_SOKOBAN,        GADGET_ID_NONE,
2810     &level.auto_exit_sokoban,
2811     NULL,
2812     "exit level if all fields solved",  "automatically finish Sokoban levels"
2813   },
2814   {
2815     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
2816     GADGET_ID_CONTINUOUS_SNAPPING,      GADGET_ID_NONE,
2817     &level.continuous_snapping,
2818     NULL,
2819     "continuous snapping",              "use snapping without releasing key"
2820   },
2821   {
2822     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
2823     GADGET_ID_BLOCK_SNAP_FIELD,         GADGET_ID_NONE,
2824     &level.block_snap_field,
2825     NULL,
2826     "block snapped field when snapping", "use snapping delay to show animation"
2827   },
2828   {
2829     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2830     GADGET_ID_BLOCK_LAST_FIELD,         GADGET_ID_NONE,
2831     &level.block_last_field,
2832     NULL,
2833     "block last field when moving",     "player blocks last field when moving"
2834   },
2835   {
2836     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2837     GADGET_ID_SP_BLOCK_LAST_FIELD,      GADGET_ID_NONE,
2838     &level.sp_block_last_field,
2839     NULL,
2840     "block last field when moving",     "player blocks last field when moving"
2841   },
2842   {
2843     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(3),
2844     GADGET_ID_INSTANT_RELOCATION,       GADGET_ID_NONE,
2845     &level.instant_relocation,
2846     NULL,
2847     "no scrolling when relocating",     "player gets relocated without delay"
2848   },
2849   {
2850     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2851     GADGET_ID_SHIFTED_RELOCATION,       GADGET_ID_NONE,
2852     &level.shifted_relocation,
2853     NULL,
2854     "no centering when relocating",     "level not centered after relocation"
2855   },
2856   {
2857     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(5),
2858     GADGET_ID_LAZY_RELOCATION,          GADGET_ID_NONE,
2859     &level.lazy_relocation,
2860     NULL,
2861     "only redraw off-screen relocation","no redraw if relocation target visible"
2862   },
2863   {
2864     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
2865     GADGET_ID_USE_START_ELEMENT,        GADGET_ID_NONE,
2866     &level.use_start_element[0],
2867     NULL,
2868     "use level start element:",        "start level at this element's position"
2869   },
2870   {
2871     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
2872     GADGET_ID_USE_ARTWORK_ELEMENT,      GADGET_ID_NONE,
2873     &level.use_artwork_element[0],
2874     NULL,
2875     "use artwork from element:",        "use player artwork from other element"
2876   },
2877   {
2878     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(12),
2879     GADGET_ID_USE_EXPLOSION_ELEMENT,    GADGET_ID_NONE,
2880     &level.use_explosion_element[0],
2881     NULL,
2882     "use explosion from element:",      "use explosion properties from element"
2883   },
2884   {
2885     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
2886     GADGET_ID_INITIAL_GRAVITY,          GADGET_ID_NONE,
2887     &level.initial_player_gravity[0],
2888     NULL,
2889     "use initial gravity",              "set initial player gravity"
2890   },
2891   {
2892     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2893     GADGET_ID_USE_INITIAL_INVENTORY,    GADGET_ID_NONE,
2894     &level.use_initial_inventory[0],
2895     NULL,
2896     "use initial inventory:",           "use collected elements on level start"
2897   },
2898   {
2899     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(6),
2900     GADGET_ID_CAN_PASS_TO_WALKABLE,     GADGET_ID_NONE,
2901     &level.can_pass_to_walkable,
2902     NULL,
2903     "can pass to walkable element",     "player can pass to empty or walkable"
2904   },
2905   {
2906     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2907     GADGET_ID_CAN_FALL_INTO_ACID,       GADGET_ID_NONE,
2908     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
2909     NULL,
2910     "can fall into acid (with gravity)","player can fall into acid pool"
2911   },
2912   {
2913     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(0),
2914     GADGET_ID_CAN_MOVE_INTO_ACID,       GADGET_ID_NONE,
2915     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
2916     NULL,
2917     "can move into acid",               "element can move into acid pool"
2918   },
2919   {
2920     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2921     GADGET_ID_DONT_COLLIDE_WITH,        GADGET_ID_NONE,
2922     &custom_element_properties[EP_DONT_COLLIDE_WITH],
2923     NULL,
2924     "deadly when colliding with",       "element is deadly when hitting player"
2925   },
2926   {
2927     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2928     GADGET_ID_ENVELOPE_AUTOWRAP,        GADGET_ID_NONE,
2929     &level.envelope[0].autowrap,
2930     NULL,
2931     "auto-wrap",                        "automatically wrap envelope text"
2932   },
2933   {
2934     -1,                                 ED_ELEMENT_SETTINGS_YPOS(1),
2935     GADGET_ID_ENVELOPE_CENTERED,        GADGET_ID_ENVELOPE_AUTOWRAP,
2936     &level.envelope[0].centered,
2937     " ",
2938     "centered",                         "automatically center envelope text"
2939   },
2940
2941   /* ---------- element settings: configure 1 (custom elements) ----------- */
2942
2943   {
2944     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2945     GADGET_ID_CUSTOM_USE_GRAPHIC,       GADGET_ID_NONE,
2946     &custom_element.use_gfx_element,
2947     NULL,
2948     "use graphic of element:",          "use existing element graphic"
2949   },
2950   {
2951     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(14),
2952     GADGET_ID_CUSTOM_USE_TEMPLATE,      GADGET_ID_NONE,
2953     &level.use_custom_template,
2954     NULL,
2955     "use template",                     "use template for custom properties"
2956   },
2957   {
2958     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(2),
2959     GADGET_ID_CUSTOM_ACCESSIBLE,        GADGET_ID_NONE,
2960     &custom_element_properties[EP_ACCESSIBLE],
2961     NULL,
2962     NULL,                               "player can walk to or pass this field"
2963   },
2964   {
2965     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
2966     GADGET_ID_CUSTOM_GRAV_REACHABLE,    GADGET_ID_NONE,
2967     &custom_element_properties[EP_GRAVITY_REACHABLE],
2968     NULL,
2969     "reachable despite gravity",        "player can walk/dig despite gravity"
2970   },
2971   {
2972     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(11),
2973     GADGET_ID_CUSTOM_USE_LAST_VALUE,    GADGET_ID_NONE,
2974     &custom_element.use_last_ce_value,
2975     NULL,
2976     "use last CE value after change",   "use last CE value after change"
2977   },
2978   {
2979     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(4),
2980     GADGET_ID_CUSTOM_WALK_TO_OBJECT,    GADGET_ID_NONE,
2981     &custom_element_properties[EP_WALK_TO_OBJECT],
2982     NULL,
2983     NULL,                               "player can dig/collect/push element"
2984   },
2985   {
2986     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
2987     GADGET_ID_CUSTOM_INDESTRUCTIBLE,    GADGET_ID_NONE,
2988     &custom_element_properties[EP_INDESTRUCTIBLE],
2989     NULL,
2990     "indestructible",                   "element is indestructible"
2991   },
2992
2993   /* ---------- element settings: configure 2 (custom elements) ----------- */
2994
2995   {
2996     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
2997     GADGET_ID_CUSTOM_CAN_MOVE,          GADGET_ID_NONE,
2998     &custom_element_properties[EP_CAN_MOVE],
2999     NULL,
3000     NULL,                               "element can move with some pattern"
3001   },
3002   {
3003     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(7),
3004     GADGET_ID_CUSTOM_CAN_FALL,          GADGET_ID_NONE,
3005     &custom_element_properties[EP_CAN_FALL],
3006     NULL,
3007     "can fall",                         "element can fall down"
3008   },
3009   {
3010     -1,                                 ED_ELEMENT_SETTINGS_YPOS(7),
3011     GADGET_ID_CUSTOM_CAN_SMASH,         GADGET_ID_CUSTOM_CAN_FALL,
3012     &custom_element_properties[EP_CAN_SMASH],
3013     " ",
3014     NULL,                               "element can smash other elements"
3015   },
3016   {
3017     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(8),
3018     GADGET_ID_CUSTOM_SLIPPERY,          GADGET_ID_NONE,
3019     &custom_element_properties[EP_SLIPPERY],
3020     NULL,
3021     NULL,                               "other elements can fall down from it"
3022   },
3023   {
3024     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(9),
3025     GADGET_ID_CUSTOM_DEADLY,            GADGET_ID_NONE,
3026     &custom_element_properties[EP_DEADLY],
3027     NULL,
3028     NULL,                               "element can kill the player"
3029   },
3030   {
3031     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(10),
3032     GADGET_ID_CUSTOM_CAN_EXPLODE,       GADGET_ID_NONE,
3033     &custom_element_properties[EP_CAN_EXPLODE],
3034     NULL,
3035     NULL,                               "element can explode"
3036   },
3037   {
3038     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(11),
3039     GADGET_ID_CUSTOM_EXPLODE_FIRE,      GADGET_ID_NONE,
3040     &custom_element_properties[EP_EXPLODES_BY_FIRE],
3041     NULL,
3042     "by fire",                          "element can explode by fire/explosion"
3043   },
3044   {
3045     -1,                                 ED_ELEMENT_SETTINGS_YPOS(11),
3046     GADGET_ID_CUSTOM_EXPLODE_SMASH,     GADGET_ID_CUSTOM_EXPLODE_FIRE,
3047     &custom_element_properties[EP_EXPLODES_SMASHED],
3048     " ",
3049     "smashed",                          "element can explode when smashed"
3050   },
3051   {
3052     -1,                                 ED_ELEMENT_SETTINGS_YPOS(11),
3053     GADGET_ID_CUSTOM_EXPLODE_IMPACT,    GADGET_ID_CUSTOM_EXPLODE_SMASH,
3054     &custom_element_properties[EP_EXPLODES_IMPACT],
3055     " ",
3056     "impact",                           "element can explode on impact"
3057   },
3058
3059   /* ---------- element settings: advanced (custom elements) --------------- */
3060
3061   {
3062     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(1),
3063     GADGET_ID_CUSTOM_CAN_CHANGE,        GADGET_ID_NONE,
3064     &custom_element_change.can_change,
3065     NULL,
3066     "element changes to:",              "change element on specified condition"
3067   },
3068   {
3069     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(2),
3070     GADGET_ID_CHANGE_DELAY,             GADGET_ID_NONE,
3071     &custom_element_change_events[CE_DELAY],
3072     NULL,
3073     NULL,                               "element changes after delay"
3074   },
3075   {
3076     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(4),
3077     GADGET_ID_CHANGE_BY_DIRECT_ACT,     GADGET_ID_NONE,
3078     &custom_element_change_events[CE_BY_DIRECT_ACTION],
3079     NULL,
3080     NULL,                               "element changes by direct action"
3081   },
3082   {
3083     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(5),
3084     GADGET_ID_CHANGE_BY_OTHER_ACT,      GADGET_ID_NONE,
3085     &custom_element_change_events[CE_BY_OTHER_ACTION],
3086     NULL,
3087     NULL,                               "element changes by other element"
3088   },
3089   {
3090     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(8),
3091     GADGET_ID_CHANGE_USE_EXPLOSION,     GADGET_ID_NONE,
3092     &custom_element_change.explode,
3093     NULL,
3094     "explode instead of change",        "element explodes instead of change"
3095   },
3096   {
3097     ED_ELEMENT_SETTINGS_XPOS(1),        ED_ELEMENT_SETTINGS_YPOS(9),
3098     GADGET_ID_CHANGE_USE_CONTENT,       GADGET_ID_NONE,
3099     &custom_element_change.use_target_content,
3100     NULL,
3101     "use extended change target:",      "element changes to more elements"
3102   },
3103   {
3104     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(11),
3105     GADGET_ID_CHANGE_ONLY_COMPLETE,     GADGET_ID_NONE,
3106     &custom_element_change.only_if_complete,
3107     NULL,
3108     "replace all or nothing",           "only replace when all can be changed"
3109   },
3110   {
3111     ED_ELEMENT_SETTINGS_XPOS(2),        ED_ELEMENT_SETTINGS_YPOS(12),
3112     GADGET_ID_CHANGE_USE_RANDOM,        GADGET_ID_NONE,
3113     &custom_element_change.use_random_replace,
3114     NULL,
3115     NULL,                               "use percentage for random replace"
3116   },
3117   {
3118     ED_ELEMENT_SETTINGS_XPOS(0),        ED_ELEMENT_SETTINGS_YPOS(13),
3119     GADGET_ID_CHANGE_HAS_ACTION,        GADGET_ID_NONE,
3120     &custom_element_change.has_action,
3121     NULL,
3122     NULL,                               "execute action on specified condition"
3123   },
3124 };
3125
3126 static struct
3127 {
3128   int x, y;
3129   int xoffset, yoffset;
3130   int gadget_id;
3131   int gadget_id_align;
3132   int *value;
3133   int area_xsize, area_ysize;
3134   char *text_left, *text_right, *text_below, *infotext;
3135 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
3136 {
3137   /* ---------- level playfield content ------------------------------------ */
3138
3139   {
3140     0,                                  0,
3141     0,                                  0,
3142     GADGET_ID_DRAWING_LEVEL,            GADGET_ID_NONE,
3143     NULL,
3144     -1, -1,     /* these values are not constant, but can change at runtime */
3145     NULL, NULL, NULL,                   NULL
3146   },
3147
3148   /* ---------- yam yam content -------------------------------------------- */
3149
3150   {
3151     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3152     ED_AREA_YAMYAM_CONTENT_XOFF(0),     ED_AREA_YAMYAM_CONTENT_YOFF(0),
3153     GADGET_ID_YAMYAM_CONTENT_0,         GADGET_ID_NONE,
3154     &level.yamyam_content[0].e[0][0],   3, 3,
3155     NULL, NULL, "1",                    NULL
3156   },
3157   {
3158     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3159     ED_AREA_YAMYAM_CONTENT_XOFF(1),     ED_AREA_YAMYAM_CONTENT_YOFF(1),
3160     GADGET_ID_YAMYAM_CONTENT_1,         GADGET_ID_NONE,
3161     &level.yamyam_content[1].e[0][0],   3, 3,
3162     NULL, NULL, "2",                    NULL
3163   },
3164   {
3165     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3166     ED_AREA_YAMYAM_CONTENT_XOFF(2),     ED_AREA_YAMYAM_CONTENT_YOFF(2),
3167     GADGET_ID_YAMYAM_CONTENT_2,         GADGET_ID_NONE,
3168     &level.yamyam_content[2].e[0][0],   3, 3,
3169     NULL, NULL, "3",                    NULL
3170   },
3171   {
3172     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3173     ED_AREA_YAMYAM_CONTENT_XOFF(3),     ED_AREA_YAMYAM_CONTENT_YOFF(3),
3174     GADGET_ID_YAMYAM_CONTENT_3,         GADGET_ID_NONE,
3175     &level.yamyam_content[3].e[0][0],   3, 3,
3176     NULL, NULL, "4",                    NULL
3177   },
3178   {
3179     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3180     ED_AREA_YAMYAM_CONTENT_XOFF(4),     ED_AREA_YAMYAM_CONTENT_YOFF(4),
3181     GADGET_ID_YAMYAM_CONTENT_4,         GADGET_ID_NONE,
3182     &level.yamyam_content[4].e[0][0],   3, 3,
3183     NULL, NULL, "5",                    NULL
3184   },
3185   {
3186     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3187     ED_AREA_YAMYAM_CONTENT_XOFF(5),     ED_AREA_YAMYAM_CONTENT_YOFF(5),
3188     GADGET_ID_YAMYAM_CONTENT_5,         GADGET_ID_NONE,
3189     &level.yamyam_content[5].e[0][0],   3, 3,
3190     NULL, NULL, "6",                    NULL
3191   },
3192   {
3193     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3194     ED_AREA_YAMYAM_CONTENT_XOFF(6),     ED_AREA_YAMYAM_CONTENT_YOFF(6),
3195     GADGET_ID_YAMYAM_CONTENT_6,         GADGET_ID_NONE,
3196     &level.yamyam_content[6].e[0][0],   3, 3,
3197     NULL, NULL, "7",                    NULL
3198   },
3199   {
3200     ED_AREA_YAMYAM_CONTENT_XPOS,        ED_AREA_YAMYAM_CONTENT_YPOS,
3201     ED_AREA_YAMYAM_CONTENT_XOFF(7),     ED_AREA_YAMYAM_CONTENT_YOFF(7),
3202     GADGET_ID_YAMYAM_CONTENT_7,         GADGET_ID_NONE,
3203     &level.yamyam_content[7].e[0][0],   3, 3,
3204     NULL, NULL, "8",                    NULL
3205   },
3206
3207   /* ---------- magic ball content ----------------------------------------- */
3208
3209   {
3210     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3211     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0), ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
3212     GADGET_ID_MAGIC_BALL_CONTENT_0,     GADGET_ID_NONE,
3213     &level.ball_content[0].e[0][0],     3, 3,
3214     NULL, NULL, "1",                    NULL
3215   },
3216   {
3217     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3218     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1), ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
3219     GADGET_ID_MAGIC_BALL_CONTENT_1,     GADGET_ID_NONE,
3220     &level.ball_content[1].e[0][0],     3, 3,
3221     NULL, NULL, "2",                    NULL
3222   },
3223   {
3224     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3225     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2), ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
3226     GADGET_ID_MAGIC_BALL_CONTENT_2,     GADGET_ID_NONE,
3227     &level.ball_content[2].e[0][0],     3, 3,
3228     NULL, NULL, "3",                    NULL
3229   },
3230   {
3231     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3232     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3), ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
3233     GADGET_ID_MAGIC_BALL_CONTENT_3,     GADGET_ID_NONE,
3234     &level.ball_content[3].e[0][0],     3, 3,
3235     NULL, NULL, "4",                    NULL
3236   },
3237   {
3238     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3239     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4), ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
3240     GADGET_ID_MAGIC_BALL_CONTENT_4,     GADGET_ID_NONE,
3241     &level.ball_content[4].e[0][0],     3, 3,
3242     NULL, NULL, "5",                    NULL
3243   },
3244   {
3245     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3246     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5), ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
3247     GADGET_ID_MAGIC_BALL_CONTENT_5,     GADGET_ID_NONE,
3248     &level.ball_content[5].e[0][0],     3, 3,
3249     NULL, NULL, "6",                    NULL
3250   },
3251   {
3252     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3253     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6), ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
3254     GADGET_ID_MAGIC_BALL_CONTENT_6,     GADGET_ID_NONE,
3255     &level.ball_content[6].e[0][0],     3, 3,
3256     NULL, NULL, "7",                    NULL
3257   },
3258   {
3259     ED_AREA_MAGIC_BALL_CONTENT_XPOS,    ED_AREA_MAGIC_BALL_CONTENT_YPOS,
3260     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7), ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
3261     GADGET_ID_MAGIC_BALL_CONTENT_7,     GADGET_ID_NONE,
3262     &level.ball_content[7].e[0][0],     3, 3,
3263     NULL, NULL, "8",                    NULL
3264   },
3265
3266   /* ---------- android content -------------------------------------------- */
3267
3268   {
3269     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(5),
3270     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3271     GADGET_ID_ANDROID_CONTENT,          GADGET_ID_NONE,
3272     &level.android_clone_element[0],    MAX_ANDROID_ELEMENTS, 1,
3273     "elements:", NULL, NULL,            "elements android can clone"
3274   },
3275
3276   /* ---------- amoeba content --------------------------------------------- */
3277
3278   {
3279     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(3),
3280     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3281     GADGET_ID_AMOEBA_CONTENT,           GADGET_ID_NONE,
3282     &level.amoeba_content,              1, 1,
3283     "content:", NULL, NULL,             "amoeba content"
3284   },
3285
3286   /* ---------- level start element ---------------------------------------- */
3287
3288   {
3289     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(10),
3290     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3291     GADGET_ID_START_ELEMENT,            GADGET_ID_USE_START_ELEMENT,
3292     &level.start_element[0],            1, 1,
3293     NULL, NULL, NULL,                   "level start element"
3294   },
3295
3296   /* ---------- player artwork element ------------------------------------- */
3297
3298   {
3299     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(11),
3300     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3301     GADGET_ID_ARTWORK_ELEMENT,          GADGET_ID_USE_ARTWORK_ELEMENT,
3302     &level.artwork_element[0],          1, 1,
3303     NULL, NULL, NULL,                   "element for player artwork"
3304   },
3305
3306   /* ---------- player explosion element ----------------------------------- */
3307
3308   {
3309     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(12),
3310     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3311     GADGET_ID_EXPLOSION_ELEMENT,        GADGET_ID_USE_EXPLOSION_ELEMENT,
3312     &level.explosion_element[0],        1, 1,
3313     NULL, NULL, NULL,                   "element for player explosion"
3314   },
3315
3316   /* ---------- player initial inventory ----------------------------------- */
3317
3318   {
3319     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3320     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3321     GADGET_ID_INVENTORY_CONTENT,        GADGET_ID_USE_INITIAL_INVENTORY,
3322     &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
3323     NULL, NULL, NULL,                   "content for initial inventory"
3324   },
3325
3326   /* ---------- element settings: configure 1 (custom elements) ----------- */
3327
3328   /* ---------- custom graphic --------------------------------------------- */
3329
3330   {
3331     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3332     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3333     GADGET_ID_CUSTOM_GRAPHIC,           GADGET_ID_CUSTOM_USE_GRAPHIC,
3334     &custom_element.gfx_element_initial,1, 1,
3335     NULL, NULL, NULL,                   "custom graphic element"
3336   },
3337
3338   /* ---------- element settings: configure 2 (custom elements) ----------- */
3339
3340   /* ---------- custom content (when exploding) ---------------------------- */
3341
3342   {
3343     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(10),
3344     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
3345     GADGET_ID_CUSTOM_CONTENT,           GADGET_ID_NONE, /* align three rows */
3346     &custom_element.content.e[0][0],    3, 3,
3347     "content:", NULL, NULL,             NULL
3348   },
3349
3350   /* ---------- custom enter and leave element (when moving) --------------- */
3351
3352   {
3353     ED_AREA_1X1_SETTINGS_XPOS(1),       ED_AREA_1X1_SETTINGS_YPOS(3),
3354     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3355     GADGET_ID_CUSTOM_MOVE_ENTER,        GADGET_ID_NONE,
3356     &custom_element.move_enter_element, 1, 1,
3357     "can dig:", " ", NULL,              "element that can be digged/collected"
3358   },
3359   {
3360     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(3),
3361     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3362     GADGET_ID_CUSTOM_MOVE_LEAVE,        GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
3363     &custom_element.move_leave_element, 1, 1,
3364     NULL, NULL, NULL,                   "element that will be left behind"
3365   },
3366
3367   /* ---------- element settings: advanced (custom elements) --------------- */
3368
3369   /* ---------- custom change target --------------------------------------- */
3370
3371   {
3372     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(1),
3373     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3374     GADGET_ID_CUSTOM_CHANGE_TARGET,     GADGET_ID_CUSTOM_CAN_CHANGE,
3375     &custom_element_change.target_element, 1, 1,
3376     NULL, "after/when:", NULL,          "new target element after change"
3377   },
3378
3379   /* ---------- custom change content (extended change target) ------------- */
3380
3381   {
3382     -1,                                 ED_AREA_3X3_SETTINGS_YPOS(9),
3383     0,                                  ED_AREA_3X3_SETTINGS_YOFF,
3384     GADGET_ID_CUSTOM_CHANGE_CONTENT,    GADGET_ID_NONE, /* align three rows */
3385     &custom_element_change.target_content.e[0][0], 3, 3,
3386     NULL, NULL, NULL,                   "new extended elements after change"
3387   },
3388
3389   /* ---------- custom change trigger (element causing change) ------------- */
3390
3391   {
3392     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(5),
3393     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3394     GADGET_ID_CUSTOM_CHANGE_TRIGGER,    GADGET_ID_CHANGE_OTHER_ACTION,
3395     &custom_element_change.initial_trigger_element, 1, 1,
3396     NULL, NULL, NULL,                   "other element triggering change"
3397   },
3398
3399   /* ---------- custom change action (element used for action) ------------- */
3400
3401   {
3402     -1,                                 ED_AREA_1X1_SETTINGS_YPOS(13),
3403     0,                                  ED_AREA_1X1_SETTINGS_YOFF,
3404     GADGET_ID_CUSTOM_CHANGE_ACTION,     GADGET_ID_ACTION_ARG,
3405     &custom_element_change.action_element, 1, 1,
3406     NULL, NULL, NULL,                   "element used as action parameter"
3407   },
3408
3409   /* ---------- group element content -------------------------------------- */
3410
3411   {
3412     ED_AREA_1X1_SETTINGS_XPOS(0),       ED_AREA_1X1_SETTINGS_YPOS(2),
3413     ED_AREA_1X1_SETTINGS_XOFF,          ED_AREA_1X1_SETTINGS_YOFF,
3414     GADGET_ID_GROUP_CONTENT,            GADGET_ID_NONE,
3415     &group_element_info.element[0],     MAX_ELEMENTS_IN_GROUP, 1,
3416     "content:", NULL, NULL,             NULL
3417   },
3418
3419   /* ---------- random background (for random painting) -------------------- */
3420
3421   {
3422     -1,                                 ED_AREA_1X1_LSETTINGS_YPOS(1),
3423     0,                                  ED_AREA_1X1_LSETTINGS_YOFF,
3424     GADGET_ID_RANDOM_BACKGROUND,        GADGET_ID_RANDOM_RESTRICTED,
3425     &random_placement_background_element, 1, 1,
3426     NULL, NULL, NULL,                   "random placement background"
3427   },
3428 };
3429
3430
3431 /*
3432   -----------------------------------------------------------------------------
3433   some internally used variables
3434   -----------------------------------------------------------------------------
3435 */
3436
3437 /* maximal size of level editor drawing area */
3438 static int MAX_ED_FIELDX, MAX_ED_FIELDY;
3439
3440 /* actual size of level editor drawing area */
3441 static int ed_fieldx, ed_fieldy;
3442
3443 /* actual position of level editor drawing area in level playfield */
3444 static int level_xpos = -1, level_ypos = -1;
3445
3446 /* actual tile size used to display playfield drawing area */
3447 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
3448
3449 #define IN_ED_FIELD(x,y)        IN_FIELD(x, y, ed_fieldx, ed_fieldy)
3450
3451 /* drawing elements on the three mouse buttons */
3452 static int new_element1 = EL_WALL;
3453 static int new_element2 = EL_EMPTY;
3454 static int new_element3 = EL_SAND;
3455
3456 #define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
3457 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
3458                                 (button) == 2 ? new_element2 : \
3459                                 (button) == 3 ? new_element3 : EL_EMPTY)
3460
3461 #define BUTTON_TILE_SIZE(x)     ((x) >= TILESIZE ? TILESIZE : MINI_TILESIZE)
3462
3463 /* forward declaration for internal use */
3464 static void ModifyEditorCounterValue(int, int);
3465 static void ModifyEditorCounterLimits(int, int, int);
3466 static void ModifyEditorSelectboxValue(int, int);
3467 static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
3468 static void ModifyEditorDrawingArea(int, int, int);
3469 static void ModifyEditorElementList();
3470 static void AdjustElementListScrollbar();
3471 static void RedrawDrawingElements();
3472 static void DrawDrawingWindow();
3473 static void DrawLevelInfoWindow();
3474 static void DrawPropertiesWindow();
3475 static void UpdateCustomElementGraphicGadgets();
3476 static boolean checkPropertiesConfig(int);
3477 static void CopyLevelToUndoBuffer(int);
3478 static void HandleDrawingAreas(struct GadgetInfo *);
3479 static void HandleCounterButtons(struct GadgetInfo *);
3480 static void HandleTextInputGadgets(struct GadgetInfo *);
3481 static void HandleTextAreaGadgets(struct GadgetInfo *);
3482 static void HandleSelectboxGadgets(struct GadgetInfo *);
3483 static void HandleTextbuttonGadgets(struct GadgetInfo *);
3484 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
3485 static void HandleRadiobuttons(struct GadgetInfo *);
3486 static void HandleCheckbuttons(struct GadgetInfo *);
3487 static void HandleControlButtons(struct GadgetInfo *);
3488 static void HandleDrawingAreaInfo(struct GadgetInfo *);
3489 static void PrintEditorGadgetInfoText(struct GadgetInfo *);
3490
3491 static int num_editor_gadgets = 0;      /* dynamically determined */
3492
3493 static struct GadgetInfo **level_editor_gadget = NULL;
3494 static int *right_gadget_border = NULL;
3495
3496 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
3497 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
3498 static boolean draw_with_brush = FALSE;
3499 static int properties_element = 0;
3500
3501 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3502 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3503 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
3504 static int undo_buffer_position = 0;
3505 static int undo_buffer_steps = 0;
3506 static int redo_buffer_steps = 0;
3507
3508 static int edit_mode;
3509 static int edit_mode_levelinfo;
3510 static int edit_mode_properties;
3511
3512 static int element_shift = 0;
3513
3514 static int editor_el_players[] =
3515 {
3516   EL_PLAYER_1,
3517   EL_PLAYER_2,
3518   EL_PLAYER_3,
3519   EL_PLAYER_4
3520 };
3521 static int *editor_el_players_ptr = editor_el_players;
3522 static int num_editor_el_players = SIZEOF_ARRAY_INT(editor_el_players);
3523
3524 static int editor_hl_boulderdash[] =
3525 {
3526   EL_INTERNAL_CASCADE_BD_ACTIVE,
3527   EL_CHAR('B'),
3528   EL_CHAR('D'),
3529   EL_EMPTY,
3530 };
3531
3532 static int editor_el_boulderdash[] =
3533 {
3534   EL_EMPTY,
3535   EL_SAND,
3536   EL_BD_ROCK,
3537   EL_BD_DIAMOND,
3538
3539   EL_STEELWALL,
3540   EL_BD_WALL,
3541   EL_BD_EXPANDABLE_WALL,
3542   EL_BD_MAGIC_WALL,
3543
3544   EL_BD_AMOEBA,
3545   EL_BD_BUTTERFLY_UP,
3546   EL_BD_FIREFLY_UP,
3547   EL_EXIT_CLOSED,
3548
3549   EL_BD_BUTTERFLY_LEFT,
3550   EL_BD_FIREFLY_LEFT,
3551   EL_BD_BUTTERFLY_RIGHT,
3552   EL_BD_FIREFLY_RIGHT,
3553
3554   EL_EMPTY,
3555   EL_BD_BUTTERFLY_DOWN,
3556   EL_BD_FIREFLY_DOWN,
3557   EL_EXIT_OPEN,
3558 };
3559 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
3560 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
3561 static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash);
3562 static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash);
3563
3564 static int editor_hl_emerald_mine[] =
3565 {
3566   EL_INTERNAL_CASCADE_EM_ACTIVE,
3567   EL_CHAR('E'),
3568   EL_CHAR('M'),
3569   EL_EMPTY,
3570 };
3571
3572 static int editor_el_emerald_mine[] =
3573 {
3574   EL_SAND,
3575   EL_ROCK,
3576   EL_QUICKSAND_EMPTY,
3577   EL_QUICKSAND_FULL,
3578
3579   EL_STEELWALL,
3580   EL_WALL,
3581   EL_WALL_SLIPPERY,
3582   EL_MAGIC_WALL,
3583
3584   EL_EMERALD,
3585   EL_DIAMOND,
3586   EL_NUT,
3587   EL_BOMB,
3588
3589   EL_WALL_EMERALD,
3590   EL_WALL_DIAMOND,
3591   EL_DYNAMITE,
3592   EL_DYNAMITE_ACTIVE,
3593
3594   EL_YAMYAM,
3595   EL_BUG_UP,
3596   EL_SPACESHIP_UP,
3597   EL_ROBOT,
3598
3599   EL_BUG_LEFT,
3600   EL_SPACESHIP_LEFT,
3601   EL_BUG_RIGHT,
3602   EL_SPACESHIP_RIGHT,
3603
3604   EL_ROBOT_WHEEL,
3605   EL_BUG_DOWN,
3606   EL_SPACESHIP_DOWN,
3607   EL_INVISIBLE_WALL,
3608
3609   EL_ACID_POOL_TOPLEFT,
3610   EL_ACID,
3611   EL_ACID_POOL_TOPRIGHT,
3612   EL_AMOEBA_DROP,
3613
3614   EL_ACID_POOL_BOTTOMLEFT,
3615   EL_ACID_POOL_BOTTOM,
3616   EL_ACID_POOL_BOTTOMRIGHT,
3617   EL_AMOEBA_WET,
3618
3619   EL_EM_KEY_1,
3620   EL_EM_KEY_2,
3621   EL_EM_KEY_3,
3622   EL_EM_KEY_4,
3623
3624   EL_EM_GATE_1,
3625   EL_EM_GATE_2,
3626   EL_EM_GATE_3,
3627   EL_EM_GATE_4,
3628
3629   EL_EM_GATE_1_GRAY,
3630   EL_EM_GATE_2_GRAY,
3631   EL_EM_GATE_3_GRAY,
3632   EL_EM_GATE_4_GRAY,
3633
3634   EL_EM_EXIT_CLOSED,
3635   EL_EM_EXIT_OPEN,
3636   EL_EM_STEEL_EXIT_CLOSED,
3637   EL_EM_STEEL_EXIT_OPEN,
3638 };
3639 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
3640 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
3641 static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine);
3642 static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine);
3643
3644 static int editor_hl_emerald_mine_club[] =
3645 {
3646   EL_INTERNAL_CASCADE_EMC_ACTIVE,
3647   EL_CHAR('E'),
3648   EL_CHAR('M'),
3649   EL_CHAR('C'),
3650 };
3651
3652 static int editor_el_emerald_mine_club[] =
3653 {
3654   EL_EMC_KEY_5,
3655   EL_EMC_KEY_6,
3656   EL_EMC_KEY_7,
3657   EL_EMC_KEY_8,
3658
3659   EL_EMC_GATE_5,
3660   EL_EMC_GATE_6,
3661   EL_EMC_GATE_7,
3662   EL_EMC_GATE_8,
3663
3664   EL_EMC_GATE_5_GRAY,
3665   EL_EMC_GATE_6_GRAY,
3666   EL_EMC_GATE_7_GRAY,
3667   EL_EMC_GATE_8_GRAY,
3668
3669   EL_EMC_STEELWALL_1,
3670   EL_EMC_STEELWALL_2,
3671   EL_EMC_STEELWALL_3,
3672   EL_EMC_STEELWALL_4,
3673
3674   EL_EMC_WALL_13,
3675   EL_EMC_WALL_14,
3676   EL_EMC_WALL_15,
3677   EL_EMC_WALL_16,
3678
3679   EL_EMC_WALL_SLIPPERY_1,
3680   EL_EMC_WALL_SLIPPERY_2,
3681   EL_EMC_WALL_SLIPPERY_3,
3682   EL_EMC_WALL_SLIPPERY_4,
3683
3684   EL_EMC_WALL_1,
3685   EL_EMC_WALL_2,
3686   EL_EMC_WALL_3,
3687   EL_EMC_WALL_4,
3688
3689   EL_EMC_WALL_5,
3690   EL_EMC_WALL_6,
3691   EL_EMC_WALL_7,
3692   EL_EMC_WALL_8,
3693
3694   EL_EMC_WALL_9,
3695   EL_EMC_WALL_10,
3696   EL_EMC_WALL_11,
3697   EL_EMC_WALL_12,
3698
3699   EL_EMC_GRASS,
3700   EL_EMC_FAKE_GRASS,
3701   EL_EMC_PLANT,
3702   EL_EMC_DRIPPER,
3703
3704   EL_EMC_MAGIC_BALL,
3705   EL_EMC_MAGIC_BALL_SWITCH,
3706   EL_SPRING,
3707   EL_EMC_SPRING_BUMPER,
3708
3709   EL_EMC_LENSES,
3710   EL_EMC_MAGNIFIER,
3711   EL_EM_DYNAMITE,
3712   EL_EM_DYNAMITE_ACTIVE,
3713
3714   EL_BALLOON,
3715   EL_YAMYAM_UP,
3716   EL_BALLOON_SWITCH_UP,
3717   EL_BALLOON_SWITCH_ANY,
3718
3719   EL_YAMYAM_LEFT,
3720   EL_BALLOON_SWITCH_LEFT,
3721   EL_YAMYAM_RIGHT,
3722   EL_BALLOON_SWITCH_RIGHT,
3723
3724   EL_EMC_ANDROID,
3725   EL_YAMYAM_DOWN,
3726   EL_BALLOON_SWITCH_DOWN,
3727   EL_BALLOON_SWITCH_NONE,
3728 };
3729 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
3730 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
3731 static int num_editor_hl_emerald_mine_club=SIZEOF_ARRAY_INT(editor_hl_emerald_mine_club);
3732 static int num_editor_el_emerald_mine_club=SIZEOF_ARRAY_INT(editor_el_emerald_mine_club);
3733
3734 static int editor_hl_rnd[] =
3735 {
3736   EL_INTERNAL_CASCADE_RND_ACTIVE,
3737   EL_CHAR('R'),
3738   EL_CHAR('N'),
3739   EL_CHAR('D'),
3740 };
3741
3742 static int editor_el_rnd[] =
3743 {
3744   EL_KEY_1,
3745   EL_KEY_2,
3746   EL_KEY_3,
3747   EL_KEY_4,
3748
3749   EL_GATE_1,
3750   EL_GATE_2,
3751   EL_GATE_3,
3752   EL_GATE_4,
3753
3754   EL_GATE_1_GRAY,
3755   EL_GATE_2_GRAY,
3756   EL_GATE_3_GRAY,
3757   EL_GATE_4_GRAY,
3758
3759   EL_ARROW_LEFT,
3760   EL_ARROW_RIGHT,
3761   EL_ARROW_UP,
3762   EL_ARROW_DOWN,
3763
3764   EL_AMOEBA_DEAD,
3765   EL_AMOEBA_DRY,
3766   EL_AMOEBA_FULL,
3767   EL_GAME_OF_LIFE,
3768
3769   EL_EMERALD_YELLOW,
3770   EL_EMERALD_RED,
3771   EL_EMERALD_PURPLE,
3772   EL_BIOMAZE,
3773
3774   EL_WALL_EMERALD_YELLOW,
3775   EL_WALL_EMERALD_RED,
3776   EL_WALL_EMERALD_PURPLE,
3777   EL_WALL_BD_DIAMOND,
3778
3779   EL_SPEED_PILL,
3780   EL_PACMAN_UP,
3781   EL_TIME_ORB_FULL,
3782   EL_TIME_ORB_EMPTY,
3783
3784   EL_PACMAN_LEFT,
3785   EL_DARK_YAMYAM,
3786   EL_PACMAN_RIGHT,
3787   EL_EMPTY,
3788
3789   EL_BLACK_ORB,
3790   EL_PACMAN_DOWN,
3791   EL_LAMP,
3792   EL_LAMP_ACTIVE,
3793
3794   EL_DYNABOMB_INCREASE_NUMBER,
3795   EL_DYNABOMB_INCREASE_SIZE,
3796   EL_DYNABOMB_INCREASE_POWER,
3797   EL_STONEBLOCK,
3798
3799   EL_MOLE,
3800   EL_PENGUIN,
3801   EL_PIG,
3802   EL_DRAGON,
3803
3804   EL_BUG,
3805   EL_MOLE_UP,
3806   EL_BD_BUTTERFLY,
3807   EL_BD_FIREFLY,
3808
3809   EL_MOLE_LEFT,
3810   EL_SATELLITE,
3811   EL_MOLE_RIGHT,
3812   EL_PACMAN,
3813
3814   EL_SPACESHIP,
3815   EL_MOLE_DOWN,
3816   EL_INVISIBLE_STEELWALL,
3817   EL_INVISIBLE_WALL,
3818
3819   EL_EXPANDABLE_WALL,
3820   EL_EXPANDABLE_WALL_HORIZONTAL,
3821   EL_EXPANDABLE_WALL_VERTICAL,
3822   EL_EXPANDABLE_WALL_ANY,
3823 };
3824 static int *editor_hl_rnd_ptr = editor_hl_rnd;
3825 static int *editor_el_rnd_ptr = editor_el_rnd;
3826 static int num_editor_hl_rnd = SIZEOF_ARRAY_INT(editor_hl_rnd);
3827 static int num_editor_el_rnd = SIZEOF_ARRAY_INT(editor_el_rnd);
3828
3829 static int editor_hl_sokoban[] =
3830 {
3831   EL_INTERNAL_CASCADE_SB_ACTIVE,
3832   EL_CHAR('S'),
3833   EL_CHAR('B'),
3834   EL_EMPTY,
3835 };
3836
3837 static int editor_el_sokoban[] =
3838 {
3839   EL_SOKOBAN_OBJECT,
3840   EL_SOKOBAN_FIELD_EMPTY,
3841   EL_SOKOBAN_FIELD_FULL,
3842   EL_SOKOBAN_FIELD_PLAYER,
3843 };
3844 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
3845 static int *editor_el_sokoban_ptr = editor_el_sokoban;
3846 static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban);
3847 static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban);
3848
3849 static int editor_hl_supaplex[] =
3850 {
3851   EL_INTERNAL_CASCADE_SP_ACTIVE,
3852   EL_CHAR('S'),
3853   EL_CHAR('P'),
3854   EL_EMPTY,
3855 };
3856
3857 static int editor_el_supaplex[] =
3858 {
3859   EL_SP_MURPHY,
3860   EL_EMPTY,
3861   EL_SP_BASE,
3862   EL_SP_BUGGY_BASE,
3863
3864   EL_SP_INFOTRON,
3865   EL_SP_ZONK,
3866   EL_SP_SNIKSNAK,
3867   EL_SP_ELECTRON,
3868
3869   EL_SP_DISK_RED,
3870   EL_SP_DISK_ORANGE,
3871   EL_SP_DISK_YELLOW,
3872   EL_SP_TERMINAL,
3873
3874   EL_SP_EXIT_CLOSED,
3875   EL_SP_PORT_HORIZONTAL,
3876   EL_SP_PORT_VERTICAL,
3877   EL_SP_PORT_ANY,
3878
3879   EL_SP_PORT_LEFT,
3880   EL_SP_PORT_RIGHT,
3881   EL_SP_PORT_UP,
3882   EL_SP_PORT_DOWN,
3883
3884   EL_SP_GRAVITY_PORT_LEFT,
3885   EL_SP_GRAVITY_PORT_RIGHT,
3886   EL_SP_GRAVITY_PORT_UP,
3887   EL_SP_GRAVITY_PORT_DOWN,
3888
3889   EL_SP_GRAVITY_ON_PORT_LEFT,
3890   EL_SP_GRAVITY_ON_PORT_RIGHT,
3891   EL_SP_GRAVITY_ON_PORT_UP,
3892   EL_SP_GRAVITY_ON_PORT_DOWN,
3893
3894   EL_SP_GRAVITY_OFF_PORT_LEFT,
3895   EL_SP_GRAVITY_OFF_PORT_RIGHT,
3896   EL_SP_GRAVITY_OFF_PORT_UP,
3897   EL_SP_GRAVITY_OFF_PORT_DOWN,
3898
3899   EL_SP_HARDWARE_GRAY,
3900   EL_SP_HARDWARE_GREEN,
3901   EL_SP_HARDWARE_BLUE,
3902   EL_SP_HARDWARE_RED,
3903
3904   EL_SP_HARDWARE_BASE_1,
3905   EL_SP_HARDWARE_BASE_2,
3906   EL_SP_HARDWARE_BASE_3,
3907   EL_SP_HARDWARE_BASE_4,
3908
3909   EL_SP_HARDWARE_BASE_5,
3910   EL_SP_HARDWARE_BASE_6,
3911   EL_SP_HARDWARE_YELLOW,
3912   EL_SP_CHIP_TOP,
3913
3914   EL_SP_CHIP_SINGLE,
3915   EL_SP_CHIP_LEFT,
3916   EL_SP_CHIP_RIGHT,
3917   EL_SP_CHIP_BOTTOM,
3918 };
3919 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
3920 static int *editor_el_supaplex_ptr = editor_el_supaplex;
3921 static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex);
3922 static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex);
3923
3924 static int editor_hl_diamond_caves[] =
3925 {
3926   EL_INTERNAL_CASCADE_DC_ACTIVE,
3927   EL_CHAR('D'),
3928   EL_CHAR('C'),
3929   EL_CHAR('2'),
3930 };
3931
3932 static int editor_el_diamond_caves[] =
3933 {
3934   EL_PEARL,
3935   EL_CRYSTAL,
3936   EL_WALL_PEARL,
3937   EL_WALL_CRYSTAL,
3938
3939   EL_CONVEYOR_BELT_1_LEFT,
3940   EL_CONVEYOR_BELT_1_MIDDLE,
3941   EL_CONVEYOR_BELT_1_RIGHT,
3942   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3943
3944   EL_CONVEYOR_BELT_2_LEFT,
3945   EL_CONVEYOR_BELT_2_MIDDLE,
3946   EL_CONVEYOR_BELT_2_RIGHT,
3947   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3948
3949   EL_CONVEYOR_BELT_3_LEFT,
3950   EL_CONVEYOR_BELT_3_MIDDLE,
3951   EL_CONVEYOR_BELT_3_RIGHT,
3952   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3953
3954   EL_CONVEYOR_BELT_4_LEFT,
3955   EL_CONVEYOR_BELT_4_MIDDLE,
3956   EL_CONVEYOR_BELT_4_RIGHT,
3957   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3958
3959   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3960   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3961   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3962   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3963
3964   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3965   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3966   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3967   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3968
3969   EL_TIMEGATE_CLOSED,
3970   EL_TIMEGATE_OPEN,
3971   EL_TIMEGATE_SWITCH,
3972   EL_DC_TIMEGATE_SWITCH,
3973
3974   EL_SWITCHGATE_CLOSED,
3975   EL_SWITCHGATE_OPEN,
3976   EL_SWITCHGATE_SWITCH_UP,
3977   EL_SWITCHGATE_SWITCH_DOWN,
3978
3979   EL_LIGHT_SWITCH,
3980   EL_LIGHT_SWITCH_ACTIVE,
3981   EL_DC_SWITCHGATE_SWITCH_UP,
3982   EL_DC_SWITCHGATE_SWITCH_DOWN,
3983
3984   EL_STEEL_EXIT_CLOSED,
3985   EL_STEEL_EXIT_OPEN,
3986   EL_STEELWALL_SLIPPERY,
3987   EL_INVISIBLE_SAND,
3988
3989   EL_QUICKSAND_FAST_EMPTY,
3990   EL_QUICKSAND_FAST_FULL,
3991   EL_LANDMINE,
3992   EL_DC_LANDMINE,
3993
3994   EL_SHIELD_NORMAL,
3995   EL_SHIELD_DEADLY,
3996   EL_EXTRA_TIME,
3997   EL_DC_MAGIC_WALL,
3998
3999   EL_ENVELOPE_1,
4000   EL_ENVELOPE_2,
4001   EL_ENVELOPE_3,
4002   EL_ENVELOPE_4,
4003
4004   EL_SIGN_RADIOACTIVITY,
4005   EL_SIGN_WHEELCHAIR,
4006   EL_SIGN_PARKING,
4007   EL_SIGN_NO_ENTRY,
4008
4009   EL_SIGN_GIVE_WAY,
4010   EL_SIGN_ENTRY_FORBIDDEN,
4011   EL_SIGN_EMERGENCY_EXIT,
4012   EL_SIGN_YIN_YANG,
4013
4014 #if 0
4015   EL_SIGN_SPERMS,
4016   EL_SIGN_BULLET,
4017   EL_SIGN_HEART,
4018   EL_SIGN_CROSS,
4019
4020   EL_SIGN_FRANKIE,
4021   EL_EMPTY,
4022   EL_EMPTY,
4023   EL_EMPTY,
4024
4025   EL_SPERMS,
4026   EL_BULLET,
4027   EL_HEART,
4028   EL_CROSS,
4029
4030   EL_FRANKIE,
4031   EL_EMPTY,
4032   EL_EMPTY,
4033   EL_EMPTY,
4034 #endif
4035
4036   EL_DC_STEELWALL_2_SINGLE,
4037   EL_DC_STEELWALL_2_TOP,
4038   EL_SIGN_EXCLAMATION,
4039   EL_SIGN_STOP,
4040
4041   EL_DC_STEELWALL_2_LEFT,
4042   EL_DC_STEELWALL_2_MIDDLE,
4043   EL_DC_STEELWALL_2_HORIZONTAL,
4044   EL_DC_STEELWALL_2_RIGHT,
4045
4046   EL_DC_STEELWALL_1_TOPLEFT,
4047   EL_DC_STEELWALL_2_VERTICAL,
4048   EL_DC_STEELWALL_1_TOPRIGHT,
4049   EL_DC_GATE_WHITE,
4050
4051   EL_DC_STEELWALL_1_VERTICAL,
4052   EL_DC_STEELWALL_2_BOTTOM,
4053   EL_DC_KEY_WHITE,
4054   EL_DC_GATE_WHITE_GRAY,
4055
4056   EL_DC_STEELWALL_1_BOTTOMLEFT,
4057   EL_DC_STEELWALL_1_HORIZONTAL,
4058   EL_DC_STEELWALL_1_BOTTOMRIGHT,
4059   EL_DC_GATE_FAKE_GRAY,
4060
4061   EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4062   EL_DC_STEELWALL_1_BOTTOM,
4063   EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4064   EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4065
4066   EL_DC_STEELWALL_1_RIGHT,
4067   EL_EMPTY,
4068   EL_DC_STEELWALL_1_LEFT,
4069   EL_EXPANDABLE_STEELWALL_VERTICAL,
4070
4071   EL_DC_STEELWALL_1_TOPRIGHT_2,
4072   EL_DC_STEELWALL_1_TOP,
4073   EL_DC_STEELWALL_1_TOPLEFT_2,
4074   EL_EXPANDABLE_STEELWALL_ANY,
4075 };
4076 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
4077 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
4078 static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves);
4079 static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves);
4080
4081 static int editor_hl_dx_boulderdash[] =
4082 {
4083   EL_INTERNAL_CASCADE_DX_ACTIVE,
4084   EL_CHAR('D'),
4085   EL_CHAR('X'),
4086   EL_EMPTY,
4087 };
4088
4089 static int editor_el_dx_boulderdash[] =
4090 {
4091   EL_EMPTY,
4092   EL_TUBE_RIGHT_DOWN,
4093   EL_TUBE_HORIZONTAL_DOWN,
4094   EL_TUBE_LEFT_DOWN,
4095
4096   EL_TUBE_HORIZONTAL,
4097   EL_TUBE_VERTICAL_RIGHT,
4098   EL_TUBE_ANY,
4099   EL_TUBE_VERTICAL_LEFT,
4100
4101   EL_TUBE_VERTICAL,
4102   EL_TUBE_RIGHT_UP,
4103   EL_TUBE_HORIZONTAL_UP,
4104   EL_TUBE_LEFT_UP,
4105
4106   EL_TRAP,
4107   EL_DX_SUPABOMB,
4108   EL_EMPTY,
4109   EL_EMPTY
4110 };
4111 static int *editor_hl_dx_boulderdash_ptr = editor_hl_dx_boulderdash;
4112 static int *editor_el_dx_boulderdash_ptr = editor_el_dx_boulderdash;
4113 static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash);
4114 static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash);
4115
4116 static int editor_hl_chars[] =
4117 {
4118   EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4119   EL_CHAR('T'),
4120   EL_CHAR('X'),
4121   EL_CHAR('T'),
4122 };
4123
4124 static int editor_el_chars[] =
4125 {
4126   EL_CHAR(' '),
4127   EL_CHAR('!'),
4128   EL_CHAR('"'),
4129   EL_CHAR('#'),
4130
4131   EL_CHAR('$'),
4132   EL_CHAR('%'),
4133   EL_CHAR('&'),
4134   EL_CHAR('\''),
4135
4136   EL_CHAR('('),
4137   EL_CHAR(')'),
4138   EL_CHAR('*'),
4139   EL_CHAR('+'),
4140
4141   EL_CHAR(','),
4142   EL_CHAR('-'),
4143   EL_CHAR('.'),
4144   EL_CHAR('/'),
4145
4146   EL_CHAR('0'),
4147   EL_CHAR('1'),
4148   EL_CHAR('2'),
4149   EL_CHAR('3'),
4150
4151   EL_CHAR('4'),
4152   EL_CHAR('5'),
4153   EL_CHAR('6'),
4154   EL_CHAR('7'),
4155
4156   EL_CHAR('8'),
4157   EL_CHAR('9'),
4158   EL_CHAR(':'),
4159   EL_CHAR(';'),
4160
4161   EL_CHAR('<'),
4162   EL_CHAR('='),
4163   EL_CHAR('>'),
4164   EL_CHAR('?'),
4165
4166   EL_CHAR('@'),
4167   EL_CHAR('A'),
4168   EL_CHAR('B'),
4169   EL_CHAR('C'),
4170
4171   EL_CHAR('D'),
4172   EL_CHAR('E'),
4173   EL_CHAR('F'),
4174   EL_CHAR('G'),
4175
4176   EL_CHAR('H'),
4177   EL_CHAR('I'),
4178   EL_CHAR('J'),
4179   EL_CHAR('K'),
4180
4181   EL_CHAR('L'),
4182   EL_CHAR('M'),
4183   EL_CHAR('N'),
4184   EL_CHAR('O'),
4185
4186   EL_CHAR('P'),
4187   EL_CHAR('Q'),
4188   EL_CHAR('R'),
4189   EL_CHAR('S'),
4190
4191   EL_CHAR('T'),
4192   EL_CHAR('U'),
4193   EL_CHAR('V'),
4194   EL_CHAR('W'),
4195
4196   EL_CHAR('X'),
4197   EL_CHAR('Y'),
4198   EL_CHAR('Z'),
4199   EL_CHAR('['),
4200
4201   EL_CHAR('\\'),
4202   EL_CHAR(']'),
4203   EL_CHAR('^'),
4204   EL_CHAR('_'),
4205
4206   EL_CHAR(CHAR_BYTE_COPYRIGHT),
4207   EL_CHAR(CHAR_BYTE_UMLAUT_A),
4208   EL_CHAR(CHAR_BYTE_UMLAUT_O),
4209   EL_CHAR(CHAR_BYTE_UMLAUT_U),
4210
4211   EL_CHAR(CHAR_BYTE_DEGREE),
4212   EL_CHAR(CHAR_BYTE_REGISTERED),
4213   EL_CHAR(FONT_ASCII_CURSOR),
4214   EL_CHAR(FONT_ASCII_BUTTON),
4215
4216   EL_CHAR(FONT_ASCII_UP),
4217   EL_CHAR(FONT_ASCII_DOWN),
4218   EL_CHAR(' '),
4219   EL_CHAR(' ')
4220 };
4221 static int *editor_hl_chars_ptr = editor_hl_chars;
4222 static int *editor_el_chars_ptr = editor_el_chars;
4223 static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars);
4224 static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars);
4225
4226 static int editor_hl_steel_chars[] =
4227 {
4228   EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4229   EL_STEEL_CHAR('T'),
4230   EL_STEEL_CHAR('X'),
4231   EL_STEEL_CHAR('T'),
4232 };
4233
4234 static int editor_el_steel_chars[] =
4235 {
4236   EL_STEEL_CHAR(' '),
4237   EL_STEEL_CHAR('!'),
4238   EL_STEEL_CHAR('"'),
4239   EL_STEEL_CHAR('#'),
4240
4241   EL_STEEL_CHAR('$'),
4242   EL_STEEL_CHAR('%'),
4243   EL_STEEL_CHAR('&'),
4244   EL_STEEL_CHAR('\''),
4245
4246   EL_STEEL_CHAR('('),
4247   EL_STEEL_CHAR(')'),
4248   EL_STEEL_CHAR('*'),
4249   EL_STEEL_CHAR('+'),
4250
4251   EL_STEEL_CHAR(','),
4252   EL_STEEL_CHAR('-'),
4253   EL_STEEL_CHAR('.'),
4254   EL_STEEL_CHAR('/'),
4255
4256   EL_STEEL_CHAR('0'),
4257   EL_STEEL_CHAR('1'),
4258   EL_STEEL_CHAR('2'),
4259   EL_STEEL_CHAR('3'),
4260
4261   EL_STEEL_CHAR('4'),
4262   EL_STEEL_CHAR('5'),
4263   EL_STEEL_CHAR('6'),
4264   EL_STEEL_CHAR('7'),
4265
4266   EL_STEEL_CHAR('8'),
4267   EL_STEEL_CHAR('9'),
4268   EL_STEEL_CHAR(':'),
4269   EL_STEEL_CHAR(';'),
4270
4271   EL_STEEL_CHAR('<'),
4272   EL_STEEL_CHAR('='),
4273   EL_STEEL_CHAR('>'),
4274   EL_STEEL_CHAR('?'),
4275
4276   EL_STEEL_CHAR('@'),
4277   EL_STEEL_CHAR('A'),
4278   EL_STEEL_CHAR('B'),
4279   EL_STEEL_CHAR('C'),
4280
4281   EL_STEEL_CHAR('D'),
4282   EL_STEEL_CHAR('E'),
4283   EL_STEEL_CHAR('F'),
4284   EL_STEEL_CHAR('G'),
4285
4286   EL_STEEL_CHAR('H'),
4287   EL_STEEL_CHAR('I'),
4288   EL_STEEL_CHAR('J'),
4289   EL_STEEL_CHAR('K'),
4290
4291   EL_STEEL_CHAR('L'),
4292   EL_STEEL_CHAR('M'),
4293   EL_STEEL_CHAR('N'),
4294   EL_STEEL_CHAR('O'),
4295
4296   EL_STEEL_CHAR('P'),
4297   EL_STEEL_CHAR('Q'),
4298   EL_STEEL_CHAR('R'),
4299   EL_STEEL_CHAR('S'),
4300
4301   EL_STEEL_CHAR('T'),
4302   EL_STEEL_CHAR('U'),
4303   EL_STEEL_CHAR('V'),
4304   EL_STEEL_CHAR('W'),
4305
4306   EL_STEEL_CHAR('X'),
4307   EL_STEEL_CHAR('Y'),
4308   EL_STEEL_CHAR('Z'),
4309   EL_STEEL_CHAR('['),
4310
4311   EL_STEEL_CHAR('\\'),
4312   EL_STEEL_CHAR(']'),
4313   EL_STEEL_CHAR('^'),
4314   EL_STEEL_CHAR('_'),
4315
4316   EL_STEEL_CHAR(CHAR_BYTE_COPYRIGHT),
4317   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_A),
4318   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_O),
4319   EL_STEEL_CHAR(CHAR_BYTE_UMLAUT_U),
4320
4321   EL_STEEL_CHAR(CHAR_BYTE_DEGREE),
4322   EL_STEEL_CHAR(CHAR_BYTE_REGISTERED),
4323   EL_STEEL_CHAR(FONT_ASCII_CURSOR),
4324   EL_STEEL_CHAR(FONT_ASCII_BUTTON),
4325
4326   EL_STEEL_CHAR(FONT_ASCII_UP),
4327   EL_STEEL_CHAR(FONT_ASCII_DOWN),
4328   EL_STEEL_CHAR(' '),
4329   EL_STEEL_CHAR(' ')
4330 };
4331 static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
4332 static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
4333 static int num_editor_hl_steel_chars = SIZEOF_ARRAY_INT(editor_hl_steel_chars);
4334 static int num_editor_el_steel_chars = SIZEOF_ARRAY_INT(editor_el_steel_chars);
4335
4336 static int editor_hl_custom[] =
4337 {
4338   EL_INTERNAL_CASCADE_CE_ACTIVE,
4339   EL_CHAR('C'),
4340   EL_CHAR('E'),
4341   EL_EMPTY,
4342 };
4343
4344 static int editor_el_custom[] =
4345 {
4346   EL_CUSTOM_START + 0,
4347   EL_CUSTOM_START + 1,
4348   EL_CUSTOM_START + 2,
4349   EL_CUSTOM_START + 3,
4350
4351   EL_CUSTOM_START + 4,
4352   EL_CUSTOM_START + 5,
4353   EL_CUSTOM_START + 6,
4354   EL_CUSTOM_START + 7,
4355
4356   EL_CUSTOM_START + 8,
4357   EL_CUSTOM_START + 9,
4358   EL_CUSTOM_START + 10,
4359   EL_CUSTOM_START + 11,
4360
4361   EL_CUSTOM_START + 12,
4362   EL_CUSTOM_START + 13,
4363   EL_CUSTOM_START + 14,
4364   EL_CUSTOM_START + 15,
4365
4366   EL_CUSTOM_START + 16,
4367   EL_CUSTOM_START + 17,
4368   EL_CUSTOM_START + 18,
4369   EL_CUSTOM_START + 19,
4370
4371   EL_CUSTOM_START + 20,
4372   EL_CUSTOM_START + 21,
4373   EL_CUSTOM_START + 22,
4374   EL_CUSTOM_START + 23,
4375
4376   EL_CUSTOM_START + 24,
4377   EL_CUSTOM_START + 25,
4378   EL_CUSTOM_START + 26,
4379   EL_CUSTOM_START + 27,
4380
4381   EL_CUSTOM_START + 28,
4382   EL_CUSTOM_START + 29,
4383   EL_CUSTOM_START + 30,
4384   EL_CUSTOM_START + 31,
4385
4386   EL_CUSTOM_START + 32,
4387   EL_CUSTOM_START + 33,
4388   EL_CUSTOM_START + 34,
4389   EL_CUSTOM_START + 35,
4390
4391   EL_CUSTOM_START + 36,
4392   EL_CUSTOM_START + 37,
4393   EL_CUSTOM_START + 38,
4394   EL_CUSTOM_START + 39,
4395
4396   EL_CUSTOM_START + 40,
4397   EL_CUSTOM_START + 41,
4398   EL_CUSTOM_START + 42,
4399   EL_CUSTOM_START + 43,
4400
4401   EL_CUSTOM_START + 44,
4402   EL_CUSTOM_START + 45,
4403   EL_CUSTOM_START + 46,
4404   EL_CUSTOM_START + 47,
4405
4406   EL_CUSTOM_START + 48,
4407   EL_CUSTOM_START + 49,
4408   EL_CUSTOM_START + 50,
4409   EL_CUSTOM_START + 51,
4410
4411   EL_CUSTOM_START + 52,
4412   EL_CUSTOM_START + 53,
4413   EL_CUSTOM_START + 54,
4414   EL_CUSTOM_START + 55,
4415
4416   EL_CUSTOM_START + 56,
4417   EL_CUSTOM_START + 57,
4418   EL_CUSTOM_START + 58,
4419   EL_CUSTOM_START + 59,
4420
4421   EL_CUSTOM_START + 60,
4422   EL_CUSTOM_START + 61,
4423   EL_CUSTOM_START + 62,
4424   EL_CUSTOM_START + 63,
4425
4426   EL_CUSTOM_START + 64,
4427   EL_CUSTOM_START + 65,
4428   EL_CUSTOM_START + 66,
4429   EL_CUSTOM_START + 67,
4430
4431   EL_CUSTOM_START + 68,
4432   EL_CUSTOM_START + 69,
4433   EL_CUSTOM_START + 70,
4434   EL_CUSTOM_START + 71,
4435
4436   EL_CUSTOM_START + 72,
4437   EL_CUSTOM_START + 73,
4438   EL_CUSTOM_START + 74,
4439   EL_CUSTOM_START + 75,
4440
4441   EL_CUSTOM_START + 76,
4442   EL_CUSTOM_START + 77,
4443   EL_CUSTOM_START + 78,
4444   EL_CUSTOM_START + 79,
4445
4446   EL_CUSTOM_START + 80,
4447   EL_CUSTOM_START + 81,
4448   EL_CUSTOM_START + 82,
4449   EL_CUSTOM_START + 83,
4450
4451   EL_CUSTOM_START + 84,
4452   EL_CUSTOM_START + 85,
4453   EL_CUSTOM_START + 86,
4454   EL_CUSTOM_START + 87,
4455
4456   EL_CUSTOM_START + 88,
4457   EL_CUSTOM_START + 89,
4458   EL_CUSTOM_START + 90,
4459   EL_CUSTOM_START + 91,
4460
4461   EL_CUSTOM_START + 92,
4462   EL_CUSTOM_START + 93,
4463   EL_CUSTOM_START + 94,
4464   EL_CUSTOM_START + 95,
4465
4466   EL_CUSTOM_START + 96,
4467   EL_CUSTOM_START + 97,
4468   EL_CUSTOM_START + 98,
4469   EL_CUSTOM_START + 99,
4470
4471   EL_CUSTOM_START + 100,
4472   EL_CUSTOM_START + 101,
4473   EL_CUSTOM_START + 102,
4474   EL_CUSTOM_START + 103,
4475
4476   EL_CUSTOM_START + 104,
4477   EL_CUSTOM_START + 105,
4478   EL_CUSTOM_START + 106,
4479   EL_CUSTOM_START + 107,
4480
4481   EL_CUSTOM_START + 108,
4482   EL_CUSTOM_START + 109,
4483   EL_CUSTOM_START + 110,
4484   EL_CUSTOM_START + 111,
4485
4486   EL_CUSTOM_START + 112,
4487   EL_CUSTOM_START + 113,
4488   EL_CUSTOM_START + 114,
4489   EL_CUSTOM_START + 115,
4490
4491   EL_CUSTOM_START + 116,
4492   EL_CUSTOM_START + 117,
4493   EL_CUSTOM_START + 118,
4494   EL_CUSTOM_START + 119,
4495
4496   EL_CUSTOM_START + 120,
4497   EL_CUSTOM_START + 121,
4498   EL_CUSTOM_START + 122,
4499   EL_CUSTOM_START + 123,
4500
4501   EL_CUSTOM_START + 124,
4502   EL_CUSTOM_START + 125,
4503   EL_CUSTOM_START + 126,
4504   EL_CUSTOM_START + 127,
4505
4506   EL_CUSTOM_START + 128,
4507   EL_CUSTOM_START + 129,
4508   EL_CUSTOM_START + 130,
4509   EL_CUSTOM_START + 131,
4510
4511   EL_CUSTOM_START + 132,
4512   EL_CUSTOM_START + 133,
4513   EL_CUSTOM_START + 134,
4514   EL_CUSTOM_START + 135,
4515
4516   EL_CUSTOM_START + 136,
4517   EL_CUSTOM_START + 137,
4518   EL_CUSTOM_START + 138,
4519   EL_CUSTOM_START + 139,
4520
4521   EL_CUSTOM_START + 140,
4522   EL_CUSTOM_START + 141,
4523   EL_CUSTOM_START + 142,
4524   EL_CUSTOM_START + 143,
4525
4526   EL_CUSTOM_START + 144,
4527   EL_CUSTOM_START + 145,
4528   EL_CUSTOM_START + 146,
4529   EL_CUSTOM_START + 147,
4530
4531   EL_CUSTOM_START + 148,
4532   EL_CUSTOM_START + 149,
4533   EL_CUSTOM_START + 150,
4534   EL_CUSTOM_START + 151,
4535
4536   EL_CUSTOM_START + 152,
4537   EL_CUSTOM_START + 153,
4538   EL_CUSTOM_START + 154,
4539   EL_CUSTOM_START + 155,
4540
4541   EL_CUSTOM_START + 156,
4542   EL_CUSTOM_START + 157,
4543   EL_CUSTOM_START + 158,
4544   EL_CUSTOM_START + 159,
4545
4546   EL_CUSTOM_START + 160,
4547   EL_CUSTOM_START + 161,
4548   EL_CUSTOM_START + 162,
4549   EL_CUSTOM_START + 163,
4550
4551   EL_CUSTOM_START + 164,
4552   EL_CUSTOM_START + 165,
4553   EL_CUSTOM_START + 166,
4554   EL_CUSTOM_START + 167,
4555
4556   EL_CUSTOM_START + 168,
4557   EL_CUSTOM_START + 169,
4558   EL_CUSTOM_START + 170,
4559   EL_CUSTOM_START + 171,
4560
4561   EL_CUSTOM_START + 172,
4562   EL_CUSTOM_START + 173,
4563   EL_CUSTOM_START + 174,
4564   EL_CUSTOM_START + 175,
4565
4566   EL_CUSTOM_START + 176,
4567   EL_CUSTOM_START + 177,
4568   EL_CUSTOM_START + 178,
4569   EL_CUSTOM_START + 179,
4570
4571   EL_CUSTOM_START + 180,
4572   EL_CUSTOM_START + 181,
4573   EL_CUSTOM_START + 182,
4574   EL_CUSTOM_START + 183,
4575
4576   EL_CUSTOM_START + 184,
4577   EL_CUSTOM_START + 185,
4578   EL_CUSTOM_START + 186,
4579   EL_CUSTOM_START + 187,
4580
4581   EL_CUSTOM_START + 188,
4582   EL_CUSTOM_START + 189,
4583   EL_CUSTOM_START + 190,
4584   EL_CUSTOM_START + 191,
4585
4586   EL_CUSTOM_START + 192,
4587   EL_CUSTOM_START + 193,
4588   EL_CUSTOM_START + 194,
4589   EL_CUSTOM_START + 195,
4590
4591   EL_CUSTOM_START + 196,
4592   EL_CUSTOM_START + 197,
4593   EL_CUSTOM_START + 198,
4594   EL_CUSTOM_START + 199,
4595
4596   EL_CUSTOM_START + 200,
4597   EL_CUSTOM_START + 201,
4598   EL_CUSTOM_START + 202,
4599   EL_CUSTOM_START + 203,
4600
4601   EL_CUSTOM_START + 204,
4602   EL_CUSTOM_START + 205,
4603   EL_CUSTOM_START + 206,
4604   EL_CUSTOM_START + 207,
4605
4606   EL_CUSTOM_START + 208,
4607   EL_CUSTOM_START + 209,
4608   EL_CUSTOM_START + 210,
4609   EL_CUSTOM_START + 211,
4610
4611   EL_CUSTOM_START + 212,
4612   EL_CUSTOM_START + 213,
4613   EL_CUSTOM_START + 214,
4614   EL_CUSTOM_START + 215,
4615
4616   EL_CUSTOM_START + 216,
4617   EL_CUSTOM_START + 217,
4618   EL_CUSTOM_START + 218,
4619   EL_CUSTOM_START + 219,
4620
4621   EL_CUSTOM_START + 220,
4622   EL_CUSTOM_START + 221,
4623   EL_CUSTOM_START + 222,
4624   EL_CUSTOM_START + 223,
4625
4626   EL_CUSTOM_START + 224,
4627   EL_CUSTOM_START + 225,
4628   EL_CUSTOM_START + 226,
4629   EL_CUSTOM_START + 227,
4630
4631   EL_CUSTOM_START + 228,
4632   EL_CUSTOM_START + 229,
4633   EL_CUSTOM_START + 230,
4634   EL_CUSTOM_START + 231,
4635
4636   EL_CUSTOM_START + 232,
4637   EL_CUSTOM_START + 233,
4638   EL_CUSTOM_START + 234,
4639   EL_CUSTOM_START + 235,
4640
4641   EL_CUSTOM_START + 236,
4642   EL_CUSTOM_START + 237,
4643   EL_CUSTOM_START + 238,
4644   EL_CUSTOM_START + 239,
4645
4646   EL_CUSTOM_START + 240,
4647   EL_CUSTOM_START + 241,
4648   EL_CUSTOM_START + 242,
4649   EL_CUSTOM_START + 243,
4650
4651   EL_CUSTOM_START + 244,
4652   EL_CUSTOM_START + 245,
4653   EL_CUSTOM_START + 246,
4654   EL_CUSTOM_START + 247,
4655
4656   EL_CUSTOM_START + 248,
4657   EL_CUSTOM_START + 249,
4658   EL_CUSTOM_START + 250,
4659   EL_CUSTOM_START + 251,
4660
4661   EL_CUSTOM_START + 252,
4662   EL_CUSTOM_START + 253,
4663   EL_CUSTOM_START + 254,
4664   EL_CUSTOM_START + 255
4665 };
4666 static int *editor_hl_custom_ptr = editor_hl_custom;
4667 static int *editor_el_custom_ptr = editor_el_custom;
4668 static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom);
4669 static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
4670
4671 static int editor_hl_group[] =
4672 {
4673   EL_INTERNAL_CASCADE_GE_ACTIVE,
4674   EL_CHAR('G'),
4675   EL_CHAR('E'),
4676   EL_EMPTY,
4677 };
4678
4679 static int editor_el_group[] =
4680 {
4681   EL_GROUP_START + 0,
4682   EL_GROUP_START + 1,
4683   EL_GROUP_START + 2,
4684   EL_GROUP_START + 3,
4685
4686   EL_GROUP_START + 4,
4687   EL_GROUP_START + 5,
4688   EL_GROUP_START + 6,
4689   EL_GROUP_START + 7,
4690
4691   EL_GROUP_START + 8,
4692   EL_GROUP_START + 9,
4693   EL_GROUP_START + 10,
4694   EL_GROUP_START + 11,
4695
4696   EL_GROUP_START + 12,
4697   EL_GROUP_START + 13,
4698   EL_GROUP_START + 14,
4699   EL_GROUP_START + 15,
4700
4701   EL_GROUP_START + 16,
4702   EL_GROUP_START + 17,
4703   EL_GROUP_START + 18,
4704   EL_GROUP_START + 19,
4705
4706   EL_GROUP_START + 20,
4707   EL_GROUP_START + 21,
4708   EL_GROUP_START + 22,
4709   EL_GROUP_START + 23,
4710
4711   EL_GROUP_START + 24,
4712   EL_GROUP_START + 25,
4713   EL_GROUP_START + 26,
4714   EL_GROUP_START + 27,
4715
4716   EL_GROUP_START + 28,
4717   EL_GROUP_START + 29,
4718   EL_GROUP_START + 30,
4719   EL_GROUP_START + 31
4720 };
4721 static int *editor_hl_group_ptr = editor_hl_group;
4722 static int *editor_el_group_ptr = editor_el_group;
4723 static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
4724 static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
4725
4726 static int editor_hl_reference[] =
4727 {
4728   EL_INTERNAL_CASCADE_REF_ACTIVE,
4729   EL_CHAR('R'),
4730   EL_CHAR('E'),
4731   EL_CHAR('F')
4732 };
4733
4734 static int editor_el_reference[] =
4735 {
4736   EL_TRIGGER_PLAYER,
4737   EL_TRIGGER_ELEMENT,
4738   EL_TRIGGER_CE_VALUE,
4739   EL_TRIGGER_CE_SCORE,
4740
4741   EL_SELF,
4742   EL_ANY_ELEMENT,
4743   EL_CURRENT_CE_VALUE,
4744   EL_CURRENT_CE_SCORE,
4745
4746   EL_PREV_CE_8,
4747   EL_PREV_CE_7,
4748   EL_PREV_CE_6,
4749   EL_PREV_CE_5,
4750
4751   EL_PREV_CE_4,
4752   EL_PREV_CE_3,
4753   EL_PREV_CE_2,
4754   EL_PREV_CE_1,
4755
4756   EL_NEXT_CE_1,
4757   EL_NEXT_CE_2,
4758   EL_NEXT_CE_3,
4759   EL_NEXT_CE_4,
4760
4761   EL_NEXT_CE_5,
4762   EL_NEXT_CE_6,
4763   EL_NEXT_CE_7,
4764   EL_NEXT_CE_8,
4765 };
4766 static int *editor_hl_reference_ptr = editor_hl_reference;
4767 static int *editor_el_reference_ptr = editor_el_reference;
4768 static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference);
4769 static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference);
4770
4771 static int editor_hl_user_defined[] =
4772 {
4773   EL_INTERNAL_CASCADE_USER_ACTIVE,
4774   EL_CHAR('M'),
4775   EL_CHAR('Y'),
4776   EL_EMPTY,
4777 };
4778
4779 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
4780 static int *editor_el_user_defined_ptr = NULL;
4781 static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined);
4782 static int num_editor_el_user_defined = 0;
4783
4784 static int editor_hl_dynamic[] =
4785 {
4786   EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4787   EL_CHAR('U'),
4788   EL_CHAR('S'),
4789   EL_CHAR('E'),
4790 };
4791
4792 static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
4793 static int *editor_el_dynamic_ptr = NULL;
4794 static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic);
4795 static int num_editor_el_dynamic = 0;
4796
4797 static int editor_hl_empty[] = { EL_EMPTY };
4798 static int *editor_el_empty = NULL;     /* dynamically allocated */
4799
4800 static int *editor_hl_empty_ptr = editor_hl_empty;
4801 static int *editor_el_empty_ptr = NULL;
4802 static int num_editor_hl_empty = 0;
4803 static int num_editor_el_empty = 0;     /* dynamically determined, if needed */
4804
4805 static boolean use_el_empty = FALSE;
4806
4807 static int *editor_elements = NULL;     /* dynamically allocated */
4808 static int num_editor_elements = 0;     /* dynamically determined */
4809
4810 static boolean setup_editor_show_always = TRUE;
4811 static boolean setup_editor_cascade_never = FALSE;
4812
4813 static int editor_hl_unused[] = { EL_EMPTY };
4814 static int *editor_hl_unused_ptr = editor_hl_unused;
4815 static int num_editor_hl_unused = 0;
4816
4817 static struct
4818 {
4819   boolean *setup_value;
4820   boolean *setup_cascade_value;
4821
4822   int **headline_list;
4823   int *headline_list_size;
4824
4825   int **element_list;
4826   int *element_list_size;
4827
4828   boolean last_setup_value;
4829 }
4830 editor_elements_info[] =
4831 {
4832   {
4833     &setup_editor_show_always,
4834     &setup_editor_cascade_never,
4835     &editor_hl_unused_ptr,              &num_editor_hl_unused,
4836     &editor_el_players_ptr,             &num_editor_el_players
4837   },
4838   {
4839     &setup.editor.el_boulderdash,
4840     &setup.editor_cascade.el_bd,
4841     &editor_hl_boulderdash_ptr,         &num_editor_hl_boulderdash,
4842     &editor_el_boulderdash_ptr,         &num_editor_el_boulderdash
4843   },
4844   {
4845     &setup.editor.el_emerald_mine,
4846     &setup.editor_cascade.el_em,
4847     &editor_hl_emerald_mine_ptr,        &num_editor_hl_emerald_mine,
4848     &editor_el_emerald_mine_ptr,        &num_editor_el_emerald_mine
4849   },
4850   {
4851     &setup.editor.el_emerald_mine_club,
4852     &setup.editor_cascade.el_emc,
4853     &editor_hl_emerald_mine_club_ptr,   &num_editor_hl_emerald_mine_club,
4854     &editor_el_emerald_mine_club_ptr,   &num_editor_el_emerald_mine_club
4855   },
4856   {
4857     &setup.editor.el_more,
4858     &setup.editor_cascade.el_rnd,
4859     &editor_hl_rnd_ptr,                 &num_editor_hl_rnd,
4860     &editor_el_rnd_ptr,                 &num_editor_el_rnd
4861   },
4862   {
4863     &setup.editor.el_sokoban,
4864     &setup.editor_cascade.el_sb,
4865     &editor_hl_sokoban_ptr,             &num_editor_hl_sokoban,
4866     &editor_el_sokoban_ptr,             &num_editor_el_sokoban
4867   },
4868   {
4869     &setup.editor.el_supaplex,
4870     &setup.editor_cascade.el_sp,
4871     &editor_hl_supaplex_ptr,            &num_editor_hl_supaplex,
4872     &editor_el_supaplex_ptr,            &num_editor_el_supaplex
4873   },
4874   {
4875     &setup.editor.el_diamond_caves,
4876     &setup.editor_cascade.el_dc,
4877     &editor_hl_diamond_caves_ptr,       &num_editor_hl_diamond_caves,
4878     &editor_el_diamond_caves_ptr,       &num_editor_el_diamond_caves
4879   },
4880   {
4881     &setup.editor.el_dx_boulderdash,
4882     &setup.editor_cascade.el_dx,
4883     &editor_hl_dx_boulderdash_ptr,      &num_editor_hl_dx_boulderdash,
4884     &editor_el_dx_boulderdash_ptr,      &num_editor_el_dx_boulderdash
4885   },
4886   {
4887     &setup.editor.el_chars,
4888     &setup.editor_cascade.el_chars,
4889     &editor_hl_chars_ptr,               &num_editor_hl_chars,
4890     &editor_el_chars_ptr,               &num_editor_el_chars
4891   },
4892   {
4893     &setup.editor.el_steel_chars,
4894     &setup.editor_cascade.el_steel_chars,
4895     &editor_hl_steel_chars_ptr,         &num_editor_hl_steel_chars,
4896     &editor_el_steel_chars_ptr,         &num_editor_el_steel_chars
4897   },
4898   {
4899     &setup.editor.el_custom,
4900     &setup.editor_cascade.el_ce,
4901     &editor_hl_custom_ptr,              &num_editor_hl_custom,
4902     &editor_el_custom_ptr,              &num_editor_el_custom
4903   },
4904   {
4905     &setup.editor.el_custom,
4906     &setup.editor_cascade.el_ge,
4907     &editor_hl_group_ptr,               &num_editor_hl_group,
4908     &editor_el_group_ptr,               &num_editor_el_group
4909   },
4910   {
4911     &setup.editor.el_custom,
4912     &setup.editor_cascade.el_ref,
4913     &editor_hl_reference_ptr,           &num_editor_hl_reference,
4914     &editor_el_reference_ptr,           &num_editor_el_reference
4915   },
4916   {
4917     &setup.editor.el_user_defined,
4918     &setup.editor_cascade.el_user,
4919     &editor_hl_user_defined_ptr,        &num_editor_hl_user_defined,
4920     &editor_el_user_defined_ptr,        &num_editor_el_user_defined
4921   },
4922   {
4923     &setup.editor.el_dynamic,
4924     &setup.editor_cascade.el_dynamic,
4925     &editor_hl_dynamic_ptr,             &num_editor_hl_dynamic,
4926     &editor_el_dynamic_ptr,             &num_editor_el_dynamic,
4927   },
4928   {
4929     &use_el_empty,
4930     &use_el_empty,
4931     &editor_hl_empty_ptr,               &num_editor_hl_empty,
4932     &editor_el_empty_ptr,               &num_editor_el_empty,
4933   },
4934   {
4935     NULL,
4936     NULL,
4937     NULL,                               NULL,
4938     NULL,                               NULL
4939   }
4940 };
4941
4942
4943 /*
4944   -----------------------------------------------------------------------------
4945   functions
4946   -----------------------------------------------------------------------------
4947 */
4948
4949 static int getMaxInfoTextLength()
4950 {
4951   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
4952 }
4953
4954 static int getTextWidthForGadget(char *text)
4955 {
4956   if (text == NULL)
4957     return 0;
4958
4959   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
4960 }
4961
4962 static int getTextWidthForDrawingArea(char *text)
4963 {
4964   if (text == NULL)
4965     return 0;
4966
4967   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
4968 }
4969
4970 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
4971 {
4972   return (gi->x + gi->width + getTextWidthForGadget(text));
4973 }
4974
4975 static char *getElementInfoText(int element)
4976 {
4977   char *info_text = NULL;
4978
4979   if (element < MAX_NUM_ELEMENTS)
4980   {
4981     if (strlen(element_info[element].description) > 0)
4982       info_text = element_info[element].description;
4983     else if (element_info[element].custom_description != NULL)
4984       info_text = element_info[element].custom_description;
4985     else if (element_info[element].editor_description != NULL)
4986       info_text = element_info[element].editor_description;
4987   }
4988
4989   if (info_text == NULL)
4990     info_text = INFOTEXT_UNKNOWN_ELEMENT;
4991
4992   return info_text;
4993 }
4994
4995 static char *getElementDescriptionFilenameExt(char *basename)
4996 {
4997   char *elements_subdir = "elements";
4998   static char *elements_subdir2 = NULL;
4999   static char *filename = NULL;
5000
5001   if (elements_subdir2 == NULL)
5002     elements_subdir2 = getPath2(DOCS_DIRECTORY, elements_subdir);
5003
5004   checked_free(filename);
5005
5006   /* 1st try: look for element description in current level set directory */
5007   filename = getPath3(getCurrentLevelDir(), elements_subdir2, basename);
5008   if (fileExists(filename))
5009     return filename;
5010
5011   free(filename);
5012
5013   /* 2nd try: look for element description in the game's base directory */
5014   filename = getPath3(options.docs_directory, elements_subdir, basename);
5015   if (fileExists(filename))
5016     return filename;
5017
5018   return NULL;
5019 }
5020
5021 char *getElementDescriptionFilename(int element)
5022 {
5023   char basename[MAX_FILENAME_LEN];
5024   char *filename;
5025
5026   /* 1st try: look for element description file for exactly this element */
5027   sprintf(basename, "%s.txt", element_info[element].token_name);
5028   filename = getElementDescriptionFilenameExt(basename);
5029   if (filename != NULL)
5030     return filename;
5031
5032   /* 2nd try: look for element description file for this element's class */
5033   sprintf(basename, "%s.txt", element_info[element].class_name);
5034   filename = getElementDescriptionFilenameExt(basename);
5035   if (filename != NULL)
5036     return filename;
5037
5038   return NULL;
5039 }
5040
5041 static void InitDynamicEditorElementList(int **elements, int *num_elements)
5042 {
5043   boolean element_found[NUM_FILE_ELEMENTS];
5044   int i, x, y;
5045
5046   /* initialize list of used elements to "not used" */
5047   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5048     element_found[i] = FALSE;
5049
5050   /* find all elements used in current level */
5051   for (y = 0; y < lev_fieldy; y++)
5052     for (x = 0; x < lev_fieldx; x++)
5053       if (Feld[x][y] < NUM_FILE_ELEMENTS)       /* should always be true */
5054         element_found[Feld[x][y]] = TRUE;
5055
5056   *num_elements = 0;
5057
5058   /* count number of elements used in current level */
5059   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5060     if (element_found[i])
5061       (*num_elements)++;
5062
5063   /* add space for up to 3 more elements for padding that may be needed */
5064   *num_elements += 3;
5065
5066   /* free memory for old list of elements, if needed */
5067   checked_free(*elements);
5068
5069   /* allocate memory for new list of elements */
5070   *elements = checked_malloc(*num_elements * sizeof(int));
5071
5072   *num_elements = 0;
5073
5074   /* add all elements used in current level (non-custom/group elements) */
5075   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5076     if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
5077       (*elements)[(*num_elements)++] = i;
5078
5079   /* add all elements used in current level (custom/group elements) */
5080   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5081     if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
5082       (*elements)[(*num_elements)++] = i;
5083
5084   while (*num_elements % 4)     /* pad with empty elements, if needed */
5085     (*elements)[(*num_elements)++] = EL_EMPTY;
5086 }
5087
5088 static void ReinitializeElementList()
5089 {
5090   static boolean initialization_needed = TRUE;
5091   int pos = 0;
5092   int i, j;
5093
5094   if (initialization_needed)
5095   {
5096     LoadSetup_EditorCascade();          /* load last editor cascade state */
5097
5098     /* initialize editor cascade element from saved cascade state */
5099     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5100     {
5101       int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
5102       boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
5103
5104       if (IS_EDITOR_CASCADE(*cascade_element))
5105         *cascade_element =
5106           (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
5107            EL_CASCADE_INACTIVE(*cascade_element));
5108     }
5109
5110     initialization_needed = FALSE;
5111   }
5112
5113   checked_free(editor_elements);
5114
5115   /* reload optional user defined element list for each invocation of editor */
5116   LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
5117                                    &num_editor_el_user_defined);
5118
5119   /* initialize dynamic level element list for each invocation of editor */
5120   InitDynamicEditorElementList(&editor_el_dynamic_ptr,
5121                                &num_editor_el_dynamic);
5122
5123   /* initialize list of empty elements (used for padding, if needed) */
5124   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
5125     editor_el_empty[i] = EL_EMPTY;
5126
5127   /* do some sanity checks for each element from element list */
5128   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5129   {
5130     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
5131     {
5132       int element = (*editor_elements_info[i].element_list)[j];
5133
5134       if (element >= NUM_FILE_ELEMENTS)
5135         Error(ERR_WARN, "editor element %d is runtime element", element);
5136
5137       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
5138         Error(ERR_WARN, "no element description for element %d", element);
5139     }
5140   }
5141
5142   num_editor_elements = 0;
5143   use_el_empty = FALSE;
5144
5145   /* determine size of element list */
5146   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5147   {
5148     boolean found_inactive_cascade = FALSE;
5149
5150     if (*editor_elements_info[i].setup_value)
5151     {
5152       if (setup.editor.el_headlines)
5153       {
5154         // required for correct padding of palette headline buttons
5155         if (*editor_elements_info[i].headline_list_size > 0)
5156           num_editor_elements += editor.palette.cols;
5157
5158         for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
5159         {
5160           int element = (*editor_elements_info[i].headline_list)[j];
5161
5162           if (IS_EDITOR_CASCADE_INACTIVE(element))
5163             found_inactive_cascade = TRUE;
5164         }
5165       }
5166
5167       if (found_inactive_cascade)
5168         continue;
5169
5170       // required for correct padding of palette element buttons
5171       int element_list_size = *editor_elements_info[i].element_list_size;
5172       int element_rows =
5173         (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
5174       int element_buttons = editor.palette.cols * element_rows;
5175
5176       num_editor_elements += element_buttons;
5177     }
5178   }
5179
5180   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
5181   {
5182     /* offer at least as many elements as element buttons exist */
5183     use_el_empty = TRUE;
5184     num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
5185
5186     num_editor_elements += num_editor_el_empty;
5187   }
5188
5189   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
5190
5191   /* fill element list */
5192   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5193   {
5194     boolean found_inactive_cascade = FALSE;
5195
5196     if (*editor_elements_info[i].setup_value)
5197     {
5198       if (setup.editor.el_headlines)
5199       {
5200         // required for correct padding of palette headline buttons
5201         int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
5202                              editor.palette.cols : 0);
5203
5204         for (j = 0; j < headline_size; j++)
5205         {
5206           // use empty elements for padding of palette headline buttons
5207           int element = (j < *editor_elements_info[i].headline_list_size ?
5208                          (*editor_elements_info[i].headline_list)[j] :
5209                          editor_el_empty[0]);
5210
5211           editor_elements[pos++] = element;
5212
5213           if (IS_EDITOR_CASCADE_INACTIVE(element))
5214             found_inactive_cascade = TRUE;
5215         }
5216       }
5217
5218       if (found_inactive_cascade)
5219         continue;
5220
5221       // required for correct padding of palette element buttons
5222       int element_list_size = *editor_elements_info[i].element_list_size;
5223       int element_rows =
5224         (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
5225       int element_buttons = editor.palette.cols * element_rows;
5226
5227       // copy all elements from element list
5228       for (j = 0; j < element_list_size; j++)
5229         editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
5230
5231       // use empty elements for padding of palette element buttons
5232       for (j = 0; j < element_buttons - element_list_size; j++)
5233         editor_elements[pos++] = editor_el_empty[0];
5234     }
5235   }
5236
5237   /* (this function is also called before editor gadgets are initialized!) */
5238   AdjustElementListScrollbar();
5239 }
5240
5241 void PrintEditorElementList()
5242 {
5243   boolean *stop = &setup.editor.el_user_defined;
5244   int i, j;
5245
5246   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
5247   {
5248     int cascade_element = (*editor_elements_info[i].headline_list)[0];
5249
5250     if (IS_EDITOR_CASCADE(cascade_element))
5251     {
5252       int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
5253       char *headline = element_info[cascade_element_show].editor_description;
5254
5255       PrintLineWithPrefix("# ", "-", 77);
5256       Print("# %s\n", headline);
5257       PrintLineWithPrefix("# ", "-", 77);
5258     }
5259
5260     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
5261     {
5262       int element = (*editor_elements_info[i].headline_list)[j];
5263
5264       if (IS_EDITOR_CASCADE(element))
5265         element = EL_CHAR_MINUS;
5266
5267       Print("# %s\n", element_info[element].token_name);
5268     }
5269
5270     if (j > 0)
5271       Print("#\n");
5272
5273     for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
5274     {
5275       int element = (*editor_elements_info[i].element_list)[j];
5276
5277       Print("# %s\n", element_info[element].token_name);
5278     }
5279
5280     if (j > 0)
5281       Print("#\n");
5282   }
5283 }
5284
5285 static void ReinitializeElementListButtons()
5286 {
5287   static boolean last_setup_value_headlines = FALSE;
5288   static boolean initialization_needed = TRUE;
5289   int i;
5290
5291   if (!initialization_needed)   /* check if editor element setup has changed */
5292   {
5293     if (last_setup_value_headlines != setup.editor.el_headlines)
5294       initialization_needed = TRUE;
5295
5296     for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5297       if (editor_elements_info[i].last_setup_value !=
5298           *editor_elements_info[i].setup_value)
5299         initialization_needed = TRUE;
5300   }
5301
5302   if (!initialization_needed)
5303     return;
5304
5305   FreeLevelEditorGadgets();
5306   CreateLevelEditorGadgets();
5307
5308   /* store current setup values for next invocation of this function */
5309   last_setup_value_headlines = setup.editor.el_headlines;
5310   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
5311     editor_elements_info[i].last_setup_value =
5312       *editor_elements_info[i].setup_value;
5313
5314   initialization_needed = FALSE;
5315 }
5316
5317 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
5318                               boolean input)
5319 {
5320   int border_graphic =
5321     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
5322   struct GraphicInfo *g = &graphic_info[border_graphic];
5323   Bitmap *src_bitmap = g->bitmap;
5324   int src_x = g->src_x;
5325   int src_y = g->src_y;
5326   int border_size = g->border_size;
5327   int border_xpos = g->width  - border_size;
5328   int border_ypos = g->height - border_size;
5329   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
5330   int i;
5331
5332   BlitBitmap(src_bitmap, drawto, src_x, src_y,
5333              border_size, border_size,
5334              dest_x - border_size, dest_y - border_size);
5335   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y,
5336              border_size, border_size,
5337              dest_x + width, dest_y - border_size);
5338   BlitBitmap(src_bitmap, drawto, src_x, src_y + border_ypos,
5339              border_size, border_size,
5340              dest_x - border_size, dest_y + height);
5341   BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_ypos,
5342              border_size, border_size,
5343              dest_x + width, dest_y + height);
5344
5345   for (i = 0; i < width / tilesize; i++)
5346   {
5347     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y,
5348                tilesize, border_size,
5349                dest_x + i * tilesize, dest_y - border_size);
5350     BlitBitmap(src_bitmap, drawto, src_x + border_size, src_y + border_ypos,
5351                tilesize, border_size,
5352                dest_x + i * tilesize, dest_y + height);
5353   }
5354
5355   for (i = 0; i < height / tilesize; i++)
5356   {
5357     BlitBitmap(src_bitmap, drawto, src_x, src_y + border_size,
5358                border_size, tilesize,
5359                dest_x - border_size, dest_y + i * tilesize);
5360     BlitBitmap(src_bitmap, drawto, src_x + border_xpos, src_y + border_size,
5361                border_size, tilesize,
5362                dest_x + width, dest_y + i * tilesize);
5363   }
5364
5365   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
5366 }
5367
5368 static void DrawEditorElement(int x, int y, int element)
5369 {
5370   DrawSizedElement(x, y, element, ed_tilesize);
5371 }
5372
5373 static void DrawEditorElementOrWall(int x, int y, int scroll_x, int scroll_y)
5374 {
5375   DrawSizedElementOrWall(x, y, scroll_x, scroll_y, ed_tilesize);
5376 }
5377
5378 static void DrawEditorLevel(int size_x, int size_y, int scroll_x, int scroll_y)
5379 {
5380   DrawSizedLevel(size_x, size_y, scroll_x, scroll_y, ed_tilesize);
5381 }
5382
5383 static void DrawDrawingArea(int id)
5384 {
5385   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
5386   int x, y;
5387
5388   int *value = drawingarea_info[id].value;
5389   int area_xsize = drawingarea_info[id].area_xsize;
5390   int area_ysize = drawingarea_info[id].area_ysize;
5391   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
5392
5393   for (x = 0; x < area_xsize; x++)
5394     for (y = 0; y < area_ysize; y++)
5395       DrawSizedGraphicExt(drawto,
5396                           gi->x + x * tilesize,
5397                           gi->y + y * tilesize,
5398                           el2edimg(value[x * area_ysize + y]), 0, tilesize);
5399 }
5400
5401 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
5402 {
5403   int x, y;
5404   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
5405   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
5406
5407   BlitBitmap(drawto, drawto,
5408              SX + (dx == -1 ? ed_tilesize : 0),
5409              SY + (dy == -1 ? ed_tilesize : 0),
5410              (ed_fieldx * ed_tilesize) - (dx != 0 ? ed_tilesize : 0),
5411              (ed_fieldy * ed_tilesize) - (dy != 0 ? ed_tilesize : 0),
5412              SX + (dx == +1 ? ed_tilesize : 0),
5413              SY + (dy == +1 ? ed_tilesize : 0));
5414
5415   if (dx)
5416   {
5417     x = (dx == 1 ? 0 : ed_fieldx - 1);
5418     for (y = 0; y < ed_fieldy; y++)
5419       DrawEditorElementOrWall(x, y, from_x, from_y);
5420   }
5421   else if (dy)
5422   {
5423     y = (dy == 1 ? 0 : ed_fieldy - 1);
5424     for (x = 0; x < ed_fieldx; x++)
5425       DrawEditorElementOrWall(x, y, from_x, from_y);
5426   }
5427
5428   redraw_mask |= REDRAW_FIELD;
5429   BackToFront();
5430 }
5431
5432 void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
5433                             int *x, int *y)
5434 {
5435   getSizedGraphicSource(el2edimg(element), 0, tile_size, bitmap, x, y);
5436 }
5437
5438 static void CreateControlButtons()
5439 {
5440   struct GadgetInfo *gi;
5441   int i;
5442
5443   /* create toolbox buttons */
5444   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
5445   {
5446     int id = controlbutton_info[i].gadget_id;
5447     int type = controlbutton_info[i].gadget_type;
5448     int graphic = controlbutton_info[i].graphic;
5449     struct XYTileSize *pos = controlbutton_info[i].pos;
5450     struct GraphicInfo *gd = &graphic_info[graphic];
5451     Bitmap *deco_bitmap = NULL;
5452     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5453     int tile_size = 0, deco_shift = 0;
5454     int gd_x1 = gd->src_x;
5455     int gd_y1 = gd->src_y;
5456     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5457     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5458     int gd_x1a = gd->src_x + gd->active_xoffset;
5459     int gd_y1a = gd->src_y + gd->active_yoffset;
5460     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
5461     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
5462     int x = pos->x;
5463     int y = pos->y;
5464     unsigned int event_mask;
5465     int radio_button_nr = RADIO_NR_NONE;
5466     boolean checked = FALSE;
5467
5468     if (type == GD_TYPE_RADIO_BUTTON)
5469     {
5470       event_mask = GD_EVENT_PRESSED;
5471       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
5472
5473       if (id == drawing_function)
5474         checked = TRUE;
5475     }
5476     else
5477     {
5478       if (id == GADGET_ID_WRAP_LEFT ||
5479           id == GADGET_ID_WRAP_RIGHT ||
5480           id == GADGET_ID_WRAP_UP ||
5481           id == GADGET_ID_WRAP_DOWN)
5482         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5483       else
5484         event_mask = GD_EVENT_RELEASED;
5485     }
5486
5487     if (id == GADGET_ID_PROPERTIES)
5488     {
5489       x += DX;
5490       y += DY;
5491     }
5492     else if (id == GADGET_ID_ELEMENT_LEFT ||
5493              id == GADGET_ID_ELEMENT_MIDDLE ||
5494              id == GADGET_ID_ELEMENT_RIGHT)
5495     {
5496       x += DX;
5497       y += DY;
5498
5499       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
5500                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
5501                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
5502
5503       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
5504                                    editor.button.element_left.tile_size :
5505                                    id == GADGET_ID_ELEMENT_MIDDLE ?
5506                                    editor.button.element_middle.tile_size :
5507                                    id == GADGET_ID_ELEMENT_RIGHT ?
5508                                    editor.button.element_right.tile_size : 0);
5509
5510       // make sure that decoration does not overlap gadget border
5511       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
5512
5513       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
5514
5515       deco_xpos = (gd->width  - tile_size) / 2;
5516       deco_ypos = (gd->height - tile_size) / 2;
5517       deco_shift = 1;
5518     }
5519     else
5520     {
5521       x += EX;
5522       y += EY;
5523     }
5524
5525     gi = CreateGadget(GDI_CUSTOM_ID, id,
5526                       GDI_CUSTOM_TYPE_ID, i,
5527                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
5528                       GDI_X, x,
5529                       GDI_Y, y,
5530                       GDI_WIDTH, gd->width,
5531                       GDI_HEIGHT, gd->height,
5532                       GDI_TYPE, type,
5533                       GDI_STATE, GD_BUTTON_UNPRESSED,
5534                       GDI_RADIO_NR, radio_button_nr,
5535                       GDI_CHECKED, checked,
5536                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5537                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5538                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
5539                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
5540                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5541                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5542                       GDI_DECORATION_SIZE, tile_size, tile_size,
5543                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
5544                       GDI_EVENT_MASK, event_mask,
5545                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5546                       GDI_CALLBACK_ACTION, HandleControlButtons,
5547                       GDI_END);
5548
5549     if (gi == NULL)
5550       Error(ERR_EXIT, "cannot create gadget");
5551
5552     level_editor_gadget[id] = gi;
5553   }
5554
5555   /* these values are not constant, but can change at runtime */
5556   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
5557   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
5558   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
5559   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
5560   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
5561   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
5562   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
5563   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
5564   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
5565   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
5566   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
5567   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
5568
5569   /* create buttons for scrolling of drawing area and element list */
5570   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
5571   {
5572     int id = scrollbutton_info[i].gadget_id;
5573     int graphic = scrollbutton_info[i].graphic;
5574     struct GraphicInfo *gd = &graphic_info[graphic];
5575     Bitmap *gd_bitmap = gd->bitmap;
5576     int gd_x1 = gd->src_x;
5577     int gd_y1 = gd->src_y;
5578     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5579     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5580     int width  = gd->width;
5581     int height = gd->height;
5582     int x = scrollbutton_pos[i].x;
5583     int y = scrollbutton_pos[i].y;
5584     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5585
5586     if (id == GADGET_ID_SCROLL_LIST_UP ||
5587         id == GADGET_ID_SCROLL_LIST_DOWN)
5588     {
5589       x += DX;
5590       y += DY;
5591     }
5592     else
5593     {
5594       x += SX;
5595       y += SY;
5596     }
5597
5598     gi = CreateGadget(GDI_CUSTOM_ID, id,
5599                       GDI_CUSTOM_TYPE_ID, i,
5600                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5601                       GDI_X, x,
5602                       GDI_Y, y,
5603                       GDI_WIDTH, width,
5604                       GDI_HEIGHT, height,
5605                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5606                       GDI_STATE, GD_BUTTON_UNPRESSED,
5607                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5608                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5609                       GDI_EVENT_MASK, event_mask,
5610                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5611                       GDI_CALLBACK_ACTION, HandleControlButtons,
5612                       GDI_END);
5613
5614     if (gi == NULL)
5615       Error(ERR_EXIT, "cannot create gadget");
5616
5617     level_editor_gadget[id] = gi;
5618   }
5619
5620   /* create buttons for element list */
5621   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
5622   {
5623     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
5624     int graphic = IMG_EDITOR_PALETTE_BUTTON;
5625     struct GraphicInfo *gd = &graphic_info[graphic];
5626     Bitmap *gd_bitmap = gd->bitmap;
5627     Bitmap *deco_bitmap;
5628     int deco_x, deco_y, deco_xpos, deco_ypos;
5629     int gd_x1 = gd->src_x;
5630     int gd_y1 = gd->src_y;
5631     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5632     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5633     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
5634     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
5635     int x = DX + ED_ELEMENTLIST_XPOS + xx * gd->width;
5636     int y = DY + ED_ELEMENTLIST_YPOS + yy * gd->height;
5637     int element = editor_elements[i];
5638     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
5639     unsigned int event_mask = GD_EVENT_RELEASED;
5640
5641     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
5642
5643     deco_xpos = (gd->width  - tile_size) / 2;
5644     deco_ypos = (gd->height - tile_size) / 2;
5645
5646     gi = CreateGadget(GDI_CUSTOM_ID, id,
5647                       GDI_CUSTOM_TYPE_ID, i,
5648                       GDI_INFO_TEXT, getElementInfoText(element),
5649                       GDI_X, x,
5650                       GDI_Y, y,
5651                       GDI_WIDTH, gd->width,
5652                       GDI_HEIGHT, gd->height,
5653                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5654                       GDI_STATE, GD_BUTTON_UNPRESSED,
5655                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5656                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5657                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5658                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5659                       GDI_DECORATION_SIZE, tile_size, tile_size,
5660                       GDI_DECORATION_SHIFTING, 1, 1,
5661                       GDI_EVENT_MASK, event_mask,
5662                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5663                       GDI_CALLBACK_ACTION, HandleControlButtons,
5664                       GDI_END);
5665
5666     if (gi == NULL)
5667       Error(ERR_EXIT, "cannot create gadget");
5668
5669     level_editor_gadget[id] = gi;
5670   }
5671 }
5672
5673 static void CreateCounterButtons()
5674 {
5675   int max_infotext_len = getMaxInfoTextLength();
5676   int i;
5677
5678   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
5679   {
5680     int j;
5681     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); /* down count button */
5682     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
5683
5684     /* determine horizontal position to the right of specified gadget */
5685     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
5686       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
5687            ED_GADGET_TEXT_DISTANCE);
5688
5689     /* determine horizontal offset for leading text */
5690     if (counterbutton_info[i].text_left != NULL)
5691       x += getTextWidthForGadget(counterbutton_info[i].text_left);
5692
5693     for (j = 0; j < 2; j++)
5694     {
5695       struct GadgetInfo *gi;
5696       int id = (j == 0 ?
5697                 counterbutton_info[i].gadget_id_down :
5698                 counterbutton_info[i].gadget_id_up);
5699       int graphic;
5700       struct GraphicInfo *gd;
5701       int gd_x1, gd_x2, gd_y1, gd_y2;
5702       unsigned int event_mask;
5703       char infotext[max_infotext_len + 1];
5704
5705       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5706
5707       if (i == ED_COUNTER_ID_SELECT_LEVEL)
5708       {
5709         graphic = (j == 0 ?
5710                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
5711                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
5712
5713         event_mask |= GD_EVENT_RELEASED;
5714
5715         if (j == 0)
5716         {
5717           x = DX + editor.button.prev_level.x;
5718           y = DY + editor.button.prev_level.y;
5719         }
5720         else
5721         {
5722           x = DX + editor.button.next_level.x;
5723           y = DY + editor.button.next_level.y;
5724         }
5725       }
5726       else
5727       {
5728         graphic = (j == 0 ?
5729                    IMG_EDITOR_COUNTER_DOWN :
5730                    IMG_EDITOR_COUNTER_UP);
5731       }
5732
5733       gd = &graphic_info[graphic];
5734
5735       gd_x1 = gd->src_x;
5736       gd_y1 = gd->src_y;
5737       gd_x2 = gd->src_x + gd->pressed_xoffset;
5738       gd_y2 = gd->src_y + gd->pressed_yoffset;
5739
5740       sprintf(infotext, "%s counter value by 1, 5 or 10",
5741               (j == 0 ? "decrease" : "increase"));
5742
5743       gi = CreateGadget(GDI_CUSTOM_ID, id,
5744                         GDI_CUSTOM_TYPE_ID, i,
5745                         GDI_INFO_TEXT, infotext,
5746                         GDI_X, x,
5747                         GDI_Y, y,
5748                         GDI_WIDTH, gd->width,
5749                         GDI_HEIGHT, gd->height,
5750                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5751                         GDI_STATE, GD_BUTTON_UNPRESSED,
5752                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5753                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5754                         GDI_EVENT_MASK, event_mask,
5755                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5756                         GDI_CALLBACK_ACTION, HandleCounterButtons,
5757                         GDI_END);
5758
5759       if (gi == NULL)
5760         Error(ERR_EXIT, "cannot create gadget");
5761
5762       level_editor_gadget[id] = gi;
5763       right_gadget_border[id] =
5764         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5765
5766       x += gi->width + ED_GADGET_SMALL_DISTANCE;        /* text count button */
5767
5768       if (j == 0)
5769       {
5770         int font_type = FONT_INPUT_1;
5771         int font_type_active = FONT_INPUT_1_ACTIVE;
5772
5773         id = counterbutton_info[i].gadget_id_text;
5774
5775         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5776
5777         if (i == ED_COUNTER_ID_SELECT_LEVEL)
5778         {
5779           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
5780
5781           font_type = FONT_LEVEL_NUMBER;
5782           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
5783
5784           x = DX + editor.input.level_number.x;
5785           y = DY + editor.input.level_number.y;
5786         }
5787         else
5788         {
5789           graphic = IMG_EDITOR_COUNTER_INPUT;
5790         }
5791
5792         gd = &graphic_info[graphic];
5793
5794         gd_x1 = gd->src_x;
5795         gd_y1 = gd->src_y;
5796         gd_x2 = gd->src_x + gd->active_xoffset;
5797         gd_y2 = gd->src_y + gd->active_yoffset;
5798
5799         gi = CreateGadget(GDI_CUSTOM_ID, id,
5800                           GDI_CUSTOM_TYPE_ID, i,
5801                           GDI_INFO_TEXT, "enter counter value",
5802                           GDI_X, x,
5803                           GDI_Y, y,
5804                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
5805                           GDI_NUMBER_VALUE, 0,
5806                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
5807                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
5808                           GDI_TEXT_SIZE, 3,     /* minimal counter text size */
5809                           GDI_TEXT_FONT, font_type,
5810                           GDI_TEXT_FONT_ACTIVE, font_type_active,
5811                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5812                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5813                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5814                           GDI_DESIGN_WIDTH, gd->width,
5815                           GDI_EVENT_MASK, event_mask,
5816                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5817                           GDI_CALLBACK_ACTION, HandleCounterButtons,
5818                           GDI_END);
5819
5820         if (gi == NULL)
5821           Error(ERR_EXIT, "cannot create gadget");
5822
5823         level_editor_gadget[id] = gi;
5824         right_gadget_border[id] =
5825           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5826
5827         x += gi->width + ED_GADGET_SMALL_DISTANCE;      /* up count button */
5828       }
5829     }
5830   }
5831 }
5832
5833 static void CreateDrawingAreas()
5834 {
5835   int i;
5836
5837   /* these values are not constant, but can change at runtime */
5838   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
5839   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
5840
5841   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
5842   {
5843     struct GadgetInfo *gi;
5844     unsigned int event_mask;
5845     int id = drawingarea_info[i].gadget_id;
5846     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
5847     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
5848     int area_xsize = drawingarea_info[i].area_xsize;
5849     int area_ysize = drawingarea_info[i].area_ysize;
5850     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
5851                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
5852
5853     event_mask =
5854       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
5855       GD_EVENT_OFF_BORDERS;
5856
5857     /* determine horizontal position to the right of specified gadget */
5858     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
5859       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
5860            ED_DRAWINGAREA_TEXT_DISTANCE);
5861
5862     /* determine horizontal offset for leading text */
5863     if (drawingarea_info[i].text_left != NULL)
5864       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
5865
5866     gi = CreateGadget(GDI_CUSTOM_ID, id,
5867                       GDI_CUSTOM_TYPE_ID, i,
5868                       GDI_X, x,
5869                       GDI_Y, y,
5870                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
5871                       GDI_AREA_SIZE, area_xsize, area_ysize,
5872                       GDI_ITEM_SIZE, item_size, item_size,
5873                       GDI_EVENT_MASK, event_mask,
5874                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
5875                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
5876                       GDI_END);
5877
5878     if (gi == NULL)
5879       Error(ERR_EXIT, "cannot create gadget");
5880
5881     level_editor_gadget[id] = gi;
5882     right_gadget_border[id] =
5883       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
5884   }
5885 }
5886
5887 static void CreateTextInputGadgets()
5888 {
5889   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
5890   int max_infotext_len = getMaxInfoTextLength();
5891   int i;
5892
5893   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
5894   {
5895     int gd_x1 = gd->src_x;
5896     int gd_y1 = gd->src_y;
5897     int gd_x2 = gd->src_x + gd->active_xoffset;
5898     int gd_y2 = gd->src_y + gd->active_yoffset;
5899     struct GadgetInfo *gi;
5900     unsigned int event_mask;
5901     char infotext[MAX_OUTPUT_LINESIZE + 1];
5902     int id = textinput_info[i].gadget_id;
5903     int x, y;
5904
5905     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
5906     {
5907       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
5908       int border_size = gd->border_size;
5909       int font_nr = FONT_INPUT_1;
5910       int font_height = getFontHeight(font_nr);
5911       int xoffset = element_border + TILEX + element_border + 3 * border_size;
5912       int yoffset = element_border + (TILEY - font_height) / 2;
5913
5914       x = (editor.settings.element_name.x != -1 ?
5915            editor.settings.element_name.x :
5916            editor.settings.element_graphic.x + xoffset) - border_size;
5917       y = (editor.settings.element_name.y != -1 ?
5918            editor.settings.element_name.y :
5919            editor.settings.element_graphic.y + yoffset) - border_size;
5920     }
5921     else
5922     {
5923       x = ED_SETTINGS_X(textinput_info[i].x);
5924       y = ED_SETTINGS_Y(textinput_info[i].y);
5925     }
5926
5927     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5928
5929     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
5930     infotext[max_infotext_len] = '\0';
5931
5932     gi = CreateGadget(GDI_CUSTOM_ID, id,
5933                       GDI_CUSTOM_TYPE_ID, i,
5934                       GDI_INFO_TEXT, infotext,
5935                       GDI_X, SX + x,
5936                       GDI_Y, SY + y,
5937                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
5938                       GDI_TEXT_VALUE, textinput_info[i].value,
5939                       GDI_TEXT_SIZE, textinput_info[i].size,
5940                       GDI_TEXT_FONT, FONT_INPUT_1,
5941                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5942                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5943                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5944                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5945                       GDI_DESIGN_WIDTH, gd->width,
5946                       GDI_EVENT_MASK, event_mask,
5947                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5948                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
5949                       GDI_END);
5950
5951     if (gi == NULL)
5952       Error(ERR_EXIT, "cannot create gadget");
5953
5954     level_editor_gadget[id] = gi;
5955   }
5956 }
5957
5958 static void CreateTextAreaGadgets()
5959 {
5960   int max_infotext_len = getMaxInfoTextLength();
5961   int i;
5962
5963   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
5964   {
5965     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
5966     int gd_x1 = gd->src_x;
5967     int gd_y1 = gd->src_y;
5968     int gd_x2 = gd->src_x + gd->active_xoffset;
5969     int gd_y2 = gd->src_y + gd->active_yoffset;
5970     struct GadgetInfo *gi;
5971     unsigned int event_mask;
5972     char infotext[MAX_OUTPUT_LINESIZE + 1];
5973     int id = textarea_info[i].gadget_id;
5974     int area_xsize = textarea_info[i].xsize;
5975     int area_ysize = textarea_info[i].ysize;
5976
5977     event_mask = GD_EVENT_TEXT_LEAVING;
5978
5979     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
5980     infotext[max_infotext_len] = '\0';
5981
5982     gi = CreateGadget(GDI_CUSTOM_ID, id,
5983                       GDI_CUSTOM_TYPE_ID, i,
5984                       GDI_INFO_TEXT, infotext,
5985                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
5986                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
5987                       GDI_TYPE, GD_TYPE_TEXT_AREA,
5988                       GDI_AREA_SIZE, area_xsize, area_ysize,
5989                       GDI_TEXT_FONT, FONT_INPUT_1,
5990                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5991                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5992                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5993                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5994                       GDI_DESIGN_WIDTH, gd->width,
5995                       GDI_EVENT_MASK, event_mask,
5996                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5997                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
5998                       GDI_END);
5999
6000     if (gi == NULL)
6001       Error(ERR_EXIT, "cannot create gadget");
6002
6003     level_editor_gadget[id] = gi;
6004   }
6005 }
6006
6007 static void CreateSelectboxGadgets()
6008 {
6009   int max_infotext_len = getMaxInfoTextLength();
6010   int i, j;
6011
6012   for (i = 0; i < ED_NUM_SELECTBOX; i++)
6013   {
6014     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
6015     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
6016     int gd_x1 = gd->src_x;
6017     int gd_y1 = gd->src_y;
6018     int gd_x2 = gd->src_x + gd->active_xoffset;
6019     int gd_y2 = gd->src_y + gd->active_yoffset;
6020     int selectbox_button_xsize = gd2->width;
6021     struct GadgetInfo *gi;
6022     unsigned int event_mask;
6023     char infotext[MAX_OUTPUT_LINESIZE + 1];
6024     int id = selectbox_info[i].gadget_id;
6025     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
6026     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
6027
6028     if (selectbox_info[i].size == -1)   /* dynamically determine size */
6029     {
6030       /* (we cannot use -1 for uninitialized values if we directly compare
6031          with results from strlen(), because the '<' and '>' operation will
6032          implicitely cast -1 to an unsigned integer value!) */
6033       selectbox_info[i].size = 0;
6034
6035       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
6036         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
6037           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
6038
6039       selectbox_info[i].size++;         /* add one character empty space */
6040     }
6041
6042     event_mask = GD_EVENT_RELEASED |
6043       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
6044
6045     /* determine horizontal position to the right of specified gadget */
6046     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
6047       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
6048            ED_GADGET_TEXT_DISTANCE);
6049
6050     /* determine horizontal offset for leading text */
6051     if (selectbox_info[i].text_left != NULL)
6052       x += getTextWidthForGadget(selectbox_info[i].text_left);
6053
6054     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
6055     infotext[max_infotext_len] = '\0';
6056
6057     gi = CreateGadget(GDI_CUSTOM_ID, id,
6058                       GDI_CUSTOM_TYPE_ID, i,
6059                       GDI_INFO_TEXT, infotext,
6060                       GDI_X, x,
6061                       GDI_Y, y,
6062                       GDI_TYPE, GD_TYPE_SELECTBOX,
6063                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
6064                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
6065                       GDI_TEXT_SIZE, selectbox_info[i].size,
6066                       GDI_TEXT_FONT, FONT_INPUT_1,
6067                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
6068                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
6069                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6070                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6071                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
6072                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
6073                       GDI_DESIGN_WIDTH, gd->width,
6074                       GDI_EVENT_MASK, event_mask,
6075                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6076                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
6077                       GDI_END);
6078
6079     if (gi == NULL)
6080       Error(ERR_EXIT, "cannot create gadget");
6081
6082     level_editor_gadget[id] = gi;
6083     right_gadget_border[id] =
6084       getRightGadgetBorder(gi, selectbox_info[i].text_right);
6085   }
6086 }
6087
6088 static void CreateTextbuttonGadgets()
6089 {
6090   int max_infotext_len = getMaxInfoTextLength();
6091   int i;
6092
6093   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
6094   {
6095     int id = textbutton_info[i].gadget_id;
6096     int is_tab_button =
6097       ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
6098        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
6099     int graphic =
6100       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
6101     int gadget_distance =
6102       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
6103     struct GraphicInfo *gd = &graphic_info[graphic];
6104     int gd_x1 = gd->src_x;
6105     int gd_y1 = gd->src_y;
6106     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6107     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6108     int gd_x1a = gd->src_x + gd->active_xoffset;
6109     int gd_y1a = gd->src_y + gd->active_yoffset;
6110     int border_xsize = gd->border_size + gd->draw_xoffset;
6111     int border_ysize = gd->border_size;
6112     struct GadgetInfo *gi;
6113     unsigned int event_mask;
6114     char infotext[MAX_OUTPUT_LINESIZE + 1];
6115     int x = SX + ED_TAB_SETTINGS_X(textbutton_info[i].x);
6116     int y = SY + ED_TAB_SETTINGS_Y(textbutton_info[i].y);
6117
6118     if (textbutton_info[i].size == -1)  /* dynamically determine size */
6119       textbutton_info[i].size = strlen(textbutton_info[i].text);
6120
6121     event_mask = GD_EVENT_RELEASED;
6122
6123     sprintf(infotext, "%s", textbutton_info[i].infotext);
6124     infotext[max_infotext_len] = '\0';
6125
6126     /* determine horizontal position to the right of specified gadget */
6127     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6128     {
6129       int gadget_id_align = textbutton_info[i].gadget_id_align;
6130
6131       x = right_gadget_border[gadget_id_align] + gadget_distance;
6132
6133       if (textbutton_info[i].y == -1)
6134         y = level_editor_gadget[gadget_id_align]->y;
6135     }
6136
6137     /* determine horizontal offset for leading text */
6138     if (textbutton_info[i].text_left != NULL)
6139       x += getTextWidthForGadget(textbutton_info[i].text_left);
6140
6141     gi = CreateGadget(GDI_CUSTOM_ID, id,
6142                       GDI_CUSTOM_TYPE_ID, i,
6143                       GDI_INFO_TEXT, infotext,
6144                       GDI_X, x,
6145                       GDI_Y, y,
6146                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
6147                       GDI_TEXT_VALUE, textbutton_info[i].text,
6148                       GDI_TEXT_SIZE, textbutton_info[i].size,
6149                       GDI_TEXT_FONT, FONT_INPUT_2,
6150                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
6151                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6152                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6153                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6154                       GDI_BORDER_SIZE, border_xsize, border_ysize,
6155                       GDI_DESIGN_WIDTH, gd->width,
6156                       GDI_DECORATION_SHIFTING, 1, 1,
6157                       GDI_EVENT_MASK, event_mask,
6158                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6159                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
6160                       GDI_END);
6161
6162     if (gi == NULL)
6163       Error(ERR_EXIT, "cannot create gadget");
6164
6165     level_editor_gadget[id] = gi;
6166     right_gadget_border[id] =
6167       getRightGadgetBorder(gi, textbutton_info[i].text_right);
6168   }
6169 }
6170
6171 static void CreateGraphicbuttonGadgets()
6172 {
6173   struct GadgetInfo *gi;
6174   unsigned int event_mask;
6175   int i;
6176
6177   /* create buttons for scrolling of drawing area and element list */
6178   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
6179   {
6180     int id = graphicbutton_info[i].gadget_id;
6181     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
6182     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
6183     struct GraphicInfo *gd = &graphic_info[graphicbutton_info[i].graphic];
6184     int gd_x1 = gd->src_x;
6185     int gd_y1 = gd->src_y;
6186     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6187     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6188
6189     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6190
6191     /* determine horizontal position to the right of specified gadget */
6192     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6193       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
6194            ED_GADGET_TEXT_DISTANCE);
6195
6196     /* determine horizontal offset for leading text */
6197     if (graphicbutton_info[i].text_left != NULL)
6198       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
6199
6200     gi = CreateGadget(GDI_CUSTOM_ID, id,
6201                       GDI_CUSTOM_TYPE_ID, i,
6202                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
6203                       GDI_X, x,
6204                       GDI_Y, y,
6205                       GDI_WIDTH, gd->width,
6206                       GDI_HEIGHT, gd->height,
6207                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6208                       GDI_STATE, GD_BUTTON_UNPRESSED,
6209                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6210                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6211                       GDI_EVENT_MASK, event_mask,
6212                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6213                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
6214                       GDI_END);
6215
6216     if (gi == NULL)
6217       Error(ERR_EXIT, "cannot create gadget");
6218
6219     level_editor_gadget[id] = gi;
6220     right_gadget_border[id] =
6221       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
6222   }
6223 }
6224
6225 static void CreateScrollbarGadgets()
6226 {
6227   int i;
6228
6229   /* these values are not constant, but can change at runtime */
6230   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
6231     SX + ED_SCROLL_HORIZONTAL_XPOS;
6232   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
6233     SY + ED_SCROLL_HORIZONTAL_YPOS;
6234   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
6235     ED_SCROLL_HORIZONTAL_XSIZE;
6236   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
6237     ED_SCROLL_HORIZONTAL_YSIZE;
6238   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
6239   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
6240   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
6241   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
6242
6243   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
6244     SX + ED_SCROLL_VERTICAL_XPOS;
6245   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
6246     SY + ED_SCROLL_VERTICAL_YPOS;
6247   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
6248     ED_SCROLL_VERTICAL_XSIZE;
6249   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
6250     ED_SCROLL_VERTICAL_YSIZE;
6251   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
6252   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
6253   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
6254   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
6255
6256   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
6257     DX + ED_SCROLL2_VERTICAL_XPOS;
6258   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
6259     DY + ED_SCROLL2_VERTICAL_YPOS;
6260   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
6261     ED_SCROLL2_VERTICAL_XSIZE;
6262   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
6263     ED_SCROLL2_VERTICAL_YSIZE;
6264   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX;
6265   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY;
6266   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = DXSIZE;
6267   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = DYSIZE;
6268
6269   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
6270   {
6271     int id = scrollbar_info[i].gadget_id;
6272     int graphic = scrollbar_info[i].graphic;
6273     struct GraphicInfo *gd = &graphic_info[graphic];
6274     int gd_x1 = gd->src_x;
6275     int gd_y1 = gd->src_y;
6276     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6277     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6278     struct GadgetInfo *gi;
6279     int items_max, items_visible, item_position;
6280     unsigned int event_mask;
6281
6282     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
6283     {
6284       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
6285       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
6286       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
6287     }
6288     else        /* drawing area scrollbars */
6289     {
6290       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
6291       {
6292         items_max = MAX(lev_fieldx + 2, ed_fieldx);
6293         items_visible = ed_fieldx;
6294         item_position = 0;
6295       }
6296       else
6297       {
6298         items_max = MAX(lev_fieldy + 2, ed_fieldy);
6299         items_visible = ed_fieldy;
6300         item_position = 0;
6301       }
6302     }
6303
6304     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
6305
6306     gi = CreateGadget(GDI_CUSTOM_ID, id,
6307                       GDI_CUSTOM_TYPE_ID, i,
6308                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
6309                       GDI_X, scrollbar_pos[i].x,
6310                       GDI_Y, scrollbar_pos[i].y,
6311                       GDI_WIDTH, scrollbar_pos[i].width,
6312                       GDI_HEIGHT, scrollbar_pos[i].height,
6313                       GDI_TYPE, scrollbar_info[i].type,
6314                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
6315                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
6316                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
6317                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
6318                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
6319                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
6320                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
6321                       GDI_STATE, GD_BUTTON_UNPRESSED,
6322                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6323                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6324                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
6325                       GDI_EVENT_MASK, event_mask,
6326                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6327                       GDI_CALLBACK_ACTION, HandleControlButtons,
6328                       GDI_END);
6329
6330     if (gi == NULL)
6331       Error(ERR_EXIT, "cannot create gadget");
6332
6333     level_editor_gadget[id] = gi;
6334   }
6335 }
6336
6337 static void CreateCheckbuttonGadgets()
6338 {
6339   struct GadgetInfo *gi;
6340   unsigned int event_mask;
6341   int i;
6342
6343   event_mask = GD_EVENT_PRESSED;
6344
6345   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
6346   {
6347     int id = checkbutton_info[i].gadget_id;
6348     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
6349                    IMG_EDITOR_CHECKBOX);
6350     struct GraphicInfo *gd = &graphic_info[graphic];
6351     int gd_x1 = gd->src_x;
6352     int gd_y1 = gd->src_y;
6353     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6354     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6355     int gd_x1a = gd->src_x + gd->active_xoffset;
6356     int gd_y1a = gd->src_y + gd->active_yoffset;
6357     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
6358     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
6359     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
6360     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
6361
6362     /* determine horizontal position to the right of specified gadget */
6363     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6364       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
6365            ED_GADGET_TEXT_DISTANCE);
6366
6367     /* determine horizontal offset for leading text */
6368     if (checkbutton_info[i].text_left != NULL)
6369       x += getTextWidthForGadget(checkbutton_info[i].text_left);
6370
6371     gi = CreateGadget(GDI_CUSTOM_ID, id,
6372                       GDI_CUSTOM_TYPE_ID, i,
6373                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
6374                       GDI_X, x,
6375                       GDI_Y, y,
6376                       GDI_WIDTH, gd->width,
6377                       GDI_HEIGHT, gd->height,
6378                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
6379                       GDI_CHECKED, *checkbutton_info[i].value,
6380                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6381                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6382                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6383                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
6384                       GDI_EVENT_MASK, event_mask,
6385                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6386                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
6387                       GDI_END);
6388
6389     if (gi == NULL)
6390       Error(ERR_EXIT, "cannot create gadget");
6391
6392     level_editor_gadget[id] = gi;
6393     right_gadget_border[id] =
6394       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
6395   }
6396 }
6397
6398 static void CreateRadiobuttonGadgets()
6399 {
6400   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_RADIOBUTTON];
6401   int gd_x1 = gd->src_x;
6402   int gd_y1 = gd->src_y;
6403   int gd_x2 = gd->src_x + gd->pressed_xoffset;
6404   int gd_y2 = gd->src_y + gd->pressed_yoffset;
6405   int gd_x1a = gd->src_x + gd->active_xoffset;
6406   int gd_y1a = gd->src_y + gd->active_yoffset;
6407   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
6408   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
6409   struct GadgetInfo *gi;
6410   unsigned int event_mask;
6411   int i;
6412
6413   event_mask = GD_EVENT_PRESSED;
6414
6415   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
6416   {
6417     int id = radiobutton_info[i].gadget_id;
6418     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
6419     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
6420
6421     int checked =
6422       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
6423
6424     /* determine horizontal position to the right of specified gadget */
6425     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
6426       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
6427            ED_GADGET_TEXT_DISTANCE);
6428
6429     /* determine horizontal offset for leading text */
6430     if (radiobutton_info[i].text_left != NULL)
6431       x += getTextWidthForGadget(radiobutton_info[i].text_left);
6432
6433     gi = CreateGadget(GDI_CUSTOM_ID, id,
6434                       GDI_CUSTOM_TYPE_ID, i,
6435                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
6436                       GDI_X, x,
6437                       GDI_Y, y,
6438                       GDI_WIDTH, gd->width,
6439                       GDI_HEIGHT, gd->height,
6440                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
6441                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
6442                       GDI_CHECKED, checked,
6443                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6444                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6445                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6446                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
6447                       GDI_EVENT_MASK, event_mask,
6448                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6449                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
6450                       GDI_END);
6451
6452     if (gi == NULL)
6453       Error(ERR_EXIT, "cannot create gadget");
6454
6455     level_editor_gadget[id] = gi;
6456     right_gadget_border[id] =
6457       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
6458   }
6459 }
6460
6461 void CreateLevelEditorGadgets()
6462 {
6463   /* force EDITOR font inside level editor */
6464   SetFontStatus(GAME_MODE_EDITOR);
6465
6466   /* these values are not constant, but can change at runtime */
6467   ed_fieldx = MAX_ED_FIELDX - 1;
6468   ed_fieldy = MAX_ED_FIELDY - 1;
6469
6470   num_editor_gadgets = NUM_EDITOR_GADGETS;
6471
6472   // printf("::: allocating %d gadgets ...\n", num_editor_gadgets);
6473
6474   level_editor_gadget =
6475     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
6476   right_gadget_border =
6477     checked_calloc(num_editor_gadgets * sizeof(int));
6478
6479   editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int));
6480   editor_el_empty_ptr = editor_el_empty;
6481
6482   ReinitializeElementList();
6483
6484   CreateControlButtons();
6485   CreateScrollbarGadgets();
6486
6487   /* order of function calls is important because of cross-references */
6488   CreateCheckbuttonGadgets();
6489   CreateCounterButtons();
6490   CreateRadiobuttonGadgets();
6491   CreateTextInputGadgets();
6492   CreateTextAreaGadgets();
6493   CreateSelectboxGadgets();
6494   CreateGraphicbuttonGadgets();
6495   CreateTextbuttonGadgets();
6496   CreateDrawingAreas();
6497
6498   ResetFontStatus();
6499 }
6500
6501 void FreeLevelEditorGadgets()
6502 {
6503   int i;
6504
6505   // printf("::: freeing %d gadgets ...\n", num_editor_gadgets);
6506
6507   for (i = 0; i < num_editor_gadgets; i++)
6508   {
6509     FreeGadget(level_editor_gadget[i]);
6510
6511     level_editor_gadget[i] = NULL;
6512   }
6513
6514   checked_free(level_editor_gadget);
6515   checked_free(right_gadget_border);
6516
6517   checked_free(editor_el_empty);
6518 }
6519
6520 static void MapCounterButtons(int id)
6521 {
6522   int font_nr = FONT_TEXT_1;
6523   int font_height = getFontHeight(font_nr);
6524   int gadget_id_down = counterbutton_info[id].gadget_id_down;
6525   int gadget_id_text = counterbutton_info[id].gadget_id_text;
6526   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
6527   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
6528   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
6529   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
6530   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
6531   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6532   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6533   int yoffset = (gi_down->height - font_height) / 2;
6534   int x_left = gi_down->x - xoffset_left;
6535   int x_right;  /* set after gadget position was modified */
6536   int y_above = gi_down->y - yoffset_above;
6537   int x = gi_down->x;
6538   int y;        /* set after gadget position was modified */
6539
6540   /* counter limits must be changed first to prevent value truncation */
6541   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
6542                             counterbutton_info[id].max_value);
6543
6544   /* right text position might have changed after setting position above */
6545   x_right = gi_up->x + gi_up->width + xoffset_right;
6546
6547   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
6548
6549   /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */
6550   if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
6551       id <= ED_COUNTER_ID_ELEMENT_VALUE4)
6552   {
6553     ModifyGadget(gi_down, GDI_Y,
6554                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6555     ModifyGadget(gi_text, GDI_Y,
6556                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6557     ModifyGadget(gi_up,   GDI_Y,
6558                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6559   }
6560
6561   /* vertical position might have changed after setting position above */
6562   y = gi_up->y + yoffset;
6563
6564   if (counterbutton_info[id].text_above)
6565     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
6566
6567   if (counterbutton_info[id].text_left)
6568     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
6569
6570   if (counterbutton_info[id].text_right)
6571     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
6572
6573   MapGadget(gi_down);
6574   MapGadget(gi_text);
6575   MapGadget(gi_up);
6576 }
6577
6578 static void MapControlButtons()
6579 {
6580   int counter_id;
6581   int i;
6582
6583   /* map toolbox buttons (excluding special CE toolbox buttons) */
6584   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
6585     MapGadget(level_editor_gadget[i]);
6586
6587   /* map toolbox buttons (element properties buttons) */
6588   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_6_BUTTONS; i++)
6589     MapGadget(level_editor_gadget[i]);
6590
6591   /* map buttons to select elements */
6592   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
6593     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
6594   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
6595   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
6596   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
6597
6598   /* map buttons to select level */
6599   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
6600   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
6601   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
6602   MapCounterButtons(counter_id);
6603 }
6604
6605 static void MapDrawingArea(int id)
6606 {
6607   int font_nr = FONT_TEXT_1;
6608   int font_height = getFontHeight(font_nr);
6609   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
6610   int area_xsize = gi->drawing.area_xsize;
6611   int area_ysize = gi->drawing.area_ysize;
6612   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
6613   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
6614   int x_left  = gi->x - xoffset_left;
6615   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
6616   int x_below = gi->x + (gi->width - xoffset_below) / 2;
6617   int y_side  = gi->y + (gi->height - font_height) / 2;
6618   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
6619
6620   if (drawingarea_info[id].text_left)
6621     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
6622
6623   if (drawingarea_info[id].text_right)
6624     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
6625
6626   if (drawingarea_info[id].text_below)
6627     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
6628
6629   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
6630   {
6631     DrawElementBorder(gi->x, gi->y,
6632                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
6633                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
6634
6635     DrawDrawingArea(id);
6636   }
6637
6638   MapGadget(gi);
6639 }
6640
6641 static void MapTextInputGadget(int id)
6642 {
6643   int font_nr = FONT_TEXT_1;
6644   int font_height = getFontHeight(font_nr);
6645   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
6646   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6647   int x_above = ED_SETTINGS_X(textinput_info[id].x);
6648   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
6649
6650   if (textinput_info[id].text_above)
6651     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
6652
6653   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
6654
6655   MapGadget(gi);
6656 }
6657
6658 static void MapTextAreaGadget(int id)
6659 {
6660   int font_nr = FONT_TEXT_1;
6661   int font_height = getFontHeight(font_nr);
6662   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
6663   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6664   int x_above = ED_SETTINGS_X(textarea_info[id].x);
6665   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
6666
6667   if (textarea_info[id].text_above)
6668     DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above);
6669
6670   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
6671
6672   MapGadget(gi);
6673 }
6674
6675 static void MapSelectboxGadget(int id)
6676 {
6677   int font_nr = FONT_TEXT_1;
6678   int font_height = getFontHeight(font_nr);
6679   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
6680   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
6681   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6682   int yoffset = (gi->height - font_height) / 2;
6683   int x_left = gi->x - xoffset_left;
6684   int x_right = gi->x + gi->width + xoffset_right;
6685   int y = gi->y + yoffset;
6686
6687   if (selectbox_info[id].text_left)
6688     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
6689
6690   if (selectbox_info[id].text_right)
6691     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
6692
6693   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
6694
6695   MapGadget(gi);
6696 }
6697
6698 static void MapTextbuttonGadget(int id)
6699 {
6700   int font_nr = FONT_TEXT_1;
6701   int font_height = getFontHeight(font_nr);
6702   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
6703   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
6704   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6705   int yoffset = (gi->height - font_height) / 2;
6706   int x_left = gi->x - xoffset_left;
6707   int x_right = gi->x + gi->width + xoffset_right;
6708   int y = gi->y + yoffset;
6709
6710   /* only show button to delete change pages when more than minimum pages */
6711   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
6712       custom_element.num_change_pages == MIN_CHANGE_PAGES)
6713     return;
6714
6715   if (textbutton_info[id].text_left)
6716     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
6717
6718   if (textbutton_info[id].text_right)
6719     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
6720
6721   MapGadget(gi);
6722 }
6723
6724 static void MapGraphicbuttonGadget(int id)
6725 {
6726   int font_nr = FONT_TEXT_1;
6727   int font_height = getFontHeight(font_nr);
6728   struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id];
6729   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
6730   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6731   int yoffset = (gi->height - font_height) / 2;
6732   int x_left = gi->x - xoffset_left;
6733   int x_right = gi->x + gi->width + xoffset_right;
6734   int y = gi->y + yoffset;
6735
6736   if (graphicbutton_info[id].text_left)
6737     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
6738
6739   if (graphicbutton_info[id].text_right)
6740     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
6741
6742   MapGadget(gi);
6743 }
6744
6745 static void MapRadiobuttonGadget(int id)
6746 {
6747   int font_nr = FONT_TEXT_1;
6748   int font_height = getFontHeight(font_nr);
6749   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
6750   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6751   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6752   int yoffset = (gi->height - font_height) / 2;
6753   int x_left = gi->x - xoffset_left;
6754   int x_right = gi->x + gi->width + xoffset_right;
6755   int y = gi->y + yoffset;
6756   boolean checked =
6757     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
6758
6759   if (radiobutton_info[id].text_left)
6760     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
6761
6762   if (radiobutton_info[id].text_right)
6763     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
6764
6765   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
6766
6767   MapGadget(gi);
6768 }
6769
6770 static void MapCheckbuttonGadget(int id)
6771 {
6772   int font_nr = FONT_TEXT_1;
6773   int font_height = getFontHeight(font_nr);
6774   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
6775   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6776   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6777   int yoffset = (gi->height - font_height) / 2;
6778   int x_left, x_right, y;       /* set after gadget position was modified */
6779
6780   /* set position for gadgets with dynamically determined position */
6781   if (checkbutton_info[id].x != -1)     /* do not change dynamic positions */
6782     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END);
6783   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
6784
6785   x_left = gi->x - xoffset_left;
6786   x_right = gi->x + gi->width + xoffset_right;
6787   y = gi->y + yoffset;
6788
6789   if (checkbutton_info[id].text_left)
6790     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
6791
6792   if (checkbutton_info[id].text_right)
6793     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
6794
6795   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
6796
6797   MapGadget(gi);
6798 }
6799
6800 static void MapMainDrawingArea()
6801 {
6802   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
6803   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
6804   int i;
6805
6806   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
6807   {
6808     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
6809           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
6810          no_horizontal_scrollbar) ||
6811         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
6812           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
6813          no_vertical_scrollbar))
6814       continue;
6815
6816     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
6817   }
6818
6819   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
6820   {
6821     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
6822         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
6823       continue;
6824
6825     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
6826   }
6827
6828   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
6829 }
6830
6831 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
6832 {
6833   int i;
6834
6835   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
6836   {
6837     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
6838         i == GADGET_ID_CUSTOM_COPY_TO ||
6839         i == GADGET_ID_CUSTOM_EXCHANGE ||
6840         i == GADGET_ID_CUSTOM_COPY ||
6841         i == GADGET_ID_CUSTOM_PASTE)
6842     {
6843       if (map)
6844         MapGadget(level_editor_gadget[i]);
6845       else
6846         UnmapGadget(level_editor_gadget[i]);
6847     }
6848   }
6849 }
6850
6851 static void MapLevelEditorToolboxCustomGadgets()
6852 {
6853   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
6854 }
6855
6856 static void UnmapLevelEditorToolboxCustomGadgets()
6857 {
6858   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
6859 }
6860
6861 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
6862 {
6863   int i;
6864
6865   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
6866   {
6867     if (i != GADGET_ID_SINGLE_ITEMS &&
6868         i != GADGET_ID_PICK_ELEMENT)
6869     {
6870       struct GadgetInfo *gi = level_editor_gadget[i];
6871
6872       if (map)
6873       {
6874         MapGadget(gi);
6875       }
6876       else
6877       {
6878         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
6879         struct GraphicInfo *gd = &graphic_info[graphic];
6880
6881         UnmapGadget(gi);
6882
6883         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
6884                    gi->width, gi->height, gi->x, gi->y);
6885
6886         redraw_mask |= REDRAW_DOOR_3;
6887       }
6888     }
6889   }
6890 }
6891
6892 static void MapLevelEditorToolboxDrawingGadgets()
6893 {
6894   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
6895 }
6896
6897 static void UnmapLevelEditorToolboxDrawingGadgets()
6898 {
6899   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
6900 }
6901
6902 static void UnmapDrawingArea(int id)
6903 {
6904   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
6905 }
6906
6907 static void UnmapLevelEditorFieldGadgets()
6908 {
6909   int i;
6910
6911   for (i = 0; i < num_editor_gadgets; i++)
6912     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
6913                           level_editor_gadget[i]->y))
6914       UnmapGadget(level_editor_gadget[i]);
6915 }
6916
6917 void UnmapLevelEditorGadgets()
6918 {
6919   int i;
6920
6921   for (i = 0; i < num_editor_gadgets; i++)
6922     UnmapGadget(level_editor_gadget[i]);
6923 }
6924
6925 static void ResetUndoBuffer()
6926 {
6927   undo_buffer_position = -1;
6928   undo_buffer_steps = -1;
6929   redo_buffer_steps = 0;
6930
6931   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6932
6933   level.changed = FALSE;
6934 }
6935
6936 static void DrawEditModeWindow()
6937 {
6938   ModifyEditorElementList();
6939   RedrawDrawingElements();
6940
6941   if (edit_mode == ED_MODE_INFO)
6942     DrawLevelInfoWindow();
6943   else if (edit_mode == ED_MODE_PROPERTIES)
6944     DrawPropertiesWindow();
6945   else  /* edit_mode == ED_MODE_DRAWING */
6946     DrawDrawingWindow();
6947 }
6948
6949 static boolean LevelChanged()
6950 {
6951   boolean field_changed = FALSE;
6952   int x, y;
6953
6954   for (y = 0; y < lev_fieldy; y++) 
6955     for (x = 0; x < lev_fieldx; x++)
6956       if (Feld[x][y] != level.field[x][y])
6957         field_changed = TRUE;
6958
6959   return (level.changed || field_changed);
6960 }
6961
6962 static boolean PrepareSavingIntoPersonalLevelSet()
6963 {
6964   static LevelDirTree *last_copied_leveldir = NULL;
6965   static LevelDirTree *last_written_leveldir = NULL;
6966   static int last_copied_level_nr = -1;
6967   static int last_written_level_nr = -1;
6968   LevelDirTree *leveldir_former = leveldir_current;
6969   int level_nr_former = level_nr;
6970   int new_level_nr;
6971
6972   // remember last mod/save so that for current session, we write
6973   // back to the same personal copy, asking only about overwrite.
6974   if (leveldir_current == last_copied_leveldir &&
6975       level_nr == last_copied_level_nr)
6976   {
6977     // "cd" to personal level set dir (as used when writing last copy)
6978     leveldir_current = last_written_leveldir;
6979     level_nr = last_written_level_nr;
6980
6981     return TRUE;
6982   }
6983
6984   if (!Request("This level is read only! "
6985                "Save into personal level set?", REQ_ASK))
6986     return FALSE;
6987
6988   // "cd" to personal level set dir (for writing copy the first time)
6989   leveldir_current =
6990     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
6991
6992   // find unused level number
6993   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
6994   {
6995     static char *level_filename = NULL;
6996
6997     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
6998
6999     if (!fileExists(level_filename))
7000       break;
7001   }
7002
7003   last_copied_leveldir = leveldir_former;
7004   last_copied_level_nr = level_nr_former;
7005
7006   last_written_leveldir = leveldir_current;
7007   last_written_level_nr = level_nr = new_level_nr;
7008
7009   return TRUE;
7010 }
7011
7012 static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
7013 {
7014   static char *filename_levelinfo = NULL, *mod_name = NULL;
7015   FILE *file;
7016
7017   // annotate this copy-and-mod in personal levelinfo.conf
7018   setString(&filename_levelinfo,
7019             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
7020
7021   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
7022   {
7023     fprintf(file, "\n");
7024     fprintf(file, "# level %d was modified from:\n", level_nr);
7025     fprintf(file, "# - previous level set name:    %s\n",
7026             former_name);
7027     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
7028             level.file_info.nr, level.name);
7029     fprintf(file, "# - previous author:            %s\n",
7030             level.author);
7031     fprintf(file, "# - previous save date:         ");
7032
7033     if (level.creation_date.src == DATE_SRC_LEVELFILE)
7034     {
7035       fprintf(file, "%04d-%02d-%02d\n",
7036               level.creation_date.year,
7037               level.creation_date.month,
7038               level.creation_date.day);
7039     }
7040     else
7041     {
7042       fprintf(file, "not recorded\n");
7043     }
7044
7045     fclose(file);
7046   }
7047
7048   if (level_nr > leveldir_current->last_level)
7049   {
7050     static char *temp_levelinfo = NULL;
7051     FILE *temp_file = NULL;
7052     char line[MAX_LINE_LEN];
7053
7054     setString(&temp_levelinfo,
7055               getPath2(getCurrentLevelDir(),
7056                        getStringCat2(LEVELINFO_FILENAME, ".new")));
7057
7058     if ((file = fopen(filename_levelinfo, MODE_READ)) &&
7059         (temp_file = fopen(temp_levelinfo, MODE_WRITE)))
7060     {
7061       while (fgets(line, MAX_LINE_LEN, file))
7062       {
7063         if (!strPrefix(line, "levels:"))
7064           fputs(line, temp_file);
7065         else
7066           fprintf(temp_file, "%-32s%d\n", "levels:", level_nr + 9);
7067       }
7068     }
7069
7070     if (temp_file)
7071       fclose(temp_file);
7072
7073     if (file)
7074       fclose(file);
7075
7076     // needs error handling; also, ok on dos/win?
7077     unlink(filename_levelinfo);
7078     rename(temp_levelinfo, filename_levelinfo);
7079   }
7080
7081   // else: allow the save even if annotation failed
7082
7083   // now... spray graffiti on the old level vital statistics
7084   // user can change these; just trying to set a good baseline
7085
7086   // don't truncate names for fear of making offensive or silly:
7087   // long-named original author only recorded in levelinfo.conf.
7088   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
7089   if (!strEqual(level.author, leveldir_current->author))
7090   {
7091     setString(&mod_name, getStringCat3(leveldir_current->author,
7092                                        " after ", level.author));
7093
7094     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
7095       setString(&mod_name,
7096                 getStringCat2(leveldir_current->author, " (ed.)"));
7097
7098     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
7099       setString(&mod_name, leveldir_current->author);
7100
7101     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
7102
7103     // less worried about truncation here
7104     setString(&mod_name, getStringCat2("Mod: ", level.name));
7105     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
7106   }
7107 }
7108
7109 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
7110                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
7111 {
7112   int x, y;
7113
7114   for (x = 0; x < lev_fieldx; x++)
7115     for (y = 0; y < lev_fieldy; y++) 
7116       dst[x][y] = src[x][y];
7117 }
7118
7119 static int setSelectboxValue(int selectbox_id, int new_value)
7120 {
7121   int new_index_value = 0;
7122   int i;
7123
7124   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
7125     if (selectbox_info[selectbox_id].options[i].value == new_value)
7126       new_index_value = i;
7127
7128   *selectbox_info[selectbox_id].value =
7129     selectbox_info[selectbox_id].options[new_index_value].value;
7130
7131   return new_index_value;
7132 }
7133
7134 static void setSelectboxSpecialActionVariablesIfNeeded()
7135 {
7136   int i;
7137
7138   /* change action mode and arg variables according to action type variable */
7139   for (i = 0; action_arg_options[i].value != -1; i++)
7140   {
7141     if (action_arg_options[i].value == custom_element_change.action_type)
7142     {
7143       int mode = action_arg_options[i].mode;
7144
7145       /* only change if corresponding selectbox has changed */
7146       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
7147           action_arg_modes[mode])
7148         custom_element_change.action_mode = -1;
7149
7150       /* only change if corresponding selectbox has changed */
7151       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
7152           action_arg_options[i].options)
7153         custom_element_change.action_arg = -1;
7154
7155       break;
7156     }
7157   }
7158 }
7159
7160 static void setSelectboxSpecialActionOptions()
7161 {
7162   int i;
7163
7164   /* change action mode and arg selectbox according to action type selectbox */
7165   for (i = 0; action_arg_options[i].value != -1; i++)
7166   {
7167     if (action_arg_options[i].value == custom_element_change.action_type)
7168     {
7169       int mode = action_arg_options[i].mode;
7170
7171       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
7172                                    action_arg_modes[mode]);
7173       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
7174                                  custom_element_change.action_mode);
7175
7176       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
7177                                    action_arg_options[i].options);
7178       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
7179                                  custom_element_change.action_arg);
7180       break;
7181     }
7182   }
7183 }
7184
7185 static void copy_custom_element_settings(int element_from, int element_to)
7186 {
7187   struct ElementInfo *ei_from = &element_info[element_from];
7188   struct ElementInfo *ei_to = &element_info[element_to];
7189
7190   copyElementInfo(ei_from, ei_to);
7191 }
7192
7193 static void replace_custom_element_in_settings(int element_from,
7194                                                int element_to)
7195 {
7196   int i, j, x, y;
7197
7198   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7199   {
7200     struct ElementInfo *ei = &element_info[i];
7201
7202     for (y = 0; y < 3; y++)
7203       for (x = 0; x < 3; x++)
7204         if (ei->content.e[x][y] == element_from)
7205           ei->content.e[x][y] = element_to;
7206
7207     for (j = 0; j < ei->num_change_pages; j++)
7208     {
7209       struct ElementChangeInfo *change = &ei->change_page[j];
7210
7211       if (change->target_element == element_from)
7212         change->target_element = element_to;
7213
7214       if (change->initial_trigger_element == element_from)
7215         change->initial_trigger_element = element_to;
7216
7217       if (change->action_element == element_from)
7218         change->action_element = element_to;
7219
7220       for (y = 0; y < 3; y++)
7221         for (x = 0; x < 3; x++)
7222           if (change->target_content.e[x][y] == element_from)
7223             change->target_content.e[x][y] = element_to;
7224     }
7225
7226     if (ei->group != NULL)                              /* group or internal */
7227       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
7228         if (ei->group->element[j] == element_from)
7229           ei->group->element[j] = element_to;
7230   }
7231 }
7232
7233 static void replace_custom_element_in_playfield(int element_from,
7234                                                 int element_to)
7235 {
7236   int x, y;
7237
7238   for (x = 0; x < lev_fieldx; x++)
7239     for (y = 0; y < lev_fieldy; y++)
7240       if (Feld[x][y] == element_from)
7241         Feld[x][y] = element_to;
7242 }
7243
7244 static boolean CopyCustomElement(int element_old, int element_new,
7245                                  int copy_mode)
7246 {
7247   if (copy_mode == GADGET_ID_CUSTOM_COPY)
7248   {
7249     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
7250                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
7251     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
7252   }
7253   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
7254   {
7255     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
7256                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
7257     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
7258
7259     level.changed = TRUE;
7260   }
7261   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
7262   {
7263     Request("Please choose custom element!", REQ_CONFIRM);
7264
7265     return FALSE;
7266   }
7267   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
7268   {
7269     Request("Please choose group element!", REQ_CONFIRM);
7270
7271     return FALSE;
7272   }
7273   else
7274   {
7275     level.changed = TRUE;
7276   }
7277
7278   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
7279   {
7280     copy_custom_element_settings(element_new, element_old);
7281   }
7282   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
7283   {
7284     copy_custom_element_settings(element_old, element_new);
7285   }
7286   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
7287   {
7288     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
7289     copy_custom_element_settings(element_new, element_old);
7290     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
7291
7292     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
7293     replace_custom_element_in_settings(element_new, element_old);
7294     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
7295
7296     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
7297     replace_custom_element_in_playfield(element_new, element_old);
7298     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
7299   }
7300
7301   UpdateCustomElementGraphicGadgets();
7302   DrawPropertiesWindow();
7303
7304   return TRUE;
7305 }
7306
7307 static void CopyCustomElementPropertiesToEditor(int element)
7308 {
7309   int i;
7310   int current_change_page = element_info[element].current_change_page;
7311
7312   /* dynamically (re)build selectbox for selecting change page */
7313   for (i = 0; i < element_info[element].num_change_pages; i++)
7314   {
7315     sprintf(options_change_page_strings[i], "%d", i + 1);
7316
7317     options_change_page[i].value = i;
7318     options_change_page[i].text = options_change_page_strings[i];
7319   }
7320
7321   options_change_page[i].value = -1;
7322   options_change_page[i].text = NULL;
7323
7324   /* needed here to initialize combined element properties */
7325   InitElementPropertiesEngine(level.game_version);
7326
7327   element_info[element].change =
7328     &element_info[element].change_page[current_change_page];
7329
7330   custom_element = element_info[element];
7331   custom_element_change = *element_info[element].change;
7332
7333   /* needed to initially set selectbox options for special action options */
7334   setSelectboxSpecialActionOptions();
7335
7336   /* needed to initially set selectbox value variables to reliable defaults */
7337   for (i = 0; i < ED_NUM_SELECTBOX; i++)
7338     setSelectboxValue(i, *selectbox_info[i].value);
7339
7340   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
7341     custom_element_properties[i] = HAS_PROPERTY(element, i);
7342
7343   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
7344     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
7345
7346   /* ---------- element settings: configure (custom elements) ------------- */
7347
7348   /* set accessible layer selectbox help value */
7349   custom_element.access_type =
7350     (IS_WALKABLE(element) ? EP_WALKABLE :
7351      IS_PASSABLE(element) ? EP_PASSABLE :
7352      custom_element.access_type);
7353   custom_element.access_layer =
7354     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
7355      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
7356      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
7357      custom_element.access_layer);
7358   custom_element.access_protected =
7359     (IS_PROTECTED(element) ? 1 : 0);
7360   custom_element_properties[EP_ACCESSIBLE] =
7361     (IS_ACCESSIBLE_OVER(element) ||
7362      IS_ACCESSIBLE_INSIDE(element) ||
7363      IS_ACCESSIBLE_UNDER(element));
7364
7365   /* set walk-to-object action selectbox help value */
7366   custom_element.walk_to_action =
7367     (IS_DIGGABLE(element) ? EP_DIGGABLE :
7368      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
7369      IS_DROPPABLE(element) ? EP_DROPPABLE :
7370      IS_THROWABLE(element) ? EP_THROWABLE :
7371      IS_PUSHABLE(element) ? EP_PUSHABLE :
7372      custom_element.walk_to_action);
7373   custom_element_properties[EP_WALK_TO_OBJECT] =
7374     (IS_DIGGABLE(element) ||
7375      IS_COLLECTIBLE_ONLY(element) ||
7376      IS_DROPPABLE(element) ||
7377      IS_THROWABLE(element) ||
7378      IS_PUSHABLE(element));
7379
7380   /* set smash targets selectbox help value */
7381   custom_element.smash_targets =
7382     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
7383      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
7384      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
7385      custom_element.smash_targets);
7386   custom_element_properties[EP_CAN_SMASH] =
7387     (CAN_SMASH_EVERYTHING(element) ||
7388      CAN_SMASH_ENEMIES(element) ||
7389      CAN_SMASH_PLAYER(element));
7390
7391   /* set deadliness selectbox help value */
7392   custom_element.deadliness =
7393     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
7394      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
7395      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
7396      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
7397      custom_element.deadliness);
7398   custom_element_properties[EP_DEADLY] =
7399     (DONT_TOUCH(element) ||
7400      DONT_GET_HIT_BY(element) ||
7401      DONT_COLLIDE_WITH(element) ||
7402      DONT_RUN_INTO(element));
7403
7404   /* ---------- element settings: advanced (custom elements) --------------- */
7405
7406   /* set "change by direct action" selectbox help value */
7407   custom_element_change.direct_action =
7408     (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
7409      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
7410      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
7411      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
7412      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
7413      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
7414      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
7415      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
7416      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
7417      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
7418      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
7419      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
7420      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
7421      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
7422      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
7423      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
7424      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
7425      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
7426      custom_element_change.direct_action);
7427
7428   /* set "change by other element action" selectbox help value */
7429   custom_element_change.other_action =
7430     (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
7431      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
7432      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
7433      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
7434      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
7435      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
7436      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
7437      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
7438      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
7439      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
7440      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
7441      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
7442      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
7443      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
7444      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
7445      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
7446      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
7447      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
7448      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
7449      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
7450      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
7451      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
7452      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
7453      custom_element_change.other_action);
7454 }
7455
7456 static void CopyGroupElementPropertiesToEditor(int element)
7457 {
7458   group_element_info = *element_info[element].group;
7459   custom_element = element_info[element];       /* needed for description */
7460 }
7461
7462 static void CopyClassicElementPropertiesToEditor(int element)
7463 {
7464   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
7465     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
7466       getMoveIntoAcidProperty(&level, element);
7467
7468   if (MAYBE_DONT_COLLIDE_WITH(element))
7469     custom_element_properties[EP_DONT_COLLIDE_WITH] =
7470       getDontCollideWithProperty(&level, element);
7471 }
7472
7473 static void CopyElementPropertiesToEditor(int element)
7474 {
7475   if (IS_CUSTOM_ELEMENT(element))
7476     CopyCustomElementPropertiesToEditor(element);
7477   else if (IS_GROUP_ELEMENT(element))
7478     CopyGroupElementPropertiesToEditor(element);
7479   else
7480     CopyClassicElementPropertiesToEditor(element);
7481 }
7482
7483 static void CopyCustomElementPropertiesToGame(int element)
7484 {
7485   int i;
7486   int access_type_and_layer;
7487
7488   /* mark that this custom element has been modified */
7489   custom_element.modified_settings = TRUE;
7490   level.changed = TRUE;
7491
7492   if (level.use_custom_template)
7493   {
7494     if (Request("Copy and modify level template?", REQ_ASK))
7495     {
7496       level.use_custom_template = FALSE;
7497       ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
7498                    GDI_CHECKED, FALSE, GDI_END);
7499     }
7500     else
7501     {
7502       LoadLevelTemplate(-1);    /* this resets all element modifications ... */
7503
7504       DrawEditModeWindow();     /* ... and copies them to 'custom_element' */
7505     }
7506   }
7507
7508   element_info[element] = custom_element;
7509   *element_info[element].change = custom_element_change;
7510
7511   /* ---------- element settings: configure (custom elements) ------------- */
7512
7513   /* set accessible property from checkbox and selectbox */
7514   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
7515   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
7516   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
7517   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
7518   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
7519   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
7520   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
7521                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
7522                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
7523   custom_element_properties[access_type_and_layer] =
7524     custom_element_properties[EP_ACCESSIBLE];
7525   custom_element_properties[EP_PROTECTED] =
7526     (custom_element.access_protected != 0 &&
7527      custom_element_properties[EP_ACCESSIBLE]);
7528
7529   /* set walk-to-object property from checkbox and selectbox */
7530   custom_element_properties[EP_DIGGABLE] = FALSE;
7531   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
7532   custom_element_properties[EP_DROPPABLE] = FALSE;
7533   custom_element_properties[EP_THROWABLE] = FALSE;
7534   custom_element_properties[EP_PUSHABLE] = FALSE;
7535   custom_element_properties[custom_element.walk_to_action] =
7536     custom_element_properties[EP_WALK_TO_OBJECT];
7537
7538   /* set smash property from checkbox and selectbox */
7539   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
7540   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
7541   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
7542   custom_element_properties[custom_element.smash_targets] =
7543     custom_element_properties[EP_CAN_SMASH];
7544
7545   /* set deadliness property from checkbox and selectbox */
7546   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
7547   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
7548   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
7549   custom_element_properties[EP_DONT_TOUCH] = FALSE;
7550   custom_element_properties[custom_element.deadliness] =
7551     custom_element_properties[EP_DEADLY];
7552
7553   /* ---------- element settings: advanced (custom elements) --------------- */
7554
7555   /* set player change event from checkbox and selectbox */
7556   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
7557   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
7558   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
7559   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
7560   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
7561   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
7562   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
7563   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
7564   custom_element_change_events[CE_SWITCHED] = FALSE;
7565   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
7566   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
7567   custom_element_change_events[CE_BLOCKED] = FALSE;
7568   custom_element_change_events[CE_IMPACT] = FALSE;
7569   custom_element_change_events[CE_SMASHED] = FALSE;
7570   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
7571   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
7572   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
7573   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
7574   custom_element_change_events[custom_element_change.direct_action] =
7575     custom_element_change_events[CE_BY_DIRECT_ACTION];
7576
7577   /* set other element action change event from checkbox and selectbox */
7578   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
7579   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
7580   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
7581   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
7582   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
7583   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
7584   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
7585   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
7586   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
7587   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
7588   custom_element_change_events[CE_TOUCHING_X] = FALSE;
7589   custom_element_change_events[CE_HITTING_X] = FALSE;
7590   custom_element_change_events[CE_DIGGING_X] = FALSE;
7591   custom_element_change_events[CE_HIT_BY_X] = FALSE;
7592   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
7593   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
7594   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
7595   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
7596   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
7597   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
7598   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
7599   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
7600   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
7601   custom_element_change_events[custom_element_change.other_action] =
7602     custom_element_change_events[CE_BY_OTHER_ACTION];
7603
7604   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
7605     SET_PROPERTY(element, i, custom_element_properties[i]);
7606
7607   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
7608     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
7609
7610   /* copy change events also to special level editor variable */
7611   custom_element = element_info[element];
7612   custom_element_change = *element_info[element].change;
7613 }
7614
7615 static void CopyGroupElementPropertiesToGame(int element)
7616 {
7617   element_info[element] = custom_element;
7618   *element_info[element].group = group_element_info;
7619
7620   /* mark that this group element has been modified */
7621   element_info[element].modified_settings = TRUE;
7622   level.changed = TRUE;
7623 }
7624
7625 static void CopyClassicElementPropertiesToGame(int element)
7626 {
7627   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
7628     setMoveIntoAcidProperty(&level, element,
7629                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
7630
7631   if (MAYBE_DONT_COLLIDE_WITH(element))
7632     setDontCollideWithProperty(&level, element,
7633                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
7634 }
7635
7636 static void CopyElementPropertiesToGame(int element)
7637 {
7638   if (IS_CUSTOM_ELEMENT(element))
7639     CopyCustomElementPropertiesToGame(element);
7640   else if (IS_GROUP_ELEMENT(element))
7641     CopyGroupElementPropertiesToGame(element);
7642   else
7643     CopyClassicElementPropertiesToGame(element);
7644 }
7645
7646 void CheckElementDescriptions()
7647 {
7648   int i;
7649
7650   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7651     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
7652       Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
7653 }
7654
7655 static int getMaxEdFieldX(boolean has_scrollbar)
7656 {
7657   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
7658   int sxsize = SXSIZE - scrollbar_width;
7659   int max_ed_fieldx = sxsize / ed_tilesize;
7660
7661   return max_ed_fieldx;
7662 }
7663
7664 static int getMaxEdFieldY(boolean has_scrollbar)
7665 {
7666   int infotext_height = INFOTEXT_YSIZE_FULL;
7667   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
7668   int sysize = SYSIZE - scrollbar_height - infotext_height;
7669   int max_ed_fieldy = sysize / ed_tilesize;
7670
7671   return max_ed_fieldy;
7672 }
7673
7674 void InitZoomLevelSettings()
7675 {
7676   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
7677   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
7678 }
7679
7680 void DrawLevelEd()
7681 {
7682   int fade_mask = REDRAW_FIELD;
7683
7684   FadeSoundsAndMusic();
7685
7686   if (CheckIfGlobalBorderHasChanged())
7687     fade_mask = REDRAW_ALL;
7688
7689   FadeOut(fade_mask);
7690
7691   /* needed if different viewport properties defined for editor */
7692   ChangeViewportPropertiesIfNeeded();
7693
7694   ClearField();
7695
7696   InitZoomLevelSettings();
7697
7698   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
7699
7700 #if DEBUG
7701   CheckElementDescriptions();
7702 #endif
7703
7704   if (level_editor_test_game)
7705   {
7706     CopyPlayfield(level.field, Feld);
7707     CopyPlayfield(FieldBackup, level.field);
7708
7709     level_editor_test_game = FALSE;
7710   }
7711   else
7712   {
7713     edit_mode = ED_MODE_DRAWING;
7714     edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
7715     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
7716
7717     ResetUndoBuffer();
7718
7719     level_xpos = -1;
7720     level_ypos = -1;
7721   }
7722
7723   /* needed for gadgets drawn on background (like palette scrollbar) */
7724   SetDoorBackgroundImage(IMG_UNDEFINED);
7725
7726   /* copy default editor door content to main double buffer */
7727   BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto,
7728              graphic_info[IMG_BACKGROUND_PALETTE].src_x,
7729              graphic_info[IMG_BACKGROUND_PALETTE].src_y,
7730              MIN(DXSIZE, graphic_info[IMG_BACKGROUND_PALETTE].width),
7731              MIN(DYSIZE, graphic_info[IMG_BACKGROUND_PALETTE].height),
7732              DX, DY);
7733
7734   /* draw bigger door */
7735   DrawSpecialEditorDoor();
7736
7737   /* draw new control window */
7738   BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto,
7739              graphic_info[IMG_BACKGROUND_TOOLBOX].src_x,
7740              graphic_info[IMG_BACKGROUND_TOOLBOX].src_y,
7741              MIN(EXSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].width),
7742              MIN(EYSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].height),
7743              EX, EY);
7744
7745   // redraw_mask |= REDRAW_ALL;
7746
7747   FreeLevelEditorGadgets();
7748   CreateLevelEditorGadgets();
7749
7750   ReinitializeElementList();            /* update dynamic level element list */
7751   ReinitializeElementListButtons();     /* custom element may look different */
7752
7753   InitElementPropertiesGfxElement();
7754
7755   UnmapAllGadgets();
7756   MapControlButtons();
7757
7758   DrawEditModeWindow();
7759
7760   DrawMaskedBorder(fade_mask);
7761
7762   FadeIn(fade_mask);
7763
7764   /* copy actual editor door content to door double buffer for OpenDoor() */
7765   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
7766 }
7767
7768 static void AdjustDrawingAreaGadgets()
7769 {
7770   int ed_xsize = lev_fieldx + 2;
7771   int ed_ysize = lev_fieldy + 2;
7772   int max_ed_fieldx = MAX_ED_FIELDX;
7773   int max_ed_fieldy = MAX_ED_FIELDY;
7774   boolean horizontal_scrollbar_needed;
7775   boolean vertical_scrollbar_needed;
7776   int x, y, width, height;
7777
7778   /* check if we need any scrollbars */
7779   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7780   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
7781
7782   /* check if we have a smaller editor field because of scrollbars */
7783   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
7784   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
7785
7786   /* check again if we now need more scrollbars because of less space */
7787   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7788   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
7789
7790   /* check if editor field gets even smaller after adding new scrollbars */
7791   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
7792   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
7793
7794   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
7795   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
7796
7797   x = SX + ed_fieldx * ed_tilesize;
7798   y = SY + ed_fieldy * ed_tilesize;
7799
7800   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
7801   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
7802
7803   /* adjust drawing area gadget */
7804   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
7805                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
7806                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
7807                GDI_END);
7808
7809   /* adjust horizontal scrollbar gadgets */
7810   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
7811                GDI_Y, y,
7812                GDI_END);
7813   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
7814                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
7815                GDI_Y, y,
7816                GDI_END);
7817   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
7818                GDI_Y, y,
7819                GDI_WIDTH, width,
7820                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
7821                GDI_END);
7822
7823   /* adjust vertical scrollbar gadgets */
7824   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
7825                GDI_X, x,
7826                GDI_END);
7827   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
7828                GDI_X, x,
7829                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
7830                GDI_END);
7831   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
7832                GDI_X, x,
7833                GDI_HEIGHT, height,
7834                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
7835                GDI_END);
7836 }
7837
7838 static void AdjustLevelScrollPosition()
7839 {
7840   if (level_xpos < -1)
7841     level_xpos = -1;
7842   if (level_xpos > lev_fieldx - ed_fieldx + 1)
7843     level_xpos = lev_fieldx - ed_fieldx + 1;
7844   if (lev_fieldx < ed_fieldx - 2)
7845     level_xpos = -1;
7846
7847   if (level_ypos < -1)
7848     level_ypos = -1;
7849   if (level_ypos > lev_fieldy - ed_fieldy + 1)
7850     level_ypos = lev_fieldy - ed_fieldy + 1;
7851   if (lev_fieldy < ed_fieldy - 2)
7852     level_ypos = -1;
7853 }
7854
7855 static void AdjustEditorScrollbar(int id)
7856 {
7857   struct GadgetInfo *gi = level_editor_gadget[id];
7858   int items_max, items_visible, item_position;
7859
7860   if (id == GADGET_ID_SCROLL_HORIZONTAL)
7861   {
7862     items_max = MAX(lev_fieldx + 2, ed_fieldx);
7863     items_visible = ed_fieldx;
7864     item_position = level_xpos + 1;
7865   }
7866   else
7867   {
7868     items_max = MAX(lev_fieldy + 2, ed_fieldy);
7869     items_visible = ed_fieldy;
7870     item_position = level_ypos + 1;
7871   }
7872
7873   if (item_position > items_max - items_visible)
7874     item_position = items_max - items_visible;
7875
7876   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7877                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7878 }
7879
7880 static void AdjustElementListScrollbar()
7881 {
7882   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
7883   int items_max, items_visible, item_position;
7884
7885   /* correct position of element list scrollbar */
7886   if (element_shift < 0)
7887     element_shift = 0;
7888   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
7889     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
7890
7891   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
7892   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
7893   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
7894
7895   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7896                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
7897                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7898 }
7899
7900 static void ModifyEditorCounterValue(int counter_id, int new_value)
7901 {
7902   int *counter_value = counterbutton_info[counter_id].value;
7903   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7904   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7905
7906   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
7907
7908   if (counter_value != NULL)
7909     *counter_value = gi->textinput.number_value;
7910 }
7911
7912 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
7913 {
7914   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7915   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7916
7917   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
7918
7919   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
7920       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
7921   {
7922     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
7923     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
7924
7925     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
7926     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
7927                  GDI_END);
7928   }
7929 }
7930
7931 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
7932 {
7933   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7934   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7935   int new_index_value = setSelectboxValue(selectbox_id, new_value);
7936
7937   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
7938 }
7939
7940 static void ModifyEditorSelectboxOptions(int selectbox_id,
7941                                          struct ValueTextInfo *options)
7942 {
7943   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7944   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7945
7946   selectbox_info[selectbox_id].options = options;
7947
7948   /* set index to zero -- list may be shorter now (correct later, if needed) */
7949   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
7950                GDI_SELECTBOX_OPTIONS, options, GDI_END);
7951 }
7952
7953 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
7954 {
7955   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
7956   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7957
7958   drawingarea_info[drawingarea_id].area_xsize = xsize;
7959   drawingarea_info[drawingarea_id].area_ysize = ysize;
7960
7961   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
7962 }
7963
7964 static void ModifyEditorElementList()
7965 {
7966   int i;
7967
7968   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7969   {
7970     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
7971     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7972     struct GadgetDesign *gd = &gi->deco.design;
7973     int element = editor_elements[element_shift + i];
7974     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
7975
7976     UnmapGadget(gi);
7977
7978     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
7979
7980     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
7981
7982     MapGadget(gi);
7983   }
7984 }
7985
7986 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
7987 {
7988   int graphic = el2edimg(element);
7989   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
7990
7991   if (pos->x == -1 &&
7992       pos->y == -1)
7993     return;
7994
7995   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
7996 }
7997
7998 static void ModifyDrawingElementButton(int element, int id)
7999 {
8000   struct GadgetInfo *gi = level_editor_gadget[id];
8001   Bitmap *deco_bitmap;
8002   int deco_x, deco_y;
8003   int tile_size = gi->deco.width;
8004
8005   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
8006
8007   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
8008 }
8009
8010 static void PickDrawingElement(int button, int element)
8011 {
8012   struct
8013   {
8014     int *new_element;
8015     struct XYTileSize *pos;
8016     int id;
8017   } de, drawing_elements[] =
8018   {
8019     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
8020     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
8021     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
8022   };
8023
8024   if (button < 1 || button > 3)
8025     return;
8026
8027   de = drawing_elements[button - 1];
8028
8029   *de.new_element = element;    // update global drawing element variable
8030
8031   DrawDrawingElementGraphic(element, de.pos);
8032   ModifyDrawingElementButton(element, de.id);
8033
8034   redraw_mask |= REDRAW_DOOR_1;
8035 }
8036
8037 static void RedrawDrawingElements()
8038 {
8039   PickDrawingElement(1, new_element1);
8040   PickDrawingElement(2, new_element2);
8041   PickDrawingElement(3, new_element3);
8042 }
8043
8044 static void DrawDrawingWindow()
8045 {
8046   stick_element_properties_window = FALSE;
8047
8048   SetMainBackgroundImage(IMG_UNDEFINED);
8049   ClearField();
8050
8051   UnmapLevelEditorFieldGadgets();
8052   UnmapLevelEditorToolboxCustomGadgets();
8053
8054   AdjustDrawingAreaGadgets();
8055   AdjustLevelScrollPosition();
8056   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
8057   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
8058
8059   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
8060
8061   MapMainDrawingArea();
8062   MapLevelEditorToolboxDrawingGadgets();
8063 }
8064
8065 static int getTabulatorBarWidth()
8066 {
8067   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
8068   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
8069
8070   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
8071 }
8072
8073 static int getTabulatorBarHeight()
8074 {
8075   return ED_TAB_BAR_HEIGHT;
8076 }
8077
8078 static void DrawLevelInfoTabulatorGadgets()
8079 {
8080   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
8081   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
8082   int gd_x = gd->x + gd_gi1->border.width / 2;
8083   int gd_y = gd->y + gd_gi1->height - 1;
8084   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
8085   int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL;
8086   int id_last  = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR;
8087   int i;
8088
8089   for (i = id_first; i <= id_last; i++)
8090   {
8091     int gadget_id = textbutton_info[i].gadget_id;
8092     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
8093     boolean active = (i != edit_mode_levelinfo);
8094
8095     /* draw background line below tabulator button */
8096     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
8097
8098     /* draw solid line below inactive tabulator buttons */
8099     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
8100       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
8101                     ED_GADGET_TINY_DISTANCE, tab_color);
8102
8103     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
8104     MapTextbuttonGadget(i);
8105   }
8106
8107   /* draw little border line below tabulator buttons */
8108   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
8109     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
8110                   ED_GADGET_TINY_DISTANCE,
8111                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
8112 }
8113
8114 static void DrawPropertiesTabulatorGadgets()
8115 {
8116   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
8117   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
8118   int gd_x = gd->x + gd_gi1->border.width / 2;
8119   int gd_y = gd->y + gd_gi1->height - 1;
8120   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
8121   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
8122   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
8123   int i;
8124
8125   /* draw two config tabulators for player elements */
8126   if (ELEM_IS_PLAYER(properties_element))
8127     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
8128
8129   /* draw two config and one "change" tabulator for custom elements */
8130   if (IS_CUSTOM_ELEMENT(properties_element))
8131     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
8132
8133   for (i = id_first; i <= id_last; i++)
8134   {
8135     int gadget_id = textbutton_info[i].gadget_id;
8136     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
8137     boolean active = (i != edit_mode_properties);
8138
8139     /* use "config 1" and "config 2" instead of "config" for players and CEs */
8140     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
8141         (ELEM_IS_PLAYER(properties_element) ||
8142          IS_CUSTOM_ELEMENT(properties_element)))
8143       continue;
8144
8145     /* draw background line below tabulator button */
8146     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
8147
8148     /* draw solid line below inactive tabulator buttons */
8149     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
8150       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
8151                     ED_GADGET_TINY_DISTANCE, tab_color);
8152
8153     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
8154     MapTextbuttonGadget(i);
8155   }
8156
8157   /* draw little border line below tabulator buttons */
8158   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
8159     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
8160                   ED_GADGET_TINY_DISTANCE,
8161                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
8162 }
8163
8164 static void DrawLevelInfoLevel()
8165 {
8166   int i;
8167
8168   /* draw counter gadgets */
8169   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
8170     MapCounterButtons(i);
8171
8172   /* draw selectbox gadgets */
8173   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
8174     MapSelectboxGadget(i);
8175
8176   /* draw text input gadgets */
8177   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
8178     MapTextInputGadget(i);
8179 }
8180
8181 static void DrawLevelInfoEditor()
8182 {
8183   int i;
8184
8185   /* draw counter gadgets */
8186   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
8187     MapCounterButtons(i);
8188
8189   /* draw checkbutton gadgets */
8190   for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
8191     MapCheckbuttonGadget(i);
8192
8193   /* draw radiobutton gadgets */
8194   for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
8195     MapRadiobuttonGadget(i);
8196
8197   /* draw drawing area */
8198   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
8199 }
8200
8201 static void DrawLevelInfoWindow()
8202 {
8203   char *text = "Global Settings";
8204   int font_nr = FONT_TITLE_1;
8205   struct MenuPosInfo *pos = &editor.settings.headline;
8206   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
8207   int sy = SY + pos->y;
8208
8209   stick_element_properties_window = FALSE;
8210
8211   UnmapLevelEditorFieldGadgets();
8212
8213   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
8214   ClearField();
8215
8216   DrawText(sx, sy, text, font_nr);
8217
8218   DrawLevelInfoTabulatorGadgets();
8219
8220   if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL)
8221     DrawLevelInfoLevel();
8222   else  /* (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR) */
8223     DrawLevelInfoEditor();
8224 }
8225
8226 static void DrawCustomContentArea()
8227 {
8228   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
8229   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8230   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
8231   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
8232   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
8233   int xoffset = ED_GADGET_SPACE_DISTANCE;
8234
8235   /* add distance for potential left text (without drawing area border) */
8236   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
8237
8238   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
8239
8240   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
8241 }
8242
8243 static void DrawCustomChangeContentArea()
8244 {
8245   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
8246   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8247   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
8248   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
8249   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
8250   int xoffset = ED_GADGET_SPACE_DISTANCE;
8251
8252   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
8253
8254   MapDrawingArea(id);
8255 }
8256
8257 static void RemoveElementContentArea(int id, int font_height)
8258 {
8259   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8260
8261   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
8262                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
8263                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8264                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
8265                  ED_GADGET_TEXT_DISTANCE + font_height);
8266 }
8267
8268 static void DrawYamYamContentAreas()
8269 {
8270   int font_nr = FONT_TEXT_1;
8271   int font_height = getFontHeight(font_nr);
8272   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
8273   int yoffset = (tilesize - font_height) / 2;
8274   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
8275   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
8276   int i;
8277
8278   /* display counter to choose number of element content areas */
8279   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
8280
8281   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
8282   {
8283     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
8284
8285     if (i < level.num_yamyam_contents)
8286     {
8287       MapDrawingArea(id);
8288     }
8289     else
8290     {
8291       UnmapDrawingArea(id);
8292
8293       /* delete content areas in case of reducing number of them */
8294       RemoveElementContentArea(id, font_height);
8295     }
8296   }
8297
8298   DrawText(x, y + 0 * tilesize, "content", font_nr);
8299   DrawText(x, y + 1 * tilesize, "when",    font_nr);
8300   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
8301 }
8302
8303 static void DrawMagicBallContentAreas()
8304 {
8305   int font_nr = FONT_TEXT_1;
8306   int font_height = getFontHeight(font_nr);
8307   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
8308   int yoffset = (tilesize - font_height) / 2;
8309   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
8310   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
8311   int i;
8312
8313   /* display counter to choose number of element content areas */
8314   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
8315
8316   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
8317   {
8318     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
8319
8320     if (i < level.num_ball_contents)
8321     {
8322       MapDrawingArea(id);
8323     }
8324     else
8325     {
8326       UnmapDrawingArea(id);
8327
8328       /* delete content areas in case of reducing number of them */
8329       RemoveElementContentArea(id, font_height);
8330     }
8331   }
8332
8333   DrawText(x, y + 0 * tilesize, "generated", font_nr);
8334   DrawText(x, y + 1 * tilesize, "when",      font_nr);
8335   DrawText(x, y + 2 * tilesize, "active",    font_nr);
8336 }
8337
8338 static void DrawAndroidElementArea(int element)
8339 {
8340   int id = ED_DRAWING_ID_ANDROID_CONTENT;
8341   int num_elements = level.num_android_clone_elements;
8342   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8343   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8344   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8345   int xsize = MAX_ANDROID_ELEMENTS;
8346   int ysize = 1;
8347
8348   /* display counter to choose number of element areas */
8349   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
8350
8351   if (drawingarea_info[id].text_left != NULL)
8352     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8353
8354   UnmapDrawingArea(id);
8355
8356   ModifyEditorDrawingArea(id, num_elements, 1);
8357
8358   /* delete content areas in case of reducing number of them */
8359   DrawBackground(sx, sy,
8360                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8361                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8362
8363   MapDrawingArea(id);
8364 }
8365
8366 static void DrawGroupElementArea(int element)
8367 {
8368   int id = ED_DRAWING_ID_GROUP_CONTENT;
8369   int num_elements = group_element_info.num_elements;
8370   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8371   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8372   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8373   int xsize = MAX_ELEMENTS_IN_GROUP;
8374   int ysize = 1;
8375
8376   if (drawingarea_info[id].text_left != NULL)
8377     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8378
8379   UnmapDrawingArea(id);
8380
8381   ModifyEditorDrawingArea(id, num_elements, 1);
8382
8383   /* delete content areas in case of reducing number of them */
8384   DrawBackground(sx, sy,
8385                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8386                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8387
8388   MapDrawingArea(id);
8389 }
8390
8391 static void DrawPlayerInitialInventoryArea(int element)
8392 {
8393   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
8394   int player_nr = GET_PLAYER_NR(element);
8395   int num_elements = level.initial_inventory_size[player_nr];
8396   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8397   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8398   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8399   int xsize = MAX_INITIAL_INVENTORY_SIZE;
8400   int ysize = 1;
8401
8402   /* determine horizontal position to the right of specified gadget */
8403   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
8404     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
8405           ED_DRAWINGAREA_TEXT_DISTANCE);
8406
8407   /* determine horizontal offset for leading text */
8408   if (drawingarea_info[id].text_left != NULL)
8409     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8410
8411   UnmapDrawingArea(id);
8412
8413   ModifyEditorDrawingArea(id, num_elements, 1);
8414
8415   /* delete content areas in case of reducing number of them */
8416   DrawBackground(sx, sy,
8417                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8418                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8419
8420   MapDrawingArea(id);
8421 }
8422
8423 static void DrawEnvelopeTextArea(int envelope_nr)
8424 {
8425   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
8426   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
8427
8428   UnmapGadget(gi);
8429   DrawBackground(gi->x, gi->y, gi->width, gi->height);
8430
8431   if (envelope_nr != -1)
8432     textarea_info[id].value = level.envelope[envelope_nr].text;
8433
8434   ModifyGadget(gi, GDI_AREA_SIZE,
8435                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
8436                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
8437                GDI_END);
8438
8439   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
8440 }
8441
8442 static boolean PrintInfoText(char *text, int font_nr, int start_line)
8443 {
8444   int font_height = getFontHeight(font_nr);
8445   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8446   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8447   int sx = SX + pad_x;
8448   int sy = SY + pad_y;
8449   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
8450
8451   if (start_line >= max_lines_per_screen)
8452     return FALSE;
8453
8454   DrawText(sx, sy + start_line * font_height, text, font_nr);
8455
8456   return TRUE;
8457 }
8458
8459 static int PrintElementDescriptionFromFile(char *filename, int start_line)
8460 {
8461   int font_nr = FONT_TEXT_2;
8462   int font_width = getFontWidth(font_nr);
8463   int font_height = getFontHeight(font_nr);
8464   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8465   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8466   int sx = SX + pad_x;
8467   int sy = SY + pad_y + start_line * font_height;
8468   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
8469   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
8470   int max_lines_drawable = max_lines_per_screen - start_line;
8471
8472   if (start_line >= max_lines_per_screen)
8473     return FALSE;
8474
8475   return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1,
8476                       max_lines_drawable, 0, -1, TRUE, FALSE, FALSE);
8477 }
8478
8479 static void DrawPropertiesInfo()
8480 {
8481   static struct
8482   {
8483     int value;
8484     char *text;
8485   }
8486   properties[] =
8487   {
8488     /* configurable properties */
8489
8490     { EP_WALKABLE_OVER,         "- player can walk over it"             },
8491     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
8492     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
8493     { EP_PASSABLE_OVER,         "- player can pass over it"             },
8494     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
8495     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
8496     { EP_PROTECTED,             "- player is protected by it"           },
8497
8498     { EP_DIGGABLE,              "- can be digged away"                  },
8499     { EP_COLLECTIBLE,           "- can be collected"                    },
8500     { EP_DROPPABLE,             "- can be dropped after collecting"     },
8501     { EP_THROWABLE,             "- can be thrown after collecting"      },
8502     { EP_PUSHABLE,              "- can be pushed"                       },
8503
8504     { EP_CAN_FALL,              "- can fall"                            },
8505     { EP_CAN_MOVE,              "- can move"                            },
8506
8507     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
8508 #if 0
8509     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
8510 #endif
8511     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
8512
8513     { EP_SLIPPERY,              "- slippery for falling elements"       },
8514     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
8515
8516     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
8517     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
8518     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
8519     { EP_DONT_TOUCH,            "- deadly when touching"                },
8520
8521     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
8522
8523     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
8524     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
8525     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
8526
8527     { EP_CAN_CHANGE,            "- can change to other element"         },
8528
8529     /* pre-defined properties */
8530     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
8531     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
8532     { EP_SWITCHABLE,            "- can be switched"                     },
8533 #if 0
8534     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
8535 #endif
8536
8537     { -1,                       NULL                                    }
8538   };
8539   char *filename = getElementDescriptionFilename(properties_element);
8540   char *percentage_text = "In this level: ";
8541   char *properties_text = "Standard properties: ";
8542   float percentage;
8543   int num_elements_in_level;
8544   int num_standard_properties = 0;
8545   int font1_nr = FONT_TEXT_1;
8546   int font2_nr = FONT_TEXT_2;
8547   int font1_width = getFontWidth(font1_nr);
8548   int font2_height = getFontHeight(font2_nr);
8549   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8550   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8551   int screen_line = 0;
8552   int i, x, y;
8553
8554   if (setup.editor.show_element_token)
8555   {
8556     DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
8557               "[%s]", element_info[properties_element].token_name);
8558     screen_line++;
8559   }
8560
8561   /* ----- print number of elements / percentage of this element in level */
8562
8563   num_elements_in_level = 0;
8564   for (y = 0; y < lev_fieldy; y++) 
8565     for (x = 0; x < lev_fieldx; x++)
8566       if (Feld[x][y] == properties_element)
8567         num_elements_in_level++;
8568   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
8569
8570   DrawTextS(pad_x, pad_y + screen_line * font2_height, font1_nr,
8571             percentage_text);
8572   DrawTextF(pad_x + strlen(percentage_text) * font1_width,
8573             pad_y + screen_line++ * font2_height, font2_nr,
8574             "%d (%.2f%%)", num_elements_in_level, percentage);
8575
8576   screen_line++;
8577
8578   /* ----- print standard properties of this element */
8579
8580   DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
8581             properties_text);
8582
8583   for (i = 0; properties[i].value != -1; i++)
8584   {
8585     if (!HAS_PROPERTY(properties_element, properties[i].value))
8586       continue;
8587
8588     DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
8589               properties[i].text);
8590     num_standard_properties++;
8591   }
8592
8593   if (num_standard_properties == 0)
8594     DrawTextS(pad_x + strlen(properties_text) * font1_width,
8595               pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
8596
8597   screen_line++;
8598
8599   /* ----- print special description of this element */
8600
8601   PrintInfoText("Description:", FONT_TEXT_1, screen_line);
8602   if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
8603     PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
8604 }
8605
8606 #define TEXT_COLLECTING         "Score for collecting"
8607 #define TEXT_SMASHING           "Score for smashing"
8608 #define TEXT_SLURPING           "Score for slurping robot"
8609 #define TEXT_CRACKING           "Score for cracking"
8610 #define TEXT_AMOEBA_SPEED       "Speed of amoeba growth"
8611 #define TEXT_DURATION           "Duration when activated"
8612 #define TEXT_BALL_DELAY         "Element generation delay"
8613 #define TEXT_MOVE_SPEED         "Speed of android moving"
8614 #define TEXT_CLONE_SPEED        "Speed of android cloning"
8615 #define TEXT_GAME_OF_LIFE_1     "Min neighbours to survive"
8616 #define TEXT_GAME_OF_LIFE_2     "Max neighbours to survive"
8617 #define TEXT_GAME_OF_LIFE_3     "Min neighbours to create"
8618 #define TEXT_GAME_OF_LIFE_4     "Max neighbours to create"
8619 #define TEXT_TIME_BONUS         "Extra time to solve level"
8620
8621 static struct
8622 {
8623   int element;
8624   int *value;
8625   char *text;
8626 } elements_with_counter[] =
8627 {
8628   { EL_EMERALD,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
8629   { EL_BD_DIAMOND,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
8630   { EL_EMERALD_YELLOW,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8631   { EL_EMERALD_RED,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8632   { EL_EMERALD_PURPLE,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8633   { EL_SP_INFOTRON,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8634   { EL_DIAMOND,         &level.score[SC_DIAMOND],       TEXT_COLLECTING },
8635   { EL_CRYSTAL,         &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
8636   { EL_PEARL,           &level.score[SC_PEARL],         TEXT_COLLECTING },
8637   { EL_BUG,             &level.score[SC_BUG],           TEXT_SMASHING   },
8638   { EL_BUG_RIGHT,       &level.score[SC_BUG],           TEXT_SMASHING   },
8639   { EL_BUG_UP,          &level.score[SC_BUG],           TEXT_SMASHING   },
8640   { EL_BUG_LEFT,        &level.score[SC_BUG],           TEXT_SMASHING   },
8641   { EL_BUG_DOWN,        &level.score[SC_BUG],           TEXT_SMASHING   },
8642   { EL_BD_BUTTERFLY,    &level.score[SC_BUG],           TEXT_SMASHING   },
8643   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],         TEXT_SMASHING   },
8644   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],         TEXT_SMASHING   },
8645   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],         TEXT_SMASHING   },
8646   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],         TEXT_SMASHING   },
8647   { EL_SP_ELECTRON,     &level.score[SC_BUG],           TEXT_SMASHING   },
8648   { EL_SPACESHIP,       &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8649   { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8650   { EL_SPACESHIP_UP,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8651   { EL_SPACESHIP_LEFT,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8652   { EL_SPACESHIP_DOWN,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8653   { EL_BD_FIREFLY,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8654   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8655   { EL_BD_FIREFLY_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8656   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8657   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8658   { EL_SP_SNIKSNAK,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8659   { EL_YAMYAM,          &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8660   { EL_YAMYAM_LEFT,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8661   { EL_YAMYAM_RIGHT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8662   { EL_YAMYAM_UP,       &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8663   { EL_YAMYAM_DOWN,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8664   { EL_DARK_YAMYAM,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8665   { EL_ROBOT,           &level.score[SC_ROBOT],         TEXT_SMASHING   },
8666   { EL_PACMAN,          &level.score[SC_PACMAN],        TEXT_SMASHING   },
8667   { EL_PACMAN_RIGHT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
8668   { EL_PACMAN_UP,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
8669   { EL_PACMAN_LEFT,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8670   { EL_PACMAN_DOWN,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8671   { EL_NUT,             &level.score[SC_NUT],           TEXT_CRACKING   },
8672   { EL_DYNAMITE,        &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8673   { EL_EM_DYNAMITE,     &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8674   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
8675   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8676   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8677   { EL_SHIELD_NORMAL,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8678   { EL_SHIELD_DEADLY,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8679   { EL_EXTRA_TIME,      &level.extra_time_score,        TEXT_COLLECTING },
8680   { EL_KEY_1,           &level.score[SC_KEY],           TEXT_COLLECTING },
8681   { EL_KEY_2,           &level.score[SC_KEY],           TEXT_COLLECTING },
8682   { EL_KEY_3,           &level.score[SC_KEY],           TEXT_COLLECTING },
8683   { EL_KEY_4,           &level.score[SC_KEY],           TEXT_COLLECTING },
8684   { EL_EM_KEY_1,        &level.score[SC_KEY],           TEXT_COLLECTING },
8685   { EL_EM_KEY_2,        &level.score[SC_KEY],           TEXT_COLLECTING },
8686   { EL_EM_KEY_3,        &level.score[SC_KEY],           TEXT_COLLECTING },
8687   { EL_EM_KEY_4,        &level.score[SC_KEY],           TEXT_COLLECTING },
8688   { EL_EMC_KEY_5,       &level.score[SC_KEY],           TEXT_COLLECTING },
8689   { EL_EMC_KEY_6,       &level.score[SC_KEY],           TEXT_COLLECTING },
8690   { EL_EMC_KEY_7,       &level.score[SC_KEY],           TEXT_COLLECTING },
8691   { EL_EMC_KEY_8,       &level.score[SC_KEY],           TEXT_COLLECTING },
8692   { EL_DC_KEY_WHITE,    &level.score[SC_KEY],           TEXT_COLLECTING },
8693   { EL_AMOEBA_WET,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8694   { EL_AMOEBA_DRY,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8695   { EL_AMOEBA_FULL,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8696   { EL_BD_AMOEBA,       &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8697   { EL_EMC_DRIPPER,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8698   { EL_MAGIC_WALL,      &level.time_magic_wall,         TEXT_DURATION   },
8699   { EL_BD_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8700   { EL_DC_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8701   { EL_ROBOT_WHEEL,     &level.time_wheel,              TEXT_DURATION   },
8702
8703   { EL_TIMEGATE_SWITCH,   &level.time_timegate,         TEXT_DURATION   },
8704   { EL_DC_TIMEGATE_SWITCH,&level.time_timegate,         TEXT_DURATION   },
8705   { EL_LIGHT_SWITCH,    &level.time_light,              TEXT_DURATION   },
8706   { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,          TEXT_DURATION   },
8707   { EL_SHIELD_NORMAL,   &level.shield_normal_time,      TEXT_DURATION   },
8708   { EL_SHIELD_DEADLY,   &level.shield_deadly_time,      TEXT_DURATION   },
8709   { EL_EXTRA_TIME,      &level.extra_time,              TEXT_TIME_BONUS },
8710   { EL_TIME_ORB_FULL,   &level.time_orb_time,           TEXT_TIME_BONUS },
8711   { EL_GAME_OF_LIFE,    &level.game_of_life[0],         TEXT_GAME_OF_LIFE_1 },
8712   { EL_GAME_OF_LIFE,    &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
8713   { EL_GAME_OF_LIFE,    &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
8714   { EL_GAME_OF_LIFE,    &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
8715   { EL_BIOMAZE,         &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
8716   { EL_BIOMAZE,         &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
8717   { EL_BIOMAZE,         &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
8718   { EL_BIOMAZE,         &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
8719
8720   { EL_EMC_ANDROID,     &level.android_move_time,       TEXT_MOVE_SPEED },
8721   { EL_EMC_ANDROID,     &level.android_clone_time,      TEXT_CLONE_SPEED },
8722   { EL_EMC_MAGIC_BALL,  &level.ball_time,               TEXT_BALL_DELAY },
8723   { EL_EMC_LENSES,      &level.lenses_score,            TEXT_COLLECTING },
8724   { EL_EMC_MAGNIFIER,   &level.magnify_score,           TEXT_COLLECTING },
8725   { EL_SPRING,          &level.slurp_score,             TEXT_SLURPING   },
8726   { EL_EMC_LENSES,      &level.lenses_time,             TEXT_DURATION   },
8727   { EL_EMC_MAGNIFIER,   &level.magnify_time,            TEXT_DURATION   },
8728
8729   { -1,                 NULL,                           NULL            }
8730 };
8731
8732 static boolean checkPropertiesConfig(int element)
8733 {
8734   int i;
8735
8736   if (IS_GEM(element) ||
8737       IS_CUSTOM_ELEMENT(element) ||
8738       IS_GROUP_ELEMENT(element) ||
8739       IS_ENVELOPE(element) ||
8740       ELEM_IS_PLAYER(element) ||
8741       HAS_EDITOR_CONTENT(element) ||
8742       CAN_GROW(element) ||
8743       COULD_MOVE_INTO_ACID(element) ||
8744       MAYBE_DONT_COLLIDE_WITH(element) ||
8745       element == EL_SOKOBAN_OBJECT ||
8746       element == EL_SOKOBAN_FIELD_EMPTY ||
8747       element == EL_SOKOBAN_FIELD_FULL)
8748     return TRUE;
8749   else
8750     for (i = 0; elements_with_counter[i].element != -1; i++)
8751       if (elements_with_counter[i].element == element)
8752         return TRUE;
8753
8754   return FALSE;
8755 }
8756
8757 static void DrawPropertiesConfig()
8758 {
8759   boolean draw_footer_line = FALSE;
8760   int max_num_element_counters = 4;
8761   int num_element_counters = 0;
8762   int i;
8763
8764   if (!checkPropertiesConfig(properties_element))
8765   {
8766     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
8767
8768     return;
8769   }
8770
8771   /* check if there are elements where a value can be chosen for */
8772   for (i = 0; elements_with_counter[i].element != -1; i++)
8773   {
8774     if (elements_with_counter[i].element == properties_element)
8775     {
8776       int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
8777
8778       counterbutton_info[counter_id].y =
8779         ED_ELEMENT_SETTINGS_YPOS(
8780                 (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
8781                 (CAN_GROW(properties_element)                ? 1 : 0) +
8782                 (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
8783                 (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
8784                 (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
8785                 num_element_counters);
8786
8787       counterbutton_info[counter_id].value = elements_with_counter[i].value;
8788       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
8789
8790       if (properties_element == EL_GAME_OF_LIFE ||
8791           properties_element == EL_BIOMAZE)
8792       {
8793         counterbutton_info[counter_id].min_value = 0;   /* min neighbours */
8794         counterbutton_info[counter_id].max_value = 8;   /* max neighbours */
8795       }
8796       else
8797       {
8798         /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */
8799         counterbutton_info[counter_id].min_value = MIN_SCORE;
8800         counterbutton_info[counter_id].max_value = MAX_SCORE;
8801       }
8802
8803       MapCounterButtons(counter_id);
8804
8805       num_element_counters++;
8806       if (num_element_counters >= max_num_element_counters)
8807         break;
8808     }
8809   }
8810
8811   if (HAS_EDITOR_CONTENT(properties_element))
8812   {
8813     /* draw stickybutton gadget */
8814     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8815
8816     if (IS_AMOEBOID(properties_element))
8817       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
8818     else if (properties_element == EL_YAMYAM ||
8819              properties_element == EL_YAMYAM_LEFT ||
8820              properties_element == EL_YAMYAM_RIGHT ||
8821              properties_element == EL_YAMYAM_UP ||
8822              properties_element == EL_YAMYAM_DOWN)
8823       DrawYamYamContentAreas();
8824     else if (properties_element == EL_EMC_MAGIC_BALL)
8825     {
8826       DrawMagicBallContentAreas();
8827
8828       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
8829       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE);
8830     }
8831     else if (properties_element == EL_EMC_ANDROID)
8832       DrawAndroidElementArea(properties_element);
8833   }
8834
8835   if (ELEM_IS_PLAYER(properties_element))
8836   {
8837     int player_nr = GET_PLAYER_NR(properties_element);
8838
8839     /* these properties can be set for every player individually */
8840
8841     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8842     {
8843       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
8844         &level.start_element[player_nr];
8845       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
8846         &level.artwork_element[player_nr];
8847       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
8848         &level.explosion_element[player_nr];
8849
8850       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
8851         &level.use_start_element[player_nr];
8852       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
8853         &level.use_artwork_element[player_nr];
8854       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
8855         &level.use_explosion_element[player_nr];
8856       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
8857         &level.initial_player_gravity[player_nr];
8858
8859       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
8860         &level.initial_player_stepsize[player_nr];
8861
8862       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
8863       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
8864                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
8865                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
8866       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
8867       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
8868       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
8869       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
8870       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
8871       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
8872       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
8873       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
8874       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
8875       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
8876
8877       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
8878       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
8879       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
8880
8881       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
8882     }
8883     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
8884     {
8885       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
8886         &level.initial_inventory_content[player_nr][0];
8887
8888       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
8889         &level.initial_inventory_size[player_nr];
8890
8891       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
8892         &level.use_initial_inventory[player_nr];
8893
8894       /* draw checkbutton gadgets */
8895       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
8896
8897       /* draw counter gadgets */
8898       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
8899
8900       /* draw drawing area gadgets */
8901       DrawPlayerInitialInventoryArea(properties_element);
8902     }
8903   }
8904
8905   if (IS_GEM(properties_element))
8906     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
8907
8908   if (properties_element == EL_EM_DYNAMITE)
8909     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
8910
8911   if (COULD_MOVE_INTO_ACID(properties_element) &&
8912       !ELEM_IS_PLAYER(properties_element) &&
8913       (!IS_CUSTOM_ELEMENT(properties_element) ||
8914        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
8915   {
8916     /* set position for checkbutton for "can move into acid" */
8917     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
8918       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
8919     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
8920       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
8921                        HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8922
8923     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
8924   }
8925
8926   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
8927     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
8928
8929   if (properties_element == EL_SPRING)
8930     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
8931
8932   if (properties_element == EL_TIME_ORB_FULL)
8933     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
8934
8935   if (CAN_GROW(properties_element))
8936   {
8937     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
8938       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8939
8940     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
8941   }
8942
8943   if (properties_element == EL_SOKOBAN_OBJECT ||
8944       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
8945       properties_element == EL_SOKOBAN_FIELD_FULL)
8946     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
8947
8948   if (IS_ENVELOPE(properties_element))
8949   {
8950     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
8951     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
8952     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
8953     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
8954     int envelope_nr = properties_element - EL_ENVELOPE_1;
8955
8956     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
8957     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
8958
8959     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
8960     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
8961
8962     /* display counter to choose size of envelope text area */
8963     MapCounterButtons(counter1_id);
8964     MapCounterButtons(counter2_id);
8965
8966     /* display checkbuttons to choose auto-wrap and alignment properties */
8967     MapCheckbuttonGadget(button1_id);
8968     MapCheckbuttonGadget(button2_id);
8969
8970     DrawEnvelopeTextArea(envelope_nr);
8971   }
8972
8973   if (IS_CUSTOM_ELEMENT(properties_element))
8974   {
8975     /* draw stickybutton gadget */
8976     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8977
8978     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8979     {
8980       /* draw checkbutton gadgets */
8981       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
8982            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
8983         MapCheckbuttonGadget(i);
8984
8985       /* draw counter gadgets */
8986       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
8987            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
8988         MapCounterButtons(i);
8989
8990       /* draw selectbox gadgets */
8991       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
8992            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
8993         MapSelectboxGadget(i);
8994
8995       /* draw textbutton gadgets */
8996       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
8997
8998       /* draw text input gadgets */
8999       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
9000
9001       /* draw drawing area gadgets */
9002       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
9003
9004       draw_footer_line = TRUE;
9005     }
9006     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
9007     {
9008       /* draw checkbutton gadgets */
9009       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
9010            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
9011         MapCheckbuttonGadget(i);
9012
9013       /* draw counter gadgets */
9014       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
9015            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
9016         MapCounterButtons(i);
9017
9018       /* draw selectbox gadgets */
9019       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
9020            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
9021         MapSelectboxGadget(i);
9022
9023       /* draw drawing area gadgets */
9024       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
9025       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
9026       DrawCustomContentArea();
9027     }
9028   }
9029   else if (IS_GROUP_ELEMENT(properties_element))
9030   {
9031     /* draw stickybutton gadget */
9032     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
9033
9034     /* draw checkbutton gadgets */
9035     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
9036     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE);
9037
9038     /* draw counter gadgets */
9039     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
9040
9041     /* draw selectbox gadgets */
9042     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
9043
9044     /* draw textbutton gadgets */
9045     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
9046
9047     /* draw drawing area gadgets */
9048     DrawGroupElementArea(properties_element);
9049
9050     /* draw text input gadgets */
9051     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
9052
9053     /* draw drawing area gadgets */
9054     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
9055
9056     draw_footer_line = TRUE;
9057   }
9058
9059   /* draw little footer border line above CE/GE use/save template gadgets */
9060   if (draw_footer_line)
9061   {
9062     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
9063     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
9064     int gd_x = gd->x + gd_gi1->border.width / 2;
9065     int gd_y = gd->y + gd_gi1->height - 1;
9066     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
9067
9068     if (tab_color != BLACK_PIXEL)               /* black => transparent */
9069       FillRectangle(drawto,
9070                     SX + ED_ELEMENT_SETTINGS_X(0),
9071                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
9072                     ED_TAB_BAR_HEIGHT,
9073                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
9074   }
9075 }
9076
9077 static void DrawPropertiesChangeDrawingAreas()
9078 {
9079   if (IS_CUSTOM_ELEMENT(properties_element))
9080   {
9081     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
9082     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
9083     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
9084
9085     DrawCustomChangeContentArea();
9086   }
9087
9088   redraw_mask |= REDRAW_FIELD;
9089 }
9090
9091 static void DrawPropertiesChange()
9092 {
9093   int i;
9094
9095   /* needed to initially set selectbox options for special action options */
9096   setSelectboxSpecialActionOptions();
9097
9098   /* draw stickybutton gadget */
9099   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
9100
9101   /* draw checkbutton gadgets */
9102   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
9103        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
9104     MapCheckbuttonGadget(i);
9105
9106   /* draw counter gadgets */
9107   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
9108        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
9109     MapCounterButtons(i);
9110
9111   /* draw selectbox gadgets */
9112   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
9113        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
9114     MapSelectboxGadget(i);
9115
9116   /* draw textbutton gadgets */
9117   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
9118        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
9119     MapTextbuttonGadget(i);
9120
9121   /* draw graphicbutton gadgets */
9122   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
9123        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
9124     MapGraphicbuttonGadget(i);
9125
9126   /* draw drawing area gadgets */
9127   DrawPropertiesChangeDrawingAreas();
9128 }
9129
9130 static void DrawEditorElementAnimation(int x, int y)
9131 {
9132   int graphic = el2img(properties_element);
9133   int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
9134                custom_element.ce_value_fixed_initial :
9135                ANIM_MODE(graphic) == ANIM_CE_SCORE ?
9136                custom_element.collect_score_initial : FrameCounter);
9137
9138   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
9139 }
9140
9141 static void DrawEditorElementName(int x, int y, int font_nr)
9142 {
9143   char *element_name = getElementInfoText(properties_element);
9144   int font_width = getFontWidth(font_nr);
9145   int font_height = getFontHeight(font_nr);
9146   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
9147   int max_chars_per_line = max_text_width / font_width;
9148   char buffer[max_chars_per_line + 1];
9149
9150   if (strlen(element_name) <= max_chars_per_line)
9151     DrawTextS(x, y, font_nr, element_name);
9152   else
9153   {
9154     int next_pos = max_chars_per_line;
9155
9156     strncpy(buffer, element_name, max_chars_per_line);
9157     buffer[max_chars_per_line] = '\0';
9158
9159     if (element_name[max_chars_per_line] == ' ')
9160       next_pos++;
9161     else
9162     {
9163       int i;
9164
9165       for (i = max_chars_per_line - 1; i >= 0; i--)
9166         if (buffer[i] == ' ')
9167           break;
9168
9169       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
9170       {
9171         buffer[i] = '\0';
9172         next_pos = i + 1;
9173       }
9174     }
9175
9176     DrawTextS(x, y - font_height / 2, font_nr, buffer);
9177
9178     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
9179     buffer[max_chars_per_line] = '\0';
9180
9181     DrawTextS(x, y + font_height / 2, font_nr, buffer);
9182   }
9183 }
9184
9185 static void DrawPropertiesWindow()
9186 {
9187   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
9188   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
9189   int border_size = gd->border_size;
9190   int font_nr = FONT_TEXT_1;
9191   int font_height = getFontHeight(font_nr);
9192   int xoffset = TILEX + element_border + 3 * border_size;
9193   int yoffset = (TILEY - font_height) / 2;
9194   int x1 = editor.settings.element_graphic.x + element_border;
9195   int y1 = editor.settings.element_graphic.y + element_border;
9196   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
9197             editor.settings.element_name.x);
9198   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
9199             editor.settings.element_name.y);
9200   char *text = "Element Settings";
9201   int font2_nr = FONT_TITLE_1;
9202   struct MenuPosInfo *pos = &editor.settings.headline;
9203   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
9204   int sy = SY + pos->y;
9205
9206   stick_element_properties_window = FALSE;
9207
9208   /* make sure that previous properties edit mode exists for this element */
9209   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
9210       !IS_CUSTOM_ELEMENT(properties_element))
9211     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
9212
9213   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
9214       !ELEM_IS_PLAYER(properties_element) &&
9215       !IS_CUSTOM_ELEMENT(properties_element))
9216     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
9217
9218   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
9219       (ELEM_IS_PLAYER(properties_element) ||
9220        IS_CUSTOM_ELEMENT(properties_element)))
9221     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
9222
9223   CopyElementPropertiesToEditor(properties_element);
9224
9225   UnmapLevelEditorFieldGadgets();
9226   UnmapLevelEditorToolboxDrawingGadgets();
9227   UnmapLevelEditorToolboxCustomGadgets();
9228
9229   if (IS_CUSTOM_ELEMENT(properties_element) ||
9230       IS_GROUP_ELEMENT(properties_element))
9231     MapLevelEditorToolboxCustomGadgets();
9232
9233   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
9234   ClearField();
9235
9236   DrawText(sx, sy, text, font2_nr);
9237
9238   FrameCounter = 0;     /* restart animation frame counter */
9239
9240   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
9241   DrawEditorElementAnimation(SX + x1, SY + y1);
9242   DrawEditorElementName(x2, y2, font_nr);
9243
9244   DrawPropertiesTabulatorGadgets();
9245
9246   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
9247     DrawPropertiesInfo();
9248   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
9249     DrawPropertiesChange();
9250   else  /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */
9251     DrawPropertiesConfig();
9252 }
9253
9254 static void UpdateCustomElementGraphicGadgets()
9255 {
9256   struct ElementInfo *ei = &element_info[properties_element];
9257   int i;
9258
9259   ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial :
9260                      properties_element);
9261
9262   ModifyEditorElementList();
9263   RedrawDrawingElements();
9264
9265   /* force redraw of all mapped drawing area gadgets */
9266   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
9267   {
9268     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
9269
9270     if (gi->mapped)
9271       MapDrawingArea(i);
9272   }
9273 }
9274
9275 static int getOpenDirectionFromTube(int element)
9276 {
9277   switch (element)
9278   {
9279     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
9280     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
9281     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
9282     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
9283     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
9284     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
9285     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
9286     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
9287     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
9288     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
9289     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
9290   }
9291
9292   return MV_NONE;
9293 }
9294
9295 static int getTubeFromOpenDirection(int direction)
9296 {
9297   switch (direction)
9298   {
9299     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
9300     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
9301     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
9302     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
9303     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
9304     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
9305     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
9306     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
9307     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
9308     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
9309     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
9310
9311     /* if only one direction, fall back to simple tube with that direction */
9312     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
9313     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
9314     case (MV_UP):                       return EL_TUBE_VERTICAL;
9315     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
9316   }
9317
9318   return EL_EMPTY;
9319 }
9320
9321 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
9322 {
9323   int element_new = getTubeFromOpenDirection(direction);
9324
9325   return (element_new != EL_EMPTY ? element_new : element_old);
9326 }
9327
9328 static int getOpenDirectionFromBelt(int element)
9329 {
9330   int belt_dir = getBeltDirFromBeltElement(element);
9331
9332   return (belt_dir == MV_LEFT ? MV_RIGHT :
9333           belt_dir == MV_RIGHT ? MV_LEFT :
9334           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
9335 }
9336
9337 static int getBeltFromNrAndOpenDirection(int nr, int direction)
9338 {
9339   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
9340                   direction == MV_RIGHT ? MV_LEFT :
9341                   direction == MV_HORIZONTAL ? MV_NONE : direction);
9342
9343   if (direction == MV_NONE)
9344     return EL_EMPTY;
9345
9346   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
9347 }
9348
9349 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
9350                                                  int element_old)
9351 {
9352   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
9353
9354   return (element_new != EL_EMPTY ? element_new : element_old);
9355 }
9356
9357 static int getOpenDirectionFromPool(int element)
9358 {
9359   switch (element)
9360   {
9361     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
9362     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
9363     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
9364     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
9365     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
9366     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
9367   }
9368
9369   return MV_NONE;
9370 }
9371
9372 static int getPoolFromOpenDirection(int direction)
9373 {
9374   switch (direction)
9375   {
9376     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
9377     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
9378     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
9379     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
9380     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
9381     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
9382   }
9383
9384   return EL_EMPTY;
9385 }
9386
9387 static int getPoolFromOpenDirectionExt(int direction, int help_element)
9388 {
9389   int element = getPoolFromOpenDirection(direction);
9390   int help_direction = getOpenDirectionFromPool(help_element);
9391
9392   if (element == EL_EMPTY)
9393   {
9394     int help_direction_vertical = help_direction & MV_VERTICAL;
9395
9396     element = getPoolFromOpenDirection(direction | help_direction_vertical);
9397   }
9398
9399   if (element == EL_EMPTY)
9400   {
9401     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
9402
9403     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
9404   }
9405
9406   return element;
9407 }
9408
9409 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
9410 {
9411   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
9412
9413   return (element_new != EL_EMPTY ? element_new : element_old);
9414 }
9415
9416 static int getOpenDirectionFromPillar(int element)
9417 {
9418   switch (element)
9419   {
9420     case EL_EMC_WALL_1:                 return (MV_DOWN);
9421     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
9422     case EL_EMC_WALL_3:                 return (MV_UP);
9423   }
9424
9425   return MV_NONE;
9426 }
9427
9428 static int getPillarFromOpenDirection(int direction)
9429 {
9430   switch (direction)
9431   {
9432     case (MV_DOWN):                     return EL_EMC_WALL_1;
9433     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
9434     case (MV_UP):                       return EL_EMC_WALL_3;
9435   }
9436
9437   return EL_EMPTY;
9438 }
9439
9440 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
9441 {
9442   int element_new = getPillarFromOpenDirection(direction);
9443
9444   return (element_new != EL_EMPTY ? element_new : element_old);
9445 }
9446
9447 static int getOpenDirectionFromSteel2(int element)
9448 {
9449   switch (element)
9450   {
9451     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
9452     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
9453     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
9454     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
9455     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
9456     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
9457     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
9458     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
9459   }
9460
9461   return MV_NONE;
9462 }
9463
9464 static int getSteel2FromOpenDirection(int direction)
9465 {
9466   switch (direction)
9467   {
9468     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
9469     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
9470     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
9471     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
9472     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
9473     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
9474     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
9475     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
9476   }
9477
9478   return EL_EMPTY;
9479 }
9480
9481 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
9482 {
9483   int element_new = getSteel2FromOpenDirection(direction);
9484
9485   return (element_new != EL_EMPTY ? element_new : element_old);
9486 }
9487
9488 static int getOpenDirectionFromChip(int element)
9489 {
9490   switch (element)
9491   {
9492     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
9493     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
9494     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
9495     case EL_SP_CHIP_TOP:                return (MV_DOWN);
9496     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
9497   }
9498
9499   return MV_NONE;
9500 }
9501
9502 static int getChipFromOpenDirection(int direction)
9503 {
9504   switch (direction)
9505   {
9506     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
9507     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
9508     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
9509     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
9510     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
9511   }
9512
9513   return EL_EMPTY;
9514 }
9515
9516 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
9517 {
9518   int element_new = getChipFromOpenDirection(direction);
9519
9520   return (element_new != EL_EMPTY ? element_new : element_old);
9521 }
9522
9523 static int getClosedTube(int x, int y)
9524 {
9525   static int xy[4][2] =
9526   {
9527     { -1, 0 },
9528     { +1, 0 },
9529     { 0, -1 },
9530     { 0, +1 }
9531   };
9532   int element_old = IntelliDrawBuffer[x][y];
9533   int direction_old = getOpenDirectionFromTube(element_old);
9534   int direction_new = MV_NONE;
9535   int i;
9536
9537   for (i = 0; i < NUM_DIRECTIONS; i++)
9538   {
9539     int xx = x + xy[i][0];
9540     int yy = y + xy[i][1];
9541     int dir = MV_DIR_FROM_BIT(i);
9542     int dir_opposite = MV_DIR_OPPOSITE(dir);
9543
9544     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
9545         (direction_old & dir) &&
9546         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9547       direction_new |= dir;
9548   }
9549
9550   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
9551 }
9552
9553 static int getClosedBelt(int x, int y)
9554 {
9555   static int xy[4][2] =
9556   {
9557     { -1, 0 },
9558     { +1, 0 },
9559     { 0, -1 },
9560     { 0, +1 }
9561   };
9562   int element_old = IntelliDrawBuffer[x][y];
9563   int nr = getBeltNrFromBeltElement(element_old);
9564   int direction_old = getOpenDirectionFromBelt(element_old);
9565   int direction_new = MV_NONE;
9566   int i;
9567
9568   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9569   {
9570     int xx = x + xy[i][0];
9571     int yy = y + xy[i][1];
9572     int dir = MV_DIR_FROM_BIT(i);
9573     int dir_opposite = MV_DIR_OPPOSITE(dir);
9574
9575     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
9576         (direction_old & dir) &&
9577         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9578       direction_new |= dir;
9579   }
9580
9581   return getBeltFromNrAndOpenDirection(nr, direction_new);
9582 }
9583
9584 static int getClosedPool(int x, int y)
9585 {
9586   static int xy[4][2] =
9587   {
9588     { -1, 0 },
9589     { +1, 0 },
9590     { 0, -1 },
9591     { 0, +1 }
9592   };
9593   int element_old = IntelliDrawBuffer[x][y];
9594   int direction_old = getOpenDirectionFromPool(element_old);
9595   int direction_new = MV_NONE;
9596   int i;
9597
9598   for (i = 0; i < NUM_DIRECTIONS; i++)
9599   {
9600     int xx = x + xy[i][0];
9601     int yy = y + xy[i][1];
9602     int dir = MV_DIR_FROM_BIT(i);
9603     int dir_opposite = MV_DIR_OPPOSITE(dir);
9604
9605     if (IN_LEV_FIELD(xx, yy) &&
9606         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
9607         (direction_old & dir) &&
9608         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9609       direction_new |= dir;
9610   }
9611
9612   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
9613 }
9614
9615 static int getClosedPillar(int x, int y)
9616 {
9617   static int xy[4][2] =
9618   {
9619     { -1, 0 },
9620     { +1, 0 },
9621     { 0, -1 },
9622     { 0, +1 }
9623   };
9624   int element_old = IntelliDrawBuffer[x][y];
9625   int direction_old = getOpenDirectionFromPillar(element_old);
9626   int direction_new = MV_NONE;
9627   int i;
9628
9629   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9630   {
9631     int xx = x + xy[i][0];
9632     int yy = y + xy[i][1];
9633     int dir = MV_DIR_FROM_BIT(i);
9634     int dir_opposite = MV_DIR_OPPOSITE(dir);
9635
9636     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
9637         (direction_old & dir) &&
9638         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9639       direction_new |= dir;
9640   }
9641
9642   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
9643 }
9644
9645 static int getClosedSteel2(int x, int y)
9646 {
9647   static int xy[4][2] =
9648   {
9649     { -1, 0 },
9650     { +1, 0 },
9651     { 0, -1 },
9652     { 0, +1 }
9653   };
9654   int element_old = IntelliDrawBuffer[x][y];
9655   int direction_old = getOpenDirectionFromSteel2(element_old);
9656   int direction_new = MV_NONE;
9657   int i;
9658
9659   for (i = 0; i < NUM_DIRECTIONS; i++)
9660   {
9661     int xx = x + xy[i][0];
9662     int yy = y + xy[i][1];
9663     int dir = MV_DIR_FROM_BIT(i);
9664     int dir_opposite = MV_DIR_OPPOSITE(dir);
9665
9666     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
9667         (direction_old & dir) &&
9668         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9669       direction_new |= dir;
9670   }
9671
9672   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
9673 }
9674
9675 static int getClosedChip(int x, int y)
9676 {
9677   static int xy[4][2] =
9678   {
9679     { -1, 0 },
9680     { +1, 0 },
9681     { 0, -1 },
9682     { 0, +1 }
9683   };
9684   int element_old = IntelliDrawBuffer[x][y];
9685   int direction_old = getOpenDirectionFromChip(element_old);
9686   int direction_new = MV_NONE;
9687   int i;
9688
9689   for (i = 0; i < NUM_DIRECTIONS; i++)
9690   {
9691     int xx = x + xy[i][0];
9692     int yy = y + xy[i][1];
9693     int dir = MV_DIR_FROM_BIT(i);
9694     int dir_opposite = MV_DIR_OPPOSITE(dir);
9695
9696     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
9697         (direction_old & dir) &&
9698         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9699       direction_new |= dir;
9700   }
9701
9702   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
9703 }
9704
9705 static void SetElementSimple(int x, int y, int element, boolean change_level)
9706 {
9707   int sx = x - level_xpos;
9708   int sy = y - level_ypos;
9709
9710   IntelliDrawBuffer[x][y] = element;
9711
9712   if (change_level)
9713     Feld[x][y] = element;
9714
9715   if (IN_ED_FIELD(sx, sy))
9716     DrawEditorElement(sx, sy, element);
9717 }
9718
9719 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
9720                                            int x2, int y2, int *element2,
9721                                            int (*close_function)(int, int),
9722                                            boolean change_level)
9723 {
9724   /* set neighbour elements to newly determined connections */
9725   SetElementSimple(x1, y1, *element1, change_level);
9726   SetElementSimple(x2, y2, *element2, change_level);
9727
9728   /* remove all open connections of neighbour elements */
9729   *element1 = close_function(x1, y1);
9730   *element2 = close_function(x2, y2);
9731
9732   /* set neighbour elements to new, minimized connections */
9733   SetElementSimple(x1, y1, *element1, change_level);
9734   SetElementSimple(x2, y2, *element2, change_level);
9735 }
9736
9737 static void SetElementIntelliDraw(int x, int y, int new_element,
9738                                   boolean change_level, int button)
9739 {
9740   static int xy[4][2] =
9741   {
9742     { -1, 0 },
9743     { +1, 0 },
9744     { 0, -1 },
9745     { 0, +1 }
9746   };
9747   static int last_x = -1;
9748   static int last_y = -1;
9749   int old_element = IntelliDrawBuffer[x][y];
9750
9751   if (new_element == EL_UNDEFINED)
9752   {
9753     last_x = -1;
9754     last_y = -1;
9755
9756     return;
9757   }
9758
9759   if (IS_TUBE(new_element))
9760   {
9761     int last_element_new = EL_UNDEFINED;
9762     int direction = MV_NONE;
9763     int i;
9764
9765     /* if old element is of same kind, keep all existing directions */
9766     if (IS_TUBE(old_element))
9767       direction |= getOpenDirectionFromTube(old_element);
9768
9769     for (i = 0; i < NUM_DIRECTIONS; i++)
9770     {
9771       int xx = x + xy[i][0];
9772       int yy = y + xy[i][1];
9773
9774       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9775           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
9776       {
9777         int dir = MV_DIR_FROM_BIT(i);
9778         int dir_opposite = MV_DIR_OPPOSITE(dir);
9779         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9780         int last_direction_old = getOpenDirectionFromTube(last_element_old);
9781         int last_direction_new = last_direction_old | dir_opposite;
9782
9783         last_element_new = getTubeFromOpenDirection(last_direction_new);
9784
9785         direction |= dir;
9786       }
9787     }
9788
9789     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
9790
9791     if (last_element_new != EL_UNDEFINED)
9792       MergeAndCloseNeighbourElements(x, y, &new_element,
9793                                      last_x, last_y, &last_element_new,
9794                                      getClosedTube, change_level);
9795   }
9796   else if (IS_BELT(new_element))
9797   {
9798     int belt_nr = getBeltNrFromBeltElement(new_element);
9799     int last_element_new = EL_UNDEFINED;
9800     int direction = MV_NONE;
9801     int i;
9802
9803     /* if old element is of same kind, keep all existing directions */
9804     if (IS_BELT(old_element))
9805       direction |= getOpenDirectionFromBelt(old_element);
9806
9807     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9808     {
9809       int xx = x + xy[i][0];
9810       int yy = y + xy[i][1];
9811
9812       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9813           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
9814       {
9815         int dir = MV_DIR_FROM_BIT(i);
9816         int dir_opposite = MV_DIR_OPPOSITE(dir);
9817         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9818         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
9819         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
9820         int last_direction_new = last_direction_old | dir_opposite;
9821
9822         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
9823                                                          last_direction_new);
9824         direction |= dir;
9825       }
9826     }
9827
9828     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
9829                                                         new_element);
9830     if (last_element_new != EL_UNDEFINED)
9831       MergeAndCloseNeighbourElements(x, y, &new_element,
9832                                      last_x, last_y, &last_element_new,
9833                                      getClosedBelt, change_level);
9834   }
9835   else if (IS_ACID_POOL_OR_ACID(new_element))
9836   {
9837     int last_element_new = EL_UNDEFINED;
9838     int direction = MV_NONE;
9839     int i;
9840
9841     /* if old element is of same kind, keep all existing directions */
9842     if (IS_ACID_POOL_OR_ACID(old_element))
9843       direction |= getOpenDirectionFromPool(old_element);
9844
9845     for (i = 0; i < NUM_DIRECTIONS; i++)
9846     {
9847       int xx = x + xy[i][0];
9848       int yy = y + xy[i][1];
9849
9850       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9851           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
9852       {
9853         int dir = MV_DIR_FROM_BIT(i);
9854         int dir_opposite = MV_DIR_OPPOSITE(dir);
9855         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9856         int last_direction_old = getOpenDirectionFromPool(last_element_old);
9857         int last_direction_new = last_direction_old | dir_opposite;
9858
9859         last_element_new = getPoolFromOpenDirection(last_direction_new);
9860
9861         direction |= dir;
9862       }
9863     }
9864
9865     /* special corrections needed for intuitively correct acid pool drawing */
9866     if (last_element_new == EL_EMPTY)
9867       last_element_new = new_element;
9868     else if (last_element_new != EL_UNDEFINED)
9869       new_element = last_element_new;
9870
9871     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
9872
9873     if (last_element_new != EL_UNDEFINED)
9874       MergeAndCloseNeighbourElements(x, y, &new_element,
9875                                      last_x, last_y, &last_element_new,
9876                                      getClosedPool, change_level);
9877   }
9878   else if (IS_EMC_PILLAR(new_element))
9879   {
9880     int last_element_new = EL_UNDEFINED;
9881     int direction = MV_NONE;
9882     int i;
9883
9884     /* if old element is of same kind, keep all existing directions */
9885     if (IS_EMC_PILLAR(old_element))
9886       direction |= getOpenDirectionFromPillar(old_element);
9887
9888     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9889     {
9890       int xx = x + xy[i][0];
9891       int yy = y + xy[i][1];
9892
9893       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9894           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
9895       {
9896         int dir = MV_DIR_FROM_BIT(i);
9897         int dir_opposite = MV_DIR_OPPOSITE(dir);
9898         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9899         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
9900         int last_direction_new = last_direction_old | dir_opposite;
9901
9902         last_element_new = getPillarFromOpenDirection(last_direction_new);
9903
9904         direction |= dir;
9905       }
9906     }
9907
9908     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
9909
9910     if (last_element_new != EL_UNDEFINED)
9911       MergeAndCloseNeighbourElements(x, y, &new_element,
9912                                      last_x, last_y, &last_element_new,
9913                                      getClosedPillar, change_level);
9914   }
9915   else if (IS_DC_STEELWALL_2(new_element))
9916   {
9917     int last_element_new = EL_UNDEFINED;
9918     int direction = MV_NONE;
9919     int i;
9920
9921     /* if old element is of same kind, keep all existing directions */
9922     if (IS_DC_STEELWALL_2(old_element))
9923       direction |= getOpenDirectionFromSteel2(old_element);
9924
9925     for (i = 0; i < NUM_DIRECTIONS; i++)
9926     {
9927       int xx = x + xy[i][0];
9928       int yy = y + xy[i][1];
9929
9930       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9931           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
9932       {
9933         int dir = MV_DIR_FROM_BIT(i);
9934         int dir_opposite = MV_DIR_OPPOSITE(dir);
9935         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9936         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
9937         int last_direction_new = last_direction_old | dir_opposite;
9938
9939         last_element_new = getSteel2FromOpenDirection(last_direction_new);
9940
9941         direction |= dir;
9942       }
9943     }
9944
9945     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
9946
9947     if (last_element_new != EL_UNDEFINED)
9948       MergeAndCloseNeighbourElements(x, y, &new_element,
9949                                      last_x, last_y, &last_element_new,
9950                                      getClosedSteel2, change_level);
9951   }
9952   else if (IS_SP_CHIP(new_element))
9953   {
9954     int last_element_new = EL_UNDEFINED;
9955     int direction = MV_NONE;
9956     int i;
9957
9958     /* (do not keep existing directions, regardless of kind of old element) */
9959
9960     for (i = 0; i < NUM_DIRECTIONS; i++)
9961     {
9962       int xx = x + xy[i][0];
9963       int yy = y + xy[i][1];
9964
9965       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9966           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
9967       {
9968         int dir = MV_DIR_FROM_BIT(i);
9969         int dir_opposite = MV_DIR_OPPOSITE(dir);
9970         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9971         int last_direction_old = getOpenDirectionFromChip(last_element_old);
9972         int last_direction_new = last_direction_old | dir_opposite;
9973
9974         if (last_direction_old == MV_NONE)
9975         {
9976           last_element_new = getChipFromOpenDirection(last_direction_new);
9977           direction |= dir;
9978         }
9979         else if (last_direction_old & (dir | dir_opposite))
9980         {
9981           direction |= MV_DIR_OPPOSITE(last_direction_old);
9982         }
9983         else
9984         {
9985           direction |= MV_DIR_OPPOSITE(dir);
9986         }
9987       }
9988     }
9989
9990     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
9991
9992     if (last_element_new != EL_UNDEFINED)
9993       MergeAndCloseNeighbourElements(x, y, &new_element,
9994                                      last_x, last_y, &last_element_new,
9995                                      getClosedChip, change_level);
9996   }
9997   else if (IS_SP_HARDWARE_BASE(new_element))
9998   {
9999     int nr = GetSimpleRandom(6);
10000
10001     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
10002                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
10003                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
10004                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
10005                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
10006   }
10007   else if (new_element == EL_SP_HARDWARE_GREEN ||
10008            new_element == EL_SP_HARDWARE_BLUE ||
10009            new_element == EL_SP_HARDWARE_RED)
10010   {
10011     int nr = GetSimpleRandom(3);
10012
10013     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
10014                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
10015   }
10016   else if (IS_GROUP_ELEMENT(new_element))
10017   {
10018     boolean connected_drawing = FALSE;
10019     int i;
10020
10021     for (i = 0; i < NUM_DIRECTIONS; i++)
10022     {
10023       int xx = x + xy[i][0];
10024       int yy = y + xy[i][1];
10025
10026       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
10027           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
10028         connected_drawing = TRUE;
10029     }
10030
10031     if (!connected_drawing)
10032       ResolveGroupElement(new_element);
10033
10034     new_element = GetElementFromGroupElement(new_element);
10035   }
10036   else if (IS_BELT_SWITCH(old_element))
10037   {
10038     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
10039     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
10040
10041     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
10042                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
10043
10044     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
10045   }
10046   else
10047   {
10048     static int swappable_elements[][2] =
10049     {
10050       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
10051       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
10052       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
10053       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
10054       { EL_EMERALD,                     EL_WALL_EMERALD                 },
10055       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
10056       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
10057       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
10058       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
10059       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
10060       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
10061       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
10062       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
10063       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
10064       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
10065       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
10066       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
10067       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
10068       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
10069       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
10070       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
10071       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
10072       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
10073       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
10074       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
10075       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
10076       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
10077       { EL_PEARL,                       EL_WALL_PEARL                   },
10078       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
10079       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
10080       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
10081       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
10082       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
10083       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
10084       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
10085       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
10086       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
10087       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
10088       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
10089       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
10090
10091       { -1,                             -1                              },
10092     };
10093     static int rotatable_elements[][4] =
10094     {
10095       {
10096         EL_BUG_UP,
10097         EL_BUG_RIGHT,
10098         EL_BUG_DOWN,
10099         EL_BUG_LEFT
10100       },
10101
10102       {
10103         EL_SPACESHIP_UP,
10104         EL_SPACESHIP_RIGHT,
10105         EL_SPACESHIP_DOWN,
10106         EL_SPACESHIP_LEFT
10107       },
10108
10109       {
10110         EL_BD_BUTTERFLY_UP,
10111         EL_BD_BUTTERFLY_RIGHT,
10112         EL_BD_BUTTERFLY_DOWN,
10113         EL_BD_BUTTERFLY_LEFT
10114       },
10115
10116       {
10117         EL_BD_FIREFLY_UP,
10118         EL_BD_FIREFLY_RIGHT,
10119         EL_BD_FIREFLY_DOWN,
10120         EL_BD_FIREFLY_LEFT
10121       },
10122
10123       {
10124         EL_PACMAN_UP,
10125         EL_PACMAN_RIGHT,
10126         EL_PACMAN_DOWN,
10127         EL_PACMAN_LEFT
10128       },
10129
10130       {
10131         EL_YAMYAM_UP,
10132         EL_YAMYAM_RIGHT,
10133         EL_YAMYAM_DOWN,
10134         EL_YAMYAM_LEFT
10135       },
10136
10137       {
10138         EL_ARROW_UP,
10139         EL_ARROW_RIGHT,
10140         EL_ARROW_DOWN,
10141         EL_ARROW_LEFT
10142       },
10143
10144       {
10145         EL_SP_PORT_UP,
10146         EL_SP_PORT_RIGHT,
10147         EL_SP_PORT_DOWN,
10148         EL_SP_PORT_LEFT
10149       },
10150
10151       {
10152         EL_SP_GRAVITY_PORT_UP,
10153         EL_SP_GRAVITY_PORT_RIGHT,
10154         EL_SP_GRAVITY_PORT_DOWN,
10155         EL_SP_GRAVITY_PORT_LEFT
10156       },
10157
10158       {
10159         EL_SP_GRAVITY_ON_PORT_UP,
10160         EL_SP_GRAVITY_ON_PORT_RIGHT,
10161         EL_SP_GRAVITY_ON_PORT_DOWN,
10162         EL_SP_GRAVITY_ON_PORT_LEFT
10163       },
10164
10165       {
10166         EL_SP_GRAVITY_OFF_PORT_UP,
10167         EL_SP_GRAVITY_OFF_PORT_RIGHT,
10168         EL_SP_GRAVITY_OFF_PORT_DOWN,
10169         EL_SP_GRAVITY_OFF_PORT_LEFT
10170       },
10171
10172       {
10173         EL_MOLE_UP,
10174         EL_MOLE_RIGHT,
10175         EL_MOLE_DOWN,
10176         EL_MOLE_LEFT
10177       },
10178
10179       {
10180         EL_BALLOON_SWITCH_UP,
10181         EL_BALLOON_SWITCH_RIGHT,
10182         EL_BALLOON_SWITCH_DOWN,
10183         EL_BALLOON_SWITCH_LEFT
10184       },
10185
10186       {
10187         -1,
10188         -1,
10189         -1,
10190         -1,
10191       },
10192     };
10193     int i, j;
10194
10195     for (i = 0; swappable_elements[i][0] != -1; i++)
10196     {
10197       int element1 = swappable_elements[i][0];
10198       int element2 = swappable_elements[i][1];
10199
10200       if (old_element == element1 || old_element == element2)
10201         new_element = (old_element == element1 ? element2 : element1);
10202     }
10203
10204     for (i = 0; rotatable_elements[i][0] != -1; i++)
10205     {
10206       for (j = 0; j < 4; j++)
10207       {
10208         int element = rotatable_elements[i][j];
10209
10210         if (old_element == element)
10211           new_element = (button == 1 ? rotatable_elements[i][(j + 3) % 4] :
10212                          button == 2 ? rotatable_elements[i][0]           :
10213                          button == 3 ? rotatable_elements[i][(j + 1) % 4] :
10214                          old_element);
10215       }
10216     }
10217   }
10218
10219   SetElementSimple(x, y, new_element, change_level);
10220
10221   last_x = x;
10222   last_y = y;
10223 }
10224
10225 static void ResetIntelliDraw()
10226 {
10227   int x, y;
10228
10229   for (x = 0; x < lev_fieldx; x++)
10230     for (y = 0; y < lev_fieldy; y++)
10231       IntelliDrawBuffer[x][y] = Feld[x][y];
10232
10233   SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
10234 }
10235
10236 static void SetElementExt(int x, int y, int element, boolean change_level,
10237                           int button)
10238 {
10239   if (element < 0)
10240     SetElementSimple(x, y, Feld[x][y], change_level);
10241   else if (GetKeyModState() & KMOD_Shift)
10242     SetElementIntelliDraw(x, y, element, change_level, button);
10243   else
10244     SetElementSimple(x, y, element, change_level);
10245 }
10246
10247 static void SetElement(int x, int y, int element)
10248 {
10249   SetElementExt(x, y, element, TRUE, -1);
10250 }
10251
10252 static void SetElementButton(int x, int y, int element, int button)
10253 {
10254   SetElementExt(x, y, element, TRUE, button);
10255 }
10256
10257 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
10258 {
10259   int lx = sx + level_xpos;
10260   int ly = sy + level_ypos;
10261
10262   SetElementExt(lx, ly, element, change_level, -1);
10263 }
10264
10265 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
10266                      int element, boolean change_level)
10267 {
10268   int xsize = ABS(to_x - from_x);
10269   int ysize = ABS(to_y - from_y);
10270   int dx = (to_x < from_x ? -1 : +1);
10271   int dy = (to_y < from_y ? -1 : +1);
10272   int i;
10273
10274   if (from_y == to_y)                   /* horizontal line */
10275   {
10276     for (i = 0; i <= xsize; i++)
10277       DrawLineElement(from_x + i * dx, from_y, element, change_level);
10278   }
10279   else if (from_x == to_x)              /* vertical line */
10280   {
10281     for (i = 0; i <= ysize; i++)
10282       DrawLineElement(from_x, from_y + i * dy, element, change_level);
10283   }
10284   else                                  /* diagonal line */
10285   {
10286     if (ysize < xsize)                  /* a < 1 */
10287     {
10288       float a = (float)ysize / (float)xsize;
10289
10290       for (i = 0; i <= xsize; i++)
10291       {
10292         int x = dx * i;
10293         int y = dy * (int)(a * i + 0.5);
10294
10295         DrawLineElement(from_x + x, from_y + y, element, change_level);
10296       }
10297     }
10298     else                                /* a >= 1 */
10299     {
10300       float a = (float)xsize / (float)ysize;
10301
10302       for (i = 0; i <= ysize; i++)
10303       {
10304         int x = dx * (int)(a * i + 0.5);
10305         int y = dy * i;
10306
10307         DrawLineElement(from_x + x, from_y + y, element, change_level);
10308       }
10309     }
10310   }
10311 }
10312
10313 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
10314                     int element, boolean change_level)
10315 {
10316   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
10317   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
10318   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
10319   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
10320 }
10321
10322 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
10323                           int element, boolean change_level)
10324 {
10325   int y;
10326
10327   if (from_y > to_y)
10328     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
10329
10330   for (y = from_y; y <= to_y; y++)
10331     DrawLine(from_x, y, to_x, y, element, change_level);
10332 }
10333
10334 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
10335                        int element, boolean change_level)
10336 {
10337   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
10338   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
10339   int len_x = ABS(to_x - from_x);
10340   int len_y = ABS(to_y - from_y);
10341   int radius, x, y;
10342
10343   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
10344
10345   /* not optimal (some points get drawn twice) but simple,
10346      and fast enough for the few points we are drawing */
10347
10348   for (x = 0; x <= radius; x++)
10349   {
10350     int sx, sy, lx, ly;
10351
10352     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
10353
10354     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
10355     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
10356     lx = sx + level_xpos;
10357     ly = sy + level_ypos;
10358
10359     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10360       DrawLineElement(sx, sy, element, change_level);
10361   }
10362
10363   for (y = 0; y <= radius; y++)
10364   {
10365     int sx, sy, lx, ly;
10366
10367     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
10368
10369     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
10370     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
10371     lx = sx + level_xpos;
10372     ly = sy + level_ypos;
10373
10374     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10375       DrawLineElement(sx, sy, element, change_level);
10376   }
10377 }
10378
10379 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
10380                     int element, boolean change_level)
10381 {
10382   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
10383   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
10384
10385   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
10386 }
10387
10388 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
10389
10390 #if DRAW_CIRCLES_BUTTON_AVAILABLE
10391 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
10392                        int element, boolean change_level)
10393 {
10394   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
10395   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
10396   int mirror_to_x2 = from_x - (to_x2 - from_x);
10397   int mirror_to_y2 = from_y - (to_y2 - from_y);
10398
10399   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
10400   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
10401   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
10402   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
10403 }
10404 #endif
10405
10406 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
10407 {
10408   int from_sx, from_sy;
10409   int to_sx, to_sy;
10410
10411   if (from_x > to_x)
10412     swap_numbers(&from_x, &to_x);
10413
10414   if (from_y > to_y)
10415     swap_numbers(&from_y, &to_y);
10416
10417   from_sx = SX + from_x * ed_tilesize;
10418   from_sy = SY + from_y * ed_tilesize;
10419   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
10420   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
10421
10422   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
10423   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
10424   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
10425   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
10426
10427   if (from_x == to_x && from_y == to_y)
10428     MarkTileDirty(from_x/2, from_y/2);
10429   else
10430     redraw_mask |= REDRAW_FIELD;
10431 }
10432
10433 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
10434                        int element, boolean change_level)
10435 {
10436   if (element == -1 || change_level)
10437     DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
10438   else
10439     DrawAreaBorder(from_x, from_y, to_x, to_y);
10440 }
10441
10442 /* values for CopyBrushExt() */
10443 #define CB_AREA_TO_BRUSH        0
10444 #define CB_BRUSH_TO_CURSOR      1
10445 #define CB_BRUSH_TO_LEVEL       2
10446 #define CB_DELETE_OLD_CURSOR    3
10447 #define CB_DUMP_BRUSH           4
10448 #define CB_DUMP_BRUSH_SMALL     5
10449
10450 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
10451                          int button, int mode)
10452 {
10453   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
10454   static int brush_width, brush_height;
10455   static int last_cursor_x = -1, last_cursor_y = -1;
10456   static boolean delete_old_brush;
10457   int new_element = BUTTON_ELEMENT(button);
10458   int x, y;
10459
10460   if (mode == CB_DUMP_BRUSH ||
10461       mode == CB_DUMP_BRUSH_SMALL)
10462   {
10463     if (!draw_with_brush)
10464     {
10465       Error(ERR_WARN, "no brush selected");
10466
10467       return;
10468     }
10469
10470     for (y = 0; y < brush_height; y++)
10471     {
10472       for (x = 0; x < brush_width; x++)
10473       {
10474         int element = brush_buffer[x][y];
10475         int element_mapped = element;
10476
10477         if (IS_CUSTOM_ELEMENT(element))
10478           element_mapped = EL_CUSTOM_START;
10479         else if (IS_GROUP_ELEMENT(element))
10480           element_mapped = EL_GROUP_START;
10481         else if (element >= NUM_FILE_ELEMENTS)
10482           element_mapped = EL_UNKNOWN;
10483
10484         // dump brush as level sketch text for the R'n'D forum:
10485         // - large tiles: `xxx (0x60 ASCII)
10486         // - small tiles: Â¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
10487         printf("%s%03d", (mode == CB_DUMP_BRUSH ? "`" : "¸"), element_mapped);
10488       }
10489
10490       printf("\n");
10491     }
10492
10493     return;
10494   }
10495
10496   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
10497     return;
10498
10499   if (mode == CB_AREA_TO_BRUSH)
10500   {
10501     int from_lx, from_ly;
10502
10503     if (from_x > to_x)
10504       swap_numbers(&from_x, &to_x);
10505
10506     if (from_y > to_y)
10507       swap_numbers(&from_y, &to_y);
10508
10509     brush_width = to_x - from_x + 1;
10510     brush_height = to_y - from_y + 1;
10511
10512     from_lx = from_x + level_xpos;
10513     from_ly = from_y + level_ypos;
10514
10515     for (y = 0; y < brush_height; y++)
10516     {
10517       for (x = 0; x < brush_width; x++)
10518       {
10519         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
10520
10521         if (button != 1)
10522           DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
10523       }
10524     }
10525
10526     if (button != 1)
10527       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10528
10529     delete_old_brush = FALSE;
10530   }
10531   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
10532            mode == CB_BRUSH_TO_LEVEL)
10533   {
10534     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
10535     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
10536     int cursor_from_x = cursor_x - brush_width / 2;
10537     int cursor_from_y = cursor_y - brush_height / 2;
10538     int border_from_x = cursor_x, border_from_y = cursor_y;
10539     int border_to_x = cursor_x, border_to_y = cursor_y;
10540
10541     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
10542       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
10543
10544     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
10545         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
10546     {
10547       delete_old_brush = FALSE;
10548       return;
10549     }
10550
10551     for (y = 0; y < brush_height; y++)
10552     {
10553       for (x = 0; x < brush_width; x++)
10554       {
10555         int sx = cursor_from_x + x;
10556         int sy = cursor_from_y + y;
10557         int lx = sx + level_xpos;
10558         int ly = sy + level_ypos;
10559         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
10560         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
10561                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
10562                        brush_buffer[x][y] : new_element);
10563
10564         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10565         {
10566           if (sx < border_from_x)
10567             border_from_x = sx;
10568           else if (sx > border_to_x)
10569             border_to_x = sx;
10570           if (sy < border_from_y)
10571             border_from_y = sy;
10572           else if (sy > border_to_y)
10573             border_to_y = sy;
10574
10575           DrawLineElement(sx, sy, element, change_level);
10576         }
10577       }
10578     }
10579
10580     if (mode != CB_DELETE_OLD_CURSOR)
10581       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
10582
10583     last_cursor_x = cursor_x;
10584     last_cursor_y = cursor_y;
10585     delete_old_brush = TRUE;
10586   }
10587 }
10588
10589 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
10590                             int button)
10591 {
10592   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
10593 }
10594
10595 static void CopyBrushToLevel(int x, int y, int button)
10596 {
10597   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
10598 }
10599
10600 static void CopyBrushToCursor(int x, int y)
10601 {
10602   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
10603 }
10604
10605 static void DeleteBrushFromCursor()
10606 {
10607   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
10608 }
10609
10610 void DumpBrush()
10611 {
10612   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
10613 }
10614
10615 void DumpBrush_Small()
10616 {
10617   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
10618 }
10619
10620 static void FloodFill(int from_x, int from_y, int fill_element)
10621 {
10622   FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy);
10623 }
10624
10625 /* values for DrawLevelText() modes */
10626 #define TEXT_INIT               0
10627 #define TEXT_SETCURSOR          1
10628 #define TEXT_WRITECHAR          2
10629 #define TEXT_BACKSPACE          3
10630 #define TEXT_NEWLINE            4
10631 #define TEXT_END                5
10632 #define TEXT_QUERY_TYPING       6
10633
10634 static int DrawLevelText(int sx, int sy, char letter, int mode)
10635 {
10636   static short delete_buffer[MAX_LEV_FIELDX];
10637   static int start_sx;
10638   static int last_sx, last_sy;
10639   static boolean typing = FALSE;
10640   int letter_element = EL_CHAR_ASCII0 + letter;
10641   int lx = 0, ly = 0;
10642
10643   /* map lower case letters to upper case and convert special characters */
10644   if (letter >= 'a' && letter <= 'z')
10645     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
10646   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
10647     letter_element = EL_CHAR_AUMLAUT;
10648   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
10649     letter_element = EL_CHAR_OUMLAUT;
10650   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
10651     letter_element = EL_CHAR_UUMLAUT;
10652   else if (letter == '^')
10653     letter_element = EL_CHAR_COPYRIGHT;
10654   else
10655     letter_element = EL_CHAR_ASCII0 + letter;
10656
10657   if (mode != TEXT_INIT)
10658   {
10659     if (!typing)
10660       return FALSE;
10661
10662     if (mode != TEXT_SETCURSOR)
10663     {
10664       sx = last_sx;
10665       sy = last_sy;
10666     }
10667
10668     lx = last_sx + level_xpos;
10669     ly = last_sy + level_ypos;
10670   }
10671
10672   switch (mode)
10673   {
10674     case TEXT_INIT:
10675       if (typing)
10676         DrawLevelText(0, 0, 0, TEXT_END);
10677
10678       typing = TRUE;
10679       start_sx = sx;
10680       last_sx = sx;
10681       last_sy = sy;
10682       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
10683       break;
10684
10685     case TEXT_SETCURSOR:
10686       DrawEditorElement(last_sx, last_sy, Feld[lx][ly]);
10687       DrawAreaBorder(sx, sy, sx, sy);
10688       last_sx = sx;
10689       last_sy = sy;
10690       break;
10691
10692     case TEXT_WRITECHAR:
10693       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
10694       {
10695         if (new_element1 >= EL_STEEL_CHAR_START &&
10696             new_element1 <= EL_STEEL_CHAR_END)
10697           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
10698
10699         delete_buffer[sx - start_sx] = Feld[lx][ly];
10700         Feld[lx][ly] = letter_element;
10701
10702         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
10703           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
10704         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
10705           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10706         else
10707           DrawLevelText(0, 0, 0, TEXT_END);
10708
10709         level.changed = TRUE;
10710       }
10711       break;
10712
10713     case TEXT_BACKSPACE:
10714       if (sx > start_sx)
10715       {
10716         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
10717         DrawEditorElement(sx - 1, sy, Feld[lx - 1][ly]);
10718         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
10719       }
10720       break;
10721
10722     case TEXT_NEWLINE:
10723       if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
10724         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10725       else
10726         DrawLevelText(0, 0, 0, TEXT_END);
10727       break;
10728
10729     case TEXT_END:
10730       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10731       DrawEditorElement(sx, sy, Feld[lx][ly]);
10732       typing = FALSE;
10733       break;
10734
10735     case TEXT_QUERY_TYPING:
10736       break;
10737
10738     default:
10739       break;
10740   }
10741
10742   return typing;
10743 }
10744
10745 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
10746                           int element, boolean change_level)
10747 {
10748   int lx = sx + level_xpos;
10749   int ly = sy + level_ypos;
10750
10751   if (element == -1)
10752     DrawEditorElement(sx, sy, Feld[lx][ly]);
10753   else
10754     DrawAreaBorder(sx, sy, sx, sy);
10755 }
10756
10757 static void CheckLevelBorderElement(boolean redraw_playfield)
10758 {
10759   int last_border_element = BorderElement;
10760
10761   SetBorderElement();
10762
10763   if (redraw_playfield && BorderElement != last_border_element)
10764     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10765 }
10766
10767 static void CopyLevelToUndoBuffer(int mode)
10768 {
10769   static boolean accumulated_undo = FALSE;
10770   boolean new_undo_buffer_position = TRUE;
10771   int x, y;
10772
10773   if (undo_buffer_steps == 0)
10774     accumulated_undo = FALSE;
10775
10776   switch (mode)
10777   {
10778     case UNDO_IMMEDIATE:
10779       accumulated_undo = FALSE;
10780       break;
10781
10782     case UNDO_ACCUMULATE:
10783       if (accumulated_undo)
10784         new_undo_buffer_position = FALSE;
10785       accumulated_undo = TRUE;
10786       break;
10787
10788     default:
10789       break;
10790   }
10791
10792   if (new_undo_buffer_position)
10793   {
10794     /* advance position in undo buffer ring */
10795     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
10796
10797     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
10798       undo_buffer_steps++;
10799   }
10800
10801   /* always reset redo buffer when storing level change into undo buffer */
10802   redo_buffer_steps = 0;
10803
10804   for (x = 0; x < lev_fieldx; x++)
10805     for (y = 0; y < lev_fieldy; y++)
10806       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
10807
10808   /* check if drawing operation forces change of border style */
10809   CheckLevelBorderElement(TRUE);
10810
10811   level.changed = TRUE;
10812 }
10813
10814 static void RandomPlacement(int new_element)
10815 {
10816   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
10817   int num_free_positions = 0;
10818   int num_percentage, num_elements;
10819   int x, y;
10820
10821   ResetIntelliDraw();
10822
10823   /* determine number of free positions for randomly placing the new element */
10824   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
10825   {
10826     free_position[x][y] =
10827       (random_placement_background_restricted ?
10828        Feld[x][y] == random_placement_background_element :
10829        Feld[x][y] != new_element);
10830
10831     if (free_position[x][y])
10832       num_free_positions++;
10833   }
10834
10835   /* determine number of new elements to place there */
10836   num_percentage = num_free_positions * random_placement_value / 100;
10837   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
10838                   num_percentage : random_placement_value);
10839
10840   /* if less free positions than elements to place, fill all these positions */
10841   if (num_free_positions < num_elements)
10842   {
10843     for (x = 0; x < lev_fieldx; x++)
10844       for (y = 0; y < lev_fieldy; y++)
10845         if (free_position[x][y])
10846           SetElement(x, y, new_element);
10847   }
10848   else
10849   {
10850     while (num_elements > 0)
10851     {
10852       x = GetSimpleRandom(lev_fieldx);
10853       y = GetSimpleRandom(lev_fieldy);
10854
10855       /* don't place element at the same position twice */
10856       if (free_position[x][y])
10857       {
10858         free_position[x][y] = FALSE;
10859         SetElement(x, y, new_element);
10860         num_elements--;
10861       }
10862     }
10863   }
10864
10865   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10866   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10867 }
10868
10869 void WrapLevel(int dx, int dy)
10870 {
10871   int wrap_dx = lev_fieldx - dx;
10872   int wrap_dy = lev_fieldy - dy;
10873   int x, y;
10874
10875   for (x = 0; x < lev_fieldx; x++)
10876     for (y = 0; y < lev_fieldy; y++)
10877       FieldBackup[x][y] = Feld[x][y];
10878
10879   for (x = 0; x < lev_fieldx; x++)
10880     for (y = 0; y < lev_fieldy; y++)
10881       Feld[x][y] =
10882         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
10883
10884   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10885   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
10886 }
10887
10888 static void HandleDrawingAreas(struct GadgetInfo *gi)
10889 {
10890   static boolean started_inside_drawing_area = FALSE;
10891   int id = gi->custom_id;
10892   boolean button_press_event;
10893   boolean button_release_event;
10894   boolean inside_drawing_area = !gi->event.off_borders;
10895   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
10896   int actual_drawing_function;
10897   int button = gi->event.button;
10898   int new_element = BUTTON_ELEMENT(button);
10899   int sx = gi->event.x, sy = gi->event.y;
10900   int min_sx = 0, min_sy = 0;
10901   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
10902   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
10903   int lx = 0, ly = 0;
10904   int min_lx = 0, min_ly = 0;
10905   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
10906   int x, y;
10907
10908   /* handle info callback for each invocation of action callback */
10909   gi->callback_info(gi);
10910
10911   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
10912   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
10913
10914   /* make sure to stay inside drawing area boundaries */
10915   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
10916   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
10917
10918   if (draw_level)
10919   {
10920     /* get positions inside level field */
10921     lx = sx + level_xpos;
10922     ly = sy + level_ypos;
10923
10924     if (!IN_LEV_FIELD(lx, ly))
10925       inside_drawing_area = FALSE;
10926
10927     /* make sure to stay inside level field boundaries */
10928     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
10929     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
10930
10931     /* correct drawing area positions accordingly */
10932     sx = lx - level_xpos;
10933     sy = ly - level_ypos;
10934   }
10935
10936   if (button_press_event)
10937     started_inside_drawing_area = inside_drawing_area;
10938
10939   if (!started_inside_drawing_area)
10940     return;
10941
10942   if (!IS_VALID_BUTTON(button))
10943     return;
10944
10945   if (!button && !button_release_event)
10946     return;
10947
10948   /* automatically switch to 'single item' drawing mode, if needed */
10949   actual_drawing_function =
10950     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
10951      drawing_function : GADGET_ID_SINGLE_ITEMS);
10952
10953   /* clicking into drawing area with pressed Control key picks element */
10954   if (GetKeyModState() & KMOD_Control)
10955   {
10956     last_drawing_function = drawing_function;
10957     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
10958   }
10959
10960   if (GetKeyModState() & KMOD_Shift)
10961   {
10962     if (button_press_event || button_release_event)
10963       ResetIntelliDraw();
10964   }
10965
10966   switch (actual_drawing_function)
10967   {
10968     case GADGET_ID_SINGLE_ITEMS:
10969       if (draw_level)
10970       {
10971         if (button_release_event)
10972         {
10973           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10974
10975           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
10976               !inside_drawing_area)
10977             DeleteBrushFromCursor();
10978         }
10979
10980         if (!button || button_release_event)
10981           break;
10982
10983         if (draw_with_brush)
10984         {
10985           CopyBrushToLevel(sx, sy, button);
10986         }
10987         else
10988         {
10989           if (new_element == EL_PLAYER_1)
10990           {
10991             /* remove player at old position */
10992             for (y = 0; y < lev_fieldy; y++)
10993               for (x = 0; x < lev_fieldx; x++)
10994                 if (Feld[x][y] == EL_PLAYER_1)
10995                   SetElement(x, y, EL_EMPTY);
10996           }
10997
10998           SetElementButton(lx, ly, new_element, button);
10999         }
11000       }
11001       else
11002       {
11003         int type_id = gi->custom_type_id;
11004         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
11005
11006         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
11007           DrawMiniGraphicExt(drawto,
11008                              gi->x + sx * MINI_TILEX,
11009                              gi->y + sy * MINI_TILEY,
11010                              el2edimg(new_element));
11011         else
11012           DrawFixedGraphicExt(drawto,
11013                               gi->x + sx * TILEX,
11014                               gi->y + sy * TILEY,
11015                               el2edimg(new_element), 0);
11016
11017         if (id == GADGET_ID_CUSTOM_GRAPHIC)
11018           new_element = GFX_ELEMENT(new_element);
11019
11020         drawingarea_info[type_id].value[pos] = new_element;
11021
11022         CopyElementPropertiesToGame(properties_element);
11023
11024         if (id == GADGET_ID_CUSTOM_GRAPHIC)
11025         {
11026           UpdateCustomElementGraphicGadgets();
11027
11028           FrameCounter = 0;     /* restart animation frame counter */
11029         }
11030       }
11031       break;
11032
11033     case GADGET_ID_CONNECTED_ITEMS:
11034       {
11035         static int last_sx = -1;
11036         static int last_sy = -1;
11037
11038         if (button_release_event)
11039           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11040
11041         if (button)
11042         {
11043           if (!button_press_event)
11044             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
11045
11046           last_sx = sx;
11047           last_sy = sy;
11048         }
11049       }
11050       break;
11051
11052     case GADGET_ID_LINE:
11053     case GADGET_ID_ARC:
11054     case GADGET_ID_RECTANGLE:
11055     case GADGET_ID_FILLED_BOX:
11056     case GADGET_ID_GRAB_BRUSH:
11057     case GADGET_ID_TEXT:
11058       {
11059         static int last_sx = -1;
11060         static int last_sy = -1;
11061         static int start_sx = -1;
11062         static int start_sy = -1;
11063         void (*draw_func)(int, int, int, int, int, boolean);
11064
11065         if (drawing_function == GADGET_ID_LINE)
11066           draw_func = DrawLine;
11067         else if (drawing_function == GADGET_ID_ARC)
11068           draw_func = DrawArc;
11069         else if (drawing_function == GADGET_ID_RECTANGLE)
11070           draw_func = DrawBox;
11071         else if (drawing_function == GADGET_ID_FILLED_BOX)
11072           draw_func = DrawFilledBox;
11073         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
11074           draw_func = SelectArea;
11075         else /* (drawing_function == GADGET_ID_TEXT) */
11076           draw_func = SetTextCursor;
11077
11078         if (button_press_event)
11079         {
11080           draw_func(sx, sy, sx, sy, new_element, FALSE);
11081           start_sx = last_sx = sx;
11082           start_sy = last_sy = sy;
11083
11084           if (drawing_function == GADGET_ID_TEXT)
11085             DrawLevelText(0, 0, 0, TEXT_END);
11086         }
11087         else if (button_release_event)
11088         {
11089           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
11090           if (drawing_function == GADGET_ID_GRAB_BRUSH)
11091           {
11092             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
11093             CopyBrushToCursor(sx, sy);
11094             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
11095                           MB_LEFTBUTTON);
11096             draw_with_brush = TRUE;
11097           }
11098           else if (drawing_function == GADGET_ID_TEXT)
11099             DrawLevelText(sx, sy, 0, TEXT_INIT);
11100           else
11101             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11102         }
11103         else if (last_sx != sx || last_sy != sy)
11104         {
11105           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
11106           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
11107           last_sx = sx;
11108           last_sy = sy;
11109         }
11110       }
11111       break;
11112
11113     case GADGET_ID_FLOOD_FILL:
11114       if (button_press_event && Feld[lx][ly] != new_element)
11115       {
11116         FloodFill(lx, ly, new_element);
11117         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11118         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11119       }
11120       break;
11121
11122     case GADGET_ID_PICK_ELEMENT:
11123       if (button_release_event)
11124         ClickOnGadget(level_editor_gadget[last_drawing_function],
11125                       MB_LEFTBUTTON);
11126       else if (draw_level)
11127         PickDrawingElement(button, Feld[lx][ly]);
11128       else
11129       {
11130         int type_id = gi->custom_type_id;
11131         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
11132
11133         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
11134       }
11135
11136       break;
11137
11138     default:
11139       break;
11140   }
11141 }
11142
11143 static void HandleCounterButtons(struct GadgetInfo *gi)
11144 {
11145   int gadget_id = gi->custom_id;
11146   int counter_id = gi->custom_type_id;
11147   int button = gi->event.button;
11148   int *counter_value = counterbutton_info[counter_id].value;
11149   int step = BUTTON_STEPSIZE(button) *
11150     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
11151
11152   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
11153   {
11154     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
11155     boolean released = (gi->event.type == GD_EVENT_RELEASED);
11156     boolean level_changed = LevelChanged();
11157
11158     if ((level_changed && pressed) || (!level_changed && released))
11159       return;
11160
11161     if (level_changed && !Request("Level has changed! Discard changes?",
11162                                   REQ_ASK))
11163     {
11164       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
11165         ModifyEditorCounterValue(counter_id, *counter_value);
11166
11167       return;
11168     }
11169   }
11170
11171   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
11172     *counter_value = gi->textinput.number_value;
11173   else
11174     ModifyEditorCounterValue(counter_id, *counter_value + step);
11175
11176   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
11177   {
11178       LoadLevel(level_nr);
11179       LoadScore(level_nr);
11180
11181       TapeErase();
11182
11183       ResetUndoBuffer();
11184       DrawEditModeWindow();
11185
11186       return;
11187   }
11188
11189   switch (counter_id)
11190   {
11191     case ED_COUNTER_ID_YAMYAM_CONTENT:
11192       DrawYamYamContentAreas();
11193       break;
11194
11195     case ED_COUNTER_ID_BALL_CONTENT:
11196       DrawMagicBallContentAreas();
11197       break;
11198
11199     case ED_COUNTER_ID_ANDROID_CONTENT:
11200       DrawAndroidElementArea(properties_element);
11201       break;
11202
11203     case ED_COUNTER_ID_GROUP_CONTENT:
11204       DrawGroupElementArea(properties_element);
11205       CopyGroupElementPropertiesToGame(properties_element);
11206       break;
11207
11208     case ED_COUNTER_ID_INVENTORY_SIZE:
11209       DrawPlayerInitialInventoryArea(properties_element);
11210       break;
11211
11212     case ED_COUNTER_ID_ENVELOPE_XSIZE:
11213     case ED_COUNTER_ID_ENVELOPE_YSIZE:
11214       DrawEnvelopeTextArea(-1);
11215       break;
11216
11217     case ED_COUNTER_ID_LEVEL_XSIZE:
11218     case ED_COUNTER_ID_LEVEL_YSIZE:
11219       lev_fieldx = level.fieldx;
11220       lev_fieldy = level.fieldy;
11221
11222       /* check if resizing of level results in change of border border */
11223       SetBorderElement();
11224
11225       break;
11226
11227     default:
11228       break;
11229   }
11230
11231   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
11232        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
11233       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
11234        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
11235     CopyElementPropertiesToGame(properties_element);
11236
11237   level.changed = TRUE;
11238 }
11239
11240 static void HandleTextInputGadgets(struct GadgetInfo *gi)
11241 {
11242   int type_id = gi->custom_type_id;
11243
11244   strcpy(textinput_info[type_id].value, gi->textinput.value);
11245
11246   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
11247   {
11248     CopyElementPropertiesToGame(properties_element);
11249
11250     ModifyEditorElementList();  /* update changed button info text */
11251   }
11252
11253   level.changed = TRUE;
11254 }
11255
11256 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
11257 {
11258   int type_id = gi->custom_type_id;
11259
11260   strncpy(textarea_info[type_id].value, gi->textarea.value,
11261           MAX_ENVELOPE_TEXT_LEN);
11262   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
11263
11264   level.changed = TRUE;
11265 }
11266
11267 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
11268 {
11269   int type_id = gi->custom_type_id;
11270   int value_old = *selectbox_info[type_id].value;
11271   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
11272
11273   *selectbox_info[type_id].value = value_new;
11274
11275   if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
11276   {
11277     element_info[properties_element].current_change_page = gi->selectbox.index;
11278
11279     DrawPropertiesWindow();
11280   }
11281   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
11282             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
11283            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
11284             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
11285            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
11286   {
11287     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
11288     {
11289       /* when changing action type, also check action mode and action arg */
11290       if (value_old != value_new)
11291         setSelectboxSpecialActionVariablesIfNeeded();
11292
11293       DrawPropertiesChange();
11294     }
11295
11296     CopyElementPropertiesToGame(properties_element);
11297
11298     level.changed = TRUE;
11299   }
11300 }
11301
11302 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
11303 {
11304   int type_id = gi->custom_type_id;
11305   int i;
11306
11307   if (type_id >= ED_TEXTBUTTON_ID_LEVELINFO_FIRST &&
11308       type_id <= ED_TEXTBUTTON_ID_LEVELINFO_LAST)
11309   {
11310     edit_mode_levelinfo = gi->custom_type_id;
11311
11312     DrawLevelInfoWindow();
11313   }
11314   else if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST &&
11315            type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST)
11316   {
11317     edit_mode_properties = gi->custom_type_id;
11318
11319     DrawPropertiesWindow();
11320   }
11321   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
11322   {
11323     char *template_filename = getDefaultLevelFilename(-1);
11324     boolean new_template = !fileExists(template_filename);
11325
11326     /* backup original "level.field" (needed to track playfield changes) */
11327     CopyPlayfield(level.field, FieldBackup);
11328
11329     /* "SaveLevelTemplate()" uses "level.field", so copy editor playfield */
11330     CopyPlayfield(Feld, level.field);
11331
11332     if (new_template ||
11333         Request("Save this template and kill the old?", REQ_ASK))
11334       SaveLevelTemplate();
11335
11336     if (new_template)
11337       Request("Template saved!", REQ_CONFIRM);
11338
11339     /* restore original "level.field" (needed to track playfield changes) */
11340     CopyPlayfield(FieldBackup, level.field);
11341   }
11342   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
11343            custom_element.num_change_pages < MAX_CHANGE_PAGES)
11344   {
11345     struct ElementInfo *ei = &element_info[properties_element];
11346
11347     setElementChangePages(ei, ei->num_change_pages + 1);
11348
11349     /* set new change page to be new current change page */
11350     ei->current_change_page = ei->num_change_pages - 1;
11351     ei->change = &ei->change_page[ei->current_change_page];
11352
11353     setElementChangeInfoToDefaults(ei->change);
11354
11355     DrawPropertiesWindow();
11356
11357     level.changed = TRUE;
11358   }
11359   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
11360            custom_element.num_change_pages > MIN_CHANGE_PAGES)
11361   {
11362     struct ElementInfo *ei = &element_info[properties_element];
11363
11364     /* copy all change pages after change page to be deleted */
11365     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
11366       ei->change_page[i] = ei->change_page[i + 1];
11367
11368     setElementChangePages(ei, ei->num_change_pages - 1);
11369
11370     DrawPropertiesWindow();
11371
11372     level.changed = TRUE;
11373   }
11374 }
11375
11376 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
11377 {
11378   int type_id = gi->custom_type_id;
11379
11380   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
11381       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
11382   {
11383     struct ElementInfo *ei = &element_info[properties_element];
11384     int step = BUTTON_STEPSIZE(gi->event.button);
11385
11386     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
11387     ei->current_change_page += step;
11388
11389     if (ei->current_change_page < 0)
11390       ei->current_change_page = 0;
11391     else if (ei->current_change_page >= ei->num_change_pages)
11392       ei->current_change_page = ei->num_change_pages - 1;
11393
11394     DrawPropertiesWindow();
11395   }
11396   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
11397            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
11398   {
11399     struct ElementInfo *ei = &element_info[properties_element];
11400     int current_change_page = ei->current_change_page;
11401
11402     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
11403       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
11404         ei->change_page[current_change_page];
11405     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
11406     {
11407       ei->change_page[current_change_page] =
11408         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
11409
11410       level.changed = TRUE;
11411     }
11412
11413     DrawPropertiesWindow();
11414   }
11415 }
11416
11417 static void HandleRadiobuttons(struct GadgetInfo *gi)
11418 {
11419   *radiobutton_info[gi->custom_type_id].value =
11420     radiobutton_info[gi->custom_type_id].checked_value;
11421
11422   level.changed = TRUE;
11423 }
11424
11425 static void HandleCheckbuttons(struct GadgetInfo *gi)
11426 {
11427   int type_id = gi->custom_type_id;
11428
11429   *checkbutton_info[type_id].value ^= TRUE;
11430
11431   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
11432       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
11433       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
11434       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
11435          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
11436         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
11437          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
11438        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
11439   {
11440     CopyElementPropertiesToGame(properties_element);
11441   }
11442
11443   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
11444   {
11445     UpdateCustomElementGraphicGadgets();
11446   }
11447   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
11448   {
11449     char *template_filename = getDefaultLevelFilename(-1);
11450
11451     if (level.use_custom_template && !fileExists(template_filename))
11452     {
11453       Request("No level template found!", REQ_CONFIRM);
11454
11455       level.use_custom_template = FALSE;
11456       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
11457
11458       return;
11459     }
11460
11461     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
11462
11463     DrawEditModeWindow();
11464   }
11465
11466   level.changed = TRUE;
11467 }
11468
11469 static void HandleControlButtons(struct GadgetInfo *gi)
11470 {
11471   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
11472   static int last_edit_mode = ED_MODE_DRAWING;
11473   static int last_custom_copy_mode = -1;
11474   int id = gi->custom_id;
11475   int button = gi->event.button;
11476   int step = BUTTON_STEPSIZE(button);
11477   int new_element = BUTTON_ELEMENT(button);
11478   int last_properties_element = properties_element;
11479   int x, y;
11480
11481   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
11482     DrawLevelText(0, 0, 0, TEXT_END);
11483
11484   if (id < ED_NUM_CTRL1_BUTTONS &&
11485       id != GADGET_ID_SINGLE_ITEMS &&
11486       id != GADGET_ID_PICK_ELEMENT &&
11487       edit_mode != ED_MODE_DRAWING &&
11488       drawing_function != GADGET_ID_PICK_ELEMENT &&
11489       !(GetKeyModState() & KMOD_Control))
11490   {
11491     DrawDrawingWindow();
11492     edit_mode = ED_MODE_DRAWING;
11493   }
11494
11495   /* element copy mode active, but no element button pressed => deactivate */
11496   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
11497     last_custom_copy_mode = -1;
11498
11499   switch (id)
11500   {
11501     case GADGET_ID_SCROLL_LEFT:
11502       if (level_xpos >= 0)
11503       {
11504         if (lev_fieldx < ed_fieldx - 2)
11505           break;
11506
11507         level_xpos -= step;
11508         if (level_xpos < -1)
11509           level_xpos = -1;
11510         if (button == 1)
11511           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
11512         else
11513           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11514
11515         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
11516                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
11517       }
11518       break;
11519
11520     case GADGET_ID_SCROLL_RIGHT:
11521       if (level_xpos <= lev_fieldx - ed_fieldx)
11522       {
11523         if (lev_fieldx < ed_fieldx - 2)
11524           break;
11525
11526         level_xpos += step;
11527         if (level_xpos > lev_fieldx - ed_fieldx + 1)
11528           level_xpos = lev_fieldx - ed_fieldx + 1;
11529         if (button == 1)
11530           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
11531         else
11532           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11533
11534         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
11535                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
11536       }
11537       break;
11538
11539     case GADGET_ID_SCROLL_UP:
11540       if (level_ypos >= 0)
11541       {
11542         if (lev_fieldy < ed_fieldy - 2)
11543           break;
11544
11545         level_ypos -= step;
11546         if (level_ypos < -1)
11547           level_ypos = -1;
11548         if (button == 1)
11549           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
11550         else
11551           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11552
11553         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11554                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11555       }
11556       break;
11557
11558     case GADGET_ID_SCROLL_DOWN:
11559       if (level_ypos <= lev_fieldy - ed_fieldy)
11560       {
11561         if (lev_fieldy < ed_fieldy - 2)
11562           break;
11563
11564         level_ypos += step;
11565         if (level_ypos > lev_fieldy - ed_fieldy + 1)
11566           level_ypos = lev_fieldy - ed_fieldy + 1;
11567         if (button == 1)
11568           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
11569         else
11570           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11571
11572         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11573                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11574       }
11575       break;
11576
11577     case GADGET_ID_SCROLL_HORIZONTAL:
11578       level_xpos = gi->event.item_position - 1;
11579
11580       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11581       BackToFront();
11582
11583       break;
11584
11585     case GADGET_ID_SCROLL_VERTICAL:
11586       level_ypos = gi->event.item_position - 1;
11587
11588       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11589       BackToFront();
11590
11591       break;
11592
11593     case GADGET_ID_SCROLL_LIST_UP:
11594     case GADGET_ID_SCROLL_LIST_DOWN:
11595     case GADGET_ID_SCROLL_LIST_VERTICAL:
11596       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
11597         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
11598       else
11599       {
11600         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
11601         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
11602
11603         if (element_shift < 0)
11604           element_shift = 0;
11605         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
11606           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
11607
11608         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
11609                      GDI_SCROLLBAR_ITEM_POSITION,
11610                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
11611       }
11612
11613       ModifyEditorElementList();
11614
11615       break;
11616
11617     case GADGET_ID_PROPERTIES:
11618       // always switch off element properties when they are already displayed
11619       last_properties_element = new_element;
11620     case GADGET_ID_ELEMENT_LEFT:
11621     case GADGET_ID_ELEMENT_MIDDLE:
11622     case GADGET_ID_ELEMENT_RIGHT:
11623       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
11624                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
11625                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
11626                             new_element);
11627
11628       if (edit_mode != ED_MODE_PROPERTIES ||
11629           properties_element != last_properties_element)
11630       {
11631         DrawPropertiesWindow();
11632         edit_mode = ED_MODE_PROPERTIES;
11633
11634         last_level_drawing_function = drawing_function;
11635         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
11636                       MB_LEFTBUTTON);
11637       }
11638       else
11639       {
11640         DrawDrawingWindow();
11641         edit_mode = ED_MODE_DRAWING;
11642
11643         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
11644                       MB_LEFTBUTTON);
11645       }
11646       break;
11647
11648     case GADGET_ID_WRAP_LEFT:
11649       WrapLevel(-step, 0);
11650       break;
11651
11652     case GADGET_ID_WRAP_RIGHT:
11653       WrapLevel(step, 0);
11654       break;
11655
11656     case GADGET_ID_WRAP_UP:
11657       WrapLevel(0, -step);
11658       break;
11659
11660     case GADGET_ID_WRAP_DOWN:
11661       WrapLevel(0, step);
11662       break;
11663
11664     case GADGET_ID_SINGLE_ITEMS:
11665     case GADGET_ID_CONNECTED_ITEMS:
11666     case GADGET_ID_LINE:
11667     case GADGET_ID_ARC:
11668     case GADGET_ID_TEXT:
11669     case GADGET_ID_RECTANGLE:
11670     case GADGET_ID_FILLED_BOX:
11671     case GADGET_ID_FLOOD_FILL:
11672     case GADGET_ID_GRAB_BRUSH:
11673     case GADGET_ID_PICK_ELEMENT:
11674       if (drawing_function != GADGET_ID_PICK_ELEMENT)
11675         last_drawing_function = drawing_function;
11676       drawing_function = id;
11677       draw_with_brush = FALSE;
11678       break;
11679
11680     case GADGET_ID_RANDOM_PLACEMENT:
11681       RandomPlacement(new_element);
11682       break;
11683
11684     case GADGET_ID_ZOOM:
11685       // zoom level editor tile size in or out (or reset to default size)
11686       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
11687                      button == 2 ? DEFAULT_EDITOR_TILESIZE :
11688                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
11689
11690       // limit zoom level by upper and lower bound
11691       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
11692
11693       InitZoomLevelSettings();
11694
11695       if (edit_mode == ED_MODE_DRAWING)
11696         DrawDrawingWindow();
11697
11698       break;
11699
11700     case GADGET_ID_CUSTOM_COPY_FROM:
11701     case GADGET_ID_CUSTOM_COPY_TO:
11702     case GADGET_ID_CUSTOM_EXCHANGE:
11703       last_custom_copy_mode = id;
11704       last_drawing_function = drawing_function;
11705       break;
11706
11707     case GADGET_ID_CUSTOM_COPY:
11708       CopyCustomElement(properties_element, -1, id);
11709       break;
11710
11711     case GADGET_ID_CUSTOM_PASTE:
11712       CopyCustomElement(-1, properties_element, id);
11713       break;
11714
11715     case GADGET_ID_UNDO:
11716       if (button == 1 && undo_buffer_steps == 0)
11717       {
11718         Request("Undo buffer empty!", REQ_CONFIRM);
11719
11720         break;
11721       }
11722       else if (button == 2)
11723       {
11724         break;
11725       }
11726       else if (button == 3 && redo_buffer_steps == 0)
11727       {
11728         Request("Redo buffer empty!", REQ_CONFIRM);
11729
11730         break;
11731       }
11732
11733       if (edit_mode != ED_MODE_DRAWING)
11734       {
11735         DrawDrawingWindow();
11736         edit_mode = ED_MODE_DRAWING;
11737       }
11738
11739       if (button == 1)
11740       {
11741         /* undo */
11742
11743         undo_buffer_position =
11744           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
11745
11746         undo_buffer_steps--;
11747         redo_buffer_steps++;
11748       }
11749       else
11750       {
11751         /* redo */
11752
11753         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
11754
11755         undo_buffer_steps++;
11756         redo_buffer_steps--;
11757       }
11758
11759       for (x = 0; x < lev_fieldx; x++)
11760         for (y = 0; y < lev_fieldy; y++)
11761           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
11762
11763       /* check if undo operation forces change of border style */
11764       CheckLevelBorderElement(FALSE);
11765
11766       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11767
11768       break;
11769
11770     case GADGET_ID_INFO:
11771       if (edit_mode != ED_MODE_INFO)
11772       {
11773         last_edit_mode = edit_mode;
11774         edit_mode = ED_MODE_INFO;
11775
11776         DrawLevelInfoWindow();
11777       }
11778       else
11779       {
11780         edit_mode = last_edit_mode;
11781
11782         DrawEditModeWindow();
11783       }
11784       break;
11785
11786     case GADGET_ID_CLEAR:
11787       if (edit_mode != ED_MODE_DRAWING)
11788       {
11789         DrawDrawingWindow();
11790         edit_mode = ED_MODE_DRAWING;
11791       }
11792
11793       for (x = 0; x < MAX_LEV_FIELDX; x++) 
11794         for (y = 0; y < MAX_LEV_FIELDY; y++) 
11795           Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
11796
11797       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
11798
11799       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11800       break;
11801
11802     case GADGET_ID_SAVE:
11803     {
11804       /* saving read-only levels into personal level set modifies global vars
11805          "leveldir_current" and "level_nr"; restore them after saving level */
11806       LevelDirTree *leveldir_former = leveldir_current;
11807       int level_nr_former = level_nr;
11808       char *level_filename;
11809       boolean new_level;
11810
11811       if (leveldir_current->readonly &&
11812           !PrepareSavingIntoPersonalLevelSet())
11813         break;
11814
11815       level_filename = getDefaultLevelFilename(level_nr);
11816       new_level = !fileExists(level_filename);
11817
11818       if (new_level ||
11819           Request("Save this level and kill the old?", REQ_ASK))
11820       {
11821         if (leveldir_former->readonly)
11822           ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
11823
11824         CopyPlayfield(Feld, level.field);
11825         SaveLevel(level_nr);
11826
11827         level.changed = FALSE;
11828
11829         if (new_level)
11830         {
11831           char level_saved_msg[64];
11832
11833           if (leveldir_former->readonly)
11834             sprintf(level_saved_msg,
11835                     "Level saved as level %d into personal level set!",
11836                     level_nr);
11837           else
11838             strcpy(level_saved_msg, "Level saved!");
11839
11840           Request(level_saved_msg, REQ_CONFIRM);
11841         }
11842       }
11843
11844       /* "cd" back to copied-from levelset (in case of saved read-only level) */
11845       leveldir_current = leveldir_former;
11846       level_nr = level_nr_former;
11847
11848       break;
11849     }
11850
11851     case GADGET_ID_TEST:
11852       if (LevelChanged())
11853         level.game_version = GAME_VERSION_ACTUAL;
11854
11855       CopyPlayfield(level.field, FieldBackup);
11856       CopyPlayfield(Feld, level.field);
11857
11858       CopyNativeLevel_RND_to_Native(&level);
11859
11860       UnmapLevelEditorGadgets();
11861       UndrawSpecialEditorDoor();
11862
11863       CloseDoor(DOOR_CLOSE_ALL);
11864
11865       /* needed before playing if editor playfield area has different size */
11866       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
11867
11868       // redraw_mask = REDRAW_ALL;
11869
11870       level_editor_test_game = TRUE;
11871
11872       StartGameActions(FALSE, setup.autorecord, level.random_seed);
11873
11874       break;
11875
11876     case GADGET_ID_EXIT:
11877       RequestExitLevelEditor(TRUE, FALSE);  /* if level has changed, ask user */
11878       break;
11879
11880     default:
11881       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
11882           id <= GADGET_ID_ELEMENTLIST_LAST)
11883       {
11884         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
11885         int new_element = editor_elements[element_position + element_shift];
11886
11887         if (IS_EDITOR_CASCADE(new_element))
11888         {
11889           int i;
11890
11891           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
11892           {
11893             int *cascade_element= &(*editor_elements_info[i].headline_list)[0];
11894             boolean *cascade_value=editor_elements_info[i].setup_cascade_value;
11895
11896             if (*cascade_element == new_element)
11897             {
11898               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
11899               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
11900
11901               /* update element selection list */
11902               ReinitializeElementList();
11903               ModifyEditorElementList();
11904
11905               /* update cascading gadget info text */
11906               PrintEditorGadgetInfoText(level_editor_gadget[id]);
11907
11908               /* save current editor cascading state */
11909               SaveSetup_EditorCascade();
11910
11911               break;
11912             }
11913           }
11914
11915           break;
11916         }
11917
11918         if (last_custom_copy_mode != -1)
11919         {
11920           if (CopyCustomElement(properties_element, new_element,
11921                                 last_custom_copy_mode))
11922           {
11923             ClickOnGadget(level_editor_gadget[last_drawing_function],
11924                           MB_LEFTBUTTON);
11925
11926             last_custom_copy_mode = -1;
11927           }
11928
11929           break;
11930         }
11931
11932         PickDrawingElement(button, new_element);
11933
11934         if (!stick_element_properties_window &&
11935             drawing_function != GADGET_ID_PICK_ELEMENT &&
11936             !(GetKeyModState() & KMOD_Control))
11937         {
11938           properties_element = new_element;
11939           if (edit_mode == ED_MODE_PROPERTIES)
11940             DrawPropertiesWindow();
11941         }
11942
11943         if (drawing_function == GADGET_ID_PICK_ELEMENT)
11944           ClickOnGadget(level_editor_gadget[last_drawing_function],
11945                         MB_LEFTBUTTON);
11946       }
11947 #ifdef DEBUG
11948       else if (gi->event.type == GD_EVENT_PRESSED)
11949         printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
11950       else if (gi->event.type == GD_EVENT_RELEASED)
11951         printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
11952       else if (gi->event.type == GD_EVENT_MOVING)
11953         printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
11954       else
11955         printf("default: HandleControlButtons: ? (id == %d)\n", id);
11956 #endif
11957       break;
11958   }
11959 }
11960
11961 void HandleLevelEditorKeyInput(Key key)
11962 {
11963   char letter = getCharFromKey(key);
11964   int button = MB_LEFTBUTTON;
11965
11966   if (drawing_function == GADGET_ID_TEXT &&
11967       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
11968   {
11969     if (letter)
11970       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
11971     else if (key == KSYM_Delete || key == KSYM_BackSpace)
11972       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
11973     else if (key == KSYM_Return)
11974       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
11975     else if (key == KSYM_Escape)
11976       DrawLevelText(0, 0, 0, TEXT_END);
11977   }
11978   else if (button_status == MB_RELEASED)
11979   {
11980     int id = GADGET_ID_NONE;
11981     int new_element_shift = element_shift;
11982     int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
11983     int i;
11984
11985     switch (key)
11986     {
11987       case KSYM_Left:
11988         id = GADGET_ID_SCROLL_LEFT;
11989         break;
11990       case KSYM_Right:
11991         id = GADGET_ID_SCROLL_RIGHT;
11992         break;
11993       case KSYM_Up:
11994         id = GADGET_ID_SCROLL_UP;
11995         break;
11996       case KSYM_Down:
11997         id = GADGET_ID_SCROLL_DOWN;
11998         break;
11999
12000       case KSYM_Page_Up:
12001       case KSYM_Page_Down:
12002         step *= (key == KSYM_Page_Up ? -1 : +1);
12003         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
12004
12005         if (element_shift < 0)
12006           element_shift = 0;
12007         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
12008           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
12009
12010         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12011                      GDI_SCROLLBAR_ITEM_POSITION,
12012                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12013
12014         ModifyEditorElementList();
12015
12016         break;
12017
12018       case KSYM_Home:
12019       case KSYM_End:
12020         element_shift = (key == KSYM_Home ? 0 :
12021                          num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
12022
12023         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12024                      GDI_SCROLLBAR_ITEM_POSITION,
12025                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12026
12027         ModifyEditorElementList();
12028
12029         break;
12030
12031       case KSYM_Insert:
12032       case KSYM_Delete:
12033
12034         /* this is needed to prevent interference with running "True X-Mouse" */
12035         if (GetKeyModStateFromEvents() & KMOD_Control)
12036           break;
12037
12038         /* check for last or next editor cascade block in element list */
12039         for (i = 0; i < num_editor_elements; i++)
12040         {
12041           if ((key == KSYM_Insert && i == element_shift) ||
12042               (key == KSYM_Delete && new_element_shift > element_shift))
12043             break;
12044
12045           /* jump to next cascade block (or to start of element list) */
12046           if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
12047             new_element_shift = i;
12048         }
12049
12050         if (i < num_editor_elements)
12051           element_shift = new_element_shift;
12052
12053         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
12054           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
12055
12056         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12057                      GDI_SCROLLBAR_ITEM_POSITION,
12058                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12059
12060         ModifyEditorElementList();
12061
12062         break;
12063
12064       case KSYM_Escape:
12065         if (edit_mode == ED_MODE_DRAWING)
12066         {
12067           RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
12068         }
12069         else if (edit_mode == ED_MODE_INFO)
12070         {
12071           HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
12072         }
12073         else if (edit_mode == ED_MODE_PROPERTIES)
12074         {
12075           HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
12076         }
12077         else            /* should never happen */
12078         {
12079           DrawDrawingWindow();
12080           edit_mode = ED_MODE_DRAWING;
12081         }
12082
12083         break;
12084
12085       default:
12086         break;
12087     }
12088
12089     if (id != GADGET_ID_NONE)
12090       ClickOnGadget(level_editor_gadget[id], button);
12091     else if (letter >= '1' && letter <= '3')
12092       ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], letter - '0');
12093     else if (letter == '?')
12094       ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], button);
12095     else if (letter == '.')
12096       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
12097     else if (letter == 'U')
12098       ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
12099     else if (letter == '-' || key == KSYM_KP_Subtract)
12100       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
12101     else if (letter == '0' || key == KSYM_KP_0)
12102       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
12103     else if (letter == '+' || key == KSYM_KP_Add ||
12104              letter == '=')     // ("Shift-=" is "+" on US keyboards)
12105       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
12106     else if (key == KSYM_Return ||
12107              key == KSYM_space ||
12108              key == setup.shortcut.toggle_pause)
12109       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
12110     else
12111       for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
12112         if (letter && letter == controlbutton_info[i].shortcut)
12113           if (!anyTextGadgetActive())
12114             ClickOnGadget(level_editor_gadget[i], button);
12115   }
12116 }
12117
12118 void HandleLevelEditorIdle()
12119 {
12120   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12121   int x = editor.settings.element_graphic.x + element_border;
12122   int y = editor.settings.element_graphic.y + element_border;
12123   static unsigned int action_delay = 0;
12124   unsigned int action_delay_value = GameFrameDelay;
12125   int i;
12126
12127   if (edit_mode != ED_MODE_PROPERTIES)
12128     return;
12129
12130   if (!DelayReached(&action_delay, action_delay_value))
12131     return;
12132
12133   for (i = 0; i < ED_NUM_SELECTBOX; i++)
12134   {
12135     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
12136
12137     if (gi->mapped && gi->active && gi->selectbox.open)
12138       return;
12139   }
12140
12141   DrawEditorElementAnimation(SX + x, SY + y);
12142
12143   redraw_mask |= REDRAW_FIELD;
12144
12145   FrameCounter++;       /* increase animation frame counter */
12146 }
12147
12148 void ClearEditorGadgetInfoText()
12149 {
12150   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
12151 }
12152
12153 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
12154 {
12155   char infotext[MAX_OUTPUT_LINESIZE + 1];
12156   char shortcut[MAX_OUTPUT_LINESIZE + 1];
12157   int max_infotext_len = getMaxInfoTextLength();
12158
12159   if (gi == NULL || strlen(gi->info_text) == 0)
12160     return;
12161
12162   strncpy(infotext, gi->info_text, max_infotext_len);
12163   infotext[max_infotext_len] = '\0';
12164
12165   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
12166   {
12167     int key = controlbutton_info[gi->custom_id].shortcut;
12168
12169     if (key)
12170     {
12171       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
12172         sprintf(shortcut, " ('.' or '%c')", key);
12173       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
12174         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
12175       else if (gi->custom_id == GADGET_ID_TEST)
12176         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
12177       else if (gi->custom_id == GADGET_ID_UNDO)
12178         sprintf(shortcut, " ('%c/Shift-U')", key);
12179       else if (gi->custom_id == GADGET_ID_ZOOM)
12180         sprintf(shortcut, " ('%c', '0', '+')", key);
12181       else
12182         sprintf(shortcut, " ('%s%c')",
12183                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
12184
12185       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
12186         strcat(infotext, shortcut);
12187     }
12188   }
12189
12190   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
12191 }
12192
12193 void HandleEditorGadgetInfoText(void *ptr)
12194 {
12195   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
12196
12197   if (game_status != GAME_MODE_EDITOR)
12198     return;
12199
12200   ClearEditorGadgetInfoText();
12201
12202   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
12203     return;
12204
12205   /* misuse this function to delete brush cursor, if needed */
12206   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
12207     DeleteBrushFromCursor();
12208
12209   PrintEditorGadgetInfoText(gi);
12210 }
12211
12212 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
12213 {
12214   static int start_lx, start_ly;
12215   int id = gi->custom_id;
12216   int type_id = gi->custom_type_id;
12217   int sx = gi->event.x;
12218   int sy = gi->event.y;
12219   int lx = sx + level_xpos;
12220   int ly = sy + level_ypos;
12221   int min_sx = 0, min_sy = 0;
12222   int max_sx = gi->drawing.area_xsize - 1;
12223   int max_sy = gi->drawing.area_ysize - 1;
12224   int actual_drawing_function = drawing_function;
12225   int max_infotext_len = getMaxInfoTextLength();
12226   char infotext[MAX_OUTPUT_LINESIZE + 1];
12227   char *text;
12228
12229   infotext[0] = '\0';           /* start with empty info text */
12230
12231   /* pressed Control key: simulate picking element */
12232   if (GetKeyModState() & KMOD_Control)
12233     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
12234
12235   ClearEditorGadgetInfoText();
12236
12237   if (gi->event.type == GD_EVENT_INFO_LEAVING)
12238     return;
12239
12240   /* make sure to stay inside drawing area boundaries */
12241   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
12242   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
12243
12244   if (id == GADGET_ID_DRAWING_LEVEL)
12245   {
12246     if (button_status)
12247     {
12248       int min_lx = 0, min_ly = 0;
12249       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
12250
12251       /* get positions inside level field */
12252       lx = sx + level_xpos;
12253       ly = sy + level_ypos;
12254
12255       /* make sure to stay inside level field boundaries */
12256       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
12257       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
12258
12259       /* correct drawing area positions accordingly */
12260       sx = lx - level_xpos;
12261       sy = ly - level_ypos;
12262     }
12263
12264     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
12265     {
12266       if (button_status)        /* if (gi->state == GD_BUTTON_PRESSED) */
12267       {
12268         if (gi->event.type == GD_EVENT_PRESSED)
12269         {
12270           start_lx = lx;
12271           start_ly = ly;
12272         }
12273
12274         switch (actual_drawing_function)
12275         {
12276           case GADGET_ID_SINGLE_ITEMS:
12277             text = "Drawing single items";
12278             break;
12279           case GADGET_ID_CONNECTED_ITEMS:
12280             text = "Drawing connected items";
12281             break;
12282           case GADGET_ID_LINE:
12283             text = "Drawing line";
12284             break;
12285           case GADGET_ID_ARC:
12286             text = "Drawing arc";
12287             break;
12288           case GADGET_ID_TEXT:
12289             text = "Setting text cursor";
12290             break;
12291           case GADGET_ID_RECTANGLE:
12292             text = "Drawing rectangle";
12293             break;
12294           case GADGET_ID_FILLED_BOX:
12295             text = "Drawing filled box";
12296             break;
12297           case GADGET_ID_FLOOD_FILL:
12298             text = "Flood fill";
12299             break;
12300           case GADGET_ID_GRAB_BRUSH:
12301             text = "Grabbing brush";
12302             break;
12303           case GADGET_ID_PICK_ELEMENT:
12304             text = "Picking element";
12305             break;
12306
12307           default:
12308             text = "Drawing position";
12309             break;
12310         }
12311
12312         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12313           sprintf(infotext, "%s: %d, %d", text, lx, ly);
12314         else
12315           sprintf(infotext, "%s: %d, %d", text,
12316                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
12317       }
12318       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12319         strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
12320       else
12321         sprintf(infotext, "Level position: %d, %d", lx, ly);
12322     }
12323
12324     /* misuse this function to draw brush cursor, if needed */
12325     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
12326     {
12327       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
12328         CopyBrushToCursor(sx, sy);
12329       else
12330         DeleteBrushFromCursor();
12331     }
12332   }
12333   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12334   {
12335     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
12336     int element = drawingarea_info[type_id].value[pos];
12337
12338     strncpy(infotext, getElementInfoText(element), max_infotext_len);
12339   }
12340   else
12341   {
12342     if (id == GADGET_ID_CUSTOM_CONTENT)
12343       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
12344     else if (id == GADGET_ID_GROUP_CONTENT)
12345       sprintf(infotext, "group element position: %d", sx + 1);
12346     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
12347              id <= GADGET_ID_YAMYAM_CONTENT_7)
12348       sprintf(infotext, "content area %d position: %d, %d",
12349               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
12350     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
12351              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
12352       sprintf(infotext, "content area %d position: %d, %d",
12353               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
12354     else if (id == GADGET_ID_ANDROID_CONTENT)
12355       sprintf(infotext, "android element position: %d", sx + 1);
12356     else if (drawingarea_info[type_id].infotext != NULL)
12357       strcpy(infotext, drawingarea_info[type_id].infotext);
12358   }
12359
12360   infotext[max_infotext_len] = '\0';
12361
12362   if (strlen(infotext) > 0)
12363     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
12364 }
12365
12366 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
12367                             boolean quick_quit)
12368 {
12369   if (!ask_if_level_has_changed ||
12370       !LevelChanged() ||
12371       Request("Level has changed! Exit without saving?",
12372               REQ_ASK | REQ_STAY_OPEN))
12373   {
12374     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
12375     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
12376
12377     /* draw normal door */
12378     UndrawSpecialEditorDoor();
12379
12380     // close editor doors if viewport definition is the same as in main menu
12381     if (vp_door_1->x      == DX     &&
12382         vp_door_1->y      == DY     &&
12383         vp_door_1->width  == DXSIZE &&
12384         vp_door_1->height == DYSIZE &&
12385         vp_door_2->x      == VX     &&
12386         vp_door_2->y      == VY     &&
12387         vp_door_2->width  == VXSIZE &&
12388         vp_door_2->height == VYSIZE)
12389       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
12390     else
12391       SetDoorState(DOOR_CLOSE_2);
12392
12393     BackToFront();
12394
12395     if (quick_quit)
12396       FadeSkipNextFadeIn();
12397
12398     SetGameStatus(GAME_MODE_MAIN);
12399
12400     DrawMainMenu();
12401   }
12402   else
12403   {
12404     if (!global.use_envelope_request)
12405     {
12406       CloseDoor(DOOR_CLOSE_1);
12407       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
12408     }
12409   }
12410 }