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