added option for 'masked' element graphics on properties buttons
[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     boolean deco_masked = FALSE;
5455     int gd_x1 = gd->src_x;
5456     int gd_y1 = gd->src_y;
5457     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5458     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5459     int gd_x1a = gd->src_x + gd->active_xoffset;
5460     int gd_y1a = gd->src_y + gd->active_yoffset;
5461     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
5462     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
5463     int x = pos->x;
5464     int y = pos->y;
5465     unsigned int event_mask;
5466     int radio_button_nr = RADIO_NR_NONE;
5467     boolean checked = FALSE;
5468
5469     if (type == GD_TYPE_RADIO_BUTTON)
5470     {
5471       event_mask = GD_EVENT_PRESSED;
5472       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
5473
5474       if (id == drawing_function)
5475         checked = TRUE;
5476     }
5477     else
5478     {
5479       if (id == GADGET_ID_WRAP_LEFT ||
5480           id == GADGET_ID_WRAP_RIGHT ||
5481           id == GADGET_ID_WRAP_UP ||
5482           id == GADGET_ID_WRAP_DOWN)
5483         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5484       else
5485         event_mask = GD_EVENT_RELEASED;
5486     }
5487
5488     if (id == GADGET_ID_PROPERTIES)
5489     {
5490       x += DX;
5491       y += DY;
5492     }
5493     else if (id == GADGET_ID_ELEMENT_LEFT ||
5494              id == GADGET_ID_ELEMENT_MIDDLE ||
5495              id == GADGET_ID_ELEMENT_RIGHT)
5496     {
5497       x += DX;
5498       y += DY;
5499
5500       int element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
5501                      id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
5502                      id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 : EL_EMPTY);
5503
5504       tile_size = BUTTON_TILE_SIZE(id == GADGET_ID_ELEMENT_LEFT ?
5505                                    editor.button.element_left.tile_size :
5506                                    id == GADGET_ID_ELEMENT_MIDDLE ?
5507                                    editor.button.element_middle.tile_size :
5508                                    id == GADGET_ID_ELEMENT_RIGHT ?
5509                                    editor.button.element_right.tile_size : 0);
5510
5511       // make sure that decoration does not overlap gadget border
5512       tile_size = MIN(tile_size, MIN(gd->width, gd->height));
5513
5514       getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x,&deco_y);
5515
5516       deco_xpos = (gd->width  - tile_size) / 2;
5517       deco_ypos = (gd->height - tile_size) / 2;
5518       deco_shift = 1;
5519       deco_masked = gd->draw_masked;
5520     }
5521     else
5522     {
5523       x += EX;
5524       y += EY;
5525     }
5526
5527     gi = CreateGadget(GDI_CUSTOM_ID, id,
5528                       GDI_CUSTOM_TYPE_ID, i,
5529                       GDI_INFO_TEXT, controlbutton_info[i].infotext,
5530                       GDI_X, x,
5531                       GDI_Y, y,
5532                       GDI_WIDTH, gd->width,
5533                       GDI_HEIGHT, gd->height,
5534                       GDI_TYPE, type,
5535                       GDI_STATE, GD_BUTTON_UNPRESSED,
5536                       GDI_RADIO_NR, radio_button_nr,
5537                       GDI_CHECKED, checked,
5538                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5539                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5540                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
5541                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
5542                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5543                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5544                       GDI_DECORATION_SIZE, tile_size, tile_size,
5545                       GDI_DECORATION_SHIFTING, deco_shift, deco_shift,
5546                       GDI_DECORATION_MASKED, deco_masked,
5547                       GDI_EVENT_MASK, event_mask,
5548                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5549                       GDI_CALLBACK_ACTION, HandleControlButtons,
5550                       GDI_END);
5551
5552     if (gi == NULL)
5553       Error(ERR_EXIT, "cannot create gadget");
5554
5555     level_editor_gadget[id] = gi;
5556   }
5557
5558   /* these values are not constant, but can change at runtime */
5559   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x    = ED_SCROLL_UP_XPOS;
5560   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y    = ED_SCROLL_UP_YPOS;
5561   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x  = ED_SCROLL_DOWN_XPOS;
5562   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y  = ED_SCROLL_DOWN_YPOS;
5563   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x  = ED_SCROLL_LEFT_XPOS;
5564   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y  = ED_SCROLL_LEFT_YPOS;
5565   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
5566   scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
5567   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x    = ED_SCROLL2_UP_XPOS;
5568   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y    = ED_SCROLL2_UP_YPOS;
5569   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x  = ED_SCROLL2_DOWN_XPOS;
5570   scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y  = ED_SCROLL2_DOWN_YPOS;
5571
5572   /* create buttons for scrolling of drawing area and element list */
5573   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
5574   {
5575     int id = scrollbutton_info[i].gadget_id;
5576     int graphic = scrollbutton_info[i].graphic;
5577     struct GraphicInfo *gd = &graphic_info[graphic];
5578     Bitmap *gd_bitmap = gd->bitmap;
5579     int gd_x1 = gd->src_x;
5580     int gd_y1 = gd->src_y;
5581     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5582     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5583     int width  = gd->width;
5584     int height = gd->height;
5585     int x = scrollbutton_pos[i].x;
5586     int y = scrollbutton_pos[i].y;
5587     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5588
5589     if (id == GADGET_ID_SCROLL_LIST_UP ||
5590         id == GADGET_ID_SCROLL_LIST_DOWN)
5591     {
5592       x += DX;
5593       y += DY;
5594     }
5595     else
5596     {
5597       x += SX;
5598       y += SY;
5599     }
5600
5601     gi = CreateGadget(GDI_CUSTOM_ID, id,
5602                       GDI_CUSTOM_TYPE_ID, i,
5603                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
5604                       GDI_X, x,
5605                       GDI_Y, y,
5606                       GDI_WIDTH, width,
5607                       GDI_HEIGHT, height,
5608                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5609                       GDI_STATE, GD_BUTTON_UNPRESSED,
5610                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5611                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5612                       GDI_EVENT_MASK, event_mask,
5613                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5614                       GDI_CALLBACK_ACTION, HandleControlButtons,
5615                       GDI_END);
5616
5617     if (gi == NULL)
5618       Error(ERR_EXIT, "cannot create gadget");
5619
5620     level_editor_gadget[id] = gi;
5621   }
5622
5623   /* create buttons for element list */
5624   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
5625   {
5626     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
5627     int graphic = IMG_EDITOR_PALETTE_BUTTON;
5628     struct GraphicInfo *gd = &graphic_info[graphic];
5629     Bitmap *gd_bitmap = gd->bitmap;
5630     Bitmap *deco_bitmap;
5631     int deco_x, deco_y, deco_xpos, deco_ypos;
5632     int gd_x1 = gd->src_x;
5633     int gd_y1 = gd->src_y;
5634     int gd_x2 = gd->src_x + gd->pressed_xoffset;
5635     int gd_y2 = gd->src_y + gd->pressed_yoffset;
5636     int xx = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
5637     int yy = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
5638     int x = DX + ED_ELEMENTLIST_XPOS + xx * gd->width;
5639     int y = DY + ED_ELEMENTLIST_YPOS + yy * gd->height;
5640     int element = editor_elements[i];
5641     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
5642     unsigned int event_mask = GD_EVENT_RELEASED;
5643
5644     getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
5645
5646     deco_xpos = (gd->width  - tile_size) / 2;
5647     deco_ypos = (gd->height - tile_size) / 2;
5648
5649     gi = CreateGadget(GDI_CUSTOM_ID, id,
5650                       GDI_CUSTOM_TYPE_ID, i,
5651                       GDI_INFO_TEXT, getElementInfoText(element),
5652                       GDI_X, x,
5653                       GDI_Y, y,
5654                       GDI_WIDTH, gd->width,
5655                       GDI_HEIGHT, gd->height,
5656                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5657                       GDI_STATE, GD_BUTTON_UNPRESSED,
5658                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
5659                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
5660                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5661                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5662                       GDI_DECORATION_SIZE, tile_size, tile_size,
5663                       GDI_DECORATION_SHIFTING, 1, 1,
5664                       GDI_EVENT_MASK, event_mask,
5665                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5666                       GDI_CALLBACK_ACTION, HandleControlButtons,
5667                       GDI_END);
5668
5669     if (gi == NULL)
5670       Error(ERR_EXIT, "cannot create gadget");
5671
5672     level_editor_gadget[id] = gi;
5673   }
5674 }
5675
5676 static void CreateCounterButtons()
5677 {
5678   int max_infotext_len = getMaxInfoTextLength();
5679   int i;
5680
5681   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
5682   {
5683     int j;
5684     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); /* down count button */
5685     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
5686
5687     /* determine horizontal position to the right of specified gadget */
5688     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
5689       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
5690            ED_GADGET_TEXT_DISTANCE);
5691
5692     /* determine horizontal offset for leading text */
5693     if (counterbutton_info[i].text_left != NULL)
5694       x += getTextWidthForGadget(counterbutton_info[i].text_left);
5695
5696     for (j = 0; j < 2; j++)
5697     {
5698       struct GadgetInfo *gi;
5699       int id = (j == 0 ?
5700                 counterbutton_info[i].gadget_id_down :
5701                 counterbutton_info[i].gadget_id_up);
5702       int graphic;
5703       struct GraphicInfo *gd;
5704       int gd_x1, gd_x2, gd_y1, gd_y2;
5705       unsigned int event_mask;
5706       char infotext[max_infotext_len + 1];
5707
5708       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
5709
5710       if (i == ED_COUNTER_ID_SELECT_LEVEL)
5711       {
5712         graphic = (j == 0 ?
5713                    IMG_GFX_EDITOR_BUTTON_PREV_LEVEL :
5714                    IMG_GFX_EDITOR_BUTTON_NEXT_LEVEL);
5715
5716         event_mask |= GD_EVENT_RELEASED;
5717
5718         if (j == 0)
5719         {
5720           x = DX + editor.button.prev_level.x;
5721           y = DY + editor.button.prev_level.y;
5722         }
5723         else
5724         {
5725           x = DX + editor.button.next_level.x;
5726           y = DY + editor.button.next_level.y;
5727         }
5728       }
5729       else
5730       {
5731         graphic = (j == 0 ?
5732                    IMG_EDITOR_COUNTER_DOWN :
5733                    IMG_EDITOR_COUNTER_UP);
5734       }
5735
5736       gd = &graphic_info[graphic];
5737
5738       gd_x1 = gd->src_x;
5739       gd_y1 = gd->src_y;
5740       gd_x2 = gd->src_x + gd->pressed_xoffset;
5741       gd_y2 = gd->src_y + gd->pressed_yoffset;
5742
5743       sprintf(infotext, "%s counter value by 1, 5 or 10",
5744               (j == 0 ? "decrease" : "increase"));
5745
5746       gi = CreateGadget(GDI_CUSTOM_ID, id,
5747                         GDI_CUSTOM_TYPE_ID, i,
5748                         GDI_INFO_TEXT, infotext,
5749                         GDI_X, x,
5750                         GDI_Y, y,
5751                         GDI_WIDTH, gd->width,
5752                         GDI_HEIGHT, gd->height,
5753                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5754                         GDI_STATE, GD_BUTTON_UNPRESSED,
5755                         GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5756                         GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5757                         GDI_EVENT_MASK, event_mask,
5758                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5759                         GDI_CALLBACK_ACTION, HandleCounterButtons,
5760                         GDI_END);
5761
5762       if (gi == NULL)
5763         Error(ERR_EXIT, "cannot create gadget");
5764
5765       level_editor_gadget[id] = gi;
5766       right_gadget_border[id] =
5767         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5768
5769       x += gi->width + ED_GADGET_SMALL_DISTANCE;        /* text count button */
5770
5771       if (j == 0)
5772       {
5773         int font_type = FONT_INPUT_1;
5774         int font_type_active = FONT_INPUT_1_ACTIVE;
5775
5776         id = counterbutton_info[i].gadget_id_text;
5777
5778         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5779
5780         if (i == ED_COUNTER_ID_SELECT_LEVEL)
5781         {
5782           graphic = IMG_GFX_EDITOR_INPUT_LEVEL_NUMBER;
5783
5784           font_type = FONT_LEVEL_NUMBER;
5785           font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
5786
5787           x = DX + editor.input.level_number.x;
5788           y = DY + editor.input.level_number.y;
5789         }
5790         else
5791         {
5792           graphic = IMG_EDITOR_COUNTER_INPUT;
5793         }
5794
5795         gd = &graphic_info[graphic];
5796
5797         gd_x1 = gd->src_x;
5798         gd_y1 = gd->src_y;
5799         gd_x2 = gd->src_x + gd->active_xoffset;
5800         gd_y2 = gd->src_y + gd->active_yoffset;
5801
5802         gi = CreateGadget(GDI_CUSTOM_ID, id,
5803                           GDI_CUSTOM_TYPE_ID, i,
5804                           GDI_INFO_TEXT, "enter counter value",
5805                           GDI_X, x,
5806                           GDI_Y, y,
5807                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
5808                           GDI_NUMBER_VALUE, 0,
5809                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
5810                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
5811                           GDI_TEXT_SIZE, 3,     /* minimal counter text size */
5812                           GDI_TEXT_FONT, font_type,
5813                           GDI_TEXT_FONT_ACTIVE, font_type_active,
5814                           GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5815                           GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5816                           GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5817                           GDI_DESIGN_WIDTH, gd->width,
5818                           GDI_EVENT_MASK, event_mask,
5819                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5820                           GDI_CALLBACK_ACTION, HandleCounterButtons,
5821                           GDI_END);
5822
5823         if (gi == NULL)
5824           Error(ERR_EXIT, "cannot create gadget");
5825
5826         level_editor_gadget[id] = gi;
5827         right_gadget_border[id] =
5828           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
5829
5830         x += gi->width + ED_GADGET_SMALL_DISTANCE;      /* up count button */
5831       }
5832     }
5833   }
5834 }
5835
5836 static void CreateDrawingAreas()
5837 {
5838   int i;
5839
5840   /* these values are not constant, but can change at runtime */
5841   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
5842   drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
5843
5844   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
5845   {
5846     struct GadgetInfo *gi;
5847     unsigned int event_mask;
5848     int id = drawingarea_info[i].gadget_id;
5849     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
5850     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
5851     int area_xsize = drawingarea_info[i].area_xsize;
5852     int area_ysize = drawingarea_info[i].area_ysize;
5853     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
5854                      ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
5855
5856     event_mask =
5857       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
5858       GD_EVENT_OFF_BORDERS;
5859
5860     /* determine horizontal position to the right of specified gadget */
5861     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
5862       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
5863            ED_DRAWINGAREA_TEXT_DISTANCE);
5864
5865     /* determine horizontal offset for leading text */
5866     if (drawingarea_info[i].text_left != NULL)
5867       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
5868
5869     gi = CreateGadget(GDI_CUSTOM_ID, id,
5870                       GDI_CUSTOM_TYPE_ID, i,
5871                       GDI_X, x,
5872                       GDI_Y, y,
5873                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
5874                       GDI_AREA_SIZE, area_xsize, area_ysize,
5875                       GDI_ITEM_SIZE, item_size, item_size,
5876                       GDI_EVENT_MASK, event_mask,
5877                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
5878                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
5879                       GDI_END);
5880
5881     if (gi == NULL)
5882       Error(ERR_EXIT, "cannot create gadget");
5883
5884     level_editor_gadget[id] = gi;
5885     right_gadget_border[id] =
5886       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
5887   }
5888 }
5889
5890 static void CreateTextInputGadgets()
5891 {
5892   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
5893   int max_infotext_len = getMaxInfoTextLength();
5894   int i;
5895
5896   for (i = 0; i < ED_NUM_TEXTINPUT; i++)
5897   {
5898     int gd_x1 = gd->src_x;
5899     int gd_y1 = gd->src_y;
5900     int gd_x2 = gd->src_x + gd->active_xoffset;
5901     int gd_y2 = gd->src_y + gd->active_yoffset;
5902     struct GadgetInfo *gi;
5903     unsigned int event_mask;
5904     char infotext[MAX_OUTPUT_LINESIZE + 1];
5905     int id = textinput_info[i].gadget_id;
5906     int x, y;
5907
5908     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
5909     {
5910       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
5911       int border_size = gd->border_size;
5912       int font_nr = FONT_INPUT_1;
5913       int font_height = getFontHeight(font_nr);
5914       int xoffset = element_border + TILEX + element_border + 3 * border_size;
5915       int yoffset = element_border + (TILEY - font_height) / 2;
5916
5917       x = (editor.settings.element_name.x != -1 ?
5918            editor.settings.element_name.x :
5919            editor.settings.element_graphic.x + xoffset) - border_size;
5920       y = (editor.settings.element_name.y != -1 ?
5921            editor.settings.element_name.y :
5922            editor.settings.element_graphic.y + yoffset) - border_size;
5923     }
5924     else
5925     {
5926       x = ED_SETTINGS_X(textinput_info[i].x);
5927       y = ED_SETTINGS_Y(textinput_info[i].y);
5928     }
5929
5930     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
5931
5932     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
5933     infotext[max_infotext_len] = '\0';
5934
5935     gi = CreateGadget(GDI_CUSTOM_ID, id,
5936                       GDI_CUSTOM_TYPE_ID, i,
5937                       GDI_INFO_TEXT, infotext,
5938                       GDI_X, SX + x,
5939                       GDI_Y, SY + y,
5940                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
5941                       GDI_TEXT_VALUE, textinput_info[i].value,
5942                       GDI_TEXT_SIZE, textinput_info[i].size,
5943                       GDI_TEXT_FONT, FONT_INPUT_1,
5944                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5945                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5946                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5947                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5948                       GDI_DESIGN_WIDTH, gd->width,
5949                       GDI_EVENT_MASK, event_mask,
5950                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
5951                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
5952                       GDI_END);
5953
5954     if (gi == NULL)
5955       Error(ERR_EXIT, "cannot create gadget");
5956
5957     level_editor_gadget[id] = gi;
5958   }
5959 }
5960
5961 static void CreateTextAreaGadgets()
5962 {
5963   int max_infotext_len = getMaxInfoTextLength();
5964   int i;
5965
5966   for (i = 0; i < ED_NUM_TEXTAREAS; i++)
5967   {
5968     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXTAREA];
5969     int gd_x1 = gd->src_x;
5970     int gd_y1 = gd->src_y;
5971     int gd_x2 = gd->src_x + gd->active_xoffset;
5972     int gd_y2 = gd->src_y + gd->active_yoffset;
5973     struct GadgetInfo *gi;
5974     unsigned int event_mask;
5975     char infotext[MAX_OUTPUT_LINESIZE + 1];
5976     int id = textarea_info[i].gadget_id;
5977     int area_xsize = textarea_info[i].xsize;
5978     int area_ysize = textarea_info[i].ysize;
5979
5980     event_mask = GD_EVENT_TEXT_LEAVING;
5981
5982     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
5983     infotext[max_infotext_len] = '\0';
5984
5985     gi = CreateGadget(GDI_CUSTOM_ID, id,
5986                       GDI_CUSTOM_TYPE_ID, i,
5987                       GDI_INFO_TEXT, infotext,
5988                       GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
5989                       GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
5990                       GDI_TYPE, GD_TYPE_TEXT_AREA,
5991                       GDI_AREA_SIZE, area_xsize, area_ysize,
5992                       GDI_TEXT_FONT, FONT_INPUT_1,
5993                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
5994                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
5995                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
5996                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
5997                       GDI_DESIGN_WIDTH, gd->width,
5998                       GDI_EVENT_MASK, event_mask,
5999                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6000                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
6001                       GDI_END);
6002
6003     if (gi == NULL)
6004       Error(ERR_EXIT, "cannot create gadget");
6005
6006     level_editor_gadget[id] = gi;
6007   }
6008 }
6009
6010 static void CreateSelectboxGadgets()
6011 {
6012   int max_infotext_len = getMaxInfoTextLength();
6013   int i, j;
6014
6015   for (i = 0; i < ED_NUM_SELECTBOX; i++)
6016   {
6017     struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_SELECTBOX_INPUT];
6018     struct GraphicInfo *gd2 = &graphic_info[IMG_EDITOR_SELECTBOX_BUTTON];
6019     int gd_x1 = gd->src_x;
6020     int gd_y1 = gd->src_y;
6021     int gd_x2 = gd->src_x + gd->active_xoffset;
6022     int gd_y2 = gd->src_y + gd->active_yoffset;
6023     int selectbox_button_xsize = gd2->width;
6024     struct GadgetInfo *gi;
6025     unsigned int event_mask;
6026     char infotext[MAX_OUTPUT_LINESIZE + 1];
6027     int id = selectbox_info[i].gadget_id;
6028     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
6029     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
6030
6031     if (selectbox_info[i].size == -1)   /* dynamically determine size */
6032     {
6033       /* (we cannot use -1 for uninitialized values if we directly compare
6034          with results from strlen(), because the '<' and '>' operation will
6035          implicitely cast -1 to an unsigned integer value!) */
6036       selectbox_info[i].size = 0;
6037
6038       for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
6039         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
6040           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
6041
6042       selectbox_info[i].size++;         /* add one character empty space */
6043     }
6044
6045     event_mask = GD_EVENT_RELEASED |
6046       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
6047
6048     /* determine horizontal position to the right of specified gadget */
6049     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
6050       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
6051            ED_GADGET_TEXT_DISTANCE);
6052
6053     /* determine horizontal offset for leading text */
6054     if (selectbox_info[i].text_left != NULL)
6055       x += getTextWidthForGadget(selectbox_info[i].text_left);
6056
6057     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
6058     infotext[max_infotext_len] = '\0';
6059
6060     gi = CreateGadget(GDI_CUSTOM_ID, id,
6061                       GDI_CUSTOM_TYPE_ID, i,
6062                       GDI_INFO_TEXT, infotext,
6063                       GDI_X, x,
6064                       GDI_Y, y,
6065                       GDI_TYPE, GD_TYPE_SELECTBOX,
6066                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
6067                       GDI_SELECTBOX_CHAR_UNSELECTABLE, '[',
6068                       GDI_TEXT_SIZE, selectbox_info[i].size,
6069                       GDI_TEXT_FONT, FONT_INPUT_1,
6070                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
6071                       GDI_TEXT_FONT_UNSELECTABLE, FONT_TEXT_1,
6072                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6073                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6074                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
6075                       GDI_BORDER_SIZE_SELECTBUTTON, selectbox_button_xsize,
6076                       GDI_DESIGN_WIDTH, gd->width,
6077                       GDI_EVENT_MASK, event_mask,
6078                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6079                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
6080                       GDI_END);
6081
6082     if (gi == NULL)
6083       Error(ERR_EXIT, "cannot create gadget");
6084
6085     level_editor_gadget[id] = gi;
6086     right_gadget_border[id] =
6087       getRightGadgetBorder(gi, selectbox_info[i].text_right);
6088   }
6089 }
6090
6091 static void CreateTextbuttonGadgets()
6092 {
6093   int max_infotext_len = getMaxInfoTextLength();
6094   int i;
6095
6096   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
6097   {
6098     int id = textbutton_info[i].gadget_id;
6099     int is_tab_button =
6100       ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
6101        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
6102     int graphic =
6103       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
6104     int gadget_distance =
6105       (is_tab_button ? ED_GADGET_SMALL_DISTANCE : ED_GADGET_TEXT_DISTANCE);
6106     struct GraphicInfo *gd = &graphic_info[graphic];
6107     int gd_x1 = gd->src_x;
6108     int gd_y1 = gd->src_y;
6109     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6110     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6111     int gd_x1a = gd->src_x + gd->active_xoffset;
6112     int gd_y1a = gd->src_y + gd->active_yoffset;
6113     int border_xsize = gd->border_size + gd->draw_xoffset;
6114     int border_ysize = gd->border_size;
6115     struct GadgetInfo *gi;
6116     unsigned int event_mask;
6117     char infotext[MAX_OUTPUT_LINESIZE + 1];
6118     int x = SX + ED_TAB_SETTINGS_X(textbutton_info[i].x);
6119     int y = SY + ED_TAB_SETTINGS_Y(textbutton_info[i].y);
6120
6121     if (textbutton_info[i].size == -1)  /* dynamically determine size */
6122       textbutton_info[i].size = strlen(textbutton_info[i].text);
6123
6124     event_mask = GD_EVENT_RELEASED;
6125
6126     sprintf(infotext, "%s", textbutton_info[i].infotext);
6127     infotext[max_infotext_len] = '\0';
6128
6129     /* determine horizontal position to the right of specified gadget */
6130     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6131     {
6132       int gadget_id_align = textbutton_info[i].gadget_id_align;
6133
6134       x = right_gadget_border[gadget_id_align] + gadget_distance;
6135
6136       if (textbutton_info[i].y == -1)
6137         y = level_editor_gadget[gadget_id_align]->y;
6138     }
6139
6140     /* determine horizontal offset for leading text */
6141     if (textbutton_info[i].text_left != NULL)
6142       x += getTextWidthForGadget(textbutton_info[i].text_left);
6143
6144     gi = CreateGadget(GDI_CUSTOM_ID, id,
6145                       GDI_CUSTOM_TYPE_ID, i,
6146                       GDI_INFO_TEXT, infotext,
6147                       GDI_X, x,
6148                       GDI_Y, y,
6149                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
6150                       GDI_TEXT_VALUE, textbutton_info[i].text,
6151                       GDI_TEXT_SIZE, textbutton_info[i].size,
6152                       GDI_TEXT_FONT, FONT_INPUT_2,
6153                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2_ACTIVE,
6154                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6155                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6156                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6157                       GDI_BORDER_SIZE, border_xsize, border_ysize,
6158                       GDI_DESIGN_WIDTH, gd->width,
6159                       GDI_DECORATION_SHIFTING, 1, 1,
6160                       GDI_EVENT_MASK, event_mask,
6161                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6162                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
6163                       GDI_END);
6164
6165     if (gi == NULL)
6166       Error(ERR_EXIT, "cannot create gadget");
6167
6168     level_editor_gadget[id] = gi;
6169     right_gadget_border[id] =
6170       getRightGadgetBorder(gi, textbutton_info[i].text_right);
6171   }
6172 }
6173
6174 static void CreateGraphicbuttonGadgets()
6175 {
6176   struct GadgetInfo *gi;
6177   unsigned int event_mask;
6178   int i;
6179
6180   /* create buttons for scrolling of drawing area and element list */
6181   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
6182   {
6183     int id = graphicbutton_info[i].gadget_id;
6184     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
6185     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
6186     struct GraphicInfo *gd = &graphic_info[graphicbutton_info[i].graphic];
6187     int gd_x1 = gd->src_x;
6188     int gd_y1 = gd->src_y;
6189     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6190     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6191
6192     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
6193
6194     /* determine horizontal position to the right of specified gadget */
6195     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6196       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
6197            ED_GADGET_TEXT_DISTANCE);
6198
6199     /* determine horizontal offset for leading text */
6200     if (graphicbutton_info[i].text_left != NULL)
6201       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
6202
6203     gi = CreateGadget(GDI_CUSTOM_ID, id,
6204                       GDI_CUSTOM_TYPE_ID, i,
6205                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
6206                       GDI_X, x,
6207                       GDI_Y, y,
6208                       GDI_WIDTH, gd->width,
6209                       GDI_HEIGHT, gd->height,
6210                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6211                       GDI_STATE, GD_BUTTON_UNPRESSED,
6212                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6213                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6214                       GDI_EVENT_MASK, event_mask,
6215                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6216                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
6217                       GDI_END);
6218
6219     if (gi == NULL)
6220       Error(ERR_EXIT, "cannot create gadget");
6221
6222     level_editor_gadget[id] = gi;
6223     right_gadget_border[id] =
6224       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
6225   }
6226 }
6227
6228 static void CreateScrollbarGadgets()
6229 {
6230   int i;
6231
6232   /* these values are not constant, but can change at runtime */
6233   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
6234     SX + ED_SCROLL_HORIZONTAL_XPOS;
6235   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
6236     SY + ED_SCROLL_HORIZONTAL_YPOS;
6237   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
6238     ED_SCROLL_HORIZONTAL_XSIZE;
6239   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
6240     ED_SCROLL_HORIZONTAL_YSIZE;
6241   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x      = SX;
6242   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y      = SY;
6243   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width  = SXSIZE;
6244   scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
6245
6246   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
6247     SX + ED_SCROLL_VERTICAL_XPOS;
6248   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
6249     SY + ED_SCROLL_VERTICAL_YPOS;
6250   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
6251     ED_SCROLL_VERTICAL_XSIZE;
6252   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
6253     ED_SCROLL_VERTICAL_YSIZE;
6254   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x      = SX;
6255   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y      = SY;
6256   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width  = SXSIZE;
6257   scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
6258
6259   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
6260     DX + ED_SCROLL2_VERTICAL_XPOS;
6261   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
6262     DY + ED_SCROLL2_VERTICAL_YPOS;
6263   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
6264     ED_SCROLL2_VERTICAL_XSIZE;
6265   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
6266     ED_SCROLL2_VERTICAL_YSIZE;
6267   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX;
6268   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY;
6269   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width  = DXSIZE;
6270   scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = DYSIZE;
6271
6272   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
6273   {
6274     int id = scrollbar_info[i].gadget_id;
6275     int graphic = scrollbar_info[i].graphic;
6276     struct GraphicInfo *gd = &graphic_info[graphic];
6277     int gd_x1 = gd->src_x;
6278     int gd_y1 = gd->src_y;
6279     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6280     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6281     struct GadgetInfo *gi;
6282     int items_max, items_visible, item_position;
6283     unsigned int event_mask;
6284
6285     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
6286     {
6287       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
6288       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
6289       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
6290     }
6291     else        /* drawing area scrollbars */
6292     {
6293       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
6294       {
6295         items_max = MAX(lev_fieldx + 2, ed_fieldx);
6296         items_visible = ed_fieldx;
6297         item_position = 0;
6298       }
6299       else
6300       {
6301         items_max = MAX(lev_fieldy + 2, ed_fieldy);
6302         items_visible = ed_fieldy;
6303         item_position = 0;
6304       }
6305     }
6306
6307     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
6308
6309     gi = CreateGadget(GDI_CUSTOM_ID, id,
6310                       GDI_CUSTOM_TYPE_ID, i,
6311                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
6312                       GDI_X, scrollbar_pos[i].x,
6313                       GDI_Y, scrollbar_pos[i].y,
6314                       GDI_WIDTH, scrollbar_pos[i].width,
6315                       GDI_HEIGHT, scrollbar_pos[i].height,
6316                       GDI_TYPE, scrollbar_info[i].type,
6317                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
6318                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
6319                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
6320                       GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
6321                       GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
6322                       GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
6323                       GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
6324                       GDI_STATE, GD_BUTTON_UNPRESSED,
6325                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6326                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6327                       GDI_BORDER_SIZE, gd->border_size, gd->border_size,
6328                       GDI_EVENT_MASK, event_mask,
6329                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6330                       GDI_CALLBACK_ACTION, HandleControlButtons,
6331                       GDI_END);
6332
6333     if (gi == NULL)
6334       Error(ERR_EXIT, "cannot create gadget");
6335
6336     level_editor_gadget[id] = gi;
6337   }
6338 }
6339
6340 static void CreateCheckbuttonGadgets()
6341 {
6342   struct GadgetInfo *gi;
6343   unsigned int event_mask;
6344   int i;
6345
6346   event_mask = GD_EVENT_PRESSED;
6347
6348   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
6349   {
6350     int id = checkbutton_info[i].gadget_id;
6351     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
6352                    IMG_EDITOR_CHECKBOX);
6353     struct GraphicInfo *gd = &graphic_info[graphic];
6354     int gd_x1 = gd->src_x;
6355     int gd_y1 = gd->src_y;
6356     int gd_x2 = gd->src_x + gd->pressed_xoffset;
6357     int gd_y2 = gd->src_y + gd->pressed_yoffset;
6358     int gd_x1a = gd->src_x + gd->active_xoffset;
6359     int gd_y1a = gd->src_y + gd->active_yoffset;
6360     int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
6361     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
6362     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
6363     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
6364
6365     /* determine horizontal position to the right of specified gadget */
6366     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
6367       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
6368            ED_GADGET_TEXT_DISTANCE);
6369
6370     /* determine horizontal offset for leading text */
6371     if (checkbutton_info[i].text_left != NULL)
6372       x += getTextWidthForGadget(checkbutton_info[i].text_left);
6373
6374     gi = CreateGadget(GDI_CUSTOM_ID, id,
6375                       GDI_CUSTOM_TYPE_ID, i,
6376                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
6377                       GDI_X, x,
6378                       GDI_Y, y,
6379                       GDI_WIDTH, gd->width,
6380                       GDI_HEIGHT, gd->height,
6381                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
6382                       GDI_CHECKED, *checkbutton_info[i].value,
6383                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6384                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6385                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6386                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
6387                       GDI_EVENT_MASK, event_mask,
6388                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6389                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
6390                       GDI_END);
6391
6392     if (gi == NULL)
6393       Error(ERR_EXIT, "cannot create gadget");
6394
6395     level_editor_gadget[id] = gi;
6396     right_gadget_border[id] =
6397       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
6398   }
6399 }
6400
6401 static void CreateRadiobuttonGadgets()
6402 {
6403   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_RADIOBUTTON];
6404   int gd_x1 = gd->src_x;
6405   int gd_y1 = gd->src_y;
6406   int gd_x2 = gd->src_x + gd->pressed_xoffset;
6407   int gd_y2 = gd->src_y + gd->pressed_yoffset;
6408   int gd_x1a = gd->src_x + gd->active_xoffset;
6409   int gd_y1a = gd->src_y + gd->active_yoffset;
6410   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
6411   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
6412   struct GadgetInfo *gi;
6413   unsigned int event_mask;
6414   int i;
6415
6416   event_mask = GD_EVENT_PRESSED;
6417
6418   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
6419   {
6420     int id = radiobutton_info[i].gadget_id;
6421     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
6422     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
6423
6424     int checked =
6425       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
6426
6427     /* determine horizontal position to the right of specified gadget */
6428     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
6429       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
6430            ED_GADGET_TEXT_DISTANCE);
6431
6432     /* determine horizontal offset for leading text */
6433     if (radiobutton_info[i].text_left != NULL)
6434       x += getTextWidthForGadget(radiobutton_info[i].text_left);
6435
6436     gi = CreateGadget(GDI_CUSTOM_ID, id,
6437                       GDI_CUSTOM_TYPE_ID, i,
6438                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
6439                       GDI_X, x,
6440                       GDI_Y, y,
6441                       GDI_WIDTH, gd->width,
6442                       GDI_HEIGHT, gd->height,
6443                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
6444                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
6445                       GDI_CHECKED, checked,
6446                       GDI_DESIGN_UNPRESSED, gd->bitmap, gd_x1, gd_y1,
6447                       GDI_DESIGN_PRESSED, gd->bitmap, gd_x2, gd_y2,
6448                       GDI_ALT_DESIGN_UNPRESSED, gd->bitmap, gd_x1a, gd_y1a,
6449                       GDI_ALT_DESIGN_PRESSED, gd->bitmap, gd_x2a, gd_y2a,
6450                       GDI_EVENT_MASK, event_mask,
6451                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
6452                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
6453                       GDI_END);
6454
6455     if (gi == NULL)
6456       Error(ERR_EXIT, "cannot create gadget");
6457
6458     level_editor_gadget[id] = gi;
6459     right_gadget_border[id] =
6460       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
6461   }
6462 }
6463
6464 void CreateLevelEditorGadgets()
6465 {
6466   /* force EDITOR font inside level editor */
6467   SetFontStatus(GAME_MODE_EDITOR);
6468
6469   /* these values are not constant, but can change at runtime */
6470   ed_fieldx = MAX_ED_FIELDX - 1;
6471   ed_fieldy = MAX_ED_FIELDY - 1;
6472
6473   num_editor_gadgets = NUM_EDITOR_GADGETS;
6474
6475   // printf("::: allocating %d gadgets ...\n", num_editor_gadgets);
6476
6477   level_editor_gadget =
6478     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
6479   right_gadget_border =
6480     checked_calloc(num_editor_gadgets * sizeof(int));
6481
6482   editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int));
6483   editor_el_empty_ptr = editor_el_empty;
6484
6485   ReinitializeElementList();
6486
6487   CreateControlButtons();
6488   CreateScrollbarGadgets();
6489
6490   /* order of function calls is important because of cross-references */
6491   CreateCheckbuttonGadgets();
6492   CreateCounterButtons();
6493   CreateRadiobuttonGadgets();
6494   CreateTextInputGadgets();
6495   CreateTextAreaGadgets();
6496   CreateSelectboxGadgets();
6497   CreateGraphicbuttonGadgets();
6498   CreateTextbuttonGadgets();
6499   CreateDrawingAreas();
6500
6501   ResetFontStatus();
6502 }
6503
6504 void FreeLevelEditorGadgets()
6505 {
6506   int i;
6507
6508   // printf("::: freeing %d gadgets ...\n", num_editor_gadgets);
6509
6510   for (i = 0; i < num_editor_gadgets; i++)
6511   {
6512     FreeGadget(level_editor_gadget[i]);
6513
6514     level_editor_gadget[i] = NULL;
6515   }
6516
6517   checked_free(level_editor_gadget);
6518   checked_free(right_gadget_border);
6519
6520   checked_free(editor_el_empty);
6521 }
6522
6523 static void MapCounterButtons(int id)
6524 {
6525   int font_nr = FONT_TEXT_1;
6526   int font_height = getFontHeight(font_nr);
6527   int gadget_id_down = counterbutton_info[id].gadget_id_down;
6528   int gadget_id_text = counterbutton_info[id].gadget_id_text;
6529   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
6530   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
6531   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
6532   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
6533   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
6534   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6535   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6536   int yoffset = (gi_down->height - font_height) / 2;
6537   int x_left = gi_down->x - xoffset_left;
6538   int x_right;  /* set after gadget position was modified */
6539   int y_above = gi_down->y - yoffset_above;
6540   int x = gi_down->x;
6541   int y;        /* set after gadget position was modified */
6542
6543   /* counter limits must be changed first to prevent value truncation */
6544   ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
6545                             counterbutton_info[id].max_value);
6546
6547   /* right text position might have changed after setting position above */
6548   x_right = gi_up->x + gi_up->width + xoffset_right;
6549
6550   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
6551
6552   /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */
6553   if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
6554       id <= ED_COUNTER_ID_ELEMENT_VALUE4)
6555   {
6556     ModifyGadget(gi_down, GDI_Y,
6557                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6558     ModifyGadget(gi_text, GDI_Y,
6559                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6560     ModifyGadget(gi_up,   GDI_Y,
6561                  SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
6562   }
6563
6564   /* vertical position might have changed after setting position above */
6565   y = gi_up->y + yoffset;
6566
6567   if (counterbutton_info[id].text_above)
6568     DrawText(x, y_above, counterbutton_info[id].text_above, font_nr);
6569
6570   if (counterbutton_info[id].text_left)
6571     DrawText(x_left, y, counterbutton_info[id].text_left, font_nr);
6572
6573   if (counterbutton_info[id].text_right)
6574     DrawText(x_right, y, counterbutton_info[id].text_right, font_nr);
6575
6576   MapGadget(gi_down);
6577   MapGadget(gi_text);
6578   MapGadget(gi_up);
6579 }
6580
6581 static void MapControlButtons()
6582 {
6583   int counter_id;
6584   int i;
6585
6586   /* map toolbox buttons (excluding special CE toolbox buttons) */
6587   for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
6588     MapGadget(level_editor_gadget[i]);
6589
6590   /* map toolbox buttons (element properties buttons) */
6591   for (i = ED_NUM_CTRL1_4_BUTTONS; i < ED_NUM_CTRL1_6_BUTTONS; i++)
6592     MapGadget(level_editor_gadget[i]);
6593
6594   /* map buttons to select elements */
6595   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
6596     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
6597   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
6598   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
6599   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
6600
6601   /* map buttons to select level */
6602   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
6603   counterbutton_info[counter_id].min_value = leveldir_current->first_level;
6604   counterbutton_info[counter_id].max_value = leveldir_current->last_level;
6605   MapCounterButtons(counter_id);
6606 }
6607
6608 static void MapDrawingArea(int id)
6609 {
6610   int font_nr = FONT_TEXT_1;
6611   int font_height = getFontHeight(font_nr);
6612   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
6613   int area_xsize = gi->drawing.area_xsize;
6614   int area_ysize = gi->drawing.area_ysize;
6615   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
6616   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
6617   int x_left  = gi->x - xoffset_left;
6618   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
6619   int x_below = gi->x + (gi->width - xoffset_below) / 2;
6620   int y_side  = gi->y + (gi->height - font_height) / 2;
6621   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
6622
6623   if (drawingarea_info[id].text_left)
6624     DrawText(x_left, y_side, drawingarea_info[id].text_left, font_nr);
6625
6626   if (drawingarea_info[id].text_right)
6627     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
6628
6629   if (drawingarea_info[id].text_below)
6630     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
6631
6632   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
6633   {
6634     DrawElementBorder(gi->x, gi->y,
6635                       area_xsize * ED_DRAWINGAREA_TILE_SIZE,
6636                       area_ysize * ED_DRAWINGAREA_TILE_SIZE, TRUE);
6637
6638     DrawDrawingArea(id);
6639   }
6640
6641   MapGadget(gi);
6642 }
6643
6644 static void MapTextInputGadget(int id)
6645 {
6646   int font_nr = FONT_TEXT_1;
6647   int font_height = getFontHeight(font_nr);
6648   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
6649   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6650   int x_above = ED_SETTINGS_X(textinput_info[id].x);
6651   int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
6652
6653   if (textinput_info[id].text_above)
6654     DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
6655
6656   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
6657
6658   MapGadget(gi);
6659 }
6660
6661 static void MapTextAreaGadget(int id)
6662 {
6663   int font_nr = FONT_TEXT_1;
6664   int font_height = getFontHeight(font_nr);
6665   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
6666   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
6667   int x_above = ED_SETTINGS_X(textarea_info[id].x);
6668   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
6669
6670   if (textarea_info[id].text_above)
6671     DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above);
6672
6673   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
6674
6675   MapGadget(gi);
6676 }
6677
6678 static void MapSelectboxGadget(int id)
6679 {
6680   int font_nr = FONT_TEXT_1;
6681   int font_height = getFontHeight(font_nr);
6682   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
6683   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
6684   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6685   int yoffset = (gi->height - font_height) / 2;
6686   int x_left = gi->x - xoffset_left;
6687   int x_right = gi->x + gi->width + xoffset_right;
6688   int y = gi->y + yoffset;
6689
6690   if (selectbox_info[id].text_left)
6691     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
6692
6693   if (selectbox_info[id].text_right)
6694     DrawText(x_right, y, selectbox_info[id].text_right, font_nr);
6695
6696   ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
6697
6698   MapGadget(gi);
6699 }
6700
6701 static void MapTextbuttonGadget(int id)
6702 {
6703   int font_nr = FONT_TEXT_1;
6704   int font_height = getFontHeight(font_nr);
6705   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
6706   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
6707   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6708   int yoffset = (gi->height - font_height) / 2;
6709   int x_left = gi->x - xoffset_left;
6710   int x_right = gi->x + gi->width + xoffset_right;
6711   int y = gi->y + yoffset;
6712
6713   /* only show button to delete change pages when more than minimum pages */
6714   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
6715       custom_element.num_change_pages == MIN_CHANGE_PAGES)
6716     return;
6717
6718   if (textbutton_info[id].text_left)
6719     DrawText(x_left, y, textbutton_info[id].text_left, font_nr);
6720
6721   if (textbutton_info[id].text_right)
6722     DrawText(x_right, y, textbutton_info[id].text_right, font_nr);
6723
6724   MapGadget(gi);
6725 }
6726
6727 static void MapGraphicbuttonGadget(int id)
6728 {
6729   int font_nr = FONT_TEXT_1;
6730   int font_height = getFontHeight(font_nr);
6731   struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id];
6732   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
6733   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6734   int yoffset = (gi->height - font_height) / 2;
6735   int x_left = gi->x - xoffset_left;
6736   int x_right = gi->x + gi->width + xoffset_right;
6737   int y = gi->y + yoffset;
6738
6739   if (graphicbutton_info[id].text_left)
6740     DrawText(x_left, y, graphicbutton_info[id].text_left, font_nr);
6741
6742   if (graphicbutton_info[id].text_right)
6743     DrawText(x_right, y, graphicbutton_info[id].text_right, font_nr);
6744
6745   MapGadget(gi);
6746 }
6747
6748 static void MapRadiobuttonGadget(int id)
6749 {
6750   int font_nr = FONT_TEXT_1;
6751   int font_height = getFontHeight(font_nr);
6752   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
6753   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6754   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6755   int yoffset = (gi->height - font_height) / 2;
6756   int x_left = gi->x - xoffset_left;
6757   int x_right = gi->x + gi->width + xoffset_right;
6758   int y = gi->y + yoffset;
6759   boolean checked =
6760     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
6761
6762   if (radiobutton_info[id].text_left)
6763     DrawText(x_left, y, radiobutton_info[id].text_left, font_nr);
6764
6765   if (radiobutton_info[id].text_right)
6766     DrawText(x_right, y, radiobutton_info[id].text_right, font_nr);
6767
6768   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
6769
6770   MapGadget(gi);
6771 }
6772
6773 static void MapCheckbuttonGadget(int id)
6774 {
6775   int font_nr = FONT_TEXT_1;
6776   int font_height = getFontHeight(font_nr);
6777   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
6778   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
6779   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
6780   int yoffset = (gi->height - font_height) / 2;
6781   int x_left, x_right, y;       /* set after gadget position was modified */
6782
6783   /* set position for gadgets with dynamically determined position */
6784   if (checkbutton_info[id].x != -1)     /* do not change dynamic positions */
6785     ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END);
6786   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
6787
6788   x_left = gi->x - xoffset_left;
6789   x_right = gi->x + gi->width + xoffset_right;
6790   y = gi->y + yoffset;
6791
6792   if (checkbutton_info[id].text_left)
6793     DrawText(x_left, y, checkbutton_info[id].text_left, font_nr);
6794
6795   if (checkbutton_info[id].text_right)
6796     DrawText(x_right, y, checkbutton_info[id].text_right, font_nr);
6797
6798   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
6799
6800   MapGadget(gi);
6801 }
6802
6803 static void MapMainDrawingArea()
6804 {
6805   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
6806   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
6807   int i;
6808
6809   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
6810   {
6811     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
6812           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
6813          no_horizontal_scrollbar) ||
6814         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
6815           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
6816          no_vertical_scrollbar))
6817       continue;
6818
6819     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
6820   }
6821
6822   for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
6823   {
6824     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
6825         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
6826       continue;
6827
6828     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
6829   }
6830
6831   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
6832 }
6833
6834 static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
6835 {
6836   int i;
6837
6838   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
6839   {
6840     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
6841         i == GADGET_ID_CUSTOM_COPY_TO ||
6842         i == GADGET_ID_CUSTOM_EXCHANGE ||
6843         i == GADGET_ID_CUSTOM_COPY ||
6844         i == GADGET_ID_CUSTOM_PASTE)
6845     {
6846       if (map)
6847         MapGadget(level_editor_gadget[i]);
6848       else
6849         UnmapGadget(level_editor_gadget[i]);
6850     }
6851   }
6852 }
6853
6854 static void MapLevelEditorToolboxCustomGadgets()
6855 {
6856   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
6857 }
6858
6859 static void UnmapLevelEditorToolboxCustomGadgets()
6860 {
6861   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
6862 }
6863
6864 static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
6865 {
6866   int i;
6867
6868   for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
6869   {
6870     if (i != GADGET_ID_SINGLE_ITEMS &&
6871         i != GADGET_ID_PICK_ELEMENT)
6872     {
6873       struct GadgetInfo *gi = level_editor_gadget[i];
6874
6875       if (map)
6876       {
6877         MapGadget(gi);
6878       }
6879       else
6880       {
6881         int graphic = IMG_EDITOR_NO_TOOLBOX_BUTTON;
6882         struct GraphicInfo *gd = &graphic_info[graphic];
6883
6884         UnmapGadget(gi);
6885
6886         BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y,
6887                    gi->width, gi->height, gi->x, gi->y);
6888
6889         redraw_mask |= REDRAW_DOOR_3;
6890       }
6891     }
6892   }
6893 }
6894
6895 static void MapLevelEditorToolboxDrawingGadgets()
6896 {
6897   MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
6898 }
6899
6900 static void UnmapLevelEditorToolboxDrawingGadgets()
6901 {
6902   MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
6903 }
6904
6905 static void UnmapDrawingArea(int id)
6906 {
6907   UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
6908 }
6909
6910 static void UnmapLevelEditorFieldGadgets()
6911 {
6912   int i;
6913
6914   for (i = 0; i < num_editor_gadgets; i++)
6915     if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
6916                           level_editor_gadget[i]->y))
6917       UnmapGadget(level_editor_gadget[i]);
6918 }
6919
6920 void UnmapLevelEditorGadgets()
6921 {
6922   int i;
6923
6924   for (i = 0; i < num_editor_gadgets; i++)
6925     UnmapGadget(level_editor_gadget[i]);
6926 }
6927
6928 static void ResetUndoBuffer()
6929 {
6930   undo_buffer_position = -1;
6931   undo_buffer_steps = -1;
6932   redo_buffer_steps = 0;
6933
6934   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6935
6936   level.changed = FALSE;
6937 }
6938
6939 static void DrawEditModeWindow()
6940 {
6941   ModifyEditorElementList();
6942   RedrawDrawingElements();
6943
6944   if (edit_mode == ED_MODE_INFO)
6945     DrawLevelInfoWindow();
6946   else if (edit_mode == ED_MODE_PROPERTIES)
6947     DrawPropertiesWindow();
6948   else  /* edit_mode == ED_MODE_DRAWING */
6949     DrawDrawingWindow();
6950 }
6951
6952 static boolean LevelChanged()
6953 {
6954   boolean field_changed = FALSE;
6955   int x, y;
6956
6957   for (y = 0; y < lev_fieldy; y++) 
6958     for (x = 0; x < lev_fieldx; x++)
6959       if (Feld[x][y] != level.field[x][y])
6960         field_changed = TRUE;
6961
6962   return (level.changed || field_changed);
6963 }
6964
6965 static boolean PrepareSavingIntoPersonalLevelSet()
6966 {
6967   static LevelDirTree *last_copied_leveldir = NULL;
6968   static LevelDirTree *last_written_leveldir = NULL;
6969   static int last_copied_level_nr = -1;
6970   static int last_written_level_nr = -1;
6971   LevelDirTree *leveldir_former = leveldir_current;
6972   int level_nr_former = level_nr;
6973   int new_level_nr;
6974
6975   // remember last mod/save so that for current session, we write
6976   // back to the same personal copy, asking only about overwrite.
6977   if (leveldir_current == last_copied_leveldir &&
6978       level_nr == last_copied_level_nr)
6979   {
6980     // "cd" to personal level set dir (as used when writing last copy)
6981     leveldir_current = last_written_leveldir;
6982     level_nr = last_written_level_nr;
6983
6984     return TRUE;
6985   }
6986
6987   if (!Request("This level is read only! "
6988                "Save into personal level set?", REQ_ASK))
6989     return FALSE;
6990
6991   // "cd" to personal level set dir (for writing copy the first time)
6992   leveldir_current =
6993     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
6994
6995   // find unused level number
6996   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
6997   {
6998     static char *level_filename = NULL;
6999
7000     setString(&level_filename, getDefaultLevelFilename(new_level_nr));
7001
7002     if (!fileExists(level_filename))
7003       break;
7004   }
7005
7006   last_copied_leveldir = leveldir_former;
7007   last_copied_level_nr = level_nr_former;
7008
7009   last_written_leveldir = leveldir_current;
7010   last_written_level_nr = level_nr = new_level_nr;
7011
7012   return TRUE;
7013 }
7014
7015 static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
7016 {
7017   static char *filename_levelinfo = NULL, *mod_name = NULL;
7018   FILE *file;
7019
7020   // annotate this copy-and-mod in personal levelinfo.conf
7021   setString(&filename_levelinfo,
7022             getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
7023
7024   if ((file = fopen(filename_levelinfo, MODE_APPEND)))
7025   {
7026     fprintf(file, "\n");
7027     fprintf(file, "# level %d was modified from:\n", level_nr);
7028     fprintf(file, "# - previous level set name:    %s\n",
7029             former_name);
7030     fprintf(file, "# - level within previous set:  %d \"%s\"\n",
7031             level.file_info.nr, level.name);
7032     fprintf(file, "# - previous author:            %s\n",
7033             level.author);
7034     fprintf(file, "# - previous save date:         ");
7035
7036     if (level.creation_date.src == DATE_SRC_LEVELFILE)
7037     {
7038       fprintf(file, "%04d-%02d-%02d\n",
7039               level.creation_date.year,
7040               level.creation_date.month,
7041               level.creation_date.day);
7042     }
7043     else
7044     {
7045       fprintf(file, "not recorded\n");
7046     }
7047
7048     fclose(file);
7049   }
7050
7051   if (level_nr > leveldir_current->last_level)
7052   {
7053     static char *temp_levelinfo = NULL;
7054     FILE *temp_file = NULL;
7055     char line[MAX_LINE_LEN];
7056
7057     setString(&temp_levelinfo,
7058               getPath2(getCurrentLevelDir(),
7059                        getStringCat2(LEVELINFO_FILENAME, ".new")));
7060
7061     if ((file = fopen(filename_levelinfo, MODE_READ)) &&
7062         (temp_file = fopen(temp_levelinfo, MODE_WRITE)))
7063     {
7064       while (fgets(line, MAX_LINE_LEN, file))
7065       {
7066         if (!strPrefix(line, "levels:"))
7067           fputs(line, temp_file);
7068         else
7069           fprintf(temp_file, "%-32s%d\n", "levels:", level_nr + 9);
7070       }
7071     }
7072
7073     if (temp_file)
7074       fclose(temp_file);
7075
7076     if (file)
7077       fclose(file);
7078
7079     // needs error handling; also, ok on dos/win?
7080     unlink(filename_levelinfo);
7081     rename(temp_levelinfo, filename_levelinfo);
7082   }
7083
7084   // else: allow the save even if annotation failed
7085
7086   // now... spray graffiti on the old level vital statistics
7087   // user can change these; just trying to set a good baseline
7088
7089   // don't truncate names for fear of making offensive or silly:
7090   // long-named original author only recorded in levelinfo.conf.
7091   // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
7092   if (!strEqual(level.author, leveldir_current->author))
7093   {
7094     setString(&mod_name, getStringCat3(leveldir_current->author,
7095                                        " after ", level.author));
7096
7097     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
7098       setString(&mod_name,
7099                 getStringCat2(leveldir_current->author, " (ed.)"));
7100
7101     if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
7102       setString(&mod_name, leveldir_current->author);
7103
7104     strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
7105
7106     // less worried about truncation here
7107     setString(&mod_name, getStringCat2("Mod: ", level.name));
7108     strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
7109   }
7110 }
7111
7112 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
7113                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
7114 {
7115   int x, y;
7116
7117   for (x = 0; x < lev_fieldx; x++)
7118     for (y = 0; y < lev_fieldy; y++) 
7119       dst[x][y] = src[x][y];
7120 }
7121
7122 static int setSelectboxValue(int selectbox_id, int new_value)
7123 {
7124   int new_index_value = 0;
7125   int i;
7126
7127   for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
7128     if (selectbox_info[selectbox_id].options[i].value == new_value)
7129       new_index_value = i;
7130
7131   *selectbox_info[selectbox_id].value =
7132     selectbox_info[selectbox_id].options[new_index_value].value;
7133
7134   return new_index_value;
7135 }
7136
7137 static void setSelectboxSpecialActionVariablesIfNeeded()
7138 {
7139   int i;
7140
7141   /* change action mode and arg variables according to action type variable */
7142   for (i = 0; action_arg_options[i].value != -1; i++)
7143   {
7144     if (action_arg_options[i].value == custom_element_change.action_type)
7145     {
7146       int mode = action_arg_options[i].mode;
7147
7148       /* only change if corresponding selectbox has changed */
7149       if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
7150           action_arg_modes[mode])
7151         custom_element_change.action_mode = -1;
7152
7153       /* only change if corresponding selectbox has changed */
7154       if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
7155           action_arg_options[i].options)
7156         custom_element_change.action_arg = -1;
7157
7158       break;
7159     }
7160   }
7161 }
7162
7163 static void setSelectboxSpecialActionOptions()
7164 {
7165   int i;
7166
7167   /* change action mode and arg selectbox according to action type selectbox */
7168   for (i = 0; action_arg_options[i].value != -1; i++)
7169   {
7170     if (action_arg_options[i].value == custom_element_change.action_type)
7171     {
7172       int mode = action_arg_options[i].mode;
7173
7174       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
7175                                    action_arg_modes[mode]);
7176       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
7177                                  custom_element_change.action_mode);
7178
7179       ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
7180                                    action_arg_options[i].options);
7181       ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
7182                                  custom_element_change.action_arg);
7183       break;
7184     }
7185   }
7186 }
7187
7188 static void copy_custom_element_settings(int element_from, int element_to)
7189 {
7190   struct ElementInfo *ei_from = &element_info[element_from];
7191   struct ElementInfo *ei_to = &element_info[element_to];
7192
7193   copyElementInfo(ei_from, ei_to);
7194 }
7195
7196 static void replace_custom_element_in_settings(int element_from,
7197                                                int element_to)
7198 {
7199   int i, j, x, y;
7200
7201   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7202   {
7203     struct ElementInfo *ei = &element_info[i];
7204
7205     for (y = 0; y < 3; y++)
7206       for (x = 0; x < 3; x++)
7207         if (ei->content.e[x][y] == element_from)
7208           ei->content.e[x][y] = element_to;
7209
7210     for (j = 0; j < ei->num_change_pages; j++)
7211     {
7212       struct ElementChangeInfo *change = &ei->change_page[j];
7213
7214       if (change->target_element == element_from)
7215         change->target_element = element_to;
7216
7217       if (change->initial_trigger_element == element_from)
7218         change->initial_trigger_element = element_to;
7219
7220       if (change->action_element == element_from)
7221         change->action_element = element_to;
7222
7223       for (y = 0; y < 3; y++)
7224         for (x = 0; x < 3; x++)
7225           if (change->target_content.e[x][y] == element_from)
7226             change->target_content.e[x][y] = element_to;
7227     }
7228
7229     if (ei->group != NULL)                              /* group or internal */
7230       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
7231         if (ei->group->element[j] == element_from)
7232           ei->group->element[j] = element_to;
7233   }
7234 }
7235
7236 static void replace_custom_element_in_playfield(int element_from,
7237                                                 int element_to)
7238 {
7239   int x, y;
7240
7241   for (x = 0; x < lev_fieldx; x++)
7242     for (y = 0; y < lev_fieldy; y++)
7243       if (Feld[x][y] == element_from)
7244         Feld[x][y] = element_to;
7245 }
7246
7247 static boolean CopyCustomElement(int element_old, int element_new,
7248                                  int copy_mode)
7249 {
7250   if (copy_mode == GADGET_ID_CUSTOM_COPY)
7251   {
7252     element_new = (IS_CUSTOM_ELEMENT(element_old) ?
7253                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
7254     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
7255   }
7256   else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
7257   {
7258     element_old = (IS_CUSTOM_ELEMENT(element_new) ?
7259                    EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
7260     copy_mode = GADGET_ID_CUSTOM_COPY_TO;
7261
7262     level.changed = TRUE;
7263   }
7264   else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
7265   {
7266     Request("Please choose custom element!", REQ_CONFIRM);
7267
7268     return FALSE;
7269   }
7270   else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
7271   {
7272     Request("Please choose group element!", REQ_CONFIRM);
7273
7274     return FALSE;
7275   }
7276   else
7277   {
7278     level.changed = TRUE;
7279   }
7280
7281   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
7282   {
7283     copy_custom_element_settings(element_new, element_old);
7284   }
7285   else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
7286   {
7287     copy_custom_element_settings(element_old, element_new);
7288   }
7289   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
7290   {
7291     copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
7292     copy_custom_element_settings(element_new, element_old);
7293     copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
7294
7295     replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
7296     replace_custom_element_in_settings(element_new, element_old);
7297     replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
7298
7299     replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
7300     replace_custom_element_in_playfield(element_new, element_old);
7301     replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
7302   }
7303
7304   UpdateCustomElementGraphicGadgets();
7305   DrawPropertiesWindow();
7306
7307   return TRUE;
7308 }
7309
7310 static void CopyCustomElementPropertiesToEditor(int element)
7311 {
7312   int i;
7313   int current_change_page = element_info[element].current_change_page;
7314
7315   /* dynamically (re)build selectbox for selecting change page */
7316   for (i = 0; i < element_info[element].num_change_pages; i++)
7317   {
7318     sprintf(options_change_page_strings[i], "%d", i + 1);
7319
7320     options_change_page[i].value = i;
7321     options_change_page[i].text = options_change_page_strings[i];
7322   }
7323
7324   options_change_page[i].value = -1;
7325   options_change_page[i].text = NULL;
7326
7327   /* needed here to initialize combined element properties */
7328   InitElementPropertiesEngine(level.game_version);
7329
7330   element_info[element].change =
7331     &element_info[element].change_page[current_change_page];
7332
7333   custom_element = element_info[element];
7334   custom_element_change = *element_info[element].change;
7335
7336   /* needed to initially set selectbox options for special action options */
7337   setSelectboxSpecialActionOptions();
7338
7339   /* needed to initially set selectbox value variables to reliable defaults */
7340   for (i = 0; i < ED_NUM_SELECTBOX; i++)
7341     setSelectboxValue(i, *selectbox_info[i].value);
7342
7343   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
7344     custom_element_properties[i] = HAS_PROPERTY(element, i);
7345
7346   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
7347     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
7348
7349   /* ---------- element settings: configure (custom elements) ------------- */
7350
7351   /* set accessible layer selectbox help value */
7352   custom_element.access_type =
7353     (IS_WALKABLE(element) ? EP_WALKABLE :
7354      IS_PASSABLE(element) ? EP_PASSABLE :
7355      custom_element.access_type);
7356   custom_element.access_layer =
7357     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
7358      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
7359      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
7360      custom_element.access_layer);
7361   custom_element.access_protected =
7362     (IS_PROTECTED(element) ? 1 : 0);
7363   custom_element_properties[EP_ACCESSIBLE] =
7364     (IS_ACCESSIBLE_OVER(element) ||
7365      IS_ACCESSIBLE_INSIDE(element) ||
7366      IS_ACCESSIBLE_UNDER(element));
7367
7368   /* set walk-to-object action selectbox help value */
7369   custom_element.walk_to_action =
7370     (IS_DIGGABLE(element) ? EP_DIGGABLE :
7371      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
7372      IS_DROPPABLE(element) ? EP_DROPPABLE :
7373      IS_THROWABLE(element) ? EP_THROWABLE :
7374      IS_PUSHABLE(element) ? EP_PUSHABLE :
7375      custom_element.walk_to_action);
7376   custom_element_properties[EP_WALK_TO_OBJECT] =
7377     (IS_DIGGABLE(element) ||
7378      IS_COLLECTIBLE_ONLY(element) ||
7379      IS_DROPPABLE(element) ||
7380      IS_THROWABLE(element) ||
7381      IS_PUSHABLE(element));
7382
7383   /* set smash targets selectbox help value */
7384   custom_element.smash_targets =
7385     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
7386      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
7387      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
7388      custom_element.smash_targets);
7389   custom_element_properties[EP_CAN_SMASH] =
7390     (CAN_SMASH_EVERYTHING(element) ||
7391      CAN_SMASH_ENEMIES(element) ||
7392      CAN_SMASH_PLAYER(element));
7393
7394   /* set deadliness selectbox help value */
7395   custom_element.deadliness =
7396     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
7397      DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
7398      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
7399      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
7400      custom_element.deadliness);
7401   custom_element_properties[EP_DEADLY] =
7402     (DONT_TOUCH(element) ||
7403      DONT_GET_HIT_BY(element) ||
7404      DONT_COLLIDE_WITH(element) ||
7405      DONT_RUN_INTO(element));
7406
7407   /* ---------- element settings: advanced (custom elements) --------------- */
7408
7409   /* set "change by direct action" selectbox help value */
7410   custom_element_change.direct_action =
7411     (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
7412      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
7413      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
7414      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
7415      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
7416      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
7417      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
7418      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
7419      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
7420      HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
7421      HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
7422      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
7423      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
7424      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
7425      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
7426      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
7427      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
7428      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
7429      custom_element_change.direct_action);
7430
7431   /* set "change by other element action" selectbox help value */
7432   custom_element_change.other_action =
7433     (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
7434      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
7435      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
7436      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
7437      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
7438      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
7439      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
7440      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
7441      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
7442      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
7443      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
7444      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
7445      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
7446      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
7447      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
7448      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
7449      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
7450      HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
7451      HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
7452      HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
7453      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
7454      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
7455      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
7456      custom_element_change.other_action);
7457 }
7458
7459 static void CopyGroupElementPropertiesToEditor(int element)
7460 {
7461   group_element_info = *element_info[element].group;
7462   custom_element = element_info[element];       /* needed for description */
7463 }
7464
7465 static void CopyClassicElementPropertiesToEditor(int element)
7466 {
7467   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
7468     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
7469       getMoveIntoAcidProperty(&level, element);
7470
7471   if (MAYBE_DONT_COLLIDE_WITH(element))
7472     custom_element_properties[EP_DONT_COLLIDE_WITH] =
7473       getDontCollideWithProperty(&level, element);
7474 }
7475
7476 static void CopyElementPropertiesToEditor(int element)
7477 {
7478   if (IS_CUSTOM_ELEMENT(element))
7479     CopyCustomElementPropertiesToEditor(element);
7480   else if (IS_GROUP_ELEMENT(element))
7481     CopyGroupElementPropertiesToEditor(element);
7482   else
7483     CopyClassicElementPropertiesToEditor(element);
7484 }
7485
7486 static void CopyCustomElementPropertiesToGame(int element)
7487 {
7488   int i;
7489   int access_type_and_layer;
7490
7491   /* mark that this custom element has been modified */
7492   custom_element.modified_settings = TRUE;
7493   level.changed = TRUE;
7494
7495   if (level.use_custom_template)
7496   {
7497     if (Request("Copy and modify level template?", REQ_ASK))
7498     {
7499       level.use_custom_template = FALSE;
7500       ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
7501                    GDI_CHECKED, FALSE, GDI_END);
7502     }
7503     else
7504     {
7505       LoadLevelTemplate(-1);    /* this resets all element modifications ... */
7506
7507       DrawEditModeWindow();     /* ... and copies them to 'custom_element' */
7508     }
7509   }
7510
7511   element_info[element] = custom_element;
7512   *element_info[element].change = custom_element_change;
7513
7514   /* ---------- element settings: configure (custom elements) ------------- */
7515
7516   /* set accessible property from checkbox and selectbox */
7517   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
7518   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
7519   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
7520   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
7521   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
7522   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
7523   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
7524                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
7525                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
7526   custom_element_properties[access_type_and_layer] =
7527     custom_element_properties[EP_ACCESSIBLE];
7528   custom_element_properties[EP_PROTECTED] =
7529     (custom_element.access_protected != 0 &&
7530      custom_element_properties[EP_ACCESSIBLE]);
7531
7532   /* set walk-to-object property from checkbox and selectbox */
7533   custom_element_properties[EP_DIGGABLE] = FALSE;
7534   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
7535   custom_element_properties[EP_DROPPABLE] = FALSE;
7536   custom_element_properties[EP_THROWABLE] = FALSE;
7537   custom_element_properties[EP_PUSHABLE] = FALSE;
7538   custom_element_properties[custom_element.walk_to_action] =
7539     custom_element_properties[EP_WALK_TO_OBJECT];
7540
7541   /* set smash property from checkbox and selectbox */
7542   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
7543   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
7544   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
7545   custom_element_properties[custom_element.smash_targets] =
7546     custom_element_properties[EP_CAN_SMASH];
7547
7548   /* set deadliness property from checkbox and selectbox */
7549   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
7550   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
7551   custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
7552   custom_element_properties[EP_DONT_TOUCH] = FALSE;
7553   custom_element_properties[custom_element.deadliness] =
7554     custom_element_properties[EP_DEADLY];
7555
7556   /* ---------- element settings: advanced (custom elements) --------------- */
7557
7558   /* set player change event from checkbox and selectbox */
7559   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
7560   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
7561   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
7562   custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
7563   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
7564   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
7565   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
7566   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
7567   custom_element_change_events[CE_SWITCHED] = FALSE;
7568   custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
7569   custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
7570   custom_element_change_events[CE_BLOCKED] = FALSE;
7571   custom_element_change_events[CE_IMPACT] = FALSE;
7572   custom_element_change_events[CE_SMASHED] = FALSE;
7573   custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
7574   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
7575   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
7576   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
7577   custom_element_change_events[custom_element_change.direct_action] =
7578     custom_element_change_events[CE_BY_DIRECT_ACTION];
7579
7580   /* set other element action change event from checkbox and selectbox */
7581   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
7582   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
7583   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
7584   custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
7585   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
7586   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
7587   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
7588   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
7589   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
7590   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
7591   custom_element_change_events[CE_TOUCHING_X] = FALSE;
7592   custom_element_change_events[CE_HITTING_X] = FALSE;
7593   custom_element_change_events[CE_DIGGING_X] = FALSE;
7594   custom_element_change_events[CE_HIT_BY_X] = FALSE;
7595   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
7596   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
7597   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
7598   custom_element_change_events[CE_MOVE_OF_X] = FALSE;
7599   custom_element_change_events[CE_CREATION_OF_X] = FALSE;
7600   custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
7601   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
7602   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
7603   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
7604   custom_element_change_events[custom_element_change.other_action] =
7605     custom_element_change_events[CE_BY_OTHER_ACTION];
7606
7607   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
7608     SET_PROPERTY(element, i, custom_element_properties[i]);
7609
7610   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
7611     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
7612
7613   /* copy change events also to special level editor variable */
7614   custom_element = element_info[element];
7615   custom_element_change = *element_info[element].change;
7616 }
7617
7618 static void CopyGroupElementPropertiesToGame(int element)
7619 {
7620   element_info[element] = custom_element;
7621   *element_info[element].group = group_element_info;
7622
7623   /* mark that this group element has been modified */
7624   element_info[element].modified_settings = TRUE;
7625   level.changed = TRUE;
7626 }
7627
7628 static void CopyClassicElementPropertiesToGame(int element)
7629 {
7630   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
7631     setMoveIntoAcidProperty(&level, element,
7632                             custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
7633
7634   if (MAYBE_DONT_COLLIDE_WITH(element))
7635     setDontCollideWithProperty(&level, element,
7636                               custom_element_properties[EP_DONT_COLLIDE_WITH]);
7637 }
7638
7639 static void CopyElementPropertiesToGame(int element)
7640 {
7641   if (IS_CUSTOM_ELEMENT(element))
7642     CopyCustomElementPropertiesToGame(element);
7643   else if (IS_GROUP_ELEMENT(element))
7644     CopyGroupElementPropertiesToGame(element);
7645   else
7646     CopyClassicElementPropertiesToGame(element);
7647 }
7648
7649 void CheckElementDescriptions()
7650 {
7651   int i;
7652
7653   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7654     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
7655       Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
7656 }
7657
7658 static int getMaxEdFieldX(boolean has_scrollbar)
7659 {
7660   int scrollbar_width = (has_scrollbar ? ED_SCROLLBUTTON_XSIZE : 0);
7661   int sxsize = SXSIZE - scrollbar_width;
7662   int max_ed_fieldx = sxsize / ed_tilesize;
7663
7664   return max_ed_fieldx;
7665 }
7666
7667 static int getMaxEdFieldY(boolean has_scrollbar)
7668 {
7669   int infotext_height = INFOTEXT_YSIZE_FULL;
7670   int scrollbar_height = (has_scrollbar ? ED_SCROLLBUTTON_YSIZE : 0);
7671   int sysize = SYSIZE - scrollbar_height - infotext_height;
7672   int max_ed_fieldy = sysize / ed_tilesize;
7673
7674   return max_ed_fieldy;
7675 }
7676
7677 void InitZoomLevelSettings()
7678 {
7679   MAX_ED_FIELDX = getMaxEdFieldX(FALSE);
7680   MAX_ED_FIELDY = getMaxEdFieldY(FALSE);
7681 }
7682
7683 void DrawLevelEd()
7684 {
7685   int fade_mask = REDRAW_FIELD;
7686
7687   FadeSoundsAndMusic();
7688
7689   if (CheckIfGlobalBorderHasChanged())
7690     fade_mask = REDRAW_ALL;
7691
7692   FadeOut(fade_mask);
7693
7694   /* needed if different viewport properties defined for editor */
7695   ChangeViewportPropertiesIfNeeded();
7696
7697   ClearField();
7698
7699   InitZoomLevelSettings();
7700
7701   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
7702
7703 #if DEBUG
7704   CheckElementDescriptions();
7705 #endif
7706
7707   if (level_editor_test_game)
7708   {
7709     CopyPlayfield(level.field, Feld);
7710     CopyPlayfield(FieldBackup, level.field);
7711
7712     level_editor_test_game = FALSE;
7713   }
7714   else
7715   {
7716     edit_mode = ED_MODE_DRAWING;
7717     edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
7718     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
7719
7720     ResetUndoBuffer();
7721
7722     level_xpos = -1;
7723     level_ypos = -1;
7724   }
7725
7726   /* needed for gadgets drawn on background (like palette scrollbar) */
7727   SetDoorBackgroundImage(IMG_UNDEFINED);
7728
7729   /* copy default editor door content to main double buffer */
7730   BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto,
7731              graphic_info[IMG_BACKGROUND_PALETTE].src_x,
7732              graphic_info[IMG_BACKGROUND_PALETTE].src_y,
7733              MIN(DXSIZE, graphic_info[IMG_BACKGROUND_PALETTE].width),
7734              MIN(DYSIZE, graphic_info[IMG_BACKGROUND_PALETTE].height),
7735              DX, DY);
7736
7737   /* draw bigger door */
7738   DrawSpecialEditorDoor();
7739
7740   /* draw new control window */
7741   BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto,
7742              graphic_info[IMG_BACKGROUND_TOOLBOX].src_x,
7743              graphic_info[IMG_BACKGROUND_TOOLBOX].src_y,
7744              MIN(EXSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].width),
7745              MIN(EYSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].height),
7746              EX, EY);
7747
7748   // redraw_mask |= REDRAW_ALL;
7749
7750   FreeLevelEditorGadgets();
7751   CreateLevelEditorGadgets();
7752
7753   ReinitializeElementList();            /* update dynamic level element list */
7754   ReinitializeElementListButtons();     /* custom element may look different */
7755
7756   InitElementPropertiesGfxElement();
7757
7758   UnmapAllGadgets();
7759   MapControlButtons();
7760
7761   DrawEditModeWindow();
7762
7763   DrawMaskedBorder(fade_mask);
7764
7765   FadeIn(fade_mask);
7766
7767   /* copy actual editor door content to door double buffer for OpenDoor() */
7768   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
7769 }
7770
7771 static void AdjustDrawingAreaGadgets()
7772 {
7773   int ed_xsize = lev_fieldx + 2;
7774   int ed_ysize = lev_fieldy + 2;
7775   int max_ed_fieldx = MAX_ED_FIELDX;
7776   int max_ed_fieldy = MAX_ED_FIELDY;
7777   boolean horizontal_scrollbar_needed;
7778   boolean vertical_scrollbar_needed;
7779   int x, y, width, height;
7780
7781   /* check if we need any scrollbars */
7782   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7783   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
7784
7785   /* check if we have a smaller editor field because of scrollbars */
7786   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
7787   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
7788
7789   /* check again if we now need more scrollbars because of less space */
7790   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
7791   vertical_scrollbar_needed   = (ed_ysize > max_ed_fieldy);
7792
7793   /* check if editor field gets even smaller after adding new scrollbars */
7794   max_ed_fieldx = getMaxEdFieldX(vertical_scrollbar_needed);
7795   max_ed_fieldy = getMaxEdFieldY(horizontal_scrollbar_needed);
7796
7797   ed_fieldx = (ed_xsize > max_ed_fieldx ? max_ed_fieldx : ed_xsize);
7798   ed_fieldy = (ed_ysize > max_ed_fieldy ? max_ed_fieldy : ed_ysize);
7799
7800   x = SX + ed_fieldx * ed_tilesize;
7801   y = SY + ed_fieldy * ed_tilesize;
7802
7803   width  = ed_fieldx * ed_tilesize - 2 * ED_SCROLLBUTTON_XSIZE;
7804   height = ed_fieldy * ed_tilesize - 2 * ED_SCROLLBUTTON_YSIZE;
7805
7806   /* adjust drawing area gadget */
7807   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
7808                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
7809                GDI_ITEM_SIZE, ed_tilesize, ed_tilesize,
7810                GDI_END);
7811
7812   /* adjust horizontal scrollbar gadgets */
7813   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LEFT],
7814                GDI_Y, y,
7815                GDI_END);
7816   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT],
7817                GDI_X, x - ED_SCROLLBUTTON_XSIZE,
7818                GDI_Y, y,
7819                GDI_END);
7820   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
7821                GDI_Y, y,
7822                GDI_WIDTH, width,
7823                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
7824                GDI_END);
7825
7826   /* adjust vertical scrollbar gadgets */
7827   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_UP],
7828                GDI_X, x,
7829                GDI_END);
7830   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN],
7831                GDI_X, x,
7832                GDI_Y, y - ED_SCROLLBUTTON_YSIZE,
7833                GDI_END);
7834   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
7835                GDI_X, x,
7836                GDI_HEIGHT, height,
7837                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
7838                GDI_END);
7839 }
7840
7841 static void AdjustLevelScrollPosition()
7842 {
7843   if (level_xpos < -1)
7844     level_xpos = -1;
7845   if (level_xpos > lev_fieldx - ed_fieldx + 1)
7846     level_xpos = lev_fieldx - ed_fieldx + 1;
7847   if (lev_fieldx < ed_fieldx - 2)
7848     level_xpos = -1;
7849
7850   if (level_ypos < -1)
7851     level_ypos = -1;
7852   if (level_ypos > lev_fieldy - ed_fieldy + 1)
7853     level_ypos = lev_fieldy - ed_fieldy + 1;
7854   if (lev_fieldy < ed_fieldy - 2)
7855     level_ypos = -1;
7856 }
7857
7858 static void AdjustEditorScrollbar(int id)
7859 {
7860   struct GadgetInfo *gi = level_editor_gadget[id];
7861   int items_max, items_visible, item_position;
7862
7863   if (id == GADGET_ID_SCROLL_HORIZONTAL)
7864   {
7865     items_max = MAX(lev_fieldx + 2, ed_fieldx);
7866     items_visible = ed_fieldx;
7867     item_position = level_xpos + 1;
7868   }
7869   else
7870   {
7871     items_max = MAX(lev_fieldy + 2, ed_fieldy);
7872     items_visible = ed_fieldy;
7873     item_position = level_ypos + 1;
7874   }
7875
7876   if (item_position > items_max - items_visible)
7877     item_position = items_max - items_visible;
7878
7879   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7880                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7881 }
7882
7883 static void AdjustElementListScrollbar()
7884 {
7885   struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
7886   int items_max, items_visible, item_position;
7887
7888   /* correct position of element list scrollbar */
7889   if (element_shift < 0)
7890     element_shift = 0;
7891   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
7892     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
7893
7894   items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
7895   items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
7896   item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
7897
7898   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
7899                GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
7900                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
7901 }
7902
7903 static void ModifyEditorCounterValue(int counter_id, int new_value)
7904 {
7905   int *counter_value = counterbutton_info[counter_id].value;
7906   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7907   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7908
7909   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
7910
7911   if (counter_value != NULL)
7912     *counter_value = gi->textinput.number_value;
7913 }
7914
7915 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
7916 {
7917   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
7918   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7919
7920   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
7921
7922   if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
7923       counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
7924   {
7925     int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
7926     struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
7927
7928     ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
7929     ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_SMALL_DISTANCE,
7930                  GDI_END);
7931   }
7932 }
7933
7934 static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
7935 {
7936   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7937   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7938   int new_index_value = setSelectboxValue(selectbox_id, new_value);
7939
7940   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
7941 }
7942
7943 static void ModifyEditorSelectboxOptions(int selectbox_id,
7944                                          struct ValueTextInfo *options)
7945 {
7946   int gadget_id = selectbox_info[selectbox_id].gadget_id;
7947   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7948
7949   selectbox_info[selectbox_id].options = options;
7950
7951   /* set index to zero -- list may be shorter now (correct later, if needed) */
7952   ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
7953                GDI_SELECTBOX_OPTIONS, options, GDI_END);
7954 }
7955
7956 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
7957 {
7958   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
7959   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7960
7961   drawingarea_info[drawingarea_id].area_xsize = xsize;
7962   drawingarea_info[drawingarea_id].area_ysize = ysize;
7963
7964   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
7965 }
7966
7967 static void ModifyEditorElementList()
7968 {
7969   int i;
7970
7971   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
7972   {
7973     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
7974     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
7975     struct GadgetDesign *gd = &gi->deco.design;
7976     int element = editor_elements[element_shift + i];
7977     int tile_size = BUTTON_TILE_SIZE(editor.palette.tile_size);
7978
7979     UnmapGadget(gi);
7980
7981     getEditorGraphicSource(element, tile_size, &gd->bitmap, &gd->x, &gd->y);
7982
7983     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
7984
7985     MapGadget(gi);
7986   }
7987 }
7988
7989 static void DrawDrawingElementGraphic(int element, struct XYTileSize *pos)
7990 {
7991   int graphic = el2edimg(element);
7992   int tile_size = BUTTON_TILE_SIZE(pos->tile_size);
7993
7994   if (pos->x == -1 &&
7995       pos->y == -1)
7996     return;
7997
7998   DrawSizedGraphicExt(drawto, DX + pos->x, DY + pos->y, graphic, 0, tile_size);
7999 }
8000
8001 static void ModifyDrawingElementButton(int element, int id)
8002 {
8003   struct GadgetInfo *gi = level_editor_gadget[id];
8004   Bitmap *deco_bitmap;
8005   int deco_x, deco_y;
8006   int tile_size = gi->deco.width;
8007
8008   getEditorGraphicSource(element, tile_size, &deco_bitmap, &deco_x, &deco_y);
8009
8010   ModifyGadget(gi, GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y, GDI_END);
8011 }
8012
8013 static void PickDrawingElement(int button, int element)
8014 {
8015   struct
8016   {
8017     int *new_element;
8018     struct XYTileSize *pos;
8019     int id;
8020   } de, drawing_elements[] =
8021   {
8022     { &new_element1, &editor.palette.element_left,   GADGET_ID_ELEMENT_LEFT   },
8023     { &new_element2, &editor.palette.element_middle, GADGET_ID_ELEMENT_MIDDLE },
8024     { &new_element3, &editor.palette.element_right,  GADGET_ID_ELEMENT_RIGHT  },
8025   };
8026
8027   if (button < 1 || button > 3)
8028     return;
8029
8030   de = drawing_elements[button - 1];
8031
8032   *de.new_element = element;    // update global drawing element variable
8033
8034   DrawDrawingElementGraphic(element, de.pos);
8035   ModifyDrawingElementButton(element, de.id);
8036
8037   redraw_mask |= REDRAW_DOOR_1;
8038 }
8039
8040 static void RedrawDrawingElements()
8041 {
8042   PickDrawingElement(1, new_element1);
8043   PickDrawingElement(2, new_element2);
8044   PickDrawingElement(3, new_element3);
8045 }
8046
8047 static void DrawDrawingWindow()
8048 {
8049   stick_element_properties_window = FALSE;
8050
8051   SetMainBackgroundImage(IMG_UNDEFINED);
8052   ClearField();
8053
8054   UnmapLevelEditorFieldGadgets();
8055   UnmapLevelEditorToolboxCustomGadgets();
8056
8057   AdjustDrawingAreaGadgets();
8058   AdjustLevelScrollPosition();
8059   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
8060   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
8061
8062   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
8063
8064   MapMainDrawingArea();
8065   MapLevelEditorToolboxDrawingGadgets();
8066 }
8067
8068 static int getTabulatorBarWidth()
8069 {
8070   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
8071   struct GadgetInfo *gd_gi4 = level_editor_gadget[GADGET_ID_PROPERTIES_CHANGE];
8072
8073   return gd_gi4->x - gd_gi1->x + gd_gi4->width;
8074 }
8075
8076 static int getTabulatorBarHeight()
8077 {
8078   return ED_TAB_BAR_HEIGHT;
8079 }
8080
8081 static void DrawLevelInfoTabulatorGadgets()
8082 {
8083   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
8084   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
8085   int gd_x = gd->x + gd_gi1->border.width / 2;
8086   int gd_y = gd->y + gd_gi1->height - 1;
8087   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
8088   int id_first = ED_TEXTBUTTON_ID_LEVELINFO_LEVEL;
8089   int id_last  = ED_TEXTBUTTON_ID_LEVELINFO_EDITOR;
8090   int i;
8091
8092   for (i = id_first; i <= id_last; i++)
8093   {
8094     int gadget_id = textbutton_info[i].gadget_id;
8095     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
8096     boolean active = (i != edit_mode_levelinfo);
8097
8098     /* draw background line below tabulator button */
8099     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
8100
8101     /* draw solid line below inactive tabulator buttons */
8102     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
8103       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
8104                     ED_GADGET_TINY_DISTANCE, tab_color);
8105
8106     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
8107     MapTextbuttonGadget(i);
8108   }
8109
8110   /* draw little border line below tabulator buttons */
8111   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
8112     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
8113                   ED_GADGET_TINY_DISTANCE,
8114                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
8115 }
8116
8117 static void DrawPropertiesTabulatorGadgets()
8118 {
8119   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
8120   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
8121   int gd_x = gd->x + gd_gi1->border.width / 2;
8122   int gd_y = gd->y + gd_gi1->height - 1;
8123   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
8124   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
8125   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
8126   int i;
8127
8128   /* draw two config tabulators for player elements */
8129   if (ELEM_IS_PLAYER(properties_element))
8130     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
8131
8132   /* draw two config and one "change" tabulator for custom elements */
8133   if (IS_CUSTOM_ELEMENT(properties_element))
8134     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
8135
8136   for (i = id_first; i <= id_last; i++)
8137   {
8138     int gadget_id = textbutton_info[i].gadget_id;
8139     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
8140     boolean active = (i != edit_mode_properties);
8141
8142     /* use "config 1" and "config 2" instead of "config" for players and CEs */
8143     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
8144         (ELEM_IS_PLAYER(properties_element) ||
8145          IS_CUSTOM_ELEMENT(properties_element)))
8146       continue;
8147
8148     /* draw background line below tabulator button */
8149     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
8150
8151     /* draw solid line below inactive tabulator buttons */
8152     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
8153       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
8154                     ED_GADGET_TINY_DISTANCE, tab_color);
8155
8156     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
8157     MapTextbuttonGadget(i);
8158   }
8159
8160   /* draw little border line below tabulator buttons */
8161   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
8162     FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
8163                   ED_GADGET_TINY_DISTANCE,
8164                   getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
8165 }
8166
8167 static void DrawLevelInfoLevel()
8168 {
8169   int i;
8170
8171   /* draw counter gadgets */
8172   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
8173     MapCounterButtons(i);
8174
8175   /* draw selectbox gadgets */
8176   for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
8177     MapSelectboxGadget(i);
8178
8179   /* draw text input gadgets */
8180   for (i = ED_TEXTINPUT_ID_LEVEL_FIRST; i <= ED_TEXTINPUT_ID_LEVEL_LAST; i++)
8181     MapTextInputGadget(i);
8182 }
8183
8184 static void DrawLevelInfoEditor()
8185 {
8186   int i;
8187
8188   /* draw counter gadgets */
8189   for (i = ED_COUNTER_ID_EDITOR_FIRST; i <= ED_COUNTER_ID_EDITOR_LAST; i++)
8190     MapCounterButtons(i);
8191
8192   /* draw checkbutton gadgets */
8193   for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
8194     MapCheckbuttonGadget(i);
8195
8196   /* draw radiobutton gadgets */
8197   for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
8198     MapRadiobuttonGadget(i);
8199
8200   /* draw drawing area */
8201   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
8202 }
8203
8204 static void DrawLevelInfoWindow()
8205 {
8206   char *text = "Global Settings";
8207   int font_nr = FONT_TITLE_1;
8208   struct MenuPosInfo *pos = &editor.settings.headline;
8209   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font_nr), pos->align);
8210   int sy = SY + pos->y;
8211
8212   stick_element_properties_window = FALSE;
8213
8214   UnmapLevelEditorFieldGadgets();
8215
8216   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
8217   ClearField();
8218
8219   DrawText(sx, sy, text, font_nr);
8220
8221   DrawLevelInfoTabulatorGadgets();
8222
8223   if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL)
8224     DrawLevelInfoLevel();
8225   else  /* (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR) */
8226     DrawLevelInfoEditor();
8227 }
8228
8229 static void DrawCustomContentArea()
8230 {
8231   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
8232   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8233   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
8234   int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
8235   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
8236   int xoffset = ED_GADGET_SPACE_DISTANCE;
8237
8238   /* add distance for potential left text (without drawing area border) */
8239   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
8240
8241   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
8242
8243   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
8244 }
8245
8246 static void DrawCustomChangeContentArea()
8247 {
8248   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
8249   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
8250   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
8251   int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
8252   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
8253   int xoffset = ED_GADGET_SPACE_DISTANCE;
8254
8255   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
8256
8257   MapDrawingArea(id);
8258 }
8259
8260 static void RemoveElementContentArea(int id, int font_height)
8261 {
8262   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8263
8264   DrawBackground(SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size,
8265                  SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size,
8266                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8267                  3 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size +
8268                  ED_GADGET_TEXT_DISTANCE + font_height);
8269 }
8270
8271 static void DrawYamYamContentAreas()
8272 {
8273   int font_nr = FONT_TEXT_1;
8274   int font_height = getFontHeight(font_nr);
8275   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
8276   int yoffset = (tilesize - font_height) / 2;
8277   int x = SX + ED_AREA_YAMYAM_CONTENT_X(3) + 4 * tilesize;
8278   int y = SY + ED_AREA_YAMYAM_CONTENT_Y(3) + yoffset;
8279   int i;
8280
8281   /* display counter to choose number of element content areas */
8282   MapCounterButtons(ED_COUNTER_ID_YAMYAM_CONTENT);
8283
8284   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
8285   {
8286     int id = ED_DRAWING_ID_YAMYAM_CONTENT_0 + i;
8287
8288     if (i < level.num_yamyam_contents)
8289     {
8290       MapDrawingArea(id);
8291     }
8292     else
8293     {
8294       UnmapDrawingArea(id);
8295
8296       /* delete content areas in case of reducing number of them */
8297       RemoveElementContentArea(id, font_height);
8298     }
8299   }
8300
8301   DrawText(x, y + 0 * tilesize, "content", font_nr);
8302   DrawText(x, y + 1 * tilesize, "when",    font_nr);
8303   DrawText(x, y + 2 * tilesize, "smashed", font_nr);
8304 }
8305
8306 static void DrawMagicBallContentAreas()
8307 {
8308   int font_nr = FONT_TEXT_1;
8309   int font_height = getFontHeight(font_nr);
8310   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
8311   int yoffset = (tilesize - font_height) / 2;
8312   int x = SX + ED_AREA_MAGIC_BALL_CONTENT_X(3) + 4 * tilesize;
8313   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_Y(3) + yoffset;
8314   int i;
8315
8316   /* display counter to choose number of element content areas */
8317   MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
8318
8319   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
8320   {
8321     int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
8322
8323     if (i < level.num_ball_contents)
8324     {
8325       MapDrawingArea(id);
8326     }
8327     else
8328     {
8329       UnmapDrawingArea(id);
8330
8331       /* delete content areas in case of reducing number of them */
8332       RemoveElementContentArea(id, font_height);
8333     }
8334   }
8335
8336   DrawText(x, y + 0 * tilesize, "generated", font_nr);
8337   DrawText(x, y + 1 * tilesize, "when",      font_nr);
8338   DrawText(x, y + 2 * tilesize, "active",    font_nr);
8339 }
8340
8341 static void DrawAndroidElementArea(int element)
8342 {
8343   int id = ED_DRAWING_ID_ANDROID_CONTENT;
8344   int num_elements = level.num_android_clone_elements;
8345   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8346   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8347   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8348   int xsize = MAX_ANDROID_ELEMENTS;
8349   int ysize = 1;
8350
8351   /* display counter to choose number of element areas */
8352   MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
8353
8354   if (drawingarea_info[id].text_left != NULL)
8355     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8356
8357   UnmapDrawingArea(id);
8358
8359   ModifyEditorDrawingArea(id, num_elements, 1);
8360
8361   /* delete content areas in case of reducing number of them */
8362   DrawBackground(sx, sy,
8363                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8364                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8365
8366   MapDrawingArea(id);
8367 }
8368
8369 static void DrawGroupElementArea(int element)
8370 {
8371   int id = ED_DRAWING_ID_GROUP_CONTENT;
8372   int num_elements = group_element_info.num_elements;
8373   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8374   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8375   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8376   int xsize = MAX_ELEMENTS_IN_GROUP;
8377   int ysize = 1;
8378
8379   if (drawingarea_info[id].text_left != NULL)
8380     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8381
8382   UnmapDrawingArea(id);
8383
8384   ModifyEditorDrawingArea(id, num_elements, 1);
8385
8386   /* delete content areas in case of reducing number of them */
8387   DrawBackground(sx, sy,
8388                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8389                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8390
8391   MapDrawingArea(id);
8392 }
8393
8394 static void DrawPlayerInitialInventoryArea(int element)
8395 {
8396   int id = ED_DRAWING_ID_INVENTORY_CONTENT;
8397   int player_nr = GET_PLAYER_NR(element);
8398   int num_elements = level.initial_inventory_size[player_nr];
8399   int border_size = ED_DRAWINGAREA_BORDER_SIZE;
8400   int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
8401   int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
8402   int xsize = MAX_INITIAL_INVENTORY_SIZE;
8403   int ysize = 1;
8404
8405   /* determine horizontal position to the right of specified gadget */
8406   if (drawingarea_info[id].gadget_id_align != GADGET_ID_NONE)
8407     sx = (right_gadget_border[drawingarea_info[id].gadget_id_align] +
8408           ED_DRAWINGAREA_TEXT_DISTANCE);
8409
8410   /* determine horizontal offset for leading text */
8411   if (drawingarea_info[id].text_left != NULL)
8412     sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
8413
8414   UnmapDrawingArea(id);
8415
8416   ModifyEditorDrawingArea(id, num_elements, 1);
8417
8418   /* delete content areas in case of reducing number of them */
8419   DrawBackground(sx, sy,
8420                  xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
8421                  ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
8422
8423   MapDrawingArea(id);
8424 }
8425
8426 static void DrawEnvelopeTextArea(int envelope_nr)
8427 {
8428   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
8429   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
8430
8431   UnmapGadget(gi);
8432   DrawBackground(gi->x, gi->y, gi->width, gi->height);
8433
8434   if (envelope_nr != -1)
8435     textarea_info[id].value = level.envelope[envelope_nr].text;
8436
8437   ModifyGadget(gi, GDI_AREA_SIZE,
8438                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
8439                *counterbutton_info[ED_COUNTER_ID_ENVELOPE_YSIZE].value,
8440                GDI_END);
8441
8442   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
8443 }
8444
8445 static boolean PrintInfoText(char *text, int font_nr, int start_line)
8446 {
8447   int font_height = getFontHeight(font_nr);
8448   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8449   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8450   int sx = SX + pad_x;
8451   int sy = SY + pad_y;
8452   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
8453
8454   if (start_line >= max_lines_per_screen)
8455     return FALSE;
8456
8457   DrawText(sx, sy + start_line * font_height, text, font_nr);
8458
8459   return TRUE;
8460 }
8461
8462 static int PrintElementDescriptionFromFile(char *filename, int start_line)
8463 {
8464   int font_nr = FONT_TEXT_2;
8465   int font_width = getFontWidth(font_nr);
8466   int font_height = getFontHeight(font_nr);
8467   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8468   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8469   int sx = SX + pad_x;
8470   int sy = SY + pad_y + start_line * font_height;
8471   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
8472   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
8473   int max_lines_drawable = max_lines_per_screen - start_line;
8474
8475   if (start_line >= max_lines_per_screen)
8476     return FALSE;
8477
8478   return DrawTextFile(sx, sy, filename, font_nr, max_chars_per_line, -1,
8479                       max_lines_drawable, 0, -1, TRUE, FALSE, FALSE);
8480 }
8481
8482 static void DrawPropertiesInfo()
8483 {
8484   static struct
8485   {
8486     int value;
8487     char *text;
8488   }
8489   properties[] =
8490   {
8491     /* configurable properties */
8492
8493     { EP_WALKABLE_OVER,         "- player can walk over it"             },
8494     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
8495     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
8496     { EP_PASSABLE_OVER,         "- player can pass over it"             },
8497     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
8498     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
8499     { EP_PROTECTED,             "- player is protected by it"           },
8500
8501     { EP_DIGGABLE,              "- can be digged away"                  },
8502     { EP_COLLECTIBLE,           "- can be collected"                    },
8503     { EP_DROPPABLE,             "- can be dropped after collecting"     },
8504     { EP_THROWABLE,             "- can be thrown after collecting"      },
8505     { EP_PUSHABLE,              "- can be pushed"                       },
8506
8507     { EP_CAN_FALL,              "- can fall"                            },
8508     { EP_CAN_MOVE,              "- can move"                            },
8509
8510     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
8511 #if 0
8512     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
8513 #endif
8514     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
8515
8516     { EP_SLIPPERY,              "- slippery for falling elements"       },
8517     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
8518
8519     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
8520     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
8521     { EP_DONT_GET_HIT_BY,       "- deadly when getting hit by"          },
8522     { EP_DONT_TOUCH,            "- deadly when touching"                },
8523
8524     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
8525
8526     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
8527     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
8528     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
8529
8530     { EP_CAN_CHANGE,            "- can change to other element"         },
8531
8532     /* pre-defined properties */
8533     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
8534     { EP_CAN_PASS_DC_MAGIC_WALL,"- can pass magic walls (DC style)"     },
8535     { EP_SWITCHABLE,            "- can be switched"                     },
8536 #if 0
8537     { EP_HAS_EDITOR_CONTENT,    "- can contain other elements"          },
8538 #endif
8539
8540     { -1,                       NULL                                    }
8541   };
8542   char *filename = getElementDescriptionFilename(properties_element);
8543   char *percentage_text = "In this level: ";
8544   char *properties_text = "Standard properties: ";
8545   float percentage;
8546   int num_elements_in_level;
8547   int num_standard_properties = 0;
8548   int font1_nr = FONT_TEXT_1;
8549   int font2_nr = FONT_TEXT_2;
8550   int font1_width = getFontWidth(font1_nr);
8551   int font2_height = getFontHeight(font2_nr);
8552   int pad_x = ED_ELEMENT_SETTINGS_X(0);
8553   int pad_y = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
8554   int screen_line = 0;
8555   int i, x, y;
8556
8557   if (setup.editor.show_element_token)
8558   {
8559     DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
8560               "[%s]", element_info[properties_element].token_name);
8561     screen_line++;
8562   }
8563
8564   /* ----- print number of elements / percentage of this element in level */
8565
8566   num_elements_in_level = 0;
8567   for (y = 0; y < lev_fieldy; y++) 
8568     for (x = 0; x < lev_fieldx; x++)
8569       if (Feld[x][y] == properties_element)
8570         num_elements_in_level++;
8571   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
8572
8573   DrawTextS(pad_x, pad_y + screen_line * font2_height, font1_nr,
8574             percentage_text);
8575   DrawTextF(pad_x + strlen(percentage_text) * font1_width,
8576             pad_y + screen_line++ * font2_height, font2_nr,
8577             "%d (%.2f%%)", num_elements_in_level, percentage);
8578
8579   screen_line++;
8580
8581   /* ----- print standard properties of this element */
8582
8583   DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
8584             properties_text);
8585
8586   for (i = 0; properties[i].value != -1; i++)
8587   {
8588     if (!HAS_PROPERTY(properties_element, properties[i].value))
8589       continue;
8590
8591     DrawTextS(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
8592               properties[i].text);
8593     num_standard_properties++;
8594   }
8595
8596   if (num_standard_properties == 0)
8597     DrawTextS(pad_x + strlen(properties_text) * font1_width,
8598               pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
8599
8600   screen_line++;
8601
8602   /* ----- print special description of this element */
8603
8604   PrintInfoText("Description:", FONT_TEXT_1, screen_line);
8605   if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
8606     PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
8607 }
8608
8609 #define TEXT_COLLECTING         "Score for collecting"
8610 #define TEXT_SMASHING           "Score for smashing"
8611 #define TEXT_SLURPING           "Score for slurping robot"
8612 #define TEXT_CRACKING           "Score for cracking"
8613 #define TEXT_AMOEBA_SPEED       "Speed of amoeba growth"
8614 #define TEXT_DURATION           "Duration when activated"
8615 #define TEXT_BALL_DELAY         "Element generation delay"
8616 #define TEXT_MOVE_SPEED         "Speed of android moving"
8617 #define TEXT_CLONE_SPEED        "Speed of android cloning"
8618 #define TEXT_GAME_OF_LIFE_1     "Min neighbours to survive"
8619 #define TEXT_GAME_OF_LIFE_2     "Max neighbours to survive"
8620 #define TEXT_GAME_OF_LIFE_3     "Min neighbours to create"
8621 #define TEXT_GAME_OF_LIFE_4     "Max neighbours to create"
8622 #define TEXT_TIME_BONUS         "Extra time to solve level"
8623
8624 static struct
8625 {
8626   int element;
8627   int *value;
8628   char *text;
8629 } elements_with_counter[] =
8630 {
8631   { EL_EMERALD,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
8632   { EL_BD_DIAMOND,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
8633   { EL_EMERALD_YELLOW,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8634   { EL_EMERALD_RED,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8635   { EL_EMERALD_PURPLE,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
8636   { EL_SP_INFOTRON,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
8637   { EL_DIAMOND,         &level.score[SC_DIAMOND],       TEXT_COLLECTING },
8638   { EL_CRYSTAL,         &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
8639   { EL_PEARL,           &level.score[SC_PEARL],         TEXT_COLLECTING },
8640   { EL_BUG,             &level.score[SC_BUG],           TEXT_SMASHING   },
8641   { EL_BUG_RIGHT,       &level.score[SC_BUG],           TEXT_SMASHING   },
8642   { EL_BUG_UP,          &level.score[SC_BUG],           TEXT_SMASHING   },
8643   { EL_BUG_LEFT,        &level.score[SC_BUG],           TEXT_SMASHING   },
8644   { EL_BUG_DOWN,        &level.score[SC_BUG],           TEXT_SMASHING   },
8645   { EL_BD_BUTTERFLY,    &level.score[SC_BUG],           TEXT_SMASHING   },
8646   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],         TEXT_SMASHING   },
8647   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],         TEXT_SMASHING   },
8648   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],         TEXT_SMASHING   },
8649   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],         TEXT_SMASHING   },
8650   { EL_SP_ELECTRON,     &level.score[SC_BUG],           TEXT_SMASHING   },
8651   { EL_SPACESHIP,       &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8652   { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8653   { EL_SPACESHIP_UP,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8654   { EL_SPACESHIP_LEFT,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8655   { EL_SPACESHIP_DOWN,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8656   { EL_BD_FIREFLY,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8657   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8658   { EL_BD_FIREFLY_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8659   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8660   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8661   { EL_SP_SNIKSNAK,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
8662   { EL_YAMYAM,          &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8663   { EL_YAMYAM_LEFT,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8664   { EL_YAMYAM_RIGHT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8665   { EL_YAMYAM_UP,       &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8666   { EL_YAMYAM_DOWN,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8667   { EL_DARK_YAMYAM,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
8668   { EL_ROBOT,           &level.score[SC_ROBOT],         TEXT_SMASHING   },
8669   { EL_PACMAN,          &level.score[SC_PACMAN],        TEXT_SMASHING   },
8670   { EL_PACMAN_RIGHT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
8671   { EL_PACMAN_UP,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
8672   { EL_PACMAN_LEFT,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8673   { EL_PACMAN_DOWN,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
8674   { EL_NUT,             &level.score[SC_NUT],           TEXT_CRACKING   },
8675   { EL_DYNAMITE,        &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8676   { EL_EM_DYNAMITE,     &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
8677   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
8678   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8679   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
8680   { EL_SHIELD_NORMAL,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8681   { EL_SHIELD_DEADLY,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
8682   { EL_EXTRA_TIME,      &level.extra_time_score,        TEXT_COLLECTING },
8683   { EL_KEY_1,           &level.score[SC_KEY],           TEXT_COLLECTING },
8684   { EL_KEY_2,           &level.score[SC_KEY],           TEXT_COLLECTING },
8685   { EL_KEY_3,           &level.score[SC_KEY],           TEXT_COLLECTING },
8686   { EL_KEY_4,           &level.score[SC_KEY],           TEXT_COLLECTING },
8687   { EL_EM_KEY_1,        &level.score[SC_KEY],           TEXT_COLLECTING },
8688   { EL_EM_KEY_2,        &level.score[SC_KEY],           TEXT_COLLECTING },
8689   { EL_EM_KEY_3,        &level.score[SC_KEY],           TEXT_COLLECTING },
8690   { EL_EM_KEY_4,        &level.score[SC_KEY],           TEXT_COLLECTING },
8691   { EL_EMC_KEY_5,       &level.score[SC_KEY],           TEXT_COLLECTING },
8692   { EL_EMC_KEY_6,       &level.score[SC_KEY],           TEXT_COLLECTING },
8693   { EL_EMC_KEY_7,       &level.score[SC_KEY],           TEXT_COLLECTING },
8694   { EL_EMC_KEY_8,       &level.score[SC_KEY],           TEXT_COLLECTING },
8695   { EL_DC_KEY_WHITE,    &level.score[SC_KEY],           TEXT_COLLECTING },
8696   { EL_AMOEBA_WET,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8697   { EL_AMOEBA_DRY,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8698   { EL_AMOEBA_FULL,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8699   { EL_BD_AMOEBA,       &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8700   { EL_EMC_DRIPPER,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
8701   { EL_MAGIC_WALL,      &level.time_magic_wall,         TEXT_DURATION   },
8702   { EL_BD_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8703   { EL_DC_MAGIC_WALL,   &level.time_magic_wall,         TEXT_DURATION   },
8704   { EL_ROBOT_WHEEL,     &level.time_wheel,              TEXT_DURATION   },
8705
8706   { EL_TIMEGATE_SWITCH,   &level.time_timegate,         TEXT_DURATION   },
8707   { EL_DC_TIMEGATE_SWITCH,&level.time_timegate,         TEXT_DURATION   },
8708   { EL_LIGHT_SWITCH,    &level.time_light,              TEXT_DURATION   },
8709   { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,          TEXT_DURATION   },
8710   { EL_SHIELD_NORMAL,   &level.shield_normal_time,      TEXT_DURATION   },
8711   { EL_SHIELD_DEADLY,   &level.shield_deadly_time,      TEXT_DURATION   },
8712   { EL_EXTRA_TIME,      &level.extra_time,              TEXT_TIME_BONUS },
8713   { EL_TIME_ORB_FULL,   &level.time_orb_time,           TEXT_TIME_BONUS },
8714   { EL_GAME_OF_LIFE,    &level.game_of_life[0],         TEXT_GAME_OF_LIFE_1 },
8715   { EL_GAME_OF_LIFE,    &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
8716   { EL_GAME_OF_LIFE,    &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
8717   { EL_GAME_OF_LIFE,    &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
8718   { EL_BIOMAZE,         &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
8719   { EL_BIOMAZE,         &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
8720   { EL_BIOMAZE,         &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
8721   { EL_BIOMAZE,         &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
8722
8723   { EL_EMC_ANDROID,     &level.android_move_time,       TEXT_MOVE_SPEED },
8724   { EL_EMC_ANDROID,     &level.android_clone_time,      TEXT_CLONE_SPEED },
8725   { EL_EMC_MAGIC_BALL,  &level.ball_time,               TEXT_BALL_DELAY },
8726   { EL_EMC_LENSES,      &level.lenses_score,            TEXT_COLLECTING },
8727   { EL_EMC_MAGNIFIER,   &level.magnify_score,           TEXT_COLLECTING },
8728   { EL_SPRING,          &level.slurp_score,             TEXT_SLURPING   },
8729   { EL_EMC_LENSES,      &level.lenses_time,             TEXT_DURATION   },
8730   { EL_EMC_MAGNIFIER,   &level.magnify_time,            TEXT_DURATION   },
8731
8732   { -1,                 NULL,                           NULL            }
8733 };
8734
8735 static boolean checkPropertiesConfig(int element)
8736 {
8737   int i;
8738
8739   if (IS_GEM(element) ||
8740       IS_CUSTOM_ELEMENT(element) ||
8741       IS_GROUP_ELEMENT(element) ||
8742       IS_ENVELOPE(element) ||
8743       ELEM_IS_PLAYER(element) ||
8744       HAS_EDITOR_CONTENT(element) ||
8745       CAN_GROW(element) ||
8746       COULD_MOVE_INTO_ACID(element) ||
8747       MAYBE_DONT_COLLIDE_WITH(element) ||
8748       element == EL_SOKOBAN_OBJECT ||
8749       element == EL_SOKOBAN_FIELD_EMPTY ||
8750       element == EL_SOKOBAN_FIELD_FULL)
8751     return TRUE;
8752   else
8753     for (i = 0; elements_with_counter[i].element != -1; i++)
8754       if (elements_with_counter[i].element == element)
8755         return TRUE;
8756
8757   return FALSE;
8758 }
8759
8760 static void DrawPropertiesConfig()
8761 {
8762   boolean draw_footer_line = FALSE;
8763   int max_num_element_counters = 4;
8764   int num_element_counters = 0;
8765   int i;
8766
8767   if (!checkPropertiesConfig(properties_element))
8768   {
8769     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
8770
8771     return;
8772   }
8773
8774   /* check if there are elements where a value can be chosen for */
8775   for (i = 0; elements_with_counter[i].element != -1; i++)
8776   {
8777     if (elements_with_counter[i].element == properties_element)
8778     {
8779       int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
8780
8781       counterbutton_info[counter_id].y =
8782         ED_ELEMENT_SETTINGS_YPOS(
8783                 (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
8784                 (CAN_GROW(properties_element)                ? 1 : 0) +
8785                 (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
8786                 (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
8787                 (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
8788                 num_element_counters);
8789
8790       counterbutton_info[counter_id].value = elements_with_counter[i].value;
8791       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
8792
8793       if (properties_element == EL_GAME_OF_LIFE ||
8794           properties_element == EL_BIOMAZE)
8795       {
8796         counterbutton_info[counter_id].min_value = 0;   /* min neighbours */
8797         counterbutton_info[counter_id].max_value = 8;   /* max neighbours */
8798       }
8799       else
8800       {
8801         /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */
8802         counterbutton_info[counter_id].min_value = MIN_SCORE;
8803         counterbutton_info[counter_id].max_value = MAX_SCORE;
8804       }
8805
8806       MapCounterButtons(counter_id);
8807
8808       num_element_counters++;
8809       if (num_element_counters >= max_num_element_counters)
8810         break;
8811     }
8812   }
8813
8814   if (HAS_EDITOR_CONTENT(properties_element))
8815   {
8816     /* draw stickybutton gadget */
8817     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8818
8819     if (IS_AMOEBOID(properties_element))
8820       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
8821     else if (properties_element == EL_YAMYAM ||
8822              properties_element == EL_YAMYAM_LEFT ||
8823              properties_element == EL_YAMYAM_RIGHT ||
8824              properties_element == EL_YAMYAM_UP ||
8825              properties_element == EL_YAMYAM_DOWN)
8826       DrawYamYamContentAreas();
8827     else if (properties_element == EL_EMC_MAGIC_BALL)
8828     {
8829       DrawMagicBallContentAreas();
8830
8831       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
8832       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE);
8833     }
8834     else if (properties_element == EL_EMC_ANDROID)
8835       DrawAndroidElementArea(properties_element);
8836   }
8837
8838   if (ELEM_IS_PLAYER(properties_element))
8839   {
8840     int player_nr = GET_PLAYER_NR(properties_element);
8841
8842     /* these properties can be set for every player individually */
8843
8844     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8845     {
8846       drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
8847         &level.start_element[player_nr];
8848       drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
8849         &level.artwork_element[player_nr];
8850       drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
8851         &level.explosion_element[player_nr];
8852
8853       checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
8854         &level.use_start_element[player_nr];
8855       checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
8856         &level.use_artwork_element[player_nr];
8857       checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
8858         &level.use_explosion_element[player_nr];
8859       checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
8860         &level.initial_player_gravity[player_nr];
8861
8862       selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
8863         &level.initial_player_stepsize[player_nr];
8864
8865       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
8866       MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
8867                            ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
8868                            ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
8869       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
8870       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
8871       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
8872       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SHIFTED_RELOCATION);
8873       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_LAZY_RELOCATION);
8874       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
8875       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
8876       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
8877       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
8878       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
8879
8880       MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
8881       MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
8882       MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
8883
8884       MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
8885     }
8886     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
8887     {
8888       drawingarea_info[ED_DRAWING_ID_INVENTORY_CONTENT].value =
8889         &level.initial_inventory_content[player_nr][0];
8890
8891       counterbutton_info[ED_COUNTER_ID_INVENTORY_SIZE].value =
8892         &level.initial_inventory_size[player_nr];
8893
8894       checkbutton_info[ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY].value =
8895         &level.use_initial_inventory[player_nr];
8896
8897       /* draw checkbutton gadgets */
8898       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
8899
8900       /* draw counter gadgets */
8901       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
8902
8903       /* draw drawing area gadgets */
8904       DrawPlayerInitialInventoryArea(properties_element);
8905     }
8906   }
8907
8908   if (IS_GEM(properties_element))
8909     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
8910
8911   if (properties_element == EL_EM_DYNAMITE)
8912     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
8913
8914   if (COULD_MOVE_INTO_ACID(properties_element) &&
8915       !ELEM_IS_PLAYER(properties_element) &&
8916       (!IS_CUSTOM_ELEMENT(properties_element) ||
8917        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
8918   {
8919     /* set position for checkbutton for "can move into acid" */
8920     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
8921       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
8922     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
8923       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
8924                        HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8925
8926     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
8927   }
8928
8929   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
8930     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
8931
8932   if (properties_element == EL_SPRING)
8933     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
8934
8935   if (properties_element == EL_TIME_ORB_FULL)
8936     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
8937
8938   if (CAN_GROW(properties_element))
8939   {
8940     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
8941       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
8942
8943     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
8944   }
8945
8946   if (properties_element == EL_SOKOBAN_OBJECT ||
8947       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
8948       properties_element == EL_SOKOBAN_FIELD_FULL)
8949     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
8950
8951   if (IS_ENVELOPE(properties_element))
8952   {
8953     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
8954     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
8955     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
8956     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
8957     int envelope_nr = properties_element - EL_ENVELOPE_1;
8958
8959     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
8960     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
8961
8962     checkbutton_info[button1_id].value = &level.envelope[envelope_nr].autowrap;
8963     checkbutton_info[button2_id].value = &level.envelope[envelope_nr].centered;
8964
8965     /* display counter to choose size of envelope text area */
8966     MapCounterButtons(counter1_id);
8967     MapCounterButtons(counter2_id);
8968
8969     /* display checkbuttons to choose auto-wrap and alignment properties */
8970     MapCheckbuttonGadget(button1_id);
8971     MapCheckbuttonGadget(button2_id);
8972
8973     DrawEnvelopeTextArea(envelope_nr);
8974   }
8975
8976   if (IS_CUSTOM_ELEMENT(properties_element))
8977   {
8978     /* draw stickybutton gadget */
8979     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
8980
8981     if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
8982     {
8983       /* draw checkbutton gadgets */
8984       for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
8985            i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
8986         MapCheckbuttonGadget(i);
8987
8988       /* draw counter gadgets */
8989       for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
8990            i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
8991         MapCounterButtons(i);
8992
8993       /* draw selectbox gadgets */
8994       for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
8995            i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
8996         MapSelectboxGadget(i);
8997
8998       /* draw textbutton gadgets */
8999       MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
9000
9001       /* draw text input gadgets */
9002       MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
9003
9004       /* draw drawing area gadgets */
9005       MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
9006
9007       draw_footer_line = TRUE;
9008     }
9009     else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
9010     {
9011       /* draw checkbutton gadgets */
9012       for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
9013            i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
9014         MapCheckbuttonGadget(i);
9015
9016       /* draw counter gadgets */
9017       for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
9018            i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
9019         MapCounterButtons(i);
9020
9021       /* draw selectbox gadgets */
9022       for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
9023            i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
9024         MapSelectboxGadget(i);
9025
9026       /* draw drawing area gadgets */
9027       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
9028       MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
9029       DrawCustomContentArea();
9030     }
9031   }
9032   else if (IS_GROUP_ELEMENT(properties_element))
9033   {
9034     /* draw stickybutton gadget */
9035     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
9036
9037     /* draw checkbutton gadgets */
9038     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
9039     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE);
9040
9041     /* draw counter gadgets */
9042     MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
9043
9044     /* draw selectbox gadgets */
9045     MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
9046
9047     /* draw textbutton gadgets */
9048     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
9049
9050     /* draw drawing area gadgets */
9051     DrawGroupElementArea(properties_element);
9052
9053     /* draw text input gadgets */
9054     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
9055
9056     /* draw drawing area gadgets */
9057     MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
9058
9059     draw_footer_line = TRUE;
9060   }
9061
9062   /* draw little footer border line above CE/GE use/save template gadgets */
9063   if (draw_footer_line)
9064   {
9065     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
9066     struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
9067     int gd_x = gd->x + gd_gi1->border.width / 2;
9068     int gd_y = gd->y + gd_gi1->height - 1;
9069     Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
9070
9071     if (tab_color != BLACK_PIXEL)               /* black => transparent */
9072       FillRectangle(drawto,
9073                     SX + ED_ELEMENT_SETTINGS_X(0),
9074                     SY + ED_ELEMENT_SETTINGS_Y(14) - ED_SETTINGS_TABS_YOFFSET -
9075                     ED_TAB_BAR_HEIGHT,
9076                     getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
9077   }
9078 }
9079
9080 static void DrawPropertiesChangeDrawingAreas()
9081 {
9082   if (IS_CUSTOM_ELEMENT(properties_element))
9083   {
9084     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
9085     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
9086     MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_ACTION);
9087
9088     DrawCustomChangeContentArea();
9089   }
9090
9091   redraw_mask |= REDRAW_FIELD;
9092 }
9093
9094 static void DrawPropertiesChange()
9095 {
9096   int i;
9097
9098   /* needed to initially set selectbox options for special action options */
9099   setSelectboxSpecialActionOptions();
9100
9101   /* draw stickybutton gadget */
9102   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
9103
9104   /* draw checkbutton gadgets */
9105   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
9106        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
9107     MapCheckbuttonGadget(i);
9108
9109   /* draw counter gadgets */
9110   for (i =  ED_COUNTER_ID_CHANGE_FIRST;
9111        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
9112     MapCounterButtons(i);
9113
9114   /* draw selectbox gadgets */
9115   for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
9116        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
9117     MapSelectboxGadget(i);
9118
9119   /* draw textbutton gadgets */
9120   for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
9121        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
9122     MapTextbuttonGadget(i);
9123
9124   /* draw graphicbutton gadgets */
9125   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
9126        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
9127     MapGraphicbuttonGadget(i);
9128
9129   /* draw drawing area gadgets */
9130   DrawPropertiesChangeDrawingAreas();
9131 }
9132
9133 static void DrawEditorElementAnimation(int x, int y)
9134 {
9135   int graphic = el2img(properties_element);
9136   int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
9137                custom_element.ce_value_fixed_initial :
9138                ANIM_MODE(graphic) == ANIM_CE_SCORE ?
9139                custom_element.collect_score_initial : FrameCounter);
9140
9141   DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
9142 }
9143
9144 static void DrawEditorElementName(int x, int y, int font_nr)
9145 {
9146   char *element_name = getElementInfoText(properties_element);
9147   int font_width = getFontWidth(font_nr);
9148   int font_height = getFontHeight(font_nr);
9149   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
9150   int max_chars_per_line = max_text_width / font_width;
9151   char buffer[max_chars_per_line + 1];
9152
9153   if (strlen(element_name) <= max_chars_per_line)
9154     DrawTextS(x, y, font_nr, element_name);
9155   else
9156   {
9157     int next_pos = max_chars_per_line;
9158
9159     strncpy(buffer, element_name, max_chars_per_line);
9160     buffer[max_chars_per_line] = '\0';
9161
9162     if (element_name[max_chars_per_line] == ' ')
9163       next_pos++;
9164     else
9165     {
9166       int i;
9167
9168       for (i = max_chars_per_line - 1; i >= 0; i--)
9169         if (buffer[i] == ' ')
9170           break;
9171
9172       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
9173       {
9174         buffer[i] = '\0';
9175         next_pos = i + 1;
9176       }
9177     }
9178
9179     DrawTextS(x, y - font_height / 2, font_nr, buffer);
9180
9181     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
9182     buffer[max_chars_per_line] = '\0';
9183
9184     DrawTextS(x, y + font_height / 2, font_nr, buffer);
9185   }
9186 }
9187
9188 static void DrawPropertiesWindow()
9189 {
9190   struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_INPUT_TEXT];
9191   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
9192   int border_size = gd->border_size;
9193   int font_nr = FONT_TEXT_1;
9194   int font_height = getFontHeight(font_nr);
9195   int xoffset = TILEX + element_border + 3 * border_size;
9196   int yoffset = (TILEY - font_height) / 2;
9197   int x1 = editor.settings.element_graphic.x + element_border;
9198   int y1 = editor.settings.element_graphic.y + element_border;
9199   int x2 = (editor.settings.element_name.x == -1 ? x1 + xoffset :
9200             editor.settings.element_name.x);
9201   int y2 = (editor.settings.element_name.y == -1 ? y1 + yoffset :
9202             editor.settings.element_name.y);
9203   char *text = "Element Settings";
9204   int font2_nr = FONT_TITLE_1;
9205   struct MenuPosInfo *pos = &editor.settings.headline;
9206   int sx = SX + ALIGNED_XPOS(pos->x, getTextWidth(text, font2_nr), pos->align);
9207   int sy = SY + pos->y;
9208
9209   stick_element_properties_window = FALSE;
9210
9211   /* make sure that previous properties edit mode exists for this element */
9212   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG_2 &&
9213       !IS_CUSTOM_ELEMENT(properties_element))
9214     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
9215
9216   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
9217       !ELEM_IS_PLAYER(properties_element) &&
9218       !IS_CUSTOM_ELEMENT(properties_element))
9219     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
9220
9221   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
9222       (ELEM_IS_PLAYER(properties_element) ||
9223        IS_CUSTOM_ELEMENT(properties_element)))
9224     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
9225
9226   CopyElementPropertiesToEditor(properties_element);
9227
9228   UnmapLevelEditorFieldGadgets();
9229   UnmapLevelEditorToolboxDrawingGadgets();
9230   UnmapLevelEditorToolboxCustomGadgets();
9231
9232   if (IS_CUSTOM_ELEMENT(properties_element) ||
9233       IS_GROUP_ELEMENT(properties_element))
9234     MapLevelEditorToolboxCustomGadgets();
9235
9236   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
9237   ClearField();
9238
9239   DrawText(sx, sy, text, font2_nr);
9240
9241   FrameCounter = 0;     /* restart animation frame counter */
9242
9243   DrawElementBorder(SX + x1, SY + y1, TILEX, TILEY, FALSE);
9244   DrawEditorElementAnimation(SX + x1, SY + y1);
9245   DrawEditorElementName(x2, y2, font_nr);
9246
9247   DrawPropertiesTabulatorGadgets();
9248
9249   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
9250     DrawPropertiesInfo();
9251   else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
9252     DrawPropertiesChange();
9253   else  /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */
9254     DrawPropertiesConfig();
9255 }
9256
9257 static void UpdateCustomElementGraphicGadgets()
9258 {
9259   struct ElementInfo *ei = &element_info[properties_element];
9260   int i;
9261
9262   ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial :
9263                      properties_element);
9264
9265   ModifyEditorElementList();
9266   RedrawDrawingElements();
9267
9268   /* force redraw of all mapped drawing area gadgets */
9269   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
9270   {
9271     struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
9272
9273     if (gi->mapped)
9274       MapDrawingArea(i);
9275   }
9276 }
9277
9278 static int getOpenDirectionFromTube(int element)
9279 {
9280   switch (element)
9281   {
9282     case EL_TUBE_LEFT_UP:               return (MV_LEFT | MV_UP);
9283     case EL_TUBE_LEFT_DOWN:             return (MV_LEFT | MV_DOWN);
9284     case EL_TUBE_RIGHT_UP:              return (MV_RIGHT | MV_UP);
9285     case EL_TUBE_RIGHT_DOWN:            return (MV_RIGHT | MV_DOWN);
9286     case EL_TUBE_HORIZONTAL:            return (MV_HORIZONTAL);
9287     case EL_TUBE_HORIZONTAL_UP:         return (MV_HORIZONTAL | MV_UP);
9288     case EL_TUBE_HORIZONTAL_DOWN:       return (MV_HORIZONTAL | MV_DOWN);
9289     case EL_TUBE_VERTICAL:              return (MV_VERTICAL);
9290     case EL_TUBE_VERTICAL_LEFT:         return (MV_VERTICAL | MV_LEFT);
9291     case EL_TUBE_VERTICAL_RIGHT:        return (MV_VERTICAL | MV_RIGHT);
9292     case EL_TUBE_ANY:                   return (MV_ANY_DIRECTION);
9293   }
9294
9295   return MV_NONE;
9296 }
9297
9298 static int getTubeFromOpenDirection(int direction)
9299 {
9300   switch (direction)
9301   {
9302     case (MV_LEFT | MV_UP):             return EL_TUBE_LEFT_UP;
9303     case (MV_LEFT | MV_DOWN):           return EL_TUBE_LEFT_DOWN;
9304     case (MV_RIGHT | MV_UP):            return EL_TUBE_RIGHT_UP;
9305     case (MV_RIGHT | MV_DOWN):          return EL_TUBE_RIGHT_DOWN;
9306     case (MV_HORIZONTAL):               return EL_TUBE_HORIZONTAL;
9307     case (MV_HORIZONTAL | MV_UP):       return EL_TUBE_HORIZONTAL_UP;
9308     case (MV_HORIZONTAL | MV_DOWN):     return EL_TUBE_HORIZONTAL_DOWN;
9309     case (MV_VERTICAL):                 return EL_TUBE_VERTICAL;
9310     case (MV_VERTICAL | MV_LEFT):       return EL_TUBE_VERTICAL_LEFT;
9311     case (MV_VERTICAL | MV_RIGHT):      return EL_TUBE_VERTICAL_RIGHT;
9312     case (MV_ANY_DIRECTION):            return EL_TUBE_ANY;
9313
9314     /* if only one direction, fall back to simple tube with that direction */
9315     case (MV_LEFT):                     return EL_TUBE_HORIZONTAL;
9316     case (MV_RIGHT):                    return EL_TUBE_HORIZONTAL;
9317     case (MV_UP):                       return EL_TUBE_VERTICAL;
9318     case (MV_DOWN):                     return EL_TUBE_VERTICAL;
9319   }
9320
9321   return EL_EMPTY;
9322 }
9323
9324 static int getTubeFromOpenDirectionNotEmpty(int direction, int element_old)
9325 {
9326   int element_new = getTubeFromOpenDirection(direction);
9327
9328   return (element_new != EL_EMPTY ? element_new : element_old);
9329 }
9330
9331 static int getOpenDirectionFromBelt(int element)
9332 {
9333   int belt_dir = getBeltDirFromBeltElement(element);
9334
9335   return (belt_dir == MV_LEFT ? MV_RIGHT :
9336           belt_dir == MV_RIGHT ? MV_LEFT :
9337           belt_dir == MV_NONE ? MV_HORIZONTAL : belt_dir);
9338 }
9339
9340 static int getBeltFromNrAndOpenDirection(int nr, int direction)
9341 {
9342   int belt_dir = (direction == MV_LEFT ? MV_RIGHT :
9343                   direction == MV_RIGHT ? MV_LEFT :
9344                   direction == MV_HORIZONTAL ? MV_NONE : direction);
9345
9346   if (direction == MV_NONE)
9347     return EL_EMPTY;
9348
9349   return getBeltElementFromBeltNrAndBeltDir(nr, belt_dir);
9350 }
9351
9352 static int getBeltFromNrAndOpenDirectionNotEmpty(int nr, int direction,
9353                                                  int element_old)
9354 {
9355   int element_new = getBeltFromNrAndOpenDirection(nr, direction);
9356
9357   return (element_new != EL_EMPTY ? element_new : element_old);
9358 }
9359
9360 static int getOpenDirectionFromPool(int element)
9361 {
9362   switch (element)
9363   {
9364     case EL_ACID_POOL_TOPLEFT:          return (MV_DOWN | MV_RIGHT);
9365     case EL_ACID_POOL_TOPRIGHT:         return (MV_DOWN | MV_LEFT);
9366     case EL_ACID_POOL_BOTTOMLEFT:       return (MV_UP | MV_RIGHT);
9367     case EL_ACID_POOL_BOTTOMRIGHT:      return (MV_UP | MV_LEFT);
9368     case EL_ACID_POOL_BOTTOM:           return (MV_HORIZONTAL | MV_UP);
9369     case EL_ACID:                       return (MV_HORIZONTAL | MV_DOWN);
9370   }
9371
9372   return MV_NONE;
9373 }
9374
9375 static int getPoolFromOpenDirection(int direction)
9376 {
9377   switch (direction)
9378   {
9379     case (MV_DOWN | MV_RIGHT):          return EL_ACID_POOL_TOPLEFT;
9380     case (MV_DOWN | MV_LEFT):           return EL_ACID_POOL_TOPRIGHT;
9381     case (MV_UP | MV_RIGHT):            return EL_ACID_POOL_BOTTOMLEFT;
9382     case (MV_UP | MV_LEFT):             return EL_ACID_POOL_BOTTOMRIGHT;
9383     case (MV_HORIZONTAL | MV_UP):       return EL_ACID_POOL_BOTTOM;
9384     case (MV_HORIZONTAL | MV_DOWN):     return EL_ACID;
9385   }
9386
9387   return EL_EMPTY;
9388 }
9389
9390 static int getPoolFromOpenDirectionExt(int direction, int help_element)
9391 {
9392   int element = getPoolFromOpenDirection(direction);
9393   int help_direction = getOpenDirectionFromPool(help_element);
9394
9395   if (element == EL_EMPTY)
9396   {
9397     int help_direction_vertical = help_direction & MV_VERTICAL;
9398
9399     element = getPoolFromOpenDirection(direction | help_direction_vertical);
9400   }
9401
9402   if (element == EL_EMPTY)
9403   {
9404     int help_direction_horizontal = help_direction & MV_HORIZONTAL;
9405
9406     element = getPoolFromOpenDirection(direction | help_direction_horizontal);
9407   }
9408
9409   return element;
9410 }
9411
9412 static int getPoolFromOpenDirectionNotEmpty(int direction, int element_old)
9413 {
9414   int element_new = getPoolFromOpenDirectionExt(direction, element_old);
9415
9416   return (element_new != EL_EMPTY ? element_new : element_old);
9417 }
9418
9419 static int getOpenDirectionFromPillar(int element)
9420 {
9421   switch (element)
9422   {
9423     case EL_EMC_WALL_1:                 return (MV_DOWN);
9424     case EL_EMC_WALL_2:                 return (MV_VERTICAL);
9425     case EL_EMC_WALL_3:                 return (MV_UP);
9426   }
9427
9428   return MV_NONE;
9429 }
9430
9431 static int getPillarFromOpenDirection(int direction)
9432 {
9433   switch (direction)
9434   {
9435     case (MV_DOWN):                     return EL_EMC_WALL_1;
9436     case (MV_VERTICAL):                 return EL_EMC_WALL_2;
9437     case (MV_UP):                       return EL_EMC_WALL_3;
9438   }
9439
9440   return EL_EMPTY;
9441 }
9442
9443 static int getPillarFromOpenDirectionNotEmpty(int direction, int element_old)
9444 {
9445   int element_new = getPillarFromOpenDirection(direction);
9446
9447   return (element_new != EL_EMPTY ? element_new : element_old);
9448 }
9449
9450 static int getOpenDirectionFromSteel2(int element)
9451 {
9452   switch (element)
9453   {
9454     case EL_DC_STEELWALL_2_LEFT:        return (MV_RIGHT);
9455     case EL_DC_STEELWALL_2_RIGHT:       return (MV_LEFT);
9456     case EL_DC_STEELWALL_2_TOP:         return (MV_DOWN);
9457     case EL_DC_STEELWALL_2_BOTTOM:      return (MV_UP);
9458     case EL_DC_STEELWALL_2_HORIZONTAL:  return (MV_HORIZONTAL);
9459     case EL_DC_STEELWALL_2_VERTICAL:    return (MV_VERTICAL);
9460     case EL_DC_STEELWALL_2_MIDDLE:      return (MV_ANY_DIRECTION);
9461     case EL_DC_STEELWALL_2_SINGLE:      return (MV_NONE);
9462   }
9463
9464   return MV_NONE;
9465 }
9466
9467 static int getSteel2FromOpenDirection(int direction)
9468 {
9469   switch (direction)
9470   {
9471     case (MV_RIGHT):                    return EL_DC_STEELWALL_2_LEFT;
9472     case (MV_LEFT):                     return EL_DC_STEELWALL_2_RIGHT;
9473     case (MV_DOWN):                     return EL_DC_STEELWALL_2_TOP;
9474     case (MV_UP):                       return EL_DC_STEELWALL_2_BOTTOM;
9475     case (MV_HORIZONTAL):               return EL_DC_STEELWALL_2_HORIZONTAL;
9476     case (MV_VERTICAL):                 return EL_DC_STEELWALL_2_VERTICAL;
9477     case (MV_ANY_DIRECTION):            return EL_DC_STEELWALL_2_MIDDLE;
9478     case (MV_NONE):                     return EL_DC_STEELWALL_2_SINGLE;
9479   }
9480
9481   return EL_EMPTY;
9482 }
9483
9484 static int getSteel2FromOpenDirectionNotEmpty(int direction, int element_old)
9485 {
9486   int element_new = getSteel2FromOpenDirection(direction);
9487
9488   return (element_new != EL_EMPTY ? element_new : element_old);
9489 }
9490
9491 static int getOpenDirectionFromChip(int element)
9492 {
9493   switch (element)
9494   {
9495     case EL_SP_CHIP_SINGLE:             return (MV_NONE);
9496     case EL_SP_CHIP_LEFT:               return (MV_RIGHT);
9497     case EL_SP_CHIP_RIGHT:              return (MV_LEFT);
9498     case EL_SP_CHIP_TOP:                return (MV_DOWN);
9499     case EL_SP_CHIP_BOTTOM:             return (MV_UP);
9500   }
9501
9502   return MV_NONE;
9503 }
9504
9505 static int getChipFromOpenDirection(int direction)
9506 {
9507   switch (direction)
9508   {
9509     case (MV_NONE):                     return EL_SP_CHIP_SINGLE;
9510     case (MV_LEFT):                     return EL_SP_CHIP_RIGHT;
9511     case (MV_RIGHT):                    return EL_SP_CHIP_LEFT;
9512     case (MV_UP):                       return EL_SP_CHIP_BOTTOM;
9513     case (MV_DOWN):                     return EL_SP_CHIP_TOP;
9514   }
9515
9516   return EL_EMPTY;
9517 }
9518
9519 static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
9520 {
9521   int element_new = getChipFromOpenDirection(direction);
9522
9523   return (element_new != EL_EMPTY ? element_new : element_old);
9524 }
9525
9526 static int getClosedTube(int x, int y)
9527 {
9528   static int xy[4][2] =
9529   {
9530     { -1, 0 },
9531     { +1, 0 },
9532     { 0, -1 },
9533     { 0, +1 }
9534   };
9535   int element_old = IntelliDrawBuffer[x][y];
9536   int direction_old = getOpenDirectionFromTube(element_old);
9537   int direction_new = MV_NONE;
9538   int i;
9539
9540   for (i = 0; i < NUM_DIRECTIONS; i++)
9541   {
9542     int xx = x + xy[i][0];
9543     int yy = y + xy[i][1];
9544     int dir = MV_DIR_FROM_BIT(i);
9545     int dir_opposite = MV_DIR_OPPOSITE(dir);
9546
9547     if (IN_LEV_FIELD(xx, yy) && IS_TUBE(IntelliDrawBuffer[xx][yy]) &&
9548         (direction_old & dir) &&
9549         (getOpenDirectionFromTube(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9550       direction_new |= dir;
9551   }
9552
9553   return getTubeFromOpenDirectionNotEmpty(direction_new, element_old);
9554 }
9555
9556 static int getClosedBelt(int x, int y)
9557 {
9558   static int xy[4][2] =
9559   {
9560     { -1, 0 },
9561     { +1, 0 },
9562     { 0, -1 },
9563     { 0, +1 }
9564   };
9565   int element_old = IntelliDrawBuffer[x][y];
9566   int nr = getBeltNrFromBeltElement(element_old);
9567   int direction_old = getOpenDirectionFromBelt(element_old);
9568   int direction_new = MV_NONE;
9569   int i;
9570
9571   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9572   {
9573     int xx = x + xy[i][0];
9574     int yy = y + xy[i][1];
9575     int dir = MV_DIR_FROM_BIT(i);
9576     int dir_opposite = MV_DIR_OPPOSITE(dir);
9577
9578     if (IN_LEV_FIELD(xx, yy) && IS_BELT(IntelliDrawBuffer[xx][yy]) &&
9579         (direction_old & dir) &&
9580         (getOpenDirectionFromBelt(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9581       direction_new |= dir;
9582   }
9583
9584   return getBeltFromNrAndOpenDirection(nr, direction_new);
9585 }
9586
9587 static int getClosedPool(int x, int y)
9588 {
9589   static int xy[4][2] =
9590   {
9591     { -1, 0 },
9592     { +1, 0 },
9593     { 0, -1 },
9594     { 0, +1 }
9595   };
9596   int element_old = IntelliDrawBuffer[x][y];
9597   int direction_old = getOpenDirectionFromPool(element_old);
9598   int direction_new = MV_NONE;
9599   int i;
9600
9601   for (i = 0; i < NUM_DIRECTIONS; i++)
9602   {
9603     int xx = x + xy[i][0];
9604     int yy = y + xy[i][1];
9605     int dir = MV_DIR_FROM_BIT(i);
9606     int dir_opposite = MV_DIR_OPPOSITE(dir);
9607
9608     if (IN_LEV_FIELD(xx, yy) &&
9609         IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[xx][yy]) &&
9610         (direction_old & dir) &&
9611         (getOpenDirectionFromPool(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9612       direction_new |= dir;
9613   }
9614
9615   return getPoolFromOpenDirectionNotEmpty(direction_new, element_old);
9616 }
9617
9618 static int getClosedPillar(int x, int y)
9619 {
9620   static int xy[4][2] =
9621   {
9622     { -1, 0 },
9623     { +1, 0 },
9624     { 0, -1 },
9625     { 0, +1 }
9626   };
9627   int element_old = IntelliDrawBuffer[x][y];
9628   int direction_old = getOpenDirectionFromPillar(element_old);
9629   int direction_new = MV_NONE;
9630   int i;
9631
9632   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9633   {
9634     int xx = x + xy[i][0];
9635     int yy = y + xy[i][1];
9636     int dir = MV_DIR_FROM_BIT(i);
9637     int dir_opposite = MV_DIR_OPPOSITE(dir);
9638
9639     if (IN_LEV_FIELD(xx, yy) && IS_EMC_PILLAR(IntelliDrawBuffer[xx][yy]) &&
9640         (direction_old & dir) &&
9641         (getOpenDirectionFromPillar(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9642       direction_new |= dir;
9643   }
9644
9645   return getPillarFromOpenDirectionNotEmpty(direction_new, element_old);
9646 }
9647
9648 static int getClosedSteel2(int x, int y)
9649 {
9650   static int xy[4][2] =
9651   {
9652     { -1, 0 },
9653     { +1, 0 },
9654     { 0, -1 },
9655     { 0, +1 }
9656   };
9657   int element_old = IntelliDrawBuffer[x][y];
9658   int direction_old = getOpenDirectionFromSteel2(element_old);
9659   int direction_new = MV_NONE;
9660   int i;
9661
9662   for (i = 0; i < NUM_DIRECTIONS; i++)
9663   {
9664     int xx = x + xy[i][0];
9665     int yy = y + xy[i][1];
9666     int dir = MV_DIR_FROM_BIT(i);
9667     int dir_opposite = MV_DIR_OPPOSITE(dir);
9668
9669     if (IN_LEV_FIELD(xx, yy) && IS_DC_STEELWALL_2(IntelliDrawBuffer[xx][yy]) &&
9670         (direction_old & dir) &&
9671         (getOpenDirectionFromSteel2(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9672       direction_new |= dir;
9673   }
9674
9675   return getSteel2FromOpenDirectionNotEmpty(direction_new, element_old);
9676 }
9677
9678 static int getClosedChip(int x, int y)
9679 {
9680   static int xy[4][2] =
9681   {
9682     { -1, 0 },
9683     { +1, 0 },
9684     { 0, -1 },
9685     { 0, +1 }
9686   };
9687   int element_old = IntelliDrawBuffer[x][y];
9688   int direction_old = getOpenDirectionFromChip(element_old);
9689   int direction_new = MV_NONE;
9690   int i;
9691
9692   for (i = 0; i < NUM_DIRECTIONS; i++)
9693   {
9694     int xx = x + xy[i][0];
9695     int yy = y + xy[i][1];
9696     int dir = MV_DIR_FROM_BIT(i);
9697     int dir_opposite = MV_DIR_OPPOSITE(dir);
9698
9699     if (IN_LEV_FIELD(xx, yy) && IS_SP_CHIP(IntelliDrawBuffer[xx][yy]) &&
9700         (direction_old & dir) &&
9701         (getOpenDirectionFromChip(IntelliDrawBuffer[xx][yy]) & dir_opposite))
9702       direction_new |= dir;
9703   }
9704
9705   return getChipFromOpenDirectionNotEmpty(direction_new, element_old);
9706 }
9707
9708 static void SetElementSimple(int x, int y, int element, boolean change_level)
9709 {
9710   int sx = x - level_xpos;
9711   int sy = y - level_ypos;
9712
9713   IntelliDrawBuffer[x][y] = element;
9714
9715   if (change_level)
9716     Feld[x][y] = element;
9717
9718   if (IN_ED_FIELD(sx, sy))
9719     DrawEditorElement(sx, sy, element);
9720 }
9721
9722 static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
9723                                            int x2, int y2, int *element2,
9724                                            int (*close_function)(int, int),
9725                                            boolean change_level)
9726 {
9727   /* set neighbour elements to newly determined connections */
9728   SetElementSimple(x1, y1, *element1, change_level);
9729   SetElementSimple(x2, y2, *element2, change_level);
9730
9731   /* remove all open connections of neighbour elements */
9732   *element1 = close_function(x1, y1);
9733   *element2 = close_function(x2, y2);
9734
9735   /* set neighbour elements to new, minimized connections */
9736   SetElementSimple(x1, y1, *element1, change_level);
9737   SetElementSimple(x2, y2, *element2, change_level);
9738 }
9739
9740 static void SetElementIntelliDraw(int x, int y, int new_element,
9741                                   boolean change_level, int button)
9742 {
9743   static int xy[4][2] =
9744   {
9745     { -1, 0 },
9746     { +1, 0 },
9747     { 0, -1 },
9748     { 0, +1 }
9749   };
9750   static int last_x = -1;
9751   static int last_y = -1;
9752   int old_element = IntelliDrawBuffer[x][y];
9753
9754   if (new_element == EL_UNDEFINED)
9755   {
9756     last_x = -1;
9757     last_y = -1;
9758
9759     return;
9760   }
9761
9762   if (IS_TUBE(new_element))
9763   {
9764     int last_element_new = EL_UNDEFINED;
9765     int direction = MV_NONE;
9766     int i;
9767
9768     /* if old element is of same kind, keep all existing directions */
9769     if (IS_TUBE(old_element))
9770       direction |= getOpenDirectionFromTube(old_element);
9771
9772     for (i = 0; i < NUM_DIRECTIONS; i++)
9773     {
9774       int xx = x + xy[i][0];
9775       int yy = y + xy[i][1];
9776
9777       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9778           IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
9779       {
9780         int dir = MV_DIR_FROM_BIT(i);
9781         int dir_opposite = MV_DIR_OPPOSITE(dir);
9782         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9783         int last_direction_old = getOpenDirectionFromTube(last_element_old);
9784         int last_direction_new = last_direction_old | dir_opposite;
9785
9786         last_element_new = getTubeFromOpenDirection(last_direction_new);
9787
9788         direction |= dir;
9789       }
9790     }
9791
9792     new_element = getTubeFromOpenDirectionNotEmpty(direction, new_element);
9793
9794     if (last_element_new != EL_UNDEFINED)
9795       MergeAndCloseNeighbourElements(x, y, &new_element,
9796                                      last_x, last_y, &last_element_new,
9797                                      getClosedTube, change_level);
9798   }
9799   else if (IS_BELT(new_element))
9800   {
9801     int belt_nr = getBeltNrFromBeltElement(new_element);
9802     int last_element_new = EL_UNDEFINED;
9803     int direction = MV_NONE;
9804     int i;
9805
9806     /* if old element is of same kind, keep all existing directions */
9807     if (IS_BELT(old_element))
9808       direction |= getOpenDirectionFromBelt(old_element);
9809
9810     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
9811     {
9812       int xx = x + xy[i][0];
9813       int yy = y + xy[i][1];
9814
9815       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9816           IS_BELT(IntelliDrawBuffer[last_x][last_y]))
9817       {
9818         int dir = MV_DIR_FROM_BIT(i);
9819         int dir_opposite = MV_DIR_OPPOSITE(dir);
9820         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9821         int last_belt_nr = getBeltNrFromBeltElement(last_element_old);
9822         int last_direction_old = getOpenDirectionFromBelt(last_element_old);
9823         int last_direction_new = last_direction_old | dir_opposite;
9824
9825         last_element_new = getBeltFromNrAndOpenDirection(last_belt_nr,
9826                                                          last_direction_new);
9827         direction |= dir;
9828       }
9829     }
9830
9831     new_element = getBeltFromNrAndOpenDirectionNotEmpty(belt_nr, direction,
9832                                                         new_element);
9833     if (last_element_new != EL_UNDEFINED)
9834       MergeAndCloseNeighbourElements(x, y, &new_element,
9835                                      last_x, last_y, &last_element_new,
9836                                      getClosedBelt, change_level);
9837   }
9838   else if (IS_ACID_POOL_OR_ACID(new_element))
9839   {
9840     int last_element_new = EL_UNDEFINED;
9841     int direction = MV_NONE;
9842     int i;
9843
9844     /* if old element is of same kind, keep all existing directions */
9845     if (IS_ACID_POOL_OR_ACID(old_element))
9846       direction |= getOpenDirectionFromPool(old_element);
9847
9848     for (i = 0; i < NUM_DIRECTIONS; i++)
9849     {
9850       int xx = x + xy[i][0];
9851       int yy = y + xy[i][1];
9852
9853       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9854           IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
9855       {
9856         int dir = MV_DIR_FROM_BIT(i);
9857         int dir_opposite = MV_DIR_OPPOSITE(dir);
9858         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9859         int last_direction_old = getOpenDirectionFromPool(last_element_old);
9860         int last_direction_new = last_direction_old | dir_opposite;
9861
9862         last_element_new = getPoolFromOpenDirection(last_direction_new);
9863
9864         direction |= dir;
9865       }
9866     }
9867
9868     /* special corrections needed for intuitively correct acid pool drawing */
9869     if (last_element_new == EL_EMPTY)
9870       last_element_new = new_element;
9871     else if (last_element_new != EL_UNDEFINED)
9872       new_element = last_element_new;
9873
9874     new_element = getPoolFromOpenDirectionNotEmpty(direction, new_element);
9875
9876     if (last_element_new != EL_UNDEFINED)
9877       MergeAndCloseNeighbourElements(x, y, &new_element,
9878                                      last_x, last_y, &last_element_new,
9879                                      getClosedPool, change_level);
9880   }
9881   else if (IS_EMC_PILLAR(new_element))
9882   {
9883     int last_element_new = EL_UNDEFINED;
9884     int direction = MV_NONE;
9885     int i;
9886
9887     /* if old element is of same kind, keep all existing directions */
9888     if (IS_EMC_PILLAR(old_element))
9889       direction |= getOpenDirectionFromPillar(old_element);
9890
9891     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
9892     {
9893       int xx = x + xy[i][0];
9894       int yy = y + xy[i][1];
9895
9896       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9897           IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
9898       {
9899         int dir = MV_DIR_FROM_BIT(i);
9900         int dir_opposite = MV_DIR_OPPOSITE(dir);
9901         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9902         int last_direction_old = getOpenDirectionFromPillar(last_element_old);
9903         int last_direction_new = last_direction_old | dir_opposite;
9904
9905         last_element_new = getPillarFromOpenDirection(last_direction_new);
9906
9907         direction |= dir;
9908       }
9909     }
9910
9911     new_element = getPillarFromOpenDirectionNotEmpty(direction, new_element);
9912
9913     if (last_element_new != EL_UNDEFINED)
9914       MergeAndCloseNeighbourElements(x, y, &new_element,
9915                                      last_x, last_y, &last_element_new,
9916                                      getClosedPillar, change_level);
9917   }
9918   else if (IS_DC_STEELWALL_2(new_element))
9919   {
9920     int last_element_new = EL_UNDEFINED;
9921     int direction = MV_NONE;
9922     int i;
9923
9924     /* if old element is of same kind, keep all existing directions */
9925     if (IS_DC_STEELWALL_2(old_element))
9926       direction |= getOpenDirectionFromSteel2(old_element);
9927
9928     for (i = 0; i < NUM_DIRECTIONS; i++)
9929     {
9930       int xx = x + xy[i][0];
9931       int yy = y + xy[i][1];
9932
9933       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9934           IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
9935       {
9936         int dir = MV_DIR_FROM_BIT(i);
9937         int dir_opposite = MV_DIR_OPPOSITE(dir);
9938         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9939         int last_direction_old = getOpenDirectionFromSteel2(last_element_old);
9940         int last_direction_new = last_direction_old | dir_opposite;
9941
9942         last_element_new = getSteel2FromOpenDirection(last_direction_new);
9943
9944         direction |= dir;
9945       }
9946     }
9947
9948     new_element = getSteel2FromOpenDirectionNotEmpty(direction, new_element);
9949
9950     if (last_element_new != EL_UNDEFINED)
9951       MergeAndCloseNeighbourElements(x, y, &new_element,
9952                                      last_x, last_y, &last_element_new,
9953                                      getClosedSteel2, change_level);
9954   }
9955   else if (IS_SP_CHIP(new_element))
9956   {
9957     int last_element_new = EL_UNDEFINED;
9958     int direction = MV_NONE;
9959     int i;
9960
9961     /* (do not keep existing directions, regardless of kind of old element) */
9962
9963     for (i = 0; i < NUM_DIRECTIONS; i++)
9964     {
9965       int xx = x + xy[i][0];
9966       int yy = y + xy[i][1];
9967
9968       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
9969           IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
9970       {
9971         int dir = MV_DIR_FROM_BIT(i);
9972         int dir_opposite = MV_DIR_OPPOSITE(dir);
9973         int last_element_old = IntelliDrawBuffer[last_x][last_y];
9974         int last_direction_old = getOpenDirectionFromChip(last_element_old);
9975         int last_direction_new = last_direction_old | dir_opposite;
9976
9977         if (last_direction_old == MV_NONE)
9978         {
9979           last_element_new = getChipFromOpenDirection(last_direction_new);
9980           direction |= dir;
9981         }
9982         else if (last_direction_old & (dir | dir_opposite))
9983         {
9984           direction |= MV_DIR_OPPOSITE(last_direction_old);
9985         }
9986         else
9987         {
9988           direction |= MV_DIR_OPPOSITE(dir);
9989         }
9990       }
9991     }
9992
9993     new_element = getChipFromOpenDirectionNotEmpty(direction, new_element);
9994
9995     if (last_element_new != EL_UNDEFINED)
9996       MergeAndCloseNeighbourElements(x, y, &new_element,
9997                                      last_x, last_y, &last_element_new,
9998                                      getClosedChip, change_level);
9999   }
10000   else if (IS_SP_HARDWARE_BASE(new_element))
10001   {
10002     int nr = GetSimpleRandom(6);
10003
10004     new_element = (nr == 0 ? EL_SP_HARDWARE_BASE_1 :
10005                    nr == 1 ? EL_SP_HARDWARE_BASE_2 :
10006                    nr == 2 ? EL_SP_HARDWARE_BASE_3 :
10007                    nr == 3 ? EL_SP_HARDWARE_BASE_4 :
10008                    nr == 4 ? EL_SP_HARDWARE_BASE_5 : EL_SP_HARDWARE_BASE_6);
10009   }
10010   else if (new_element == EL_SP_HARDWARE_GREEN ||
10011            new_element == EL_SP_HARDWARE_BLUE ||
10012            new_element == EL_SP_HARDWARE_RED)
10013   {
10014     int nr = GetSimpleRandom(3);
10015
10016     new_element = (nr == 0 ? EL_SP_HARDWARE_GREEN :
10017                    nr == 1 ? EL_SP_HARDWARE_BLUE : EL_SP_HARDWARE_RED);
10018   }
10019   else if (IS_GROUP_ELEMENT(new_element))
10020   {
10021     boolean connected_drawing = FALSE;
10022     int i;
10023
10024     for (i = 0; i < NUM_DIRECTIONS; i++)
10025     {
10026       int xx = x + xy[i][0];
10027       int yy = y + xy[i][1];
10028
10029       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
10030           IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
10031         connected_drawing = TRUE;
10032     }
10033
10034     if (!connected_drawing)
10035       ResolveGroupElement(new_element);
10036
10037     new_element = GetElementFromGroupElement(new_element);
10038   }
10039   else if (IS_BELT_SWITCH(old_element))
10040   {
10041     int belt_nr = getBeltNrFromBeltSwitchElement(old_element);
10042     int belt_dir = getBeltDirFromBeltSwitchElement(old_element);
10043
10044     belt_dir = (belt_dir == MV_LEFT ? MV_NONE :
10045                 belt_dir == MV_NONE ? MV_RIGHT : MV_LEFT);
10046
10047     new_element = getBeltSwitchElementFromBeltNrAndBeltDir(belt_nr, belt_dir);
10048   }
10049   else
10050   {
10051     static int swappable_elements[][2] =
10052     {
10053       { EL_EXIT_CLOSED,                 EL_EXIT_OPEN                    },
10054       { EL_DYNAMITE,                    EL_DYNAMITE_ACTIVE              },
10055       { EL_EM_DYNAMITE,                 EL_EM_DYNAMITE_ACTIVE           },
10056       { EL_QUICKSAND_EMPTY,             EL_QUICKSAND_FULL               },
10057       { EL_EMERALD,                     EL_WALL_EMERALD                 },
10058       { EL_EMERALD_YELLOW,              EL_WALL_EMERALD_YELLOW          },
10059       { EL_EMERALD_RED,                 EL_WALL_EMERALD_RED             },
10060       { EL_EMERALD_PURPLE,              EL_WALL_EMERALD_PURPLE          },
10061       { EL_DIAMOND,                     EL_WALL_DIAMOND                 },
10062       { EL_BD_DIAMOND,                  EL_WALL_BD_DIAMOND              },
10063       { EL_GATE_1,                      EL_GATE_1_GRAY                  },
10064       { EL_GATE_2,                      EL_GATE_2_GRAY                  },
10065       { EL_GATE_3,                      EL_GATE_3_GRAY                  },
10066       { EL_GATE_4,                      EL_GATE_4_GRAY                  },
10067       { EL_EM_GATE_1,                   EL_EM_GATE_1_GRAY               },
10068       { EL_EM_GATE_2,                   EL_EM_GATE_2_GRAY               },
10069       { EL_EM_GATE_3,                   EL_EM_GATE_3_GRAY               },
10070       { EL_EM_GATE_4,                   EL_EM_GATE_4_GRAY               },
10071       { EL_EMC_GATE_5,                  EL_EMC_GATE_5_GRAY              },
10072       { EL_EMC_GATE_6,                  EL_EMC_GATE_6_GRAY              },
10073       { EL_EMC_GATE_7,                  EL_EMC_GATE_7_GRAY              },
10074       { EL_EMC_GATE_8,                  EL_EMC_GATE_8_GRAY              },
10075       { EL_DC_GATE_WHITE,               EL_DC_GATE_WHITE_GRAY           },
10076       { EL_TIME_ORB_EMPTY,              EL_TIME_ORB_FULL                },
10077       { EL_LAMP,                        EL_LAMP_ACTIVE                  },
10078       { EL_SOKOBAN_FIELD_EMPTY,         EL_SOKOBAN_FIELD_FULL           },
10079       { EL_SP_BASE,                     EL_SP_BUGGY_BASE                },
10080       { EL_PEARL,                       EL_WALL_PEARL                   },
10081       { EL_CRYSTAL,                     EL_WALL_CRYSTAL                 },
10082       { EL_TIMEGATE_CLOSED,             EL_TIMEGATE_OPEN                },
10083       { EL_SWITCHGATE_CLOSED,           EL_SWITCHGATE_OPEN              },
10084       { EL_SWITCHGATE_SWITCH_UP,        EL_SWITCHGATE_SWITCH_DOWN       },
10085       { EL_DC_SWITCHGATE_SWITCH_UP,     EL_DC_SWITCHGATE_SWITCH_DOWN    },
10086       { EL_LIGHT_SWITCH,                EL_LIGHT_SWITCH_ACTIVE          },
10087       { EL_LANDMINE,                    EL_DC_LANDMINE                  },
10088       { EL_SHIELD_NORMAL,               EL_SHIELD_DEADLY                },
10089       { EL_STEEL_EXIT_CLOSED,           EL_STEEL_EXIT_OPEN              },
10090       { EL_EM_EXIT_CLOSED,              EL_EM_EXIT_OPEN                 },
10091       { EL_EM_STEEL_EXIT_CLOSED,        EL_EM_STEEL_EXIT_OPEN           },
10092       { EL_QUICKSAND_FAST_EMPTY,        EL_QUICKSAND_FAST_FULL          },
10093
10094       { -1,                             -1                              },
10095     };
10096     static int rotatable_elements[][4] =
10097     {
10098       {
10099         EL_BUG_UP,
10100         EL_BUG_RIGHT,
10101         EL_BUG_DOWN,
10102         EL_BUG_LEFT
10103       },
10104
10105       {
10106         EL_SPACESHIP_UP,
10107         EL_SPACESHIP_RIGHT,
10108         EL_SPACESHIP_DOWN,
10109         EL_SPACESHIP_LEFT
10110       },
10111
10112       {
10113         EL_BD_BUTTERFLY_UP,
10114         EL_BD_BUTTERFLY_RIGHT,
10115         EL_BD_BUTTERFLY_DOWN,
10116         EL_BD_BUTTERFLY_LEFT
10117       },
10118
10119       {
10120         EL_BD_FIREFLY_UP,
10121         EL_BD_FIREFLY_RIGHT,
10122         EL_BD_FIREFLY_DOWN,
10123         EL_BD_FIREFLY_LEFT
10124       },
10125
10126       {
10127         EL_PACMAN_UP,
10128         EL_PACMAN_RIGHT,
10129         EL_PACMAN_DOWN,
10130         EL_PACMAN_LEFT
10131       },
10132
10133       {
10134         EL_YAMYAM_UP,
10135         EL_YAMYAM_RIGHT,
10136         EL_YAMYAM_DOWN,
10137         EL_YAMYAM_LEFT
10138       },
10139
10140       {
10141         EL_ARROW_UP,
10142         EL_ARROW_RIGHT,
10143         EL_ARROW_DOWN,
10144         EL_ARROW_LEFT
10145       },
10146
10147       {
10148         EL_SP_PORT_UP,
10149         EL_SP_PORT_RIGHT,
10150         EL_SP_PORT_DOWN,
10151         EL_SP_PORT_LEFT
10152       },
10153
10154       {
10155         EL_SP_GRAVITY_PORT_UP,
10156         EL_SP_GRAVITY_PORT_RIGHT,
10157         EL_SP_GRAVITY_PORT_DOWN,
10158         EL_SP_GRAVITY_PORT_LEFT
10159       },
10160
10161       {
10162         EL_SP_GRAVITY_ON_PORT_UP,
10163         EL_SP_GRAVITY_ON_PORT_RIGHT,
10164         EL_SP_GRAVITY_ON_PORT_DOWN,
10165         EL_SP_GRAVITY_ON_PORT_LEFT
10166       },
10167
10168       {
10169         EL_SP_GRAVITY_OFF_PORT_UP,
10170         EL_SP_GRAVITY_OFF_PORT_RIGHT,
10171         EL_SP_GRAVITY_OFF_PORT_DOWN,
10172         EL_SP_GRAVITY_OFF_PORT_LEFT
10173       },
10174
10175       {
10176         EL_MOLE_UP,
10177         EL_MOLE_RIGHT,
10178         EL_MOLE_DOWN,
10179         EL_MOLE_LEFT
10180       },
10181
10182       {
10183         EL_BALLOON_SWITCH_UP,
10184         EL_BALLOON_SWITCH_RIGHT,
10185         EL_BALLOON_SWITCH_DOWN,
10186         EL_BALLOON_SWITCH_LEFT
10187       },
10188
10189       {
10190         -1,
10191         -1,
10192         -1,
10193         -1,
10194       },
10195     };
10196     int i, j;
10197
10198     for (i = 0; swappable_elements[i][0] != -1; i++)
10199     {
10200       int element1 = swappable_elements[i][0];
10201       int element2 = swappable_elements[i][1];
10202
10203       if (old_element == element1 || old_element == element2)
10204         new_element = (old_element == element1 ? element2 : element1);
10205     }
10206
10207     for (i = 0; rotatable_elements[i][0] != -1; i++)
10208     {
10209       for (j = 0; j < 4; j++)
10210       {
10211         int element = rotatable_elements[i][j];
10212
10213         if (old_element == element)
10214           new_element = (button == 1 ? rotatable_elements[i][(j + 3) % 4] :
10215                          button == 2 ? rotatable_elements[i][0]           :
10216                          button == 3 ? rotatable_elements[i][(j + 1) % 4] :
10217                          old_element);
10218       }
10219     }
10220   }
10221
10222   SetElementSimple(x, y, new_element, change_level);
10223
10224   last_x = x;
10225   last_y = y;
10226 }
10227
10228 static void ResetIntelliDraw()
10229 {
10230   int x, y;
10231
10232   for (x = 0; x < lev_fieldx; x++)
10233     for (y = 0; y < lev_fieldy; y++)
10234       IntelliDrawBuffer[x][y] = Feld[x][y];
10235
10236   SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
10237 }
10238
10239 static void SetElementExt(int x, int y, int element, boolean change_level,
10240                           int button)
10241 {
10242   if (element < 0)
10243     SetElementSimple(x, y, Feld[x][y], change_level);
10244   else if (GetKeyModState() & KMOD_Shift)
10245     SetElementIntelliDraw(x, y, element, change_level, button);
10246   else
10247     SetElementSimple(x, y, element, change_level);
10248 }
10249
10250 static void SetElement(int x, int y, int element)
10251 {
10252   SetElementExt(x, y, element, TRUE, -1);
10253 }
10254
10255 static void SetElementButton(int x, int y, int element, int button)
10256 {
10257   SetElementExt(x, y, element, TRUE, button);
10258 }
10259
10260 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
10261 {
10262   int lx = sx + level_xpos;
10263   int ly = sy + level_ypos;
10264
10265   SetElementExt(lx, ly, element, change_level, -1);
10266 }
10267
10268 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
10269                      int element, boolean change_level)
10270 {
10271   int xsize = ABS(to_x - from_x);
10272   int ysize = ABS(to_y - from_y);
10273   int dx = (to_x < from_x ? -1 : +1);
10274   int dy = (to_y < from_y ? -1 : +1);
10275   int i;
10276
10277   if (from_y == to_y)                   /* horizontal line */
10278   {
10279     for (i = 0; i <= xsize; i++)
10280       DrawLineElement(from_x + i * dx, from_y, element, change_level);
10281   }
10282   else if (from_x == to_x)              /* vertical line */
10283   {
10284     for (i = 0; i <= ysize; i++)
10285       DrawLineElement(from_x, from_y + i * dy, element, change_level);
10286   }
10287   else                                  /* diagonal line */
10288   {
10289     if (ysize < xsize)                  /* a < 1 */
10290     {
10291       float a = (float)ysize / (float)xsize;
10292
10293       for (i = 0; i <= xsize; i++)
10294       {
10295         int x = dx * i;
10296         int y = dy * (int)(a * i + 0.5);
10297
10298         DrawLineElement(from_x + x, from_y + y, element, change_level);
10299       }
10300     }
10301     else                                /* a >= 1 */
10302     {
10303       float a = (float)xsize / (float)ysize;
10304
10305       for (i = 0; i <= ysize; i++)
10306       {
10307         int x = dx * (int)(a * i + 0.5);
10308         int y = dy * i;
10309
10310         DrawLineElement(from_x + x, from_y + y, element, change_level);
10311       }
10312     }
10313   }
10314 }
10315
10316 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
10317                     int element, boolean change_level)
10318 {
10319   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
10320   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
10321   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
10322   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
10323 }
10324
10325 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
10326                           int element, boolean change_level)
10327 {
10328   int y;
10329
10330   if (from_y > to_y)
10331     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
10332
10333   for (y = from_y; y <= to_y; y++)
10334     DrawLine(from_x, y, to_x, y, element, change_level);
10335 }
10336
10337 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
10338                        int element, boolean change_level)
10339 {
10340   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
10341   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
10342   int len_x = ABS(to_x - from_x);
10343   int len_y = ABS(to_y - from_y);
10344   int radius, x, y;
10345
10346   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
10347
10348   /* not optimal (some points get drawn twice) but simple,
10349      and fast enough for the few points we are drawing */
10350
10351   for (x = 0; x <= radius; x++)
10352   {
10353     int sx, sy, lx, ly;
10354
10355     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
10356
10357     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
10358     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
10359     lx = sx + level_xpos;
10360     ly = sy + level_ypos;
10361
10362     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10363       DrawLineElement(sx, sy, element, change_level);
10364   }
10365
10366   for (y = 0; y <= radius; y++)
10367   {
10368     int sx, sy, lx, ly;
10369
10370     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
10371
10372     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
10373     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
10374     lx = sx + level_xpos;
10375     ly = sy + level_ypos;
10376
10377     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10378       DrawLineElement(sx, sy, element, change_level);
10379   }
10380 }
10381
10382 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
10383                     int element, boolean change_level)
10384 {
10385   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
10386   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
10387
10388   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
10389 }
10390
10391 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
10392
10393 #if DRAW_CIRCLES_BUTTON_AVAILABLE
10394 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
10395                        int element, boolean change_level)
10396 {
10397   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
10398   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
10399   int mirror_to_x2 = from_x - (to_x2 - from_x);
10400   int mirror_to_y2 = from_y - (to_y2 - from_y);
10401
10402   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
10403   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
10404   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
10405   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
10406 }
10407 #endif
10408
10409 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
10410 {
10411   int from_sx, from_sy;
10412   int to_sx, to_sy;
10413
10414   if (from_x > to_x)
10415     swap_numbers(&from_x, &to_x);
10416
10417   if (from_y > to_y)
10418     swap_numbers(&from_y, &to_y);
10419
10420   from_sx = SX + from_x * ed_tilesize;
10421   from_sy = SY + from_y * ed_tilesize;
10422   to_sx = SX + (to_x + 1) * ed_tilesize - 1;
10423   to_sy = SY + (to_y + 1) * ed_tilesize - 1;
10424
10425   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
10426   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
10427   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
10428   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
10429
10430   if (from_x == to_x && from_y == to_y)
10431     MarkTileDirty(from_x/2, from_y/2);
10432   else
10433     redraw_mask |= REDRAW_FIELD;
10434 }
10435
10436 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
10437                        int element, boolean change_level)
10438 {
10439   if (element == -1 || change_level)
10440     DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
10441   else
10442     DrawAreaBorder(from_x, from_y, to_x, to_y);
10443 }
10444
10445 /* values for CopyBrushExt() */
10446 #define CB_AREA_TO_BRUSH        0
10447 #define CB_BRUSH_TO_CURSOR      1
10448 #define CB_BRUSH_TO_LEVEL       2
10449 #define CB_DELETE_OLD_CURSOR    3
10450 #define CB_DUMP_BRUSH           4
10451 #define CB_DUMP_BRUSH_SMALL     5
10452
10453 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
10454                          int button, int mode)
10455 {
10456   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
10457   static int brush_width, brush_height;
10458   static int last_cursor_x = -1, last_cursor_y = -1;
10459   static boolean delete_old_brush;
10460   int new_element = BUTTON_ELEMENT(button);
10461   int x, y;
10462
10463   if (mode == CB_DUMP_BRUSH ||
10464       mode == CB_DUMP_BRUSH_SMALL)
10465   {
10466     if (!draw_with_brush)
10467     {
10468       Error(ERR_WARN, "no brush selected");
10469
10470       return;
10471     }
10472
10473     for (y = 0; y < brush_height; y++)
10474     {
10475       for (x = 0; x < brush_width; x++)
10476       {
10477         int element = brush_buffer[x][y];
10478         int element_mapped = element;
10479
10480         if (IS_CUSTOM_ELEMENT(element))
10481           element_mapped = EL_CUSTOM_START;
10482         else if (IS_GROUP_ELEMENT(element))
10483           element_mapped = EL_GROUP_START;
10484         else if (element >= NUM_FILE_ELEMENTS)
10485           element_mapped = EL_UNKNOWN;
10486
10487         // dump brush as level sketch text for the R'n'D forum:
10488         // - large tiles: `xxx (0x60 ASCII)
10489         // - small tiles: Â¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
10490         printf("%s%03d", (mode == CB_DUMP_BRUSH ? "`" : "¸"), element_mapped);
10491       }
10492
10493       printf("\n");
10494     }
10495
10496     return;
10497   }
10498
10499   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
10500     return;
10501
10502   if (mode == CB_AREA_TO_BRUSH)
10503   {
10504     int from_lx, from_ly;
10505
10506     if (from_x > to_x)
10507       swap_numbers(&from_x, &to_x);
10508
10509     if (from_y > to_y)
10510       swap_numbers(&from_y, &to_y);
10511
10512     brush_width = to_x - from_x + 1;
10513     brush_height = to_y - from_y + 1;
10514
10515     from_lx = from_x + level_xpos;
10516     from_ly = from_y + level_ypos;
10517
10518     for (y = 0; y < brush_height; y++)
10519     {
10520       for (x = 0; x < brush_width; x++)
10521       {
10522         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
10523
10524         if (button != 1)
10525           DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
10526       }
10527     }
10528
10529     if (button != 1)
10530       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10531
10532     delete_old_brush = FALSE;
10533   }
10534   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
10535            mode == CB_BRUSH_TO_LEVEL)
10536   {
10537     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
10538     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
10539     int cursor_from_x = cursor_x - brush_width / 2;
10540     int cursor_from_y = cursor_y - brush_height / 2;
10541     int border_from_x = cursor_x, border_from_y = cursor_y;
10542     int border_to_x = cursor_x, border_to_y = cursor_y;
10543
10544     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
10545       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
10546
10547     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
10548         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
10549     {
10550       delete_old_brush = FALSE;
10551       return;
10552     }
10553
10554     for (y = 0; y < brush_height; y++)
10555     {
10556       for (x = 0; x < brush_width; x++)
10557       {
10558         int sx = cursor_from_x + x;
10559         int sy = cursor_from_y + y;
10560         int lx = sx + level_xpos;
10561         int ly = sy + level_ypos;
10562         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
10563         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
10564                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
10565                        brush_buffer[x][y] : new_element);
10566
10567         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
10568         {
10569           if (sx < border_from_x)
10570             border_from_x = sx;
10571           else if (sx > border_to_x)
10572             border_to_x = sx;
10573           if (sy < border_from_y)
10574             border_from_y = sy;
10575           else if (sy > border_to_y)
10576             border_to_y = sy;
10577
10578           DrawLineElement(sx, sy, element, change_level);
10579         }
10580       }
10581     }
10582
10583     if (mode != CB_DELETE_OLD_CURSOR)
10584       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
10585
10586     last_cursor_x = cursor_x;
10587     last_cursor_y = cursor_y;
10588     delete_old_brush = TRUE;
10589   }
10590 }
10591
10592 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
10593                             int button)
10594 {
10595   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
10596 }
10597
10598 static void CopyBrushToLevel(int x, int y, int button)
10599 {
10600   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
10601 }
10602
10603 static void CopyBrushToCursor(int x, int y)
10604 {
10605   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
10606 }
10607
10608 static void DeleteBrushFromCursor()
10609 {
10610   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
10611 }
10612
10613 void DumpBrush()
10614 {
10615   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
10616 }
10617
10618 void DumpBrush_Small()
10619 {
10620   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH_SMALL);
10621 }
10622
10623 static void FloodFill(int from_x, int from_y, int fill_element)
10624 {
10625   FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy);
10626 }
10627
10628 /* values for DrawLevelText() modes */
10629 #define TEXT_INIT               0
10630 #define TEXT_SETCURSOR          1
10631 #define TEXT_WRITECHAR          2
10632 #define TEXT_BACKSPACE          3
10633 #define TEXT_NEWLINE            4
10634 #define TEXT_END                5
10635 #define TEXT_QUERY_TYPING       6
10636
10637 static int DrawLevelText(int sx, int sy, char letter, int mode)
10638 {
10639   static short delete_buffer[MAX_LEV_FIELDX];
10640   static int start_sx;
10641   static int last_sx, last_sy;
10642   static boolean typing = FALSE;
10643   int letter_element = EL_CHAR_ASCII0 + letter;
10644   int lx = 0, ly = 0;
10645
10646   /* map lower case letters to upper case and convert special characters */
10647   if (letter >= 'a' && letter <= 'z')
10648     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
10649   else if (letter == CHAR_BYTE_UMLAUT_a || letter == CHAR_BYTE_UMLAUT_A)
10650     letter_element = EL_CHAR_AUMLAUT;
10651   else if (letter == CHAR_BYTE_UMLAUT_o || letter == CHAR_BYTE_UMLAUT_O)
10652     letter_element = EL_CHAR_OUMLAUT;
10653   else if (letter == CHAR_BYTE_UMLAUT_u || letter == CHAR_BYTE_UMLAUT_U)
10654     letter_element = EL_CHAR_UUMLAUT;
10655   else if (letter == '^')
10656     letter_element = EL_CHAR_COPYRIGHT;
10657   else
10658     letter_element = EL_CHAR_ASCII0 + letter;
10659
10660   if (mode != TEXT_INIT)
10661   {
10662     if (!typing)
10663       return FALSE;
10664
10665     if (mode != TEXT_SETCURSOR)
10666     {
10667       sx = last_sx;
10668       sy = last_sy;
10669     }
10670
10671     lx = last_sx + level_xpos;
10672     ly = last_sy + level_ypos;
10673   }
10674
10675   switch (mode)
10676   {
10677     case TEXT_INIT:
10678       if (typing)
10679         DrawLevelText(0, 0, 0, TEXT_END);
10680
10681       typing = TRUE;
10682       start_sx = sx;
10683       last_sx = sx;
10684       last_sy = sy;
10685       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
10686       break;
10687
10688     case TEXT_SETCURSOR:
10689       DrawEditorElement(last_sx, last_sy, Feld[lx][ly]);
10690       DrawAreaBorder(sx, sy, sx, sy);
10691       last_sx = sx;
10692       last_sy = sy;
10693       break;
10694
10695     case TEXT_WRITECHAR:
10696       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
10697       {
10698         if (new_element1 >= EL_STEEL_CHAR_START &&
10699             new_element1 <= EL_STEEL_CHAR_END)
10700           letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
10701
10702         delete_buffer[sx - start_sx] = Feld[lx][ly];
10703         Feld[lx][ly] = letter_element;
10704
10705         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
10706           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
10707         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
10708           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10709         else
10710           DrawLevelText(0, 0, 0, TEXT_END);
10711
10712         level.changed = TRUE;
10713       }
10714       break;
10715
10716     case TEXT_BACKSPACE:
10717       if (sx > start_sx)
10718       {
10719         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
10720         DrawEditorElement(sx - 1, sy, Feld[lx - 1][ly]);
10721         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
10722       }
10723       break;
10724
10725     case TEXT_NEWLINE:
10726       if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
10727         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
10728       else
10729         DrawLevelText(0, 0, 0, TEXT_END);
10730       break;
10731
10732     case TEXT_END:
10733       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10734       DrawEditorElement(sx, sy, Feld[lx][ly]);
10735       typing = FALSE;
10736       break;
10737
10738     case TEXT_QUERY_TYPING:
10739       break;
10740
10741     default:
10742       break;
10743   }
10744
10745   return typing;
10746 }
10747
10748 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
10749                           int element, boolean change_level)
10750 {
10751   int lx = sx + level_xpos;
10752   int ly = sy + level_ypos;
10753
10754   if (element == -1)
10755     DrawEditorElement(sx, sy, Feld[lx][ly]);
10756   else
10757     DrawAreaBorder(sx, sy, sx, sy);
10758 }
10759
10760 static void CheckLevelBorderElement(boolean redraw_playfield)
10761 {
10762   int last_border_element = BorderElement;
10763
10764   SetBorderElement();
10765
10766   if (redraw_playfield && BorderElement != last_border_element)
10767     DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10768 }
10769
10770 static void CopyLevelToUndoBuffer(int mode)
10771 {
10772   static boolean accumulated_undo = FALSE;
10773   boolean new_undo_buffer_position = TRUE;
10774   int x, y;
10775
10776   if (undo_buffer_steps == 0)
10777     accumulated_undo = FALSE;
10778
10779   switch (mode)
10780   {
10781     case UNDO_IMMEDIATE:
10782       accumulated_undo = FALSE;
10783       break;
10784
10785     case UNDO_ACCUMULATE:
10786       if (accumulated_undo)
10787         new_undo_buffer_position = FALSE;
10788       accumulated_undo = TRUE;
10789       break;
10790
10791     default:
10792       break;
10793   }
10794
10795   if (new_undo_buffer_position)
10796   {
10797     /* advance position in undo buffer ring */
10798     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
10799
10800     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
10801       undo_buffer_steps++;
10802   }
10803
10804   /* always reset redo buffer when storing level change into undo buffer */
10805   redo_buffer_steps = 0;
10806
10807   for (x = 0; x < lev_fieldx; x++)
10808     for (y = 0; y < lev_fieldy; y++)
10809       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
10810
10811   /* check if drawing operation forces change of border style */
10812   CheckLevelBorderElement(TRUE);
10813
10814   level.changed = TRUE;
10815 }
10816
10817 static void RandomPlacement(int new_element)
10818 {
10819   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
10820   int num_free_positions = 0;
10821   int num_percentage, num_elements;
10822   int x, y;
10823
10824   ResetIntelliDraw();
10825
10826   /* determine number of free positions for randomly placing the new element */
10827   for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
10828   {
10829     free_position[x][y] =
10830       (random_placement_background_restricted ?
10831        Feld[x][y] == random_placement_background_element :
10832        Feld[x][y] != new_element);
10833
10834     if (free_position[x][y])
10835       num_free_positions++;
10836   }
10837
10838   /* determine number of new elements to place there */
10839   num_percentage = num_free_positions * random_placement_value / 100;
10840   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
10841                   num_percentage : random_placement_value);
10842
10843   /* if less free positions than elements to place, fill all these positions */
10844   if (num_free_positions < num_elements)
10845   {
10846     for (x = 0; x < lev_fieldx; x++)
10847       for (y = 0; y < lev_fieldy; y++)
10848         if (free_position[x][y])
10849           SetElement(x, y, new_element);
10850   }
10851   else
10852   {
10853     while (num_elements > 0)
10854     {
10855       x = GetSimpleRandom(lev_fieldx);
10856       y = GetSimpleRandom(lev_fieldy);
10857
10858       /* don't place element at the same position twice */
10859       if (free_position[x][y])
10860       {
10861         free_position[x][y] = FALSE;
10862         SetElement(x, y, new_element);
10863         num_elements--;
10864       }
10865     }
10866   }
10867
10868   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10869   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10870 }
10871
10872 void WrapLevel(int dx, int dy)
10873 {
10874   int wrap_dx = lev_fieldx - dx;
10875   int wrap_dy = lev_fieldy - dy;
10876   int x, y;
10877
10878   for (x = 0; x < lev_fieldx; x++)
10879     for (y = 0; y < lev_fieldy; y++)
10880       FieldBackup[x][y] = Feld[x][y];
10881
10882   for (x = 0; x < lev_fieldx; x++)
10883     for (y = 0; y < lev_fieldy; y++)
10884       Feld[x][y] =
10885         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
10886
10887   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
10888   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
10889 }
10890
10891 static void HandleDrawingAreas(struct GadgetInfo *gi)
10892 {
10893   static boolean started_inside_drawing_area = FALSE;
10894   int id = gi->custom_id;
10895   boolean button_press_event;
10896   boolean button_release_event;
10897   boolean inside_drawing_area = !gi->event.off_borders;
10898   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
10899   int actual_drawing_function;
10900   int button = gi->event.button;
10901   int new_element = BUTTON_ELEMENT(button);
10902   int sx = gi->event.x, sy = gi->event.y;
10903   int min_sx = 0, min_sy = 0;
10904   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
10905   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
10906   int lx = 0, ly = 0;
10907   int min_lx = 0, min_ly = 0;
10908   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
10909   int x, y;
10910
10911   /* handle info callback for each invocation of action callback */
10912   gi->callback_info(gi);
10913
10914   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
10915   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
10916
10917   /* make sure to stay inside drawing area boundaries */
10918   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
10919   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
10920
10921   if (draw_level)
10922   {
10923     /* get positions inside level field */
10924     lx = sx + level_xpos;
10925     ly = sy + level_ypos;
10926
10927     if (!IN_LEV_FIELD(lx, ly))
10928       inside_drawing_area = FALSE;
10929
10930     /* make sure to stay inside level field boundaries */
10931     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
10932     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
10933
10934     /* correct drawing area positions accordingly */
10935     sx = lx - level_xpos;
10936     sy = ly - level_ypos;
10937   }
10938
10939   if (button_press_event)
10940     started_inside_drawing_area = inside_drawing_area;
10941
10942   if (!started_inside_drawing_area)
10943     return;
10944
10945   if (!IS_VALID_BUTTON(button))
10946     return;
10947
10948   if (!button && !button_release_event)
10949     return;
10950
10951   /* automatically switch to 'single item' drawing mode, if needed */
10952   actual_drawing_function =
10953     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
10954      drawing_function : GADGET_ID_SINGLE_ITEMS);
10955
10956   /* clicking into drawing area with pressed Control key picks element */
10957   if (GetKeyModState() & KMOD_Control)
10958   {
10959     last_drawing_function = drawing_function;
10960     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
10961   }
10962
10963   if (GetKeyModState() & KMOD_Shift)
10964   {
10965     if (button_press_event || button_release_event)
10966       ResetIntelliDraw();
10967   }
10968
10969   switch (actual_drawing_function)
10970   {
10971     case GADGET_ID_SINGLE_ITEMS:
10972       if (draw_level)
10973       {
10974         if (button_release_event)
10975         {
10976           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
10977
10978           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
10979               !inside_drawing_area)
10980             DeleteBrushFromCursor();
10981         }
10982
10983         if (!button || button_release_event)
10984           break;
10985
10986         if (draw_with_brush)
10987         {
10988           CopyBrushToLevel(sx, sy, button);
10989         }
10990         else
10991         {
10992           if (new_element == EL_PLAYER_1)
10993           {
10994             /* remove player at old position */
10995             for (y = 0; y < lev_fieldy; y++)
10996               for (x = 0; x < lev_fieldx; x++)
10997                 if (Feld[x][y] == EL_PLAYER_1)
10998                   SetElement(x, y, EL_EMPTY);
10999           }
11000
11001           SetElementButton(lx, ly, new_element, button);
11002         }
11003       }
11004       else
11005       {
11006         int type_id = gi->custom_type_id;
11007         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
11008
11009         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
11010           DrawMiniGraphicExt(drawto,
11011                              gi->x + sx * MINI_TILEX,
11012                              gi->y + sy * MINI_TILEY,
11013                              el2edimg(new_element));
11014         else
11015           DrawFixedGraphicExt(drawto,
11016                               gi->x + sx * TILEX,
11017                               gi->y + sy * TILEY,
11018                               el2edimg(new_element), 0);
11019
11020         if (id == GADGET_ID_CUSTOM_GRAPHIC)
11021           new_element = GFX_ELEMENT(new_element);
11022
11023         drawingarea_info[type_id].value[pos] = new_element;
11024
11025         CopyElementPropertiesToGame(properties_element);
11026
11027         if (id == GADGET_ID_CUSTOM_GRAPHIC)
11028         {
11029           UpdateCustomElementGraphicGadgets();
11030
11031           FrameCounter = 0;     /* restart animation frame counter */
11032         }
11033       }
11034       break;
11035
11036     case GADGET_ID_CONNECTED_ITEMS:
11037       {
11038         static int last_sx = -1;
11039         static int last_sy = -1;
11040
11041         if (button_release_event)
11042           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11043
11044         if (button)
11045         {
11046           if (!button_press_event)
11047             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
11048
11049           last_sx = sx;
11050           last_sy = sy;
11051         }
11052       }
11053       break;
11054
11055     case GADGET_ID_LINE:
11056     case GADGET_ID_ARC:
11057     case GADGET_ID_RECTANGLE:
11058     case GADGET_ID_FILLED_BOX:
11059     case GADGET_ID_GRAB_BRUSH:
11060     case GADGET_ID_TEXT:
11061       {
11062         static int last_sx = -1;
11063         static int last_sy = -1;
11064         static int start_sx = -1;
11065         static int start_sy = -1;
11066         void (*draw_func)(int, int, int, int, int, boolean);
11067
11068         if (drawing_function == GADGET_ID_LINE)
11069           draw_func = DrawLine;
11070         else if (drawing_function == GADGET_ID_ARC)
11071           draw_func = DrawArc;
11072         else if (drawing_function == GADGET_ID_RECTANGLE)
11073           draw_func = DrawBox;
11074         else if (drawing_function == GADGET_ID_FILLED_BOX)
11075           draw_func = DrawFilledBox;
11076         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
11077           draw_func = SelectArea;
11078         else /* (drawing_function == GADGET_ID_TEXT) */
11079           draw_func = SetTextCursor;
11080
11081         if (button_press_event)
11082         {
11083           draw_func(sx, sy, sx, sy, new_element, FALSE);
11084           start_sx = last_sx = sx;
11085           start_sy = last_sy = sy;
11086
11087           if (drawing_function == GADGET_ID_TEXT)
11088             DrawLevelText(0, 0, 0, TEXT_END);
11089         }
11090         else if (button_release_event)
11091         {
11092           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
11093           if (drawing_function == GADGET_ID_GRAB_BRUSH)
11094           {
11095             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
11096             CopyBrushToCursor(sx, sy);
11097             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
11098                           MB_LEFTBUTTON);
11099             draw_with_brush = TRUE;
11100           }
11101           else if (drawing_function == GADGET_ID_TEXT)
11102             DrawLevelText(sx, sy, 0, TEXT_INIT);
11103           else
11104             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11105         }
11106         else if (last_sx != sx || last_sy != sy)
11107         {
11108           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
11109           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
11110           last_sx = sx;
11111           last_sy = sy;
11112         }
11113       }
11114       break;
11115
11116     case GADGET_ID_FLOOD_FILL:
11117       if (button_press_event && Feld[lx][ly] != new_element)
11118       {
11119         FloodFill(lx, ly, new_element);
11120         DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11121         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
11122       }
11123       break;
11124
11125     case GADGET_ID_PICK_ELEMENT:
11126       if (button_release_event)
11127         ClickOnGadget(level_editor_gadget[last_drawing_function],
11128                       MB_LEFTBUTTON);
11129       else if (draw_level)
11130         PickDrawingElement(button, Feld[lx][ly]);
11131       else
11132       {
11133         int type_id = gi->custom_type_id;
11134         int pos = sx * drawingarea_info[type_id].area_ysize + sy;
11135
11136         PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
11137       }
11138
11139       break;
11140
11141     default:
11142       break;
11143   }
11144 }
11145
11146 static void HandleCounterButtons(struct GadgetInfo *gi)
11147 {
11148   int gadget_id = gi->custom_id;
11149   int counter_id = gi->custom_type_id;
11150   int button = gi->event.button;
11151   int *counter_value = counterbutton_info[counter_id].value;
11152   int step = BUTTON_STEPSIZE(button) *
11153     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
11154
11155   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
11156   {
11157     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
11158     boolean released = (gi->event.type == GD_EVENT_RELEASED);
11159     boolean level_changed = LevelChanged();
11160
11161     if ((level_changed && pressed) || (!level_changed && released))
11162       return;
11163
11164     if (level_changed && !Request("Level has changed! Discard changes?",
11165                                   REQ_ASK))
11166     {
11167       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
11168         ModifyEditorCounterValue(counter_id, *counter_value);
11169
11170       return;
11171     }
11172   }
11173
11174   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
11175     *counter_value = gi->textinput.number_value;
11176   else
11177     ModifyEditorCounterValue(counter_id, *counter_value + step);
11178
11179   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
11180   {
11181       LoadLevel(level_nr);
11182       LoadScore(level_nr);
11183
11184       TapeErase();
11185
11186       ResetUndoBuffer();
11187       DrawEditModeWindow();
11188
11189       return;
11190   }
11191
11192   switch (counter_id)
11193   {
11194     case ED_COUNTER_ID_YAMYAM_CONTENT:
11195       DrawYamYamContentAreas();
11196       break;
11197
11198     case ED_COUNTER_ID_BALL_CONTENT:
11199       DrawMagicBallContentAreas();
11200       break;
11201
11202     case ED_COUNTER_ID_ANDROID_CONTENT:
11203       DrawAndroidElementArea(properties_element);
11204       break;
11205
11206     case ED_COUNTER_ID_GROUP_CONTENT:
11207       DrawGroupElementArea(properties_element);
11208       CopyGroupElementPropertiesToGame(properties_element);
11209       break;
11210
11211     case ED_COUNTER_ID_INVENTORY_SIZE:
11212       DrawPlayerInitialInventoryArea(properties_element);
11213       break;
11214
11215     case ED_COUNTER_ID_ENVELOPE_XSIZE:
11216     case ED_COUNTER_ID_ENVELOPE_YSIZE:
11217       DrawEnvelopeTextArea(-1);
11218       break;
11219
11220     case ED_COUNTER_ID_LEVEL_XSIZE:
11221     case ED_COUNTER_ID_LEVEL_YSIZE:
11222       lev_fieldx = level.fieldx;
11223       lev_fieldy = level.fieldy;
11224
11225       /* check if resizing of level results in change of border border */
11226       SetBorderElement();
11227
11228       break;
11229
11230     default:
11231       break;
11232   }
11233
11234   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
11235        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
11236       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
11237        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
11238     CopyElementPropertiesToGame(properties_element);
11239
11240   level.changed = TRUE;
11241 }
11242
11243 static void HandleTextInputGadgets(struct GadgetInfo *gi)
11244 {
11245   int type_id = gi->custom_type_id;
11246
11247   strcpy(textinput_info[type_id].value, gi->textinput.value);
11248
11249   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
11250   {
11251     CopyElementPropertiesToGame(properties_element);
11252
11253     ModifyEditorElementList();  /* update changed button info text */
11254   }
11255
11256   level.changed = TRUE;
11257 }
11258
11259 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
11260 {
11261   int type_id = gi->custom_type_id;
11262
11263   strncpy(textarea_info[type_id].value, gi->textarea.value,
11264           MAX_ENVELOPE_TEXT_LEN);
11265   textarea_info[type_id].value[MAX_ENVELOPE_TEXT_LEN] = '\0';
11266
11267   level.changed = TRUE;
11268 }
11269
11270 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
11271 {
11272   int type_id = gi->custom_type_id;
11273   int value_old = *selectbox_info[type_id].value;
11274   int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
11275
11276   *selectbox_info[type_id].value = value_new;
11277
11278   if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
11279   {
11280     element_info[properties_element].current_change_page = gi->selectbox.index;
11281
11282     DrawPropertiesWindow();
11283   }
11284   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
11285             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
11286            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
11287             type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
11288            (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
11289   {
11290     if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
11291     {
11292       /* when changing action type, also check action mode and action arg */
11293       if (value_old != value_new)
11294         setSelectboxSpecialActionVariablesIfNeeded();
11295
11296       DrawPropertiesChange();
11297     }
11298
11299     CopyElementPropertiesToGame(properties_element);
11300
11301     level.changed = TRUE;
11302   }
11303 }
11304
11305 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
11306 {
11307   int type_id = gi->custom_type_id;
11308   int i;
11309
11310   if (type_id >= ED_TEXTBUTTON_ID_LEVELINFO_FIRST &&
11311       type_id <= ED_TEXTBUTTON_ID_LEVELINFO_LAST)
11312   {
11313     edit_mode_levelinfo = gi->custom_type_id;
11314
11315     DrawLevelInfoWindow();
11316   }
11317   else if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST &&
11318            type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST)
11319   {
11320     edit_mode_properties = gi->custom_type_id;
11321
11322     DrawPropertiesWindow();
11323   }
11324   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
11325   {
11326     char *template_filename = getDefaultLevelFilename(-1);
11327     boolean new_template = !fileExists(template_filename);
11328
11329     /* backup original "level.field" (needed to track playfield changes) */
11330     CopyPlayfield(level.field, FieldBackup);
11331
11332     /* "SaveLevelTemplate()" uses "level.field", so copy editor playfield */
11333     CopyPlayfield(Feld, level.field);
11334
11335     if (new_template ||
11336         Request("Save this template and kill the old?", REQ_ASK))
11337       SaveLevelTemplate();
11338
11339     if (new_template)
11340       Request("Template saved!", REQ_CONFIRM);
11341
11342     /* restore original "level.field" (needed to track playfield changes) */
11343     CopyPlayfield(FieldBackup, level.field);
11344   }
11345   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
11346            custom_element.num_change_pages < MAX_CHANGE_PAGES)
11347   {
11348     struct ElementInfo *ei = &element_info[properties_element];
11349
11350     setElementChangePages(ei, ei->num_change_pages + 1);
11351
11352     /* set new change page to be new current change page */
11353     ei->current_change_page = ei->num_change_pages - 1;
11354     ei->change = &ei->change_page[ei->current_change_page];
11355
11356     setElementChangeInfoToDefaults(ei->change);
11357
11358     DrawPropertiesWindow();
11359
11360     level.changed = TRUE;
11361   }
11362   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
11363            custom_element.num_change_pages > MIN_CHANGE_PAGES)
11364   {
11365     struct ElementInfo *ei = &element_info[properties_element];
11366
11367     /* copy all change pages after change page to be deleted */
11368     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
11369       ei->change_page[i] = ei->change_page[i + 1];
11370
11371     setElementChangePages(ei, ei->num_change_pages - 1);
11372
11373     DrawPropertiesWindow();
11374
11375     level.changed = TRUE;
11376   }
11377 }
11378
11379 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
11380 {
11381   int type_id = gi->custom_type_id;
11382
11383   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
11384       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
11385   {
11386     struct ElementInfo *ei = &element_info[properties_element];
11387     int step = BUTTON_STEPSIZE(gi->event.button);
11388
11389     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
11390     ei->current_change_page += step;
11391
11392     if (ei->current_change_page < 0)
11393       ei->current_change_page = 0;
11394     else if (ei->current_change_page >= ei->num_change_pages)
11395       ei->current_change_page = ei->num_change_pages - 1;
11396
11397     DrawPropertiesWindow();
11398   }
11399   else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
11400            type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
11401   {
11402     struct ElementInfo *ei = &element_info[properties_element];
11403     int current_change_page = ei->current_change_page;
11404
11405     if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
11406       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
11407         ei->change_page[current_change_page];
11408     else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
11409     {
11410       ei->change_page[current_change_page] =
11411         element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
11412
11413       level.changed = TRUE;
11414     }
11415
11416     DrawPropertiesWindow();
11417   }
11418 }
11419
11420 static void HandleRadiobuttons(struct GadgetInfo *gi)
11421 {
11422   *radiobutton_info[gi->custom_type_id].value =
11423     radiobutton_info[gi->custom_type_id].checked_value;
11424
11425   level.changed = TRUE;
11426 }
11427
11428 static void HandleCheckbuttons(struct GadgetInfo *gi)
11429 {
11430   int type_id = gi->custom_type_id;
11431
11432   *checkbutton_info[type_id].value ^= TRUE;
11433
11434   if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
11435       type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
11436       type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
11437       (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
11438          type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
11439         (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
11440          type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
11441        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
11442   {
11443     CopyElementPropertiesToGame(properties_element);
11444   }
11445
11446   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
11447   {
11448     UpdateCustomElementGraphicGadgets();
11449   }
11450   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
11451   {
11452     char *template_filename = getDefaultLevelFilename(-1);
11453
11454     if (level.use_custom_template && !fileExists(template_filename))
11455     {
11456       Request("No level template found!", REQ_CONFIRM);
11457
11458       level.use_custom_template = FALSE;
11459       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
11460
11461       return;
11462     }
11463
11464     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
11465
11466     DrawEditModeWindow();
11467   }
11468
11469   level.changed = TRUE;
11470 }
11471
11472 static void HandleControlButtons(struct GadgetInfo *gi)
11473 {
11474   static int last_level_drawing_function = GADGET_ID_SINGLE_ITEMS;
11475   static int last_edit_mode = ED_MODE_DRAWING;
11476   static int last_custom_copy_mode = -1;
11477   int id = gi->custom_id;
11478   int button = gi->event.button;
11479   int step = BUTTON_STEPSIZE(button);
11480   int new_element = BUTTON_ELEMENT(button);
11481   int last_properties_element = properties_element;
11482   int x, y;
11483
11484   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
11485     DrawLevelText(0, 0, 0, TEXT_END);
11486
11487   if (id < ED_NUM_CTRL1_BUTTONS &&
11488       id != GADGET_ID_SINGLE_ITEMS &&
11489       id != GADGET_ID_PICK_ELEMENT &&
11490       edit_mode != ED_MODE_DRAWING &&
11491       drawing_function != GADGET_ID_PICK_ELEMENT &&
11492       !(GetKeyModState() & KMOD_Control))
11493   {
11494     DrawDrawingWindow();
11495     edit_mode = ED_MODE_DRAWING;
11496   }
11497
11498   /* element copy mode active, but no element button pressed => deactivate */
11499   if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
11500     last_custom_copy_mode = -1;
11501
11502   switch (id)
11503   {
11504     case GADGET_ID_SCROLL_LEFT:
11505       if (level_xpos >= 0)
11506       {
11507         if (lev_fieldx < ed_fieldx - 2)
11508           break;
11509
11510         level_xpos -= step;
11511         if (level_xpos < -1)
11512           level_xpos = -1;
11513         if (button == 1)
11514           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
11515         else
11516           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11517
11518         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
11519                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
11520       }
11521       break;
11522
11523     case GADGET_ID_SCROLL_RIGHT:
11524       if (level_xpos <= lev_fieldx - ed_fieldx)
11525       {
11526         if (lev_fieldx < ed_fieldx - 2)
11527           break;
11528
11529         level_xpos += step;
11530         if (level_xpos > lev_fieldx - ed_fieldx + 1)
11531           level_xpos = lev_fieldx - ed_fieldx + 1;
11532         if (button == 1)
11533           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
11534         else
11535           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11536
11537         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
11538                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
11539       }
11540       break;
11541
11542     case GADGET_ID_SCROLL_UP:
11543       if (level_ypos >= 0)
11544       {
11545         if (lev_fieldy < ed_fieldy - 2)
11546           break;
11547
11548         level_ypos -= step;
11549         if (level_ypos < -1)
11550           level_ypos = -1;
11551         if (button == 1)
11552           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
11553         else
11554           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11555
11556         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11557                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11558       }
11559       break;
11560
11561     case GADGET_ID_SCROLL_DOWN:
11562       if (level_ypos <= lev_fieldy - ed_fieldy)
11563       {
11564         if (lev_fieldy < ed_fieldy - 2)
11565           break;
11566
11567         level_ypos += step;
11568         if (level_ypos > lev_fieldy - ed_fieldy + 1)
11569           level_ypos = lev_fieldy - ed_fieldy + 1;
11570         if (button == 1)
11571           ScrollEditorLevel(level_xpos, level_ypos, ED_SCROLL_UP);
11572         else
11573           DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11574
11575         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
11576                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
11577       }
11578       break;
11579
11580     case GADGET_ID_SCROLL_HORIZONTAL:
11581       level_xpos = gi->event.item_position - 1;
11582
11583       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11584       BackToFront();
11585
11586       break;
11587
11588     case GADGET_ID_SCROLL_VERTICAL:
11589       level_ypos = gi->event.item_position - 1;
11590
11591       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11592       BackToFront();
11593
11594       break;
11595
11596     case GADGET_ID_SCROLL_LIST_UP:
11597     case GADGET_ID_SCROLL_LIST_DOWN:
11598     case GADGET_ID_SCROLL_LIST_VERTICAL:
11599       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
11600         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
11601       else
11602       {
11603         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
11604         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
11605
11606         if (element_shift < 0)
11607           element_shift = 0;
11608         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
11609           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
11610
11611         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
11612                      GDI_SCROLLBAR_ITEM_POSITION,
11613                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
11614       }
11615
11616       ModifyEditorElementList();
11617
11618       break;
11619
11620     case GADGET_ID_PROPERTIES:
11621       // always switch off element properties when they are already displayed
11622       last_properties_element = new_element;
11623     case GADGET_ID_ELEMENT_LEFT:
11624     case GADGET_ID_ELEMENT_MIDDLE:
11625     case GADGET_ID_ELEMENT_RIGHT:
11626       properties_element = (id == GADGET_ID_ELEMENT_LEFT   ? new_element1 :
11627                             id == GADGET_ID_ELEMENT_MIDDLE ? new_element2 :
11628                             id == GADGET_ID_ELEMENT_RIGHT  ? new_element3 :
11629                             new_element);
11630
11631       if (edit_mode != ED_MODE_PROPERTIES ||
11632           properties_element != last_properties_element)
11633       {
11634         DrawPropertiesWindow();
11635         edit_mode = ED_MODE_PROPERTIES;
11636
11637         last_level_drawing_function = drawing_function;
11638         ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
11639                       MB_LEFTBUTTON);
11640       }
11641       else
11642       {
11643         DrawDrawingWindow();
11644         edit_mode = ED_MODE_DRAWING;
11645
11646         ClickOnGadget(level_editor_gadget[last_level_drawing_function],
11647                       MB_LEFTBUTTON);
11648       }
11649       break;
11650
11651     case GADGET_ID_WRAP_LEFT:
11652       WrapLevel(-step, 0);
11653       break;
11654
11655     case GADGET_ID_WRAP_RIGHT:
11656       WrapLevel(step, 0);
11657       break;
11658
11659     case GADGET_ID_WRAP_UP:
11660       WrapLevel(0, -step);
11661       break;
11662
11663     case GADGET_ID_WRAP_DOWN:
11664       WrapLevel(0, step);
11665       break;
11666
11667     case GADGET_ID_SINGLE_ITEMS:
11668     case GADGET_ID_CONNECTED_ITEMS:
11669     case GADGET_ID_LINE:
11670     case GADGET_ID_ARC:
11671     case GADGET_ID_TEXT:
11672     case GADGET_ID_RECTANGLE:
11673     case GADGET_ID_FILLED_BOX:
11674     case GADGET_ID_FLOOD_FILL:
11675     case GADGET_ID_GRAB_BRUSH:
11676     case GADGET_ID_PICK_ELEMENT:
11677       if (drawing_function != GADGET_ID_PICK_ELEMENT)
11678         last_drawing_function = drawing_function;
11679       drawing_function = id;
11680       draw_with_brush = FALSE;
11681       break;
11682
11683     case GADGET_ID_RANDOM_PLACEMENT:
11684       RandomPlacement(new_element);
11685       break;
11686
11687     case GADGET_ID_ZOOM:
11688       // zoom level editor tile size in or out (or reset to default size)
11689       ed_tilesize = (button == 1 ? ed_tilesize * 2 :
11690                      button == 2 ? DEFAULT_EDITOR_TILESIZE :
11691                      button == 3 ? ed_tilesize / 2 : ed_tilesize);
11692
11693       // limit zoom level by upper and lower bound
11694       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
11695
11696       InitZoomLevelSettings();
11697
11698       if (edit_mode == ED_MODE_DRAWING)
11699         DrawDrawingWindow();
11700
11701       break;
11702
11703     case GADGET_ID_CUSTOM_COPY_FROM:
11704     case GADGET_ID_CUSTOM_COPY_TO:
11705     case GADGET_ID_CUSTOM_EXCHANGE:
11706       last_custom_copy_mode = id;
11707       last_drawing_function = drawing_function;
11708       break;
11709
11710     case GADGET_ID_CUSTOM_COPY:
11711       CopyCustomElement(properties_element, -1, id);
11712       break;
11713
11714     case GADGET_ID_CUSTOM_PASTE:
11715       CopyCustomElement(-1, properties_element, id);
11716       break;
11717
11718     case GADGET_ID_UNDO:
11719       if (button == 1 && undo_buffer_steps == 0)
11720       {
11721         Request("Undo buffer empty!", REQ_CONFIRM);
11722
11723         break;
11724       }
11725       else if (button == 2)
11726       {
11727         break;
11728       }
11729       else if (button == 3 && redo_buffer_steps == 0)
11730       {
11731         Request("Redo buffer empty!", REQ_CONFIRM);
11732
11733         break;
11734       }
11735
11736       if (edit_mode != ED_MODE_DRAWING)
11737       {
11738         DrawDrawingWindow();
11739         edit_mode = ED_MODE_DRAWING;
11740       }
11741
11742       if (button == 1)
11743       {
11744         /* undo */
11745
11746         undo_buffer_position =
11747           (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
11748
11749         undo_buffer_steps--;
11750         redo_buffer_steps++;
11751       }
11752       else
11753       {
11754         /* redo */
11755
11756         undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
11757
11758         undo_buffer_steps++;
11759         redo_buffer_steps--;
11760       }
11761
11762       for (x = 0; x < lev_fieldx; x++)
11763         for (y = 0; y < lev_fieldy; y++)
11764           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
11765
11766       /* check if undo operation forces change of border style */
11767       CheckLevelBorderElement(FALSE);
11768
11769       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11770
11771       break;
11772
11773     case GADGET_ID_INFO:
11774       if (edit_mode != ED_MODE_INFO)
11775       {
11776         last_edit_mode = edit_mode;
11777         edit_mode = ED_MODE_INFO;
11778
11779         DrawLevelInfoWindow();
11780       }
11781       else
11782       {
11783         edit_mode = last_edit_mode;
11784
11785         DrawEditModeWindow();
11786       }
11787       break;
11788
11789     case GADGET_ID_CLEAR:
11790       if (edit_mode != ED_MODE_DRAWING)
11791       {
11792         DrawDrawingWindow();
11793         edit_mode = ED_MODE_DRAWING;
11794       }
11795
11796       for (x = 0; x < MAX_LEV_FIELDX; x++) 
11797         for (y = 0; y < MAX_LEV_FIELDY; y++) 
11798           Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
11799
11800       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
11801
11802       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
11803       break;
11804
11805     case GADGET_ID_SAVE:
11806     {
11807       /* saving read-only levels into personal level set modifies global vars
11808          "leveldir_current" and "level_nr"; restore them after saving level */
11809       LevelDirTree *leveldir_former = leveldir_current;
11810       int level_nr_former = level_nr;
11811       char *level_filename;
11812       boolean new_level;
11813
11814       if (leveldir_current->readonly &&
11815           !PrepareSavingIntoPersonalLevelSet())
11816         break;
11817
11818       level_filename = getDefaultLevelFilename(level_nr);
11819       new_level = !fileExists(level_filename);
11820
11821       if (new_level ||
11822           Request("Save this level and kill the old?", REQ_ASK))
11823       {
11824         if (leveldir_former->readonly)
11825           ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
11826
11827         CopyPlayfield(Feld, level.field);
11828         SaveLevel(level_nr);
11829
11830         level.changed = FALSE;
11831
11832         if (new_level)
11833         {
11834           char level_saved_msg[64];
11835
11836           if (leveldir_former->readonly)
11837             sprintf(level_saved_msg,
11838                     "Level saved as level %d into personal level set!",
11839                     level_nr);
11840           else
11841             strcpy(level_saved_msg, "Level saved!");
11842
11843           Request(level_saved_msg, REQ_CONFIRM);
11844         }
11845       }
11846
11847       /* "cd" back to copied-from levelset (in case of saved read-only level) */
11848       leveldir_current = leveldir_former;
11849       level_nr = level_nr_former;
11850
11851       break;
11852     }
11853
11854     case GADGET_ID_TEST:
11855       if (LevelChanged())
11856         level.game_version = GAME_VERSION_ACTUAL;
11857
11858       CopyPlayfield(level.field, FieldBackup);
11859       CopyPlayfield(Feld, level.field);
11860
11861       CopyNativeLevel_RND_to_Native(&level);
11862
11863       UnmapLevelEditorGadgets();
11864       UndrawSpecialEditorDoor();
11865
11866       CloseDoor(DOOR_CLOSE_ALL);
11867
11868       /* needed before playing if editor playfield area has different size */
11869       ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
11870
11871       // redraw_mask = REDRAW_ALL;
11872
11873       level_editor_test_game = TRUE;
11874
11875       StartGameActions(FALSE, setup.autorecord, level.random_seed);
11876
11877       break;
11878
11879     case GADGET_ID_EXIT:
11880       RequestExitLevelEditor(TRUE, FALSE);  /* if level has changed, ask user */
11881       break;
11882
11883     default:
11884       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
11885           id <= GADGET_ID_ELEMENTLIST_LAST)
11886       {
11887         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
11888         int new_element = editor_elements[element_position + element_shift];
11889
11890         if (IS_EDITOR_CASCADE(new_element))
11891         {
11892           int i;
11893
11894           for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
11895           {
11896             int *cascade_element= &(*editor_elements_info[i].headline_list)[0];
11897             boolean *cascade_value=editor_elements_info[i].setup_cascade_value;
11898
11899             if (*cascade_element == new_element)
11900             {
11901               *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
11902               *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
11903
11904               /* update element selection list */
11905               ReinitializeElementList();
11906               ModifyEditorElementList();
11907
11908               /* update cascading gadget info text */
11909               PrintEditorGadgetInfoText(level_editor_gadget[id]);
11910
11911               /* save current editor cascading state */
11912               SaveSetup_EditorCascade();
11913
11914               break;
11915             }
11916           }
11917
11918           break;
11919         }
11920
11921         if (last_custom_copy_mode != -1)
11922         {
11923           if (CopyCustomElement(properties_element, new_element,
11924                                 last_custom_copy_mode))
11925           {
11926             ClickOnGadget(level_editor_gadget[last_drawing_function],
11927                           MB_LEFTBUTTON);
11928
11929             last_custom_copy_mode = -1;
11930           }
11931
11932           break;
11933         }
11934
11935         PickDrawingElement(button, new_element);
11936
11937         if (!stick_element_properties_window &&
11938             drawing_function != GADGET_ID_PICK_ELEMENT &&
11939             !(GetKeyModState() & KMOD_Control))
11940         {
11941           properties_element = new_element;
11942           if (edit_mode == ED_MODE_PROPERTIES)
11943             DrawPropertiesWindow();
11944         }
11945
11946         if (drawing_function == GADGET_ID_PICK_ELEMENT)
11947           ClickOnGadget(level_editor_gadget[last_drawing_function],
11948                         MB_LEFTBUTTON);
11949       }
11950 #ifdef DEBUG
11951       else if (gi->event.type == GD_EVENT_PRESSED)
11952         printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
11953       else if (gi->event.type == GD_EVENT_RELEASED)
11954         printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
11955       else if (gi->event.type == GD_EVENT_MOVING)
11956         printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
11957       else
11958         printf("default: HandleControlButtons: ? (id == %d)\n", id);
11959 #endif
11960       break;
11961   }
11962 }
11963
11964 void HandleLevelEditorKeyInput(Key key)
11965 {
11966   char letter = getCharFromKey(key);
11967   int button = MB_LEFTBUTTON;
11968
11969   if (drawing_function == GADGET_ID_TEXT &&
11970       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
11971   {
11972     if (letter)
11973       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
11974     else if (key == KSYM_Delete || key == KSYM_BackSpace)
11975       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
11976     else if (key == KSYM_Return)
11977       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
11978     else if (key == KSYM_Escape)
11979       DrawLevelText(0, 0, 0, TEXT_END);
11980   }
11981   else if (button_status == MB_RELEASED)
11982   {
11983     int id = GADGET_ID_NONE;
11984     int new_element_shift = element_shift;
11985     int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
11986     int i;
11987
11988     switch (key)
11989     {
11990       case KSYM_Left:
11991         id = GADGET_ID_SCROLL_LEFT;
11992         break;
11993       case KSYM_Right:
11994         id = GADGET_ID_SCROLL_RIGHT;
11995         break;
11996       case KSYM_Up:
11997         id = GADGET_ID_SCROLL_UP;
11998         break;
11999       case KSYM_Down:
12000         id = GADGET_ID_SCROLL_DOWN;
12001         break;
12002
12003       case KSYM_Page_Up:
12004       case KSYM_Page_Down:
12005         step *= (key == KSYM_Page_Up ? -1 : +1);
12006         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
12007
12008         if (element_shift < 0)
12009           element_shift = 0;
12010         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
12011           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
12012
12013         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12014                      GDI_SCROLLBAR_ITEM_POSITION,
12015                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12016
12017         ModifyEditorElementList();
12018
12019         break;
12020
12021       case KSYM_Home:
12022       case KSYM_End:
12023         element_shift = (key == KSYM_Home ? 0 :
12024                          num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
12025
12026         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12027                      GDI_SCROLLBAR_ITEM_POSITION,
12028                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12029
12030         ModifyEditorElementList();
12031
12032         break;
12033
12034       case KSYM_Insert:
12035       case KSYM_Delete:
12036
12037         /* this is needed to prevent interference with running "True X-Mouse" */
12038         if (GetKeyModStateFromEvents() & KMOD_Control)
12039           break;
12040
12041         /* check for last or next editor cascade block in element list */
12042         for (i = 0; i < num_editor_elements; i++)
12043         {
12044           if ((key == KSYM_Insert && i == element_shift) ||
12045               (key == KSYM_Delete && new_element_shift > element_shift))
12046             break;
12047
12048           /* jump to next cascade block (or to start of element list) */
12049           if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
12050             new_element_shift = i;
12051         }
12052
12053         if (i < num_editor_elements)
12054           element_shift = new_element_shift;
12055
12056         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
12057           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
12058
12059         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
12060                      GDI_SCROLLBAR_ITEM_POSITION,
12061                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
12062
12063         ModifyEditorElementList();
12064
12065         break;
12066
12067       case KSYM_Escape:
12068         if (edit_mode == ED_MODE_DRAWING)
12069         {
12070           RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
12071         }
12072         else if (edit_mode == ED_MODE_INFO)
12073         {
12074           HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
12075         }
12076         else if (edit_mode == ED_MODE_PROPERTIES)
12077         {
12078           HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
12079         }
12080         else            /* should never happen */
12081         {
12082           DrawDrawingWindow();
12083           edit_mode = ED_MODE_DRAWING;
12084         }
12085
12086         break;
12087
12088       default:
12089         break;
12090     }
12091
12092     if (id != GADGET_ID_NONE)
12093       ClickOnGadget(level_editor_gadget[id], button);
12094     else if (letter >= '1' && letter <= '3')
12095       ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], letter - '0');
12096     else if (letter == '?')
12097       ClickOnGadget(level_editor_gadget[GADGET_ID_PROPERTIES], button);
12098     else if (letter == '.')
12099       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
12100     else if (letter == 'U')
12101       ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
12102     else if (letter == '-' || key == KSYM_KP_Subtract)
12103       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
12104     else if (letter == '0' || key == KSYM_KP_0)
12105       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
12106     else if (letter == '+' || key == KSYM_KP_Add ||
12107              letter == '=')     // ("Shift-=" is "+" on US keyboards)
12108       ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
12109     else if (key == KSYM_Return ||
12110              key == KSYM_space ||
12111              key == setup.shortcut.toggle_pause)
12112       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
12113     else
12114       for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
12115         if (letter && letter == controlbutton_info[i].shortcut)
12116           if (!anyTextGadgetActive())
12117             ClickOnGadget(level_editor_gadget[i], button);
12118   }
12119 }
12120
12121 void HandleLevelEditorIdle()
12122 {
12123   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
12124   int x = editor.settings.element_graphic.x + element_border;
12125   int y = editor.settings.element_graphic.y + element_border;
12126   static unsigned int action_delay = 0;
12127   unsigned int action_delay_value = GameFrameDelay;
12128   int i;
12129
12130   if (edit_mode != ED_MODE_PROPERTIES)
12131     return;
12132
12133   if (!DelayReached(&action_delay, action_delay_value))
12134     return;
12135
12136   for (i = 0; i < ED_NUM_SELECTBOX; i++)
12137   {
12138     struct GadgetInfo *gi = level_editor_gadget[selectbox_info[i].gadget_id];
12139
12140     if (gi->mapped && gi->active && gi->selectbox.open)
12141       return;
12142   }
12143
12144   DrawEditorElementAnimation(SX + x, SY + y);
12145
12146   redraw_mask |= REDRAW_FIELD;
12147
12148   FrameCounter++;       /* increase animation frame counter */
12149 }
12150
12151 void ClearEditorGadgetInfoText()
12152 {
12153   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
12154 }
12155
12156 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
12157 {
12158   char infotext[MAX_OUTPUT_LINESIZE + 1];
12159   char shortcut[MAX_OUTPUT_LINESIZE + 1];
12160   int max_infotext_len = getMaxInfoTextLength();
12161
12162   if (gi == NULL || strlen(gi->info_text) == 0)
12163     return;
12164
12165   strncpy(infotext, gi->info_text, max_infotext_len);
12166   infotext[max_infotext_len] = '\0';
12167
12168   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
12169   {
12170     int key = controlbutton_info[gi->custom_id].shortcut;
12171
12172     if (key)
12173     {
12174       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
12175         sprintf(shortcut, " ('.' or '%c')", key);
12176       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
12177         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
12178       else if (gi->custom_id == GADGET_ID_TEST)
12179         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
12180       else if (gi->custom_id == GADGET_ID_UNDO)
12181         sprintf(shortcut, " ('%c/Shift-U')", key);
12182       else if (gi->custom_id == GADGET_ID_ZOOM)
12183         sprintf(shortcut, " ('%c', '0', '+')", key);
12184       else
12185         sprintf(shortcut, " ('%s%c')",
12186                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
12187
12188       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
12189         strcat(infotext, shortcut);
12190     }
12191   }
12192
12193   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, INFOTEXT_FONT);
12194 }
12195
12196 void HandleEditorGadgetInfoText(void *ptr)
12197 {
12198   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
12199
12200   if (game_status != GAME_MODE_EDITOR)
12201     return;
12202
12203   ClearEditorGadgetInfoText();
12204
12205   if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
12206     return;
12207
12208   /* misuse this function to delete brush cursor, if needed */
12209   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
12210     DeleteBrushFromCursor();
12211
12212   PrintEditorGadgetInfoText(gi);
12213 }
12214
12215 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
12216 {
12217   static int start_lx, start_ly;
12218   int id = gi->custom_id;
12219   int type_id = gi->custom_type_id;
12220   int sx = gi->event.x;
12221   int sy = gi->event.y;
12222   int lx = sx + level_xpos;
12223   int ly = sy + level_ypos;
12224   int min_sx = 0, min_sy = 0;
12225   int max_sx = gi->drawing.area_xsize - 1;
12226   int max_sy = gi->drawing.area_ysize - 1;
12227   int actual_drawing_function = drawing_function;
12228   int max_infotext_len = getMaxInfoTextLength();
12229   char infotext[MAX_OUTPUT_LINESIZE + 1];
12230   char *text;
12231
12232   infotext[0] = '\0';           /* start with empty info text */
12233
12234   /* pressed Control key: simulate picking element */
12235   if (GetKeyModState() & KMOD_Control)
12236     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
12237
12238   ClearEditorGadgetInfoText();
12239
12240   if (gi->event.type == GD_EVENT_INFO_LEAVING)
12241     return;
12242
12243   /* make sure to stay inside drawing area boundaries */
12244   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
12245   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
12246
12247   if (id == GADGET_ID_DRAWING_LEVEL)
12248   {
12249     if (button_status)
12250     {
12251       int min_lx = 0, min_ly = 0;
12252       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
12253
12254       /* get positions inside level field */
12255       lx = sx + level_xpos;
12256       ly = sy + level_ypos;
12257
12258       /* make sure to stay inside level field boundaries */
12259       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
12260       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
12261
12262       /* correct drawing area positions accordingly */
12263       sx = lx - level_xpos;
12264       sy = ly - level_ypos;
12265     }
12266
12267     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
12268     {
12269       if (button_status)        /* if (gi->state == GD_BUTTON_PRESSED) */
12270       {
12271         if (gi->event.type == GD_EVENT_PRESSED)
12272         {
12273           start_lx = lx;
12274           start_ly = ly;
12275         }
12276
12277         switch (actual_drawing_function)
12278         {
12279           case GADGET_ID_SINGLE_ITEMS:
12280             text = "Drawing single items";
12281             break;
12282           case GADGET_ID_CONNECTED_ITEMS:
12283             text = "Drawing connected items";
12284             break;
12285           case GADGET_ID_LINE:
12286             text = "Drawing line";
12287             break;
12288           case GADGET_ID_ARC:
12289             text = "Drawing arc";
12290             break;
12291           case GADGET_ID_TEXT:
12292             text = "Setting text cursor";
12293             break;
12294           case GADGET_ID_RECTANGLE:
12295             text = "Drawing rectangle";
12296             break;
12297           case GADGET_ID_FILLED_BOX:
12298             text = "Drawing filled box";
12299             break;
12300           case GADGET_ID_FLOOD_FILL:
12301             text = "Flood fill";
12302             break;
12303           case GADGET_ID_GRAB_BRUSH:
12304             text = "Grabbing brush";
12305             break;
12306           case GADGET_ID_PICK_ELEMENT:
12307             text = "Picking element";
12308             break;
12309
12310           default:
12311             text = "Drawing position";
12312             break;
12313         }
12314
12315         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12316           sprintf(infotext, "%s: %d, %d", text, lx, ly);
12317         else
12318           sprintf(infotext, "%s: %d, %d", text,
12319                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
12320       }
12321       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12322         strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
12323       else
12324         sprintf(infotext, "Level position: %d, %d", lx, ly);
12325     }
12326
12327     /* misuse this function to draw brush cursor, if needed */
12328     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
12329     {
12330       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
12331         CopyBrushToCursor(sx, sy);
12332       else
12333         DeleteBrushFromCursor();
12334     }
12335   }
12336   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
12337   {
12338     int pos = sx * drawingarea_info[type_id].area_ysize + sy;
12339     int element = drawingarea_info[type_id].value[pos];
12340
12341     strncpy(infotext, getElementInfoText(element), max_infotext_len);
12342   }
12343   else
12344   {
12345     if (id == GADGET_ID_CUSTOM_CONTENT)
12346       sprintf(infotext, "custom element content position: %d, %d", sx, sy);
12347     else if (id == GADGET_ID_GROUP_CONTENT)
12348       sprintf(infotext, "group element position: %d", sx + 1);
12349     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
12350              id <= GADGET_ID_YAMYAM_CONTENT_7)
12351       sprintf(infotext, "content area %d position: %d, %d",
12352               id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
12353     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
12354              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
12355       sprintf(infotext, "content area %d position: %d, %d",
12356               id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
12357     else if (id == GADGET_ID_ANDROID_CONTENT)
12358       sprintf(infotext, "android element position: %d", sx + 1);
12359     else if (drawingarea_info[type_id].infotext != NULL)
12360       strcpy(infotext, drawingarea_info[type_id].infotext);
12361   }
12362
12363   infotext[max_infotext_len] = '\0';
12364
12365   if (strlen(infotext) > 0)
12366     DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, INFOTEXT_FONT, infotext);
12367 }
12368
12369 void RequestExitLevelEditor(boolean ask_if_level_has_changed,
12370                             boolean quick_quit)
12371 {
12372   if (!ask_if_level_has_changed ||
12373       !LevelChanged() ||
12374       Request("Level has changed! Exit without saving?",
12375               REQ_ASK | REQ_STAY_OPEN))
12376   {
12377     struct RectWithBorder *vp_door_1 = &viewport.door_1[GAME_MODE_MAIN];
12378     struct RectWithBorder *vp_door_2 = &viewport.door_2[GAME_MODE_MAIN];
12379
12380     /* draw normal door */
12381     UndrawSpecialEditorDoor();
12382
12383     // close editor doors if viewport definition is the same as in main menu
12384     if (vp_door_1->x      == DX     &&
12385         vp_door_1->y      == DY     &&
12386         vp_door_1->width  == DXSIZE &&
12387         vp_door_1->height == DYSIZE &&
12388         vp_door_2->x      == VX     &&
12389         vp_door_2->y      == VY     &&
12390         vp_door_2->width  == VXSIZE &&
12391         vp_door_2->height == VYSIZE)
12392       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
12393     else
12394       SetDoorState(DOOR_CLOSE_2);
12395
12396     BackToFront();
12397
12398     if (quick_quit)
12399       FadeSkipNextFadeIn();
12400
12401     SetGameStatus(GAME_MODE_MAIN);
12402
12403     DrawMainMenu();
12404   }
12405   else
12406   {
12407     if (!global.use_envelope_request)
12408     {
12409       CloseDoor(DOOR_CLOSE_1);
12410       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
12411     }
12412   }
12413 }