rnd-20030919-1-src
[rocksndiamonds.git] / src / editor.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * editor.c                                                 *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "libgame/libgame.h"
17
18 #include "editor.h"
19 #include "screens.h"
20 #include "tools.h"
21 #include "files.h"
22 #include "game.h"
23 #include "init.h"
24 #include "tape.h"
25
26
27 /*
28   -----------------------------------------------------------------------------
29   screen and artwork graphic pixel position definitions
30   -----------------------------------------------------------------------------
31 */
32
33 /* positions in the level editor */
34 #define ED_WIN_MB_LEFT_XPOS             6
35 #define ED_WIN_MB_LEFT_YPOS             258
36 #define ED_WIN_MB_MIDDLE_XPOS           42
37 #define ED_WIN_MB_MIDDLE_YPOS           ED_WIN_MB_LEFT_YPOS
38 #define ED_WIN_MB_RIGHT_XPOS            78
39 #define ED_WIN_MB_RIGHT_YPOS            ED_WIN_MB_LEFT_YPOS
40
41 /* values for the control window */
42 #define ED_CTRL_BUTTONS_GFX_YPOS        236
43 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS    142
44
45 #define ED_CTRL1_BUTTONS_HORIZ          4
46 #define ED_CTRL1_BUTTONS_VERT           4
47 #define ED_CTRL1_BUTTON_XSIZE           22
48 #define ED_CTRL1_BUTTON_YSIZE           22
49 #define ED_CTRL1_BUTTONS_XPOS           6
50 #define ED_CTRL1_BUTTONS_YPOS           6
51 #define ED_CTRL2_BUTTONS_HORIZ          3
52 #define ED_CTRL2_BUTTONS_VERT           2
53 #define ED_CTRL2_BUTTON_XSIZE           30
54 #define ED_CTRL2_BUTTON_YSIZE           20
55 #define ED_CTRL2_BUTTONS_XPOS           5
56 #define ED_CTRL2_BUTTONS_YPOS           99
57 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
58 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
59 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
60
61 /* values for the element list */
62 #define ED_ELEMENTLIST_XPOS             5
63 #define ED_ELEMENTLIST_YPOS             30
64 #define ED_ELEMENTLIST_XSIZE            20
65 #define ED_ELEMENTLIST_YSIZE            20
66 #define ED_ELEMENTLIST_BUTTONS_HORIZ    4
67 #define ED_ELEMENTLIST_BUTTONS_VERT     11
68 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
69                                          ED_ELEMENTLIST_BUTTONS_VERT)
70
71 /* standard distances */
72 #define ED_BORDER_SIZE                  3
73 #define ED_BORDER_TEXT_XSIZE            5
74 #define ED_BORDER_AREA_YSIZE            1
75
76 #define ED_GADGET_DISTANCE              2
77 #define ED_GADGET_TEXT_DISTANCE         (2 * ED_GADGET_DISTANCE)
78 #define ED_DRAWINGAREA_TEXT_DISTANCE    (ED_GADGET_TEXT_DISTANCE + \
79                                          MINI_TILEX / 2)
80
81 /* values for the setting windows */
82 #define ED_SETTINGS_XSTART              (3 * MINI_TILEX / 2)
83 #define ED_SETTINGS_YSTART              (MINI_TILEY * 10)
84
85 #define ED_XOFFSET_CHECKBOX             (ED_CHECKBUTTON_XSIZE + \
86                                          2 * ED_GADGET_DISTANCE)
87
88 #define ED_SETTINGS_XOFFSET             ED_XOFFSET_CHECKBOX
89 #define ED_SETTINGS_YOFFSET             (3 * MINI_TILEY / 2)
90
91 #define ED_SETTINGS_XPOS(n)             (ED_SETTINGS_XSTART + \
92                                          n * ED_SETTINGS_XOFFSET)
93 #define ED_SETTINGS_YPOS(n)             (ED_SETTINGS_YSTART + \
94                                          n * ED_SETTINGS_YOFFSET)
95
96 #define ED_SETTINGS1_YPOS               MINI_TILEY
97 #define ED_SETTINGS2_XPOS               MINI_TILEX
98 #define ED_SETTINGS2_YPOS               (ED_SETTINGS1_YPOS + 12 * TILEY - 2)
99
100 /* values for counter gadgets */
101 #define ED_COUNTER_YSTART               (ED_SETTINGS1_YPOS + 2 * TILEY)
102 #define ED_COUNTER_YDISTANCE            (3 * MINI_TILEY)
103 #define ED_COUNTER_YPOS(n)              (ED_COUNTER_YSTART + \
104                                          n * ED_COUNTER_YDISTANCE)
105 #define ED_COUNTER2_YPOS(n)             (ED_COUNTER_YSTART + \
106                                          n * ED_COUNTER_YDISTANCE - 2)
107
108 /* values for element content drawing areas */
109 /* amoeba content */
110 #define ED_AREA_ELEM_CONTENT_XPOS       ( 2 * MINI_TILEX)
111 #define ED_AREA_ELEM_CONTENT_YPOS       (22 * MINI_TILEY)
112
113 /* yamyam content */
114 #define ED_AREA_YAMYAM_CONTENT_XPOS(n)  (ED_AREA_ELEM_CONTENT_XPOS + \
115                                          5 * (n % 4) * MINI_TILEX)
116 #define ED_AREA_YAMYAM_CONTENT_YPOS(n)  (ED_AREA_ELEM_CONTENT_YPOS + \
117                                          6 * (n / 4) * MINI_TILEY)
118
119 /* custom change target */
120 #define ED_AREA_ELEM_CONTENT2_YPOS      (ED_SETTINGS_YPOS(2) + \
121                                          ED_GADGET_DISTANCE)
122 /* optional custom graphic */
123 #define ED_AREA_ELEM_CONTENT3_YPOS      (ED_SETTINGS_YPOS(1) + \
124                                          ED_GADGET_DISTANCE)
125 /* custom element content */
126 #define ED_AREA_ELEM_CONTENT4_XPOS      (29 * MINI_TILEX)
127 #define ED_AREA_ELEM_CONTENT4_YPOS      (ED_SETTINGS_YPOS(12) + \
128                                          ED_GADGET_DISTANCE - MINI_TILEY)
129 /* custom change trigger element */
130 #define ED_AREA_ELEM_CONTENT5_YPOS      (ED_SETTINGS_YPOS(6) + \
131                                          ED_GADGET_DISTANCE)
132 /* extended custom change target */
133 #define ED_AREA_ELEM_CONTENT6_XPOS      (29 * MINI_TILEX)
134 #define ED_AREA_ELEM_CONTENT6_YPOS      (ED_SETTINGS_YPOS(9) + \
135                                          ED_GADGET_DISTANCE - MINI_TILEY)
136
137 /* values for random placement background drawing area */
138 #define ED_AREA_RANDOM_BACKGROUND_YPOS  (31 * MINI_TILEY)
139
140 /* values for scrolling gadgets for drawing area */
141 #define ED_SCROLLBUTTON_XPOS            24
142 #define ED_SCROLLBUTTON_YPOS            0
143 #define ED_SCROLLBAR_XPOS               24
144 #define ED_SCROLLBAR_YPOS               64
145
146 #define ED_SCROLLBUTTON_XSIZE           16
147 #define ED_SCROLLBUTTON_YSIZE           16
148
149 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
150 #define ED_SCROLL_UP_YPOS               (0)
151 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
152 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
153 #define ED_SCROLL_LEFT_XPOS             (0)
154 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
155 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
156 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
157 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
158 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
159 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
160 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
161 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
162 #define ED_SCROLL_VERTICAL_YPOS   (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
163 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
164 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
165
166 /* values for scrolling gadgets for element list */
167 #define ED_SCROLLBUTTON2_XPOS           50
168 #define ED_SCROLLBUTTON2_YPOS           0
169 #define ED_SCROLLBAR2_XPOS              50
170 #define ED_SCROLLBAR2_YPOS              20
171
172 #define ED_SCROLLBUTTON2_XSIZE          10
173 #define ED_SCROLLBUTTON2_YSIZE          10
174
175 #define ED_SCROLL2_UP_XPOS              85
176 #define ED_SCROLL2_UP_YPOS              30
177 #define ED_SCROLL2_DOWN_XPOS            ED_SCROLL2_UP_XPOS
178 #define ED_SCROLL2_DOWN_YPOS            (ED_SCROLL2_UP_YPOS + \
179                                          ED_ELEMENTLIST_BUTTONS_VERT * \
180                                          ED_ELEMENTLIST_YSIZE - \
181                                          ED_SCROLLBUTTON2_YSIZE)
182 #define ED_SCROLL2_VERTICAL_XPOS        ED_SCROLL2_UP_XPOS
183 #define ED_SCROLL2_VERTICAL_YPOS        (ED_SCROLL2_UP_YPOS + \
184                                          ED_SCROLLBUTTON2_YSIZE)
185 #define ED_SCROLL2_VERTICAL_XSIZE       ED_SCROLLBUTTON2_XSIZE
186 #define ED_SCROLL2_VERTICAL_YSIZE       (ED_ELEMENTLIST_BUTTONS_VERT * \
187                                          ED_ELEMENTLIST_YSIZE - \
188                                          2 * ED_SCROLLBUTTON2_YSIZE)
189
190 /* values for checkbutton gadgets */
191 #define ED_CHECKBUTTON_XSIZE            ED_BUTTON_COUNT_XSIZE
192 #define ED_CHECKBUTTON_YSIZE            ED_BUTTON_COUNT_YSIZE
193 #define ED_CHECKBUTTON_UNCHECKED_XPOS   ED_BUTTON_MINUS_XPOS
194 #define ED_CHECKBUTTON_CHECKED_XPOS     ED_BUTTON_PLUS_XPOS
195 #define ED_CHECKBUTTON_YPOS             (ED_BUTTON_MINUS_YPOS + 22)
196 #define ED_RADIOBUTTON_YPOS             (ED_BUTTON_MINUS_YPOS + 44)
197 #define ED_STICKYBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 66)
198
199 /* some positions in the editor control window */
200 #define ED_BUTTON_ELEM_XPOS             6
201 #define ED_BUTTON_ELEM_YPOS             30
202 #define ED_BUTTON_ELEM_XSIZE            22
203 #define ED_BUTTON_ELEM_YSIZE            22
204
205 /* some values for text input, selectbox and counter gadgets */
206 #define ED_BUTTON_COUNT_YPOS            60
207 #define ED_BUTTON_COUNT_XSIZE           20
208 #define ED_BUTTON_COUNT_YSIZE           20
209 #define ED_WIN_COUNT_XPOS               (2 + ED_BUTTON_COUNT_XSIZE + 2)
210 #define ED_WIN_COUNT_YPOS               ED_BUTTON_COUNT_YPOS
211 #define ED_WIN_COUNT_XSIZE              52
212 #define ED_WIN_COUNT_YSIZE              ED_BUTTON_COUNT_YSIZE
213 #define ED_WIN_COUNT2_XPOS              27
214 #define ED_WIN_COUNT2_YPOS              3
215 #define ED_WIN_COUNT2_XSIZE             46
216 #define ED_WIN_COUNT2_YSIZE             ED_BUTTON_COUNT_YSIZE
217
218 #define ED_BUTTON_MINUS_XPOS            2
219 #define ED_BUTTON_MINUS_YPOS            ED_BUTTON_COUNT_YPOS
220 #define ED_BUTTON_MINUS_XSIZE           ED_BUTTON_COUNT_XSIZE
221 #define ED_BUTTON_MINUS_YSIZE           ED_BUTTON_COUNT_YSIZE
222 #define ED_BUTTON_PLUS_XPOS             (ED_WIN_COUNT_XPOS + \
223                                          ED_WIN_COUNT_XSIZE + 2)
224 #define ED_BUTTON_PLUS_YPOS             ED_BUTTON_COUNT_YPOS
225 #define ED_BUTTON_PLUS_XSIZE            ED_BUTTON_COUNT_XSIZE
226 #define ED_BUTTON_PLUS_YSIZE            ED_BUTTON_COUNT_YSIZE
227
228 #define ED_SELECTBOX_XPOS               ED_WIN_COUNT_XPOS
229 #define ED_SELECTBOX_YPOS               (ED_WIN_COUNT_YPOS + \
230                                          2 + ED_WIN_COUNT_YSIZE)
231 #define ED_SELECTBOX_XSIZE              ED_WIN_COUNT_XSIZE
232 #define ED_SELECTBOX_YSIZE              ED_WIN_COUNT_YSIZE
233
234 #define ED_SELECTBOX_BUTTON_XSIZE       14
235
236 #define ED_TEXTBUTTON_XPOS              ED_WIN_COUNT_XPOS
237 #define ED_TEXTBUTTON_YPOS              (ED_WIN_COUNT_YPOS + \
238                                          4 * (2 + ED_WIN_COUNT_YSIZE))
239 #define ED_TEXTBUTTON_INACTIVE_YPOS     ED_TEXTBUTTON_YPOS
240
241 #define ED_TEXTBUTTON_TAB_XPOS          ED_WIN_COUNT_XPOS
242 #define ED_TEXTBUTTON_TAB_YPOS          (ED_WIN_COUNT_YPOS + \
243                                          2 * (2 + ED_WIN_COUNT_YSIZE))
244 #define ED_TEXTBUTTON_TAB_INACTIVE_YPOS (ED_WIN_COUNT_YPOS + \
245                                          3 * (2 + ED_WIN_COUNT_YSIZE))
246
247 #define ED_TEXTBUTTON_XSIZE             ED_WIN_COUNT_XSIZE
248 #define ED_TEXTBUTTON_YSIZE             ED_WIN_COUNT_YSIZE
249
250 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
251 #define INFOTEXT_XPOS                   SX
252 #define INFOTEXT_YPOS                   (SY + SYSIZE - MINI_TILEX + 2)
253 #define INFOTEXT_XSIZE                  SXSIZE
254 #define INFOTEXT_YSIZE                  MINI_TILEX
255
256
257 /*
258   -----------------------------------------------------------------------------
259   editor gadget definitions
260   -----------------------------------------------------------------------------
261 */
262
263 /* drawing toolbox buttons */
264 #define GADGET_ID_NONE                  -1
265 #define GADGET_ID_TOOLBOX_FIRST         0
266
267 #define GADGET_ID_SINGLE_ITEMS          (GADGET_ID_TOOLBOX_FIRST + 0)
268 #define GADGET_ID_CONNECTED_ITEMS       (GADGET_ID_TOOLBOX_FIRST + 1)
269 #define GADGET_ID_LINE                  (GADGET_ID_TOOLBOX_FIRST + 2)
270 #define GADGET_ID_ARC                   (GADGET_ID_TOOLBOX_FIRST + 3)
271 #define GADGET_ID_RECTANGLE             (GADGET_ID_TOOLBOX_FIRST + 4)
272 #define GADGET_ID_FILLED_BOX            (GADGET_ID_TOOLBOX_FIRST + 5)
273 #define GADGET_ID_WRAP_UP               (GADGET_ID_TOOLBOX_FIRST + 6)
274 #define GADGET_ID_TEXT                  (GADGET_ID_TOOLBOX_FIRST + 7)
275 #define GADGET_ID_FLOOD_FILL            (GADGET_ID_TOOLBOX_FIRST + 8)
276 #define GADGET_ID_WRAP_LEFT             (GADGET_ID_TOOLBOX_FIRST + 9)
277 #define GADGET_ID_PROPERTIES            (GADGET_ID_TOOLBOX_FIRST + 10)
278 #define GADGET_ID_WRAP_RIGHT            (GADGET_ID_TOOLBOX_FIRST + 11)
279 #define GADGET_ID_RANDOM_PLACEMENT      (GADGET_ID_TOOLBOX_FIRST + 12)
280 #define GADGET_ID_GRAB_BRUSH            (GADGET_ID_TOOLBOX_FIRST + 13)
281 #define GADGET_ID_WRAP_DOWN             (GADGET_ID_TOOLBOX_FIRST + 14)
282 #define GADGET_ID_PICK_ELEMENT          (GADGET_ID_TOOLBOX_FIRST + 15)
283 #define GADGET_ID_UNDO                  (GADGET_ID_TOOLBOX_FIRST + 16)
284 #define GADGET_ID_INFO                  (GADGET_ID_TOOLBOX_FIRST + 17)
285 #define GADGET_ID_SAVE                  (GADGET_ID_TOOLBOX_FIRST + 18)
286 #define GADGET_ID_CLEAR                 (GADGET_ID_TOOLBOX_FIRST + 19)
287 #define GADGET_ID_TEST                  (GADGET_ID_TOOLBOX_FIRST + 20)
288 #define GADGET_ID_EXIT                  (GADGET_ID_TOOLBOX_FIRST + 21)
289
290 /* counter button identifiers */
291 #define GADGET_ID_COUNTER_FIRST         (GADGET_ID_TOOLBOX_FIRST + 22)
292
293 #define GADGET_ID_SELECT_LEVEL_DOWN     (GADGET_ID_COUNTER_FIRST + 0)
294 #define GADGET_ID_SELECT_LEVEL_TEXT     (GADGET_ID_COUNTER_FIRST + 1)
295 #define GADGET_ID_SELECT_LEVEL_UP       (GADGET_ID_COUNTER_FIRST + 2)
296 #define GADGET_ID_LEVEL_XSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 3)
297 #define GADGET_ID_LEVEL_XSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 4)
298 #define GADGET_ID_LEVEL_XSIZE_UP        (GADGET_ID_COUNTER_FIRST + 5)
299 #define GADGET_ID_LEVEL_YSIZE_DOWN      (GADGET_ID_COUNTER_FIRST + 6)
300 #define GADGET_ID_LEVEL_YSIZE_TEXT      (GADGET_ID_COUNTER_FIRST + 7)
301 #define GADGET_ID_LEVEL_YSIZE_UP        (GADGET_ID_COUNTER_FIRST + 8)
302 #define GADGET_ID_LEVEL_RANDOM_DOWN     (GADGET_ID_COUNTER_FIRST + 9)
303 #define GADGET_ID_LEVEL_RANDOM_TEXT     (GADGET_ID_COUNTER_FIRST + 10)
304 #define GADGET_ID_LEVEL_RANDOM_UP       (GADGET_ID_COUNTER_FIRST + 11)
305 #define GADGET_ID_LEVEL_GEMSLIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 12)
306 #define GADGET_ID_LEVEL_GEMSLIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 13)
307 #define GADGET_ID_LEVEL_GEMSLIMIT_UP    (GADGET_ID_COUNTER_FIRST + 14)
308 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN  (GADGET_ID_COUNTER_FIRST + 15)
309 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT  (GADGET_ID_COUNTER_FIRST + 16)
310 #define GADGET_ID_LEVEL_TIMELIMIT_UP    (GADGET_ID_COUNTER_FIRST + 17)
311 #define GADGET_ID_LEVEL_TIMESCORE_DOWN  (GADGET_ID_COUNTER_FIRST + 18)
312 #define GADGET_ID_LEVEL_TIMESCORE_TEXT  (GADGET_ID_COUNTER_FIRST + 19)
313 #define GADGET_ID_LEVEL_TIMESCORE_UP    (GADGET_ID_COUNTER_FIRST + 20)
314 #define GADGET_ID_ELEMENT_SCORE_DOWN    (GADGET_ID_COUNTER_FIRST + 21)
315 #define GADGET_ID_ELEMENT_SCORE_TEXT    (GADGET_ID_COUNTER_FIRST + 22)
316 #define GADGET_ID_ELEMENT_SCORE_UP      (GADGET_ID_COUNTER_FIRST + 23)
317 #define GADGET_ID_ELEMENT_CONTENT_DOWN  (GADGET_ID_COUNTER_FIRST + 24)
318 #define GADGET_ID_ELEMENT_CONTENT_TEXT  (GADGET_ID_COUNTER_FIRST + 25)
319 #define GADGET_ID_ELEMENT_CONTENT_UP    (GADGET_ID_COUNTER_FIRST + 26)
320 #define GADGET_ID_ENVELOPE_XSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 27)
321 #define GADGET_ID_ENVELOPE_XSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 28)
322 #define GADGET_ID_ENVELOPE_XSIZE_UP     (GADGET_ID_COUNTER_FIRST + 29)
323 #define GADGET_ID_ENVELOPE_YSIZE_DOWN   (GADGET_ID_COUNTER_FIRST + 30)
324 #define GADGET_ID_ENVELOPE_YSIZE_TEXT   (GADGET_ID_COUNTER_FIRST + 31)
325 #define GADGET_ID_ENVELOPE_YSIZE_UP     (GADGET_ID_COUNTER_FIRST + 32)
326 #define GADGET_ID_CUSTOM_SCORE_DOWN     (GADGET_ID_COUNTER_FIRST + 33)
327 #define GADGET_ID_CUSTOM_SCORE_TEXT     (GADGET_ID_COUNTER_FIRST + 34)
328 #define GADGET_ID_CUSTOM_SCORE_UP       (GADGET_ID_COUNTER_FIRST + 35)
329 #define GADGET_ID_CUSTOM_GEMCOUNT_DOWN  (GADGET_ID_COUNTER_FIRST + 36)
330 #define GADGET_ID_CUSTOM_GEMCOUNT_TEXT  (GADGET_ID_COUNTER_FIRST + 37)
331 #define GADGET_ID_CUSTOM_GEMCOUNT_UP    (GADGET_ID_COUNTER_FIRST + 38)
332 #define GADGET_ID_PUSH_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 39)
333 #define GADGET_ID_PUSH_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 40)
334 #define GADGET_ID_PUSH_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 41)
335 #define GADGET_ID_PUSH_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 42)
336 #define GADGET_ID_PUSH_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 43)
337 #define GADGET_ID_PUSH_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 44)
338 #define GADGET_ID_MOVE_DELAY_FIX_DOWN   (GADGET_ID_COUNTER_FIRST + 45)
339 #define GADGET_ID_MOVE_DELAY_FIX_TEXT   (GADGET_ID_COUNTER_FIRST + 46)
340 #define GADGET_ID_MOVE_DELAY_FIX_UP     (GADGET_ID_COUNTER_FIRST + 47)
341 #define GADGET_ID_MOVE_DELAY_RND_DOWN   (GADGET_ID_COUNTER_FIRST + 48)
342 #define GADGET_ID_MOVE_DELAY_RND_TEXT   (GADGET_ID_COUNTER_FIRST + 49)
343 #define GADGET_ID_MOVE_DELAY_RND_UP     (GADGET_ID_COUNTER_FIRST + 50)
344 #define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 51)
345 #define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 52)
346 #define GADGET_ID_CHANGE_DELAY_FIX_UP   (GADGET_ID_COUNTER_FIRST + 53)
347 #define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 54)
348 #define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 55)
349 #define GADGET_ID_CHANGE_DELAY_RND_UP   (GADGET_ID_COUNTER_FIRST + 56)
350 #define GADGET_ID_CHANGE_CONT_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 57)
351 #define GADGET_ID_CHANGE_CONT_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 58)
352 #define GADGET_ID_CHANGE_CONT_RND_UP    (GADGET_ID_COUNTER_FIRST + 59)
353
354 /* drawing area identifiers */
355 #define GADGET_ID_DRAWING_AREA_FIRST    (GADGET_ID_COUNTER_FIRST + 60)
356
357 #define GADGET_ID_DRAWING_LEVEL         (GADGET_ID_DRAWING_AREA_FIRST + 0)
358 #define GADGET_ID_ELEMENT_CONTENT_0     (GADGET_ID_DRAWING_AREA_FIRST + 1)
359 #define GADGET_ID_ELEMENT_CONTENT_1     (GADGET_ID_DRAWING_AREA_FIRST + 2)
360 #define GADGET_ID_ELEMENT_CONTENT_2     (GADGET_ID_DRAWING_AREA_FIRST + 3)
361 #define GADGET_ID_ELEMENT_CONTENT_3     (GADGET_ID_DRAWING_AREA_FIRST + 4)
362 #define GADGET_ID_ELEMENT_CONTENT_4     (GADGET_ID_DRAWING_AREA_FIRST + 5)
363 #define GADGET_ID_ELEMENT_CONTENT_5     (GADGET_ID_DRAWING_AREA_FIRST + 6)
364 #define GADGET_ID_ELEMENT_CONTENT_6     (GADGET_ID_DRAWING_AREA_FIRST + 7)
365 #define GADGET_ID_ELEMENT_CONTENT_7     (GADGET_ID_DRAWING_AREA_FIRST + 8)
366 #define GADGET_ID_AMOEBA_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 9)
367 #define GADGET_ID_CUSTOM_GRAPHIC        (GADGET_ID_DRAWING_AREA_FIRST + 10)
368 #define GADGET_ID_CUSTOM_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 11)
369 #define GADGET_ID_CUSTOM_CHANGE_TARGET  (GADGET_ID_DRAWING_AREA_FIRST + 12)
370 #define GADGET_ID_CUSTOM_CHANGE_CONTENT (GADGET_ID_DRAWING_AREA_FIRST + 13)
371 #define GADGET_ID_CUSTOM_CHANGE_TRIGGER (GADGET_ID_DRAWING_AREA_FIRST + 14)
372 #define GADGET_ID_RANDOM_BACKGROUND     (GADGET_ID_DRAWING_AREA_FIRST + 15)
373
374 /* text input identifiers */
375 #define GADGET_ID_TEXT_INPUT_FIRST      (GADGET_ID_DRAWING_AREA_FIRST + 16)
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_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 0)
390 #define GADGET_ID_CUSTOM_CONSISTENCY    (GADGET_ID_SELECTBOX_FIRST + 1)
391 #define GADGET_ID_CUSTOM_DEADLINESS     (GADGET_ID_SELECTBOX_FIRST + 2)
392 #define GADGET_ID_CUSTOM_MOVE_PATTERN   (GADGET_ID_SELECTBOX_FIRST + 3)
393 #define GADGET_ID_CUSTOM_MOVE_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 4)
394 #define GADGET_ID_CUSTOM_MOVE_STEPSIZE  (GADGET_ID_SELECTBOX_FIRST + 5)
395 #define GADGET_ID_CUSTOM_SMASH_TARGETS  (GADGET_ID_SELECTBOX_FIRST + 6)
396 #define GADGET_ID_CUSTOM_SLIPPERY_TYPE  (GADGET_ID_SELECTBOX_FIRST + 7)
397 #define GADGET_ID_CUSTOM_ACCESS_TYPE    (GADGET_ID_SELECTBOX_FIRST + 8)
398 #define GADGET_ID_CUSTOM_ACCESS_LAYER   (GADGET_ID_SELECTBOX_FIRST + 9)
399 #define GADGET_ID_CHANGE_TIME_UNITS     (GADGET_ID_SELECTBOX_FIRST + 10)
400 #define GADGET_ID_CHANGE_DIRECT_ACTION  (GADGET_ID_SELECTBOX_FIRST + 11)
401 #define GADGET_ID_CHANGE_OTHER_ACTION   (GADGET_ID_SELECTBOX_FIRST + 12)
402 #define GADGET_ID_CHANGE_POWER          (GADGET_ID_SELECTBOX_FIRST + 13)
403 #define GADGET_ID_SELECT_CHANGE_PAGE    (GADGET_ID_SELECTBOX_FIRST + 14)
404
405 /* textbutton identifiers */
406 #define GADGET_ID_TEXTBUTTON_FIRST      (GADGET_ID_SELECTBOX_FIRST + 15)
407
408 #define GADGET_ID_PROPERTIES_INFO       (GADGET_ID_TEXTBUTTON_FIRST + 0)
409 #define GADGET_ID_PROPERTIES_CONFIG     (GADGET_ID_TEXTBUTTON_FIRST + 1)
410 #define GADGET_ID_PROPERTIES_ADVANCED   (GADGET_ID_TEXTBUTTON_FIRST + 2)
411 #define GADGET_ID_SAVE_AS_TEMPLATE      (GADGET_ID_TEXTBUTTON_FIRST + 3)
412 #define GADGET_ID_ADD_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 4)
413 #define GADGET_ID_DEL_CHANGE_PAGE       (GADGET_ID_TEXTBUTTON_FIRST + 5)
414
415 /* graphicbutton identifiers */
416 #define GADGET_ID_GRAPHICBUTTON_FIRST   (GADGET_ID_TEXTBUTTON_FIRST + 6)
417
418 #define GADGET_ID_PREV_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 0)
419 #define GADGET_ID_NEXT_CHANGE_PAGE      (GADGET_ID_GRAPHICBUTTON_FIRST + 1)
420
421 /* gadgets for scrolling of drawing area */
422 #define GADGET_ID_SCROLLING_FIRST       (GADGET_ID_GRAPHICBUTTON_FIRST + 2)
423
424 #define GADGET_ID_SCROLL_UP             (GADGET_ID_SCROLLING_FIRST + 0)
425 #define GADGET_ID_SCROLL_DOWN           (GADGET_ID_SCROLLING_FIRST + 1)
426 #define GADGET_ID_SCROLL_LEFT           (GADGET_ID_SCROLLING_FIRST + 2)
427 #define GADGET_ID_SCROLL_RIGHT          (GADGET_ID_SCROLLING_FIRST + 3)
428 #define GADGET_ID_SCROLL_HORIZONTAL     (GADGET_ID_SCROLLING_FIRST + 4)
429 #define GADGET_ID_SCROLL_VERTICAL       (GADGET_ID_SCROLLING_FIRST + 5)
430
431 /* gadgets for scrolling element list */
432 #define GADGET_ID_SCROLLING_LIST_FIRST  (GADGET_ID_SCROLLING_FIRST + 6)
433
434 #define GADGET_ID_SCROLL_LIST_UP        (GADGET_ID_SCROLLING_LIST_FIRST + 0)
435 #define GADGET_ID_SCROLL_LIST_DOWN      (GADGET_ID_SCROLLING_LIST_FIRST + 1)
436 #define GADGET_ID_SCROLL_LIST_VERTICAL  (GADGET_ID_SCROLLING_LIST_FIRST + 2)
437
438 /* checkbuttons for level/element properties */
439 #define GADGET_ID_CHECKBUTTON_FIRST     (GADGET_ID_SCROLLING_LIST_FIRST + 3)
440
441 #define GADGET_ID_RANDOM_PERCENTAGE     (GADGET_ID_CHECKBUTTON_FIRST + 0)
442 #define GADGET_ID_RANDOM_QUANTITY       (GADGET_ID_CHECKBUTTON_FIRST + 1)
443 #define GADGET_ID_RANDOM_RESTRICTED     (GADGET_ID_CHECKBUTTON_FIRST + 2)
444 #define GADGET_ID_DOUBLE_SPEED          (GADGET_ID_CHECKBUTTON_FIRST + 3)
445 #define GADGET_ID_GRAVITY               (GADGET_ID_CHECKBUTTON_FIRST + 4)
446 #define GADGET_ID_STICK_ELEMENT         (GADGET_ID_CHECKBUTTON_FIRST + 5)
447 #define GADGET_ID_EM_SLIPPERY_GEMS      (GADGET_ID_CHECKBUTTON_FIRST + 6)
448 #define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 7)
449 #define GADGET_ID_CUSTOM_EXPLODE_FIRE   (GADGET_ID_CHECKBUTTON_FIRST + 8)
450 #define GADGET_ID_CUSTOM_EXPLODE_SMASH  (GADGET_ID_CHECKBUTTON_FIRST + 9)
451 #define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 10)
452 #define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 11)
453 #define GADGET_ID_CUSTOM_DEADLY         (GADGET_ID_CHECKBUTTON_FIRST + 12)
454 #define GADGET_ID_CUSTOM_CAN_MOVE       (GADGET_ID_CHECKBUTTON_FIRST + 13)
455 #define GADGET_ID_CUSTOM_CAN_FALL       (GADGET_ID_CHECKBUTTON_FIRST + 14)
456 #define GADGET_ID_CUSTOM_CAN_SMASH      (GADGET_ID_CHECKBUTTON_FIRST + 15)
457 #define GADGET_ID_CUSTOM_SLIPPERY       (GADGET_ID_CHECKBUTTON_FIRST + 16)
458 #define GADGET_ID_CUSTOM_ACCESSIBLE     (GADGET_ID_CHECKBUTTON_FIRST + 17)
459 #define GADGET_ID_CUSTOM_USE_GRAPHIC    (GADGET_ID_CHECKBUTTON_FIRST + 18)
460 #define GADGET_ID_CUSTOM_USE_TEMPLATE   (GADGET_ID_CHECKBUTTON_FIRST + 19)
461 #define GADGET_ID_CUSTOM_CAN_CHANGE     (GADGET_ID_CHECKBUTTON_FIRST + 20)
462 #define GADGET_ID_CHANGE_USE_CONTENT    (GADGET_ID_CHECKBUTTON_FIRST + 21)
463 #define GADGET_ID_CHANGE_USE_EXPLOSION  (GADGET_ID_CHECKBUTTON_FIRST + 22)
464 #define GADGET_ID_CHANGE_ONLY_COMPLETE  (GADGET_ID_CHECKBUTTON_FIRST + 23)
465 #define GADGET_ID_CHANGE_USE_RANDOM     (GADGET_ID_CHECKBUTTON_FIRST + 24)
466 #define GADGET_ID_CHANGE_DELAY          (GADGET_ID_CHECKBUTTON_FIRST + 25)
467 #define GADGET_ID_CHANGE_BY_DIRECT_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 26)
468 #define GADGET_ID_CHANGE_BY_OTHER_ACT   (GADGET_ID_CHECKBUTTON_FIRST + 27)
469
470 /* gadgets for buttons in element list */
471 #define GADGET_ID_ELEMENTLIST_FIRST     (GADGET_ID_CHECKBUTTON_FIRST + 28)
472 #define GADGET_ID_ELEMENTLIST_LAST      (GADGET_ID_ELEMENTLIST_FIRST +  \
473                                         ED_NUM_ELEMENTLIST_BUTTONS - 1)
474
475 #define NUM_EDITOR_GADGETS              (GADGET_ID_ELEMENTLIST_LAST + 1)
476
477 /* radio button numbers */
478 #define RADIO_NR_NONE                   0
479 #define RADIO_NR_DRAWING_TOOLBOX        1
480 #define RADIO_NR_RANDOM_ELEMENTS        2
481
482 /* values for counter gadgets */
483 #define ED_COUNTER_ID_SELECT_LEVEL      0
484 #define ED_COUNTER_ID_LEVEL_XSIZE       1
485 #define ED_COUNTER_ID_LEVEL_YSIZE       2
486 #define ED_COUNTER_ID_LEVEL_GEMSLIMIT   3
487 #define ED_COUNTER_ID_LEVEL_TIMELIMIT   4
488 #define ED_COUNTER_ID_LEVEL_TIMESCORE   5
489 #define ED_COUNTER_ID_LEVEL_RANDOM      6
490 #define ED_COUNTER_ID_ELEMENT_SCORE     7
491 #define ED_COUNTER_ID_ELEMENT_CONTENT   8
492 #define ED_COUNTER_ID_ENVELOPE_XSIZE    9
493 #define ED_COUNTER_ID_ENVELOPE_YSIZE    10
494 #define ED_COUNTER_ID_CUSTOM_SCORE      11
495 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT   12
496 #define ED_COUNTER_ID_PUSH_DELAY_FIX    13
497 #define ED_COUNTER_ID_PUSH_DELAY_RND    14
498 #define ED_COUNTER_ID_MOVE_DELAY_FIX    15
499 #define ED_COUNTER_ID_MOVE_DELAY_RND    16
500 #define ED_COUNTER_ID_CHANGE_DELAY_FIX  17
501 #define ED_COUNTER_ID_CHANGE_DELAY_RND  18
502 #define ED_COUNTER_ID_CHANGE_CONT_RND   19
503
504 #define ED_NUM_COUNTERBUTTONS           20
505
506 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
507 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM
508
509 #define ED_COUNTER_ID_CUSTOM_FIRST      ED_COUNTER_ID_CUSTOM_SCORE
510 #define ED_COUNTER_ID_CUSTOM_LAST       ED_COUNTER_ID_MOVE_DELAY_RND
511
512 #define ED_COUNTER_ID_CHANGE_FIRST      ED_COUNTER_ID_CHANGE_DELAY_FIX
513 #define ED_COUNTER_ID_CHANGE_LAST       ED_COUNTER_ID_CHANGE_CONT_RND
514
515 /* values for scrollbutton gadgets */
516 #define ED_SCROLLBUTTON_ID_AREA_UP      0
517 #define ED_SCROLLBUTTON_ID_AREA_DOWN    1
518 #define ED_SCROLLBUTTON_ID_AREA_LEFT    2
519 #define ED_SCROLLBUTTON_ID_AREA_RIGHT   3
520 #define ED_SCROLLBUTTON_ID_LIST_UP      4
521 #define ED_SCROLLBUTTON_ID_LIST_DOWN    5
522
523 #define ED_NUM_SCROLLBUTTONS            6
524
525 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
526 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
527
528 /* values for scrollbar gadgets */
529 #define ED_SCROLLBAR_ID_AREA_HORIZONTAL 0
530 #define ED_SCROLLBAR_ID_AREA_VERTICAL   1
531 #define ED_SCROLLBAR_ID_LIST_VERTICAL   2
532
533 #define ED_NUM_SCROLLBARS               3
534
535 #define ED_SCROLLBAR_ID_AREA_FIRST      ED_SCROLLBAR_ID_AREA_HORIZONTAL
536 #define ED_SCROLLBAR_ID_AREA_LAST       ED_SCROLLBAR_ID_AREA_VERTICAL
537
538 /* values for text input gadgets */
539 #define ED_TEXTINPUT_ID_LEVEL_NAME      0
540 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR    1
541 #define ED_TEXTINPUT_ID_ELEMENT_NAME    2
542
543 #define ED_NUM_TEXTINPUT                3
544
545 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
546 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
547
548 /* values for text area gadgets */
549 #define ED_TEXTAREA_ID_ENVELOPE_INFO    0
550
551 #define ED_NUM_TEXTAREAS                        1
552
553 #define ED_TEXTAREA_ID_LEVEL_FIRST      ED_TEXTAREA_ID_ENVELOPE
554 #define ED_TEXTAREA_ID_LEVEL_LAST       ED_TEXTAREA_ID_ENVELOPE
555
556 /* values for selectbox gadgets */
557 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE      0
558 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER     1
559 #define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION   2
560 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN     3
561 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION   4
562 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE    5
563 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS    6
564 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE    7
565 #define ED_SELECTBOX_ID_CUSTOM_DEADLINESS       8
566 #define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY      9
567 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS       10
568 #define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION    11
569 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION     12
570 #define ED_SELECTBOX_ID_CHANGE_POWER            13
571 #define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE      14
572
573 #define ED_NUM_SELECTBOX                        15
574
575 #define ED_SELECTBOX_ID_CUSTOM_FIRST    ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
576 #define ED_SELECTBOX_ID_CUSTOM_LAST     ED_SELECTBOX_ID_CUSTOM_CONSISTENCY
577
578 #define ED_SELECTBOX_ID_CHANGE_FIRST    ED_SELECTBOX_ID_CHANGE_TIME_UNITS
579 #define ED_SELECTBOX_ID_CHANGE_LAST     ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
580
581 /* values for textbutton gadgets */
582 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO        0
583 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG      1
584 #define ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED    2
585 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE       3
586 #define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE        4
587 #define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE        5
588
589 #define ED_NUM_TEXTBUTTONS                      6
590
591 #define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
592 #define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED
593
594 #define ED_TEXTBUTTON_ID_CHANGE_FIRST   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE
595 #define ED_TEXTBUTTON_ID_CHANGE_LAST    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
596
597 /* values for graphicbutton gadgets */
598 #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE    0
599 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE    1
600
601 #define ED_NUM_GRAPHICBUTTONS                   2
602
603 #define ED_GRAPHICBUTTON_ID_CHANGE_FIRST   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
604 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST    ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE
605
606 /* values for checkbutton gadgets */
607 #define ED_CHECKBUTTON_ID_DOUBLE_SPEED          0
608 #define ED_CHECKBUTTON_ID_GRAVITY               1
609 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED     2
610 #define ED_CHECKBUTTON_ID_STICK_ELEMENT         3
611 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS      4
612 #define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE     5
613 #define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 6
614 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE       7
615 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL       8
616 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH      9
617 #define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY       10
618 #define ED_CHECKBUTTON_ID_CUSTOM_DEADLY         11
619 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 12
620 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE   13
621 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH  14
622 #define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 15
623 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC    16
624 #define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE     17
625 #define ED_CHECKBUTTON_ID_CHANGE_DELAY          18
626 #define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT  19
627 #define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT   20
628 #define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION  21
629 #define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT    22
630 #define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE  23
631 #define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM     24
632 #define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE   25
633
634 #define ED_NUM_CHECKBUTTONS                     26
635
636 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_DOUBLE_SPEED
637 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
638
639 #define ED_CHECKBUTTON_ID_CUSTOM_FIRST  ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
640 #define ED_CHECKBUTTON_ID_CUSTOM_LAST   ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
641
642 #define ED_CHECKBUTTON_ID_CHANGE_FIRST  ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
643 #define ED_CHECKBUTTON_ID_CHANGE_LAST   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE
644
645 /* values for radiobutton gadgets */
646 #define ED_RADIOBUTTON_ID_PERCENTAGE    0
647 #define ED_RADIOBUTTON_ID_QUANTITY      1
648
649 #define ED_NUM_RADIOBUTTONS             2
650
651 #define ED_RADIOBUTTON_ID_LEVEL_FIRST   ED_RADIOBUTTON_ID_PERCENTAGE
652 #define ED_RADIOBUTTON_ID_LEVEL_LAST    ED_RADIOBUTTON_ID_QUANTITY
653
654 /* values for drawing area gadgets */
655 #define ED_DRAWING_ID_DRAWING_LEVEL             0
656 #define ED_DRAWING_ID_ELEMENT_CONTENT_0         1
657 #define ED_DRAWING_ID_ELEMENT_CONTENT_1         2
658 #define ED_DRAWING_ID_ELEMENT_CONTENT_2         3
659 #define ED_DRAWING_ID_ELEMENT_CONTENT_3         4
660 #define ED_DRAWING_ID_ELEMENT_CONTENT_4         5
661 #define ED_DRAWING_ID_ELEMENT_CONTENT_5         6
662 #define ED_DRAWING_ID_ELEMENT_CONTENT_6         7
663 #define ED_DRAWING_ID_ELEMENT_CONTENT_7         8
664 #define ED_DRAWING_ID_AMOEBA_CONTENT            9
665 #define ED_DRAWING_ID_CUSTOM_GRAPHIC            10
666 #define ED_DRAWING_ID_CUSTOM_CONTENT            11
667 #define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET      12
668 #define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT     13
669 #define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER     14
670 #define ED_DRAWING_ID_RANDOM_BACKGROUND         15
671
672 #define ED_NUM_DRAWING_AREAS                    16
673
674
675 /*
676   -----------------------------------------------------------------------------
677   some internally used definitions
678   -----------------------------------------------------------------------------
679 */
680
681 /* values for CopyLevelToUndoBuffer() */
682 #define UNDO_IMMEDIATE                  0
683 #define UNDO_ACCUMULATE                 1
684
685 /* values for scrollbars */
686 #define ED_SCROLL_NO                    0
687 #define ED_SCROLL_LEFT                  1
688 #define ED_SCROLL_RIGHT                 2
689 #define ED_SCROLL_UP                    4
690 #define ED_SCROLL_DOWN                  8
691
692 /* screens in the level editor */
693 #define ED_MODE_DRAWING                 0
694 #define ED_MODE_INFO                    1
695 #define ED_MODE_PROPERTIES              2
696
697 /* sub-screens in the element properties section */
698 #define ED_MODE_PROPERTIES_INFO         ED_TEXTBUTTON_ID_PROPERTIES_INFO
699 #define ED_MODE_PROPERTIES_CONFIG       ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
700 #define ED_MODE_PROPERTIES_ADVANCED     ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED
701
702 /* how many steps can be cancelled */
703 #define NUM_UNDO_STEPS                  (10 + 1)
704
705 /* values for elements with score for certain actions */
706 #define MIN_SCORE                       0
707 #define MAX_SCORE                       255
708
709 /* values for elements with count for collecting */
710 #define MIN_COLLECT_COUNT               0
711 #define MAX_COLLECT_COUNT               100
712
713 /* values for random placement */
714 #define RANDOM_USE_PERCENTAGE           0
715 #define RANDOM_USE_QUANTITY             1
716
717 /* maximal size of level editor drawing area */
718 #define MAX_ED_FIELDX           (2 * SCR_FIELDX)
719 #define MAX_ED_FIELDY           (2 * SCR_FIELDY - 1)
720
721
722 /*
723   -----------------------------------------------------------------------------
724   some internally used data structure definitions
725   -----------------------------------------------------------------------------
726 */
727
728 static struct
729 {
730   char shortcut;
731   char *text;
732 } control_info[ED_NUM_CTRL_BUTTONS] =
733 {
734   { 's',        "draw single items"             },
735   { 'd',        "draw connected items"          },
736   { 'l',        "draw lines"                    },
737   { 'a',        "draw arcs"                     },
738   { 'r',        "draw outline rectangles"       },
739   { 'R',        "draw filled rectangles"        },
740   { '\0',       "wrap (rotate) level up"        },
741   { 't',        "enter text elements"           },
742   { 'f',        "flood fill"                    },
743   { '\0',       "wrap (rotate) level left"      },
744   { '?',        "properties of drawing element" },
745   { '\0',       "wrap (rotate) level right"     },
746   { '\0',       "random element placement"      },
747   { 'b',        "grab brush"                    },
748   { '\0',       "wrap (rotate) level down"      },
749   { ',',        "pick drawing element"          },
750   { 'U',        "undo last operation"           },
751   { 'I',        "level properties"              },
752   { 'S',        "save level"                    },
753   { 'C',        "clear level"                   },
754   { 'T',        "test level"                    },
755   { 'E',        "exit level editor"             }
756 };
757
758 static int random_placement_value = 10;
759 static int random_placement_method = RANDOM_USE_QUANTITY;
760 static int random_placement_background_element = EL_SAND;
761 static boolean random_placement_background_restricted = FALSE;
762 static boolean stick_element_properties_window = FALSE;
763 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
764 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
765 static struct ElementChangeInfo custom_element_change;
766 static struct ElementInfo custom_element;
767
768 static struct
769 {
770   int x, y;
771   int min_value, max_value;
772   int gadget_id_down, gadget_id_up;
773   int gadget_id_text;
774   int gadget_id_align;
775   int *value;
776   char *text_above, *text_left, *text_right;
777 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
778 {
779   /* ---------- level and editor settings ---------------------------------- */
780
781   {
782     DX + 5 - SX,                        DY + 3 - SY,
783     1,                                  100,
784     GADGET_ID_SELECT_LEVEL_DOWN,        GADGET_ID_SELECT_LEVEL_UP,
785     GADGET_ID_SELECT_LEVEL_TEXT,        GADGET_ID_NONE,
786     &level_nr,
787     NULL,                               NULL, NULL
788   },
789   {
790     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(2),
791     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
792     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
793     GADGET_ID_LEVEL_XSIZE_TEXT,         GADGET_ID_NONE,
794     &level.fieldx,
795     "playfield size:",                  NULL, "width",
796   },
797   {
798     -1,                                 ED_COUNTER_YPOS(2),
799     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
800     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
801     GADGET_ID_LEVEL_YSIZE_TEXT,         GADGET_ID_LEVEL_XSIZE_UP,
802     &level.fieldy,
803     NULL,                               " ", "height",
804   },
805   {
806     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(3),
807     0,                                  999,
808     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,     GADGET_ID_LEVEL_GEMSLIMIT_UP,
809     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,     GADGET_ID_NONE,
810     &level.gems_needed,
811     "number of emeralds to collect:",   NULL, NULL
812   },
813   {
814     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(4),
815     0,                                  999,
816     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
817     GADGET_ID_LEVEL_TIMELIMIT_TEXT,     GADGET_ID_NONE,
818     &level.time,
819     "time available to solve level:",   NULL, "(0 => no time limit)"
820   },
821   {
822     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(5),
823     0,                                  255,
824     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
825     GADGET_ID_LEVEL_TIMESCORE_TEXT,     GADGET_ID_NONE,
826     &level.score[SC_TIME_BONUS],
827     "score for each 10 seconds left:",  NULL, NULL
828   },
829   {
830     ED_SETTINGS_XPOS(0),                ED_COUNTER2_YPOS(8),
831     1,                                  100,
832     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
833     GADGET_ID_LEVEL_RANDOM_TEXT,        GADGET_ID_NONE,
834     &random_placement_value,
835     "random element placement:",        NULL, "in"
836   },
837
838   /* ---------- element settings: configure (various elements) ------------- */
839
840   {
841     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(0),
842     MIN_SCORE,                          MAX_SCORE,
843     GADGET_ID_ELEMENT_SCORE_DOWN,       GADGET_ID_ELEMENT_SCORE_UP,
844     GADGET_ID_ELEMENT_SCORE_TEXT,       GADGET_ID_NONE,
845     NULL,                               /* will be set when used */
846     NULL,                               NULL, NULL
847   },
848   {
849     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(6),
850     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
851     GADGET_ID_ELEMENT_CONTENT_DOWN,     GADGET_ID_ELEMENT_CONTENT_UP,
852     GADGET_ID_ELEMENT_CONTENT_TEXT,     GADGET_ID_NONE,
853     &level.num_yamyam_contents,
854     NULL,                               NULL, "number of content areas"
855   },
856   {
857     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(0),
858     MIN_ENVELOPE_XSIZE,                 MAX_ENVELOPE_XSIZE,
859     GADGET_ID_ENVELOPE_XSIZE_DOWN,      GADGET_ID_ENVELOPE_XSIZE_UP,
860     GADGET_ID_ENVELOPE_XSIZE_TEXT,      GADGET_ID_NONE,
861     &level.envelope_xsize,
862     NULL,                               NULL, "width",
863   },
864   {
865     -1,                                 ED_SETTINGS_YPOS(0),
866     MIN_ENVELOPE_YSIZE,                 MAX_ENVELOPE_YSIZE,
867     GADGET_ID_ENVELOPE_YSIZE_DOWN,      GADGET_ID_ENVELOPE_YSIZE_UP,
868     GADGET_ID_ENVELOPE_YSIZE_TEXT,      GADGET_ID_ENVELOPE_XSIZE_UP,
869     &level.envelope_ysize,
870     NULL,                               " ", "height",
871   },
872
873   /* ---------- element settings: configure (custom elements) ------------- */
874
875   {
876     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(3),
877     MIN_SCORE,                          MAX_SCORE,
878     GADGET_ID_CUSTOM_SCORE_DOWN,        GADGET_ID_CUSTOM_SCORE_UP,
879     GADGET_ID_CUSTOM_SCORE_TEXT,        GADGET_ID_NONE,
880     &custom_element.collect_score,
881     NULL,                               "score", " "
882   },
883   {
884     -1,                                 ED_SETTINGS_YPOS(3),
885     MIN_COLLECT_COUNT,                  MAX_COLLECT_COUNT,
886     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,     GADGET_ID_CUSTOM_GEMCOUNT_UP,
887     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,     GADGET_ID_CUSTOM_SCORE_UP,
888     &custom_element.collect_count,
889     NULL,                               "count", NULL
890   },
891   {
892     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(4),
893     0,                                  999,
894     GADGET_ID_PUSH_DELAY_FIX_DOWN,      GADGET_ID_PUSH_DELAY_FIX_UP,
895     GADGET_ID_PUSH_DELAY_FIX_TEXT,      GADGET_ID_NONE,
896     &custom_element.push_delay_fixed,
897     NULL,                               "push delay", NULL
898   },
899   {
900     -1,                                 ED_SETTINGS_YPOS(4),
901     0,                                  999,
902     GADGET_ID_PUSH_DELAY_RND_DOWN,      GADGET_ID_PUSH_DELAY_RND_UP,
903     GADGET_ID_PUSH_DELAY_RND_TEXT,      GADGET_ID_PUSH_DELAY_FIX_UP,
904     &custom_element.push_delay_random,
905     NULL,                               "+random", NULL
906   },
907   {
908     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(7),
909     0,                                  999,
910     GADGET_ID_MOVE_DELAY_FIX_DOWN,      GADGET_ID_MOVE_DELAY_FIX_UP,
911     GADGET_ID_MOVE_DELAY_FIX_TEXT,      GADGET_ID_NONE,
912     &custom_element.move_delay_fixed,
913     NULL,                               "move delay", NULL
914   },
915   {
916     -1,                                 ED_SETTINGS_YPOS(7),
917     0,                                  999,
918     GADGET_ID_MOVE_DELAY_RND_DOWN,      GADGET_ID_MOVE_DELAY_RND_UP,
919     GADGET_ID_MOVE_DELAY_RND_TEXT,      GADGET_ID_MOVE_DELAY_FIX_UP,
920     &custom_element.move_delay_random,
921     NULL,                               "+random", NULL
922   },
923
924   /* ---------- element settings: advanced (custom elements) --------------- */
925
926   {
927     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(3),
928     0,                                  999,
929     GADGET_ID_CHANGE_DELAY_FIX_DOWN,    GADGET_ID_CHANGE_DELAY_FIX_UP,
930     GADGET_ID_CHANGE_DELAY_FIX_TEXT,    GADGET_ID_NONE,
931     &custom_element_change.delay_fixed,
932     NULL,                               "delay", NULL,
933   },
934   {
935     -1,                                 ED_SETTINGS_YPOS(3),
936     0,                                  999,
937     GADGET_ID_CHANGE_DELAY_RND_DOWN,    GADGET_ID_CHANGE_DELAY_RND_UP,
938     GADGET_ID_CHANGE_DELAY_RND_TEXT,    GADGET_ID_CHANGE_DELAY_FIX_UP,
939     &custom_element_change.delay_random,
940     NULL,                               "+random", NULL
941   },
942   {
943     ED_SETTINGS_XPOS(3),                ED_SETTINGS_YPOS(11),
944     0,                                  100,
945     GADGET_ID_CHANGE_CONT_RND_DOWN,     GADGET_ID_CHANGE_CONT_RND_UP,
946     GADGET_ID_CHANGE_CONT_RND_TEXT,     GADGET_ID_NONE,
947     &custom_element_change.random,
948     NULL,                               "use random change:", "(%)"
949   },
950 };
951
952 static struct
953 {
954   int x, y;
955   int gadget_id;
956   int size;
957   char *value;
958   char *text_above, *infotext;
959 } textinput_info[ED_NUM_TEXTINPUT] =
960 {
961   {
962     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(0),
963     GADGET_ID_LEVEL_NAME,
964     MAX_LEVEL_NAME_LEN,
965     level.name,
966     "Title:", "Title"
967   },
968   {
969     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(1),
970     GADGET_ID_LEVEL_AUTHOR,
971     MAX_LEVEL_AUTHOR_LEN,
972     level.author,
973     "Author:", "Author"
974   },
975   {
976     5 * MINI_TILEX,                     5 * MINI_TILEY - ED_BORDER_SIZE,
977     GADGET_ID_ELEMENT_NAME,
978     MAX_ELEMENT_NAME_LEN - 2,           /* currently 2 chars less editable */
979     custom_element.description,
980     NULL, "Element name"
981   }
982 };
983
984 static struct
985 {
986   int x, y;
987   int gadget_id;
988   int xsize, ysize;
989   char *value;
990   char *text_above, *infotext;
991 } textarea_info[ED_NUM_TEXTAREAS] =
992 {
993   {
994     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(2),
995     GADGET_ID_ENVELOPE_INFO,
996     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
997     level.envelope,
998     "Envelope Info:", "Envelope Info"
999   }
1000 };
1001
1002 static struct ValueTextInfo options_access_type[] =
1003 {
1004   { EP_WALKABLE,                "walk"                          },
1005   { EP_PASSABLE,                "pass"                          },
1006   { -1,                         NULL                            }
1007 };
1008
1009 static struct ValueTextInfo options_access_layer[] =
1010 {
1011   { EP_ACCESSIBLE_OVER,         "over"                          },
1012   { EP_ACCESSIBLE_INSIDE,       "inside"                        },
1013   { EP_ACCESSIBLE_UNDER,        "under"                         },
1014   { -1,                         NULL                            }
1015 };
1016
1017 static struct ValueTextInfo options_walk_to_action[] =
1018 {
1019   { EP_DIGGABLE,                "diggable"                      },
1020   { EP_COLLECTIBLE_ONLY,        "collectible"                   },
1021   { EP_DROPPABLE,               "collectible & droppable"       },
1022   { EP_PUSHABLE,                "pushable"                      },
1023   { -1,                         NULL                            }
1024 };
1025
1026 static struct ValueTextInfo options_move_pattern[] =
1027 {
1028   { MV_LEFT,                    "left"                          },
1029   { MV_RIGHT,                   "right"                         },
1030   { MV_UP,                      "up"                            },
1031   { MV_DOWN,                    "down"                          },
1032   { MV_HORIZONTAL,              "horizontal"                    },
1033   { MV_VERTICAL,                "vertical"                      },
1034   { MV_ALL_DIRECTIONS,          "all directions"                },
1035   { MV_TOWARDS_PLAYER,          "towards player"                },
1036   { MV_AWAY_FROM_PLAYER,        "away from player"              },
1037   { MV_ALONG_LEFT_SIDE,         "along left side"               },
1038   { MV_ALONG_RIGHT_SIDE,        "along right side"              },
1039   { MV_TURNING_LEFT,            "turning left"                  },
1040   { MV_TURNING_RIGHT,           "turning right"                 },
1041   { -1,                         NULL                            }
1042 };
1043
1044 static struct ValueTextInfo options_move_direction[] =
1045 {
1046   { MV_NO_MOVING,               "automatic"                     },
1047   { MV_LEFT,                    "left"                          },
1048   { MV_RIGHT,                   "right"                         },
1049   { MV_UP,                      "up"                            },
1050   { MV_DOWN,                    "down"                          },
1051   { -1,                         NULL                            }
1052 };
1053
1054 static struct ValueTextInfo options_move_stepsize[] =
1055 {
1056   { 1,                          "very slow"                     },
1057   { 2,                          "slow"                          },
1058   { 4,                          "normal"                        },
1059   { 8,                          "fast"                          },
1060   { 16,                         "very fast"                     },
1061   { -1,                         NULL                            }
1062 };
1063
1064 static struct ValueTextInfo options_smash_targets[] =
1065 {
1066   { EP_CAN_SMASH_PLAYER,        "player"                        },
1067 #if 0
1068   { EP_CAN_SMASH_ENEMIES,       "enemies"                       },
1069 #endif
1070   { EP_CAN_SMASH_EVERYTHING,    "everything"                    },
1071   { -1,                         NULL                            }
1072 };
1073
1074 static struct ValueTextInfo options_slippery_type[] =
1075 {
1076   { SLIPPERY_ANY_RANDOM,        "random"                        },
1077   { SLIPPERY_ANY_LEFT_RIGHT,    "left, right"                   },
1078   { SLIPPERY_ANY_RIGHT_LEFT,    "right, left"                   },
1079   { SLIPPERY_ONLY_LEFT,         "only left"                     },
1080   { SLIPPERY_ONLY_RIGHT,        "only right"                    },
1081   { -1,                         NULL                            }
1082 };
1083
1084 static struct ValueTextInfo options_deadliness[] =
1085 {
1086   { EP_DONT_RUN_INTO,           "running into"                  },
1087   { EP_DONT_COLLIDE_WITH,       "colliding with"                },
1088   { EP_DONT_TOUCH,              "touching"                      },
1089   { -1,                         NULL                            }
1090 };
1091
1092 static struct ValueTextInfo options_consistency[] =
1093 {
1094   { EP_CAN_EXPLODE_3X3,         "can explode 3x3"               },
1095   { EP_CAN_EXPLODE_1X1,         "can explode 1x1"               },
1096   { EP_INDESTRUCTIBLE,          "indestructible"                },
1097   { -1,                         NULL                            }
1098 };
1099
1100 static struct ValueTextInfo options_time_units[] =
1101 {
1102   { FRAMES_PER_SECOND,          "seconds"                       },
1103   { 1,                          "frames"                        },
1104   { -1,                         NULL                            }
1105 };
1106
1107 static struct ValueTextInfo options_change_direct_action[] =
1108 {
1109   { CE_TOUCHED_BY_PLAYER,       "touched by player"             },
1110   { CE_PRESSED_BY_PLAYER,       "pressed by player"             },
1111   { CE_PUSHED_BY_PLAYER,        "pushed by player"              },
1112   { CE_DROPPED_BY_PLAYER,       "dropped by player"             },
1113   { CE_COLLISION,               "collision"                     },
1114   { CE_IMPACT,                  "impact"                        },
1115   { CE_SMASHED,                 "smashed"                       },
1116   { -1,                         NULL                            }
1117 };
1118
1119 static struct ValueTextInfo options_change_other_action[] =
1120 {
1121   { CE_OTHER_GETS_TOUCHED,      "player touches"                },
1122   { CE_OTHER_GETS_PRESSED,      "player presses"                },
1123   { CE_OTHER_GETS_PUSHED,       "player pushes"                 },
1124   { CE_OTHER_GETS_DIGGED,       "player digs"                   },
1125   { CE_OTHER_GETS_COLLECTED,    "player collects"               },
1126   { CE_OTHER_GETS_DROPPED,      "player drops"                  },
1127   { CE_OTHER_IS_TOUCHING,       "touching"                      },
1128   { CE_OTHER_IS_CHANGING,       "change of"                     },
1129   { CE_OTHER_IS_EXPLODING,      "explosion of"                  },
1130   { -1,                         NULL                            }
1131 };
1132
1133 static struct ValueTextInfo options_change_power[] =
1134 {
1135   { CP_NON_DESTRUCTIVE,         "empty"                         },
1136   { CP_HALF_DESTRUCTIVE,        "diggable"                      },
1137   { CP_FULL_DESTRUCTIVE,        "destructible"                  },
1138   { -1,                         NULL                            }
1139 };
1140
1141 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
1142 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
1143 {
1144   { -1,                         NULL                            }
1145 };
1146
1147 static struct
1148 {
1149   int x, y;
1150   int gadget_id;
1151   int gadget_id_align;
1152   int size;     /* char size of selectbox or '-1' (dynamically determined) */
1153   struct ValueTextInfo *options;
1154   int *value;
1155   char *text_left, *text_right, *infotext;
1156 } selectbox_info[ED_NUM_SELECTBOX] =
1157 {
1158   /* ---------- element settings: configure (custom elements) ------------- */
1159
1160   {
1161     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(1),
1162     GADGET_ID_CUSTOM_ACCESS_TYPE,       GADGET_ID_NONE,
1163     -1,
1164     options_access_type,
1165     &custom_element.access_type,
1166     "player can", NULL,                 "type of access to this field"
1167   },
1168   {
1169     -1,                                 ED_SETTINGS_YPOS(1),
1170     GADGET_ID_CUSTOM_ACCESS_LAYER,      GADGET_ID_CUSTOM_ACCESS_TYPE,
1171     -1,
1172     options_access_layer,
1173     &custom_element.access_layer,
1174     NULL, NULL,                         "layer of access for this field"
1175   },
1176   {
1177     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(2),
1178     GADGET_ID_CUSTOM_WALK_TO_ACTION,    GADGET_ID_NONE,
1179     -1,
1180     options_walk_to_action,
1181     &custom_element.walk_to_action,
1182     NULL, NULL,                         "diggable/collectible/pushable"
1183   },
1184   {
1185     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(5),
1186     GADGET_ID_CUSTOM_MOVE_PATTERN,      GADGET_ID_NONE,
1187     -1,
1188     options_move_pattern,
1189     &custom_element.move_pattern,
1190     "can move", NULL,                   "element move direction"
1191   },
1192   {
1193     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(6),
1194     GADGET_ID_CUSTOM_MOVE_DIRECTION,    GADGET_ID_NONE,
1195     -1,
1196     options_move_direction,
1197     &custom_element.move_direction_initial,
1198     "starts moving", NULL,              "initial element move direction"
1199   },
1200   {
1201     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(8),
1202     GADGET_ID_CUSTOM_MOVE_STEPSIZE,     GADGET_ID_NONE,
1203     -1,
1204     options_move_stepsize,
1205     &custom_element.move_stepsize,
1206     "move/fall speed", NULL,            "speed of element movement"
1207   },
1208   {
1209     -1,                                 ED_SETTINGS_YPOS(9),
1210     GADGET_ID_CUSTOM_SMASH_TARGETS,     GADGET_ID_CUSTOM_CAN_SMASH,
1211     -1,
1212     options_smash_targets,
1213     &custom_element.smash_targets,
1214     "can smash", NULL,                  "elements that can be smashed"
1215   },
1216   {
1217     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(10),
1218     GADGET_ID_CUSTOM_SLIPPERY_TYPE,     GADGET_ID_NONE,
1219     -1,
1220     options_slippery_type,
1221     &custom_element.slippery_type,
1222     "slippery", NULL,                   "where other elements fall down"
1223   },
1224   {
1225     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(11),
1226     GADGET_ID_CUSTOM_DEADLINESS,        GADGET_ID_NONE,
1227     -1,
1228     options_deadliness,
1229     &custom_element.deadliness,
1230     "deadly when", NULL,                "deadliness of element"
1231   },
1232   {
1233     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(12),
1234     GADGET_ID_CUSTOM_CONSISTENCY,       GADGET_ID_NONE,
1235     -1,
1236     options_consistency,
1237     &custom_element.consistency,
1238     NULL, NULL,                         "consistency/destructibility"
1239   },
1240
1241   /* ---------- element settings: advanced (custom elements) --------------- */
1242
1243   {
1244     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(4),
1245     GADGET_ID_CHANGE_TIME_UNITS,        GADGET_ID_NONE,
1246     -1,
1247     options_time_units,
1248     &custom_element_change.delay_frames,
1249     "delay time given in", NULL,        "delay time units for change"
1250   },
1251   {
1252     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(5),
1253     GADGET_ID_CHANGE_DIRECT_ACTION,     GADGET_ID_NONE,
1254     -1,
1255     options_change_direct_action,
1256     &custom_element_change.direct_action,
1257     NULL, NULL,                         "type of direct action"
1258   },
1259   {
1260     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(6),
1261     GADGET_ID_CHANGE_OTHER_ACTION,      GADGET_ID_NONE,
1262     -1,
1263     options_change_other_action,
1264     &custom_element_change.other_action,
1265     NULL, "element:",                   "type of other element action"
1266   },
1267   {
1268     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(9),
1269     GADGET_ID_CHANGE_POWER,             GADGET_ID_NONE,
1270     -1,
1271     options_change_power,
1272     &custom_element_change.power,
1273     "replace when", NULL,               "which elements can be replaced"
1274   },
1275   {
1276     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(13),
1277     GADGET_ID_SELECT_CHANGE_PAGE,       GADGET_ID_NONE,
1278     3,
1279     options_change_page,
1280     &custom_element.current_change_page,
1281     NULL, NULL,                         "element config page"
1282   },
1283 };
1284
1285 static struct
1286 {
1287   int x, y;
1288   int gadget_id;
1289   int gadget_id_align;
1290   int size;
1291   char *text;
1292   char *text_left, *text_right, *infotext;
1293 } textbutton_info[ED_NUM_TEXTBUTTONS] =
1294 {
1295   {
1296     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(1),
1297     GADGET_ID_PROPERTIES_INFO,          GADGET_ID_NONE,
1298     11,                                 "Information",                  
1299     NULL, NULL,                         "Show information about element"
1300   },
1301   {
1302     ED_SETTINGS_XPOS(0) + 166,          ED_COUNTER_YPOS(1),
1303     GADGET_ID_PROPERTIES_CONFIG,        GADGET_ID_NONE,
1304     11,                                 "Configure",
1305     NULL, NULL,                         "Configure element properties"
1306   },
1307   {
1308     ED_SETTINGS_XPOS(0) + 332,          ED_COUNTER_YPOS(1),
1309     GADGET_ID_PROPERTIES_ADVANCED,      GADGET_ID_NONE,
1310     11,                                 "Advanced",
1311     NULL, NULL,                         "Advanced element configuration"
1312   },
1313   {
1314     -1,                                 ED_SETTINGS_YPOS(12),
1315     GADGET_ID_SAVE_AS_TEMPLATE,         GADGET_ID_CUSTOM_USE_TEMPLATE,
1316     -1,                                 "Save as template",
1317     " ", NULL,                          "Save current settings as new template"
1318   },
1319   {
1320     -1,                                 ED_SETTINGS_YPOS(13),
1321     GADGET_ID_ADD_CHANGE_PAGE,          GADGET_ID_NEXT_CHANGE_PAGE,
1322     -1,                                 "New",
1323     " ", NULL,                          "Add new config page"
1324   },
1325   {
1326     -1,                                 ED_SETTINGS_YPOS(13),
1327     GADGET_ID_DEL_CHANGE_PAGE,          GADGET_ID_ADD_CHANGE_PAGE,
1328     -1,                                 "Delete",
1329     NULL, NULL,                         "Delete current config page"
1330   },
1331 };
1332
1333 static struct
1334 {
1335   int gd_x, gd_y;
1336   int x, y;
1337   int width, height;
1338   int gadget_id;
1339   int gadget_id_align;
1340   char *text_left, *text_right, *infotext;
1341 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
1342 {
1343   {
1344     ED_BUTTON_MINUS_XPOS,               ED_BUTTON_COUNT_YPOS,
1345     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(13),
1346     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
1347     GADGET_ID_PREV_CHANGE_PAGE,         GADGET_ID_NONE,
1348     NULL, NULL,                         "select previous config page"
1349   },
1350   {
1351     ED_BUTTON_PLUS_XPOS,                ED_BUTTON_COUNT_YPOS,
1352     -1,                                 ED_SETTINGS_YPOS(13),
1353     ED_BUTTON_COUNT_XSIZE,              ED_BUTTON_COUNT_YSIZE,
1354     GADGET_ID_NEXT_CHANGE_PAGE,         GADGET_ID_SELECT_CHANGE_PAGE,
1355     NULL, "config page",                "select next config page"
1356   },
1357 };
1358
1359 static struct
1360 {
1361   int gd_x, gd_y;
1362   int x, y;
1363   int gadget_id;
1364   char *infotext;
1365 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
1366 {
1367   {
1368     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
1369     ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,
1370     GADGET_ID_SCROLL_UP,
1371     "scroll level editing area up"
1372   },
1373   {
1374     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
1375     ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,
1376     GADGET_ID_SCROLL_DOWN,
1377     "scroll level editing area down"
1378   },
1379   {
1380     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
1381     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
1382     GADGET_ID_SCROLL_LEFT,
1383     "scroll level editing area left"
1384   },
1385   {
1386     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
1387     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
1388     GADGET_ID_SCROLL_RIGHT,
1389     "scroll level editing area right"
1390   },
1391   {
1392     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 0 * ED_SCROLLBUTTON2_YSIZE,
1393     ED_SCROLL2_UP_XPOS,     ED_SCROLL2_UP_YPOS,
1394     GADGET_ID_SCROLL_LIST_UP,
1395     "scroll element list up ('Page Up')"
1396   },
1397   {
1398     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE,
1399     ED_SCROLL2_DOWN_XPOS,   ED_SCROLL2_DOWN_YPOS,
1400     GADGET_ID_SCROLL_LIST_DOWN,
1401     "scroll element list down ('Page Down')"
1402   },
1403 };
1404
1405 static struct
1406 {
1407   int gd_x, gd_y;
1408   int x, y;
1409   int width, height;
1410   int type;
1411   int gadget_id;
1412   char *infotext;
1413 } scrollbar_info[ED_NUM_SCROLLBARS] =
1414 {
1415   {
1416     ED_SCROLLBAR_XPOS,                  ED_SCROLLBAR_YPOS,
1417     SX + ED_SCROLL_HORIZONTAL_XPOS,     SY + ED_SCROLL_HORIZONTAL_YPOS,
1418     ED_SCROLL_HORIZONTAL_XSIZE,         ED_SCROLL_HORIZONTAL_YSIZE,
1419     GD_TYPE_SCROLLBAR_HORIZONTAL,
1420     GADGET_ID_SCROLL_HORIZONTAL,
1421     "scroll level editing area horizontally"
1422   },
1423   {
1424     ED_SCROLLBAR_XPOS,                  ED_SCROLLBAR_YPOS,
1425     SX + ED_SCROLL_VERTICAL_XPOS,       SY + ED_SCROLL_VERTICAL_YPOS,
1426     ED_SCROLL_VERTICAL_XSIZE,           ED_SCROLL_VERTICAL_YSIZE,
1427     GD_TYPE_SCROLLBAR_VERTICAL,
1428     GADGET_ID_SCROLL_VERTICAL,
1429     "scroll level editing area vertically"
1430   },
1431   {
1432     ED_SCROLLBAR2_XPOS,                 ED_SCROLLBAR2_YPOS,
1433     DX + ED_SCROLL2_VERTICAL_XPOS,      DY + ED_SCROLL2_VERTICAL_YPOS,
1434     ED_SCROLL2_VERTICAL_XSIZE,          ED_SCROLL2_VERTICAL_YSIZE,
1435     GD_TYPE_SCROLLBAR_VERTICAL,
1436     GADGET_ID_SCROLL_LIST_VERTICAL,
1437     "scroll element list vertically"
1438   }
1439 };
1440
1441 static struct
1442 {
1443   int x, y;
1444   int gadget_id;
1445   int gadget_id_align;
1446   int radio_button_nr;
1447   int *value;
1448   int checked_value;
1449   char *text_left, *text_right, *infotext;
1450 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
1451 {
1452   {
1453     -1,                                 ED_COUNTER2_YPOS(8),
1454     GADGET_ID_RANDOM_PERCENTAGE,        GADGET_ID_LEVEL_RANDOM_UP,
1455     RADIO_NR_RANDOM_ELEMENTS,
1456     &random_placement_method,           RANDOM_USE_PERCENTAGE,
1457     " ", "percentage",                  "use percentage for random elements"
1458   },
1459   {
1460     -1,                                 ED_COUNTER2_YPOS(8),
1461     GADGET_ID_RANDOM_QUANTITY,          GADGET_ID_RANDOM_PERCENTAGE,
1462     RADIO_NR_RANDOM_ELEMENTS,
1463     &random_placement_method,           RANDOM_USE_QUANTITY,
1464     " ", "quantity",                    "use quantity for random elements"
1465   }
1466 };
1467
1468 static struct
1469 {
1470   int x, y;
1471   int gadget_id;
1472   int gadget_id_align;
1473   boolean *value;
1474   char *text_left, *text_right, *infotext;
1475 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
1476 {
1477   /* ---------- level and editor settings ---------------------------------- */
1478
1479   {
1480     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(6) - MINI_TILEY,
1481     GADGET_ID_DOUBLE_SPEED,             GADGET_ID_NONE,
1482     &level.double_speed,
1483     NULL, "double speed movement",      "set movement speed of player"
1484   },
1485   {
1486     -1,                                 ED_COUNTER_YPOS(6) - MINI_TILEY,
1487     GADGET_ID_GRAVITY,                  GADGET_ID_DOUBLE_SPEED,
1488     &level.gravity,
1489     " ", "gravity",                     "set level gravity"
1490   },
1491   {
1492     ED_SETTINGS_XPOS(0),                ED_COUNTER2_YPOS(9) - MINI_TILEY,
1493     GADGET_ID_RANDOM_RESTRICTED,        GADGET_ID_NONE,
1494     &random_placement_background_restricted,
1495     NULL,
1496     "restrict random placement to:",    "set random placement restriction"
1497   },
1498
1499   /* ---------- element settings: configure (various elements) ------------- */
1500
1501   {
1502     ED_SETTINGS_XPOS(0),                0,      /* set at runtime */
1503     GADGET_ID_STICK_ELEMENT,            GADGET_ID_NONE,
1504     &stick_element_properties_window,
1505     NULL,
1506     "stick this screen to edit content","stick this screen to edit content"
1507   },
1508   {
1509     ED_SETTINGS_XPOS(0),                ED_COUNTER_YPOS(4),
1510     GADGET_ID_EM_SLIPPERY_GEMS,         GADGET_ID_NONE,
1511     &level.em_slippery_gems,
1512     NULL,
1513     "slip down from certain flat walls","use EM style slipping behaviour"
1514   },
1515
1516   /* ---------- element settings: configure (custom elements) ------------- */
1517
1518   {
1519     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(1),
1520     GADGET_ID_CUSTOM_ACCESSIBLE,        GADGET_ID_NONE,
1521     &custom_element_properties[EP_ACCESSIBLE],
1522     NULL, NULL,                         "player can walk to or pass this field"
1523   },
1524   {
1525     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(2),
1526     GADGET_ID_CUSTOM_WALK_TO_OBJECT,    GADGET_ID_NONE,
1527     &custom_element_properties[EP_WALK_TO_OBJECT],
1528     NULL, NULL,                         "player can dig/collect/push element"
1529   },
1530   {
1531     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(5),
1532     GADGET_ID_CUSTOM_CAN_MOVE,          GADGET_ID_NONE,
1533     &custom_element_properties[EP_CAN_MOVE],
1534     NULL, NULL,                         "element can move in some direction"
1535   },
1536   {
1537     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(9),
1538     GADGET_ID_CUSTOM_CAN_FALL,          GADGET_ID_NONE,
1539     &custom_element_properties[EP_CAN_FALL],
1540     NULL, "can fall",                   "element can fall down"
1541   },
1542   {
1543     -1,                                 ED_SETTINGS_YPOS(9),
1544     GADGET_ID_CUSTOM_CAN_SMASH,         GADGET_ID_CUSTOM_CAN_FALL,
1545     &custom_element_properties[EP_CAN_SMASH],
1546     " ", NULL,                          "element can smash other elements"
1547   },
1548   {
1549     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(10),
1550     GADGET_ID_CUSTOM_SLIPPERY,          GADGET_ID_NONE,
1551     &custom_element_properties[EP_SLIPPERY],
1552     NULL, NULL,                         "other elements can fall down from it"
1553   },
1554   {
1555     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(11),
1556     GADGET_ID_CUSTOM_DEADLY,            GADGET_ID_NONE,
1557     &custom_element_properties[EP_DEADLY],
1558     NULL, NULL,                         "element can kill the player"
1559   },
1560   {
1561     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(12),
1562     GADGET_ID_CUSTOM_EXPLODE_RESULT,    GADGET_ID_NONE,
1563     &custom_element_properties[EP_EXPLODE_RESULT],
1564     NULL, NULL,                         "set consistency/destructibility"
1565   },
1566   {
1567     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(13),
1568     GADGET_ID_CUSTOM_EXPLODE_FIRE,      GADGET_ID_NONE,
1569     &custom_element.can_explode_by_fire,
1570     NULL, "by fire",                    "element can explode by fire/explosion"
1571   },
1572   {
1573     -1,                                 ED_SETTINGS_YPOS(13),
1574     GADGET_ID_CUSTOM_EXPLODE_SMASH,     GADGET_ID_CUSTOM_EXPLODE_FIRE,
1575     &custom_element.can_explode_smashed,
1576     " ", "smashed",                     "element can explode when smashed"
1577   },
1578   {
1579     -1,                                 ED_SETTINGS_YPOS(13),
1580     GADGET_ID_CUSTOM_EXPLODE_IMPACT,    GADGET_ID_CUSTOM_EXPLODE_SMASH,
1581     &custom_element.can_explode_impact,
1582     " ", "impact",                      "element can explode on impact"
1583   },
1584
1585   /* ---------- element settings: advanced (custom elements) --------------- */
1586
1587   {
1588     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(1),
1589     GADGET_ID_CUSTOM_USE_GRAPHIC,       GADGET_ID_NONE,
1590     &custom_element.use_gfx_element,
1591     NULL, "use graphic of element:",    "use graphic for custom element"
1592   },
1593   {
1594     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(2),
1595     GADGET_ID_CUSTOM_CAN_CHANGE,        GADGET_ID_NONE,
1596     &custom_element_change.can_change,
1597     NULL, "element changes to:",        "element can change to other element"
1598   },
1599   {
1600     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(3),
1601     GADGET_ID_CHANGE_DELAY,             GADGET_ID_NONE,
1602     &custom_element_change_events[CE_DELAY],
1603     NULL, NULL,                         "element changes after delay"
1604   },
1605   {
1606     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(5),
1607     GADGET_ID_CHANGE_BY_DIRECT_ACT,     GADGET_ID_NONE,
1608     &custom_element_change_events[CE_BY_DIRECT_ACTION],
1609     NULL, NULL,                         "element changes by direct action"
1610   },
1611   {
1612     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(6),
1613     GADGET_ID_CHANGE_BY_OTHER_ACT,      GADGET_ID_NONE,
1614     &custom_element_change_events[CE_BY_OTHER_ACTION],
1615     NULL, NULL,                         "element changes by other element"
1616   },
1617   {
1618     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(7),
1619     GADGET_ID_CHANGE_USE_EXPLOSION,     GADGET_ID_NONE,
1620     &custom_element_change.explode,
1621     NULL, "explode instead of change",  "element explodes instead of change"
1622   },
1623   {
1624     ED_SETTINGS_XPOS(1),                ED_SETTINGS_YPOS(8),
1625     GADGET_ID_CHANGE_USE_CONTENT,       GADGET_ID_NONE,
1626     &custom_element_change.use_content,
1627     NULL, "use extended change target:","element changes to more elements"
1628   },
1629   {
1630     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(10),
1631     GADGET_ID_CHANGE_ONLY_COMPLETE,     GADGET_ID_NONE,
1632     &custom_element_change.only_complete,
1633     NULL, "only use complete change",   "only use complete extended content"
1634   },
1635   {
1636     ED_SETTINGS_XPOS(2),                ED_SETTINGS_YPOS(11),
1637     GADGET_ID_CHANGE_USE_RANDOM,        GADGET_ID_NONE,
1638     &custom_element_change.use_random_change,
1639     NULL, NULL,                         "use random value for new content"
1640   },
1641   {
1642     ED_SETTINGS_XPOS(0),                ED_SETTINGS_YPOS(12),
1643     GADGET_ID_CUSTOM_USE_TEMPLATE,      GADGET_ID_NONE,
1644     &level.use_custom_template,
1645     NULL, "use template",               "use template for custom properties"
1646   },
1647 };
1648
1649 static struct
1650 {
1651   int x, y;
1652   int area_xsize, area_ysize;
1653   int gadget_id;
1654   int gadget_id_align;
1655   char *text_left, *text_right, *text_below;
1656 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
1657 {
1658   /* ---------- level playfield content ------------------------------------ */
1659
1660   {
1661     0, 0,
1662     MAX_ED_FIELDX, MAX_ED_FIELDY,
1663     GADGET_ID_DRAWING_LEVEL,            GADGET_ID_NONE,
1664     NULL, NULL,                         NULL
1665   },
1666
1667   /* ---------- yam yam content -------------------------------------------- */
1668
1669   {
1670     ED_AREA_YAMYAM_CONTENT_XPOS(0),     ED_AREA_YAMYAM_CONTENT_YPOS(0),
1671     3, 3,
1672     GADGET_ID_ELEMENT_CONTENT_0,        GADGET_ID_NONE,
1673     NULL, NULL,                         "1"
1674   },
1675   {
1676     ED_AREA_YAMYAM_CONTENT_XPOS(1),     ED_AREA_YAMYAM_CONTENT_YPOS(1),
1677     3, 3,
1678     GADGET_ID_ELEMENT_CONTENT_1,        GADGET_ID_NONE,
1679     NULL, NULL,                         "2"
1680   },
1681   {
1682     ED_AREA_YAMYAM_CONTENT_XPOS(2),     ED_AREA_YAMYAM_CONTENT_YPOS(2),
1683     3, 3,
1684     GADGET_ID_ELEMENT_CONTENT_2,        GADGET_ID_NONE,
1685     NULL, NULL,                         "3"
1686   },
1687   {
1688     ED_AREA_YAMYAM_CONTENT_XPOS(3),     ED_AREA_YAMYAM_CONTENT_YPOS(3),
1689     3, 3,
1690     GADGET_ID_ELEMENT_CONTENT_3,        GADGET_ID_NONE,
1691     NULL, NULL,                         "4"
1692   },
1693   {
1694     ED_AREA_YAMYAM_CONTENT_XPOS(4),     ED_AREA_YAMYAM_CONTENT_YPOS(4),
1695     3, 3,
1696     GADGET_ID_ELEMENT_CONTENT_4,        GADGET_ID_NONE,
1697     NULL, NULL,                         "5"
1698   },
1699   {
1700     ED_AREA_YAMYAM_CONTENT_XPOS(5),     ED_AREA_YAMYAM_CONTENT_YPOS(5),
1701     3, 3,
1702     GADGET_ID_ELEMENT_CONTENT_5,        GADGET_ID_NONE,
1703     NULL, NULL,                         "6"
1704   },
1705   {
1706     ED_AREA_YAMYAM_CONTENT_XPOS(6),     ED_AREA_YAMYAM_CONTENT_YPOS(6),
1707     3, 3,
1708     GADGET_ID_ELEMENT_CONTENT_6,        GADGET_ID_NONE,
1709     NULL, NULL,                         "7"
1710   },
1711   {
1712     ED_AREA_YAMYAM_CONTENT_XPOS(7),     ED_AREA_YAMYAM_CONTENT_YPOS(7),
1713     3, 3,
1714     GADGET_ID_ELEMENT_CONTENT_7,        GADGET_ID_NONE,
1715     NULL, NULL,                         "8"
1716   },
1717
1718   /* ---------- amoeba content --------------------------------------------- */
1719
1720   {
1721     ED_AREA_ELEM_CONTENT_XPOS,          ED_AREA_ELEM_CONTENT_YPOS,
1722     1, 1,
1723     GADGET_ID_AMOEBA_CONTENT,           GADGET_ID_NONE,
1724     NULL, "content of amoeba",          NULL
1725   },
1726
1727   /* ---------- custom graphic --------------------------------------------- */
1728
1729   {
1730     -1,                                 ED_AREA_ELEM_CONTENT3_YPOS,
1731     1, 1,
1732     GADGET_ID_CUSTOM_GRAPHIC,           GADGET_ID_CUSTOM_USE_GRAPHIC,
1733     NULL, NULL,                         NULL
1734   },
1735
1736   /* ---------- custom content (when exploding) ---------------------------- */
1737
1738   {
1739     ED_AREA_ELEM_CONTENT4_XPOS,         ED_AREA_ELEM_CONTENT4_YPOS,
1740     3, 3,
1741     GADGET_ID_CUSTOM_CONTENT,           GADGET_ID_NONE, /* align three rows */
1742     "content:", NULL,                   NULL
1743   },
1744
1745   /* ---------- custom change target --------------------------------------- */
1746
1747   {
1748     -1,                                 ED_AREA_ELEM_CONTENT2_YPOS,
1749     1, 1,
1750     GADGET_ID_CUSTOM_CHANGE_TARGET,     GADGET_ID_CUSTOM_CAN_CHANGE,
1751     NULL, "after/when:",                NULL
1752   },
1753
1754   /* ---------- custom change content (extended change target) ------------- */
1755
1756   {
1757     ED_AREA_ELEM_CONTENT6_XPOS,         ED_AREA_ELEM_CONTENT6_YPOS,
1758     3, 3,
1759     GADGET_ID_CUSTOM_CHANGE_CONTENT,    GADGET_ID_NONE, /* align three rows */
1760     NULL, NULL,                         NULL
1761   },
1762
1763   /* ---------- custom change trigger (element causing change) ------------- */
1764
1765   {
1766     -1,                                 ED_AREA_ELEM_CONTENT5_YPOS,
1767     1, 1,
1768     GADGET_ID_CUSTOM_CHANGE_TRIGGER,    GADGET_ID_CHANGE_OTHER_ACTION,
1769     NULL, NULL,                         NULL
1770   },
1771
1772   /* ---------- random background (for random painting) -------------------- */
1773
1774   {
1775     -1,                                 ED_AREA_RANDOM_BACKGROUND_YPOS,
1776     1, 1,
1777     GADGET_ID_RANDOM_BACKGROUND,        GADGET_ID_RANDOM_RESTRICTED,
1778     NULL, NULL,                         NULL
1779   },
1780 };
1781
1782
1783 /*
1784   -----------------------------------------------------------------------------
1785   some internally used variables
1786   -----------------------------------------------------------------------------
1787 */
1788
1789 /* actual size of level editor drawing area */
1790 static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
1791
1792 /* actual position of level editor drawing area in level playfield */
1793 static int level_xpos = -1, level_ypos = -1;
1794
1795 #define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldy)
1796
1797 /* drawing elements on the three mouse buttons */
1798 static int new_element1 = EL_WALL;
1799 static int new_element2 = EL_EMPTY;
1800 static int new_element3 = EL_SAND;
1801
1802 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
1803                                 (button) == 2 ? new_element2 : \
1804                                 (button) == 3 ? new_element3 : EL_EMPTY)
1805 #define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10)
1806
1807 /* forward declaration for internal use */
1808 static void ModifyEditorCounter(int, int);
1809 static void ModifyEditorCounterLimits(int, int, int);
1810 static void ModifyEditorSelectbox(int, int);
1811 static void ModifyEditorElementList();
1812 static void RedrawDrawingElements();
1813 static void DrawDrawingWindow();
1814 static void DrawLevelInfoWindow();
1815 static void DrawPropertiesWindow();
1816 static boolean checkPropertiesConfig();
1817 static void CopyLevelToUndoBuffer(int);
1818 static void HandleDrawingAreas(struct GadgetInfo *);
1819 static void HandleCounterButtons(struct GadgetInfo *);
1820 static void HandleTextInputGadgets(struct GadgetInfo *);
1821 static void HandleTextAreaGadgets(struct GadgetInfo *);
1822 static void HandleSelectboxGadgets(struct GadgetInfo *);
1823 static void HandleTextbuttonGadgets(struct GadgetInfo *);
1824 static void HandleGraphicbuttonGadgets(struct GadgetInfo *);
1825 static void HandleRadiobuttons(struct GadgetInfo *);
1826 static void HandleCheckbuttons(struct GadgetInfo *);
1827 static void HandleControlButtons(struct GadgetInfo *);
1828 static void HandleDrawingAreaInfo(struct GadgetInfo *);
1829
1830 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
1831 static int right_gadget_border[NUM_EDITOR_GADGETS];
1832
1833 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
1834 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
1835 static boolean draw_with_brush = FALSE;
1836 static int properties_element = 0;
1837
1838 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
1839 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
1840 static int undo_buffer_position = 0;
1841 static int undo_buffer_steps = 0;
1842
1843 static int edit_mode;
1844 static int edit_mode_properties;
1845
1846 static int element_shift = 0;
1847
1848 static int editor_hl_boulderdash[] =
1849 {
1850   EL_CHAR('B'),
1851   EL_CHAR('O'),
1852   EL_CHAR('U'),
1853   EL_CHAR('L'),
1854
1855   EL_CHAR('-'),
1856   EL_CHAR('D'),
1857   EL_CHAR('E'),
1858   EL_CHAR('R'),
1859
1860   EL_CHAR('D'),
1861   EL_CHAR('A'),
1862   EL_CHAR('S'),
1863   EL_CHAR('H'),
1864 };
1865
1866 static int editor_el_boulderdash[] =
1867 {
1868   EL_PLAYER_1,
1869   EL_EMPTY,
1870   EL_SAND,
1871   EL_STEELWALL,
1872
1873   EL_BD_WALL,
1874   EL_BD_MAGIC_WALL,
1875   EL_EXIT_CLOSED,
1876   EL_EXIT_OPEN,
1877
1878   EL_BD_DIAMOND,
1879   EL_BD_BUTTERFLY_UP,
1880   EL_BD_FIREFLY_UP,
1881   EL_BD_ROCK,
1882
1883   EL_BD_BUTTERFLY_LEFT,
1884   EL_BD_FIREFLY_LEFT,
1885   EL_BD_BUTTERFLY_RIGHT,
1886   EL_BD_FIREFLY_RIGHT,
1887
1888   EL_BD_AMOEBA,
1889   EL_BD_BUTTERFLY_DOWN,
1890   EL_BD_FIREFLY_DOWN,
1891   EL_EMPTY,
1892 };
1893 static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash);
1894 static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash);
1895
1896 static int editor_hl_emerald_mine[] =
1897 {
1898   EL_CHAR('E'),
1899   EL_CHAR('M'),
1900   EL_CHAR('E'),
1901   EL_CHAR('-'),
1902
1903   EL_CHAR('R'),
1904   EL_CHAR('A'),
1905   EL_CHAR('L'),
1906   EL_CHAR('D'),
1907
1908   EL_CHAR('M'),
1909   EL_CHAR('I'),
1910   EL_CHAR('N'),
1911   EL_CHAR('E'),
1912 };
1913
1914 static int editor_el_emerald_mine[] =
1915 {
1916   EL_PLAYER_1,
1917   EL_PLAYER_2,
1918   EL_PLAYER_3,
1919   EL_PLAYER_4,
1920
1921   EL_PLAYER_1,
1922   EL_EMPTY,
1923   EL_SAND,
1924   EL_ROCK,
1925
1926   EL_STEELWALL,
1927   EL_WALL,
1928   EL_WALL_SLIPPERY,
1929   EL_MAGIC_WALL,
1930
1931   EL_EMERALD,
1932   EL_DIAMOND,
1933   EL_NUT,
1934   EL_BOMB,
1935
1936   EL_WALL_EMERALD,
1937   EL_WALL_DIAMOND,
1938   EL_QUICKSAND_EMPTY,
1939   EL_QUICKSAND_FULL,
1940
1941   EL_DYNAMITE,
1942   EL_DYNAMITE_ACTIVE,
1943   EL_EXIT_CLOSED,
1944   EL_EXIT_OPEN,
1945
1946   EL_YAMYAM,
1947   EL_BUG_UP,
1948   EL_SPACESHIP_UP,
1949   EL_ROBOT,
1950
1951   EL_BUG_LEFT,
1952   EL_SPACESHIP_LEFT,
1953   EL_BUG_RIGHT,
1954   EL_SPACESHIP_RIGHT,
1955
1956   EL_ROBOT_WHEEL,
1957   EL_BUG_DOWN,
1958   EL_SPACESHIP_DOWN,
1959   EL_INVISIBLE_WALL,
1960
1961   EL_ACID_POOL_TOPLEFT,
1962   EL_ACID,
1963   EL_ACID_POOL_TOPRIGHT,
1964   EL_EMPTY,
1965
1966   EL_ACID_POOL_BOTTOMLEFT,
1967   EL_ACID_POOL_BOTTOM,
1968   EL_ACID_POOL_BOTTOMRIGHT,
1969   EL_EMPTY,
1970
1971   EL_AMOEBA_DROP,
1972   EL_AMOEBA_DEAD,
1973   EL_AMOEBA_WET,
1974   EL_AMOEBA_DRY,
1975
1976   EL_EM_KEY_1_FILE,
1977   EL_EM_KEY_2_FILE,
1978   EL_EM_KEY_3_FILE,
1979   EL_EM_KEY_4_FILE,
1980
1981   EL_EM_GATE_1,
1982   EL_EM_GATE_2,
1983   EL_EM_GATE_3,
1984   EL_EM_GATE_4,
1985
1986   EL_EM_GATE_1_GRAY,
1987   EL_EM_GATE_2_GRAY,
1988   EL_EM_GATE_3_GRAY,
1989   EL_EM_GATE_4_GRAY,
1990 };
1991 static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine);
1992 static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine);
1993
1994 static int editor_hl_more[] =
1995 {
1996   EL_CHAR('M'),
1997   EL_CHAR('O'),
1998   EL_CHAR('R'),
1999   EL_CHAR('E'),
2000 };
2001
2002 static int editor_el_more[] =
2003 {
2004   EL_KEY_1,
2005   EL_KEY_2,
2006   EL_KEY_3,
2007   EL_KEY_4,
2008
2009   EL_GATE_1,
2010   EL_GATE_2,
2011   EL_GATE_3,
2012   EL_GATE_4,
2013
2014   EL_GATE_1_GRAY,
2015   EL_GATE_2_GRAY,
2016   EL_GATE_3_GRAY,
2017   EL_GATE_4_GRAY,
2018
2019   EL_ARROW_LEFT,
2020   EL_ARROW_RIGHT,
2021   EL_ARROW_UP,
2022   EL_ARROW_DOWN,
2023
2024   EL_AMOEBA_FULL,
2025   EL_EMERALD_YELLOW,
2026   EL_EMERALD_RED,
2027   EL_EMERALD_PURPLE,
2028
2029   EL_WALL_BD_DIAMOND,
2030   EL_WALL_EMERALD_YELLOW,
2031   EL_WALL_EMERALD_RED,
2032   EL_WALL_EMERALD_PURPLE,
2033
2034   EL_GAME_OF_LIFE,
2035   EL_PACMAN_UP,
2036   EL_TIME_ORB_FULL,
2037   EL_TIME_ORB_EMPTY,
2038
2039   EL_PACMAN_LEFT,
2040   EL_DARK_YAMYAM,
2041   EL_PACMAN_RIGHT,
2042   EL_EXPANDABLE_WALL,
2043
2044   EL_BIOMAZE,
2045   EL_PACMAN_DOWN,
2046   EL_LAMP,
2047   EL_LAMP_ACTIVE,
2048
2049   EL_DYNABOMB_INCREASE_NUMBER,
2050   EL_DYNABOMB_INCREASE_SIZE,
2051   EL_DYNABOMB_INCREASE_POWER,
2052   EL_STONEBLOCK,
2053
2054   EL_MOLE,
2055   EL_PENGUIN,
2056   EL_PIG,
2057   EL_DRAGON,
2058
2059   EL_EMPTY,
2060   EL_MOLE_UP,
2061   EL_EMPTY,
2062   EL_EMPTY,
2063
2064   EL_MOLE_LEFT,
2065   EL_EMPTY,
2066   EL_MOLE_RIGHT,
2067   EL_EMPTY,
2068
2069   EL_EMPTY,
2070   EL_MOLE_DOWN,
2071   EL_BALLOON,
2072   EL_BALLOON_SWITCH_ANY,
2073
2074   EL_BALLOON_SWITCH_LEFT,
2075   EL_BALLOON_SWITCH_RIGHT,
2076   EL_BALLOON_SWITCH_UP,
2077   EL_BALLOON_SWITCH_DOWN,
2078
2079   EL_SATELLITE,
2080   EL_EXPANDABLE_WALL_HORIZONTAL,
2081   EL_EXPANDABLE_WALL_VERTICAL,
2082   EL_EXPANDABLE_WALL_ANY,
2083
2084   EL_INVISIBLE_STEELWALL,
2085   EL_INVISIBLE_WALL,
2086   EL_SPEED_PILL,
2087   EL_BLACK_ORB,
2088
2089   EL_EMC_STEELWALL_1,
2090   EL_EMC_WALL_1,
2091   EL_EMC_WALL_2,
2092   EL_EMC_WALL_3,
2093
2094   EL_EMC_WALL_4,
2095   EL_EMC_WALL_5,
2096   EL_EMC_WALL_6,
2097   EL_EMC_WALL_7,
2098 };
2099 static int num_editor_hl_more = SIZEOF_ARRAY_INT(editor_hl_more);
2100 static int num_editor_el_more = SIZEOF_ARRAY_INT(editor_el_more);
2101
2102 static int editor_hl_sokoban[] =
2103 {
2104   EL_CHAR('S'),
2105   EL_CHAR('O'),
2106   EL_CHAR('K'),
2107   EL_CHAR('O'),
2108
2109   EL_CHAR('-'),
2110   EL_CHAR('B'),
2111   EL_CHAR('A'),
2112   EL_CHAR('N'),
2113 };
2114
2115 static int editor_el_sokoban[] =
2116 {
2117   EL_SOKOBAN_OBJECT,
2118   EL_SOKOBAN_FIELD_EMPTY,
2119   EL_SOKOBAN_FIELD_FULL,
2120   EL_STEELWALL,
2121 };
2122 static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban);
2123 static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban);
2124
2125 static int editor_hl_supaplex[] =
2126 {
2127   EL_CHAR('S'),
2128   EL_CHAR('U'),
2129   EL_CHAR('P'),
2130   EL_CHAR('A'),
2131
2132   EL_CHAR('P'),
2133   EL_CHAR('L'),
2134   EL_CHAR('E'),
2135   EL_CHAR('X'),
2136 };
2137
2138 static int editor_el_supaplex[] =
2139 {
2140   EL_SP_EMPTY,
2141   EL_SP_ZONK,
2142   EL_SP_BASE,
2143   EL_SP_MURPHY,
2144
2145   EL_SP_INFOTRON,
2146   EL_SP_CHIP_SINGLE,
2147   EL_SP_HARDWARE_GRAY,
2148   EL_SP_EXIT_CLOSED,
2149
2150   EL_SP_DISK_ORANGE,
2151   EL_SP_PORT_RIGHT,
2152   EL_SP_PORT_DOWN,
2153   EL_SP_PORT_LEFT,
2154
2155   EL_SP_PORT_UP,
2156   EL_SP_GRAVITY_PORT_RIGHT,
2157   EL_SP_GRAVITY_PORT_DOWN,
2158   EL_SP_GRAVITY_PORT_LEFT,
2159
2160   EL_SP_GRAVITY_PORT_UP,
2161   EL_SP_SNIKSNAK,
2162   EL_SP_DISK_YELLOW,
2163   EL_SP_TERMINAL,
2164
2165   EL_SP_DISK_RED,
2166   EL_SP_PORT_VERTICAL,
2167   EL_SP_PORT_HORIZONTAL,
2168   EL_SP_PORT_ANY,
2169
2170   EL_SP_ELECTRON,
2171   EL_SP_BUGGY_BASE,
2172   EL_SP_CHIP_LEFT,
2173   EL_SP_CHIP_RIGHT,
2174
2175   EL_SP_HARDWARE_BASE_1,
2176   EL_SP_HARDWARE_GREEN,
2177   EL_SP_HARDWARE_BLUE,
2178   EL_SP_HARDWARE_RED,
2179
2180   EL_SP_HARDWARE_YELLOW,
2181   EL_SP_HARDWARE_BASE_2,
2182   EL_SP_HARDWARE_BASE_3,
2183   EL_SP_HARDWARE_BASE_4,
2184
2185   EL_SP_HARDWARE_BASE_5,
2186   EL_SP_HARDWARE_BASE_6,
2187   EL_SP_CHIP_TOP,
2188   EL_SP_CHIP_BOTTOM,
2189 };
2190 static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex);
2191 static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex);
2192
2193 static int editor_hl_diamond_caves[] =
2194 {
2195   EL_CHAR('D'),
2196   EL_CHAR('I'),
2197   EL_CHAR('A'),
2198   EL_CHAR('-'),
2199
2200   EL_CHAR('M'),
2201   EL_CHAR('O'),
2202   EL_CHAR('N'),
2203   EL_CHAR('D'),
2204
2205   EL_CHAR('C'),
2206   EL_CHAR('A'),
2207   EL_CHAR('V'),
2208   EL_CHAR('E'),
2209
2210   EL_CHAR('S'),
2211   EL_CHAR(' '),
2212   EL_CHAR('I'),
2213   EL_CHAR('I'),
2214 };
2215
2216 static int editor_el_diamond_caves[] =
2217 {
2218   EL_PEARL,
2219   EL_CRYSTAL,
2220   EL_WALL_PEARL,
2221   EL_WALL_CRYSTAL,
2222
2223   EL_CONVEYOR_BELT_1_LEFT,
2224   EL_CONVEYOR_BELT_1_MIDDLE,
2225   EL_CONVEYOR_BELT_1_RIGHT,
2226   EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2227
2228   EL_CONVEYOR_BELT_2_LEFT,
2229   EL_CONVEYOR_BELT_2_MIDDLE,
2230   EL_CONVEYOR_BELT_2_RIGHT,
2231   EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2232
2233   EL_CONVEYOR_BELT_3_LEFT,
2234   EL_CONVEYOR_BELT_3_MIDDLE,
2235   EL_CONVEYOR_BELT_3_RIGHT,
2236   EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2237
2238   EL_CONVEYOR_BELT_4_LEFT,
2239   EL_CONVEYOR_BELT_4_MIDDLE,
2240   EL_CONVEYOR_BELT_4_RIGHT,
2241   EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2242
2243   EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2244   EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2245   EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2246   EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2247
2248   EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2249   EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2250   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2251   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2252
2253   EL_SWITCHGATE_OPEN,
2254   EL_SWITCHGATE_CLOSED,
2255   EL_SWITCHGATE_SWITCH_UP,
2256   EL_ENVELOPE,
2257
2258   EL_TIMEGATE_CLOSED,
2259   EL_TIMEGATE_OPEN,
2260   EL_TIMEGATE_SWITCH,
2261   EL_EMPTY,
2262
2263   EL_LANDMINE,
2264   EL_INVISIBLE_SAND,
2265   EL_STEELWALL_SLIPPERY,
2266   EL_EMPTY,
2267
2268   EL_SIGN_EXCLAMATION,
2269   EL_SIGN_STOP,
2270   EL_LIGHT_SWITCH,
2271   EL_LIGHT_SWITCH_ACTIVE,
2272
2273   EL_SHIELD_NORMAL,
2274   EL_SHIELD_DEADLY,
2275   EL_EXTRA_TIME,
2276   EL_EMPTY,
2277 };
2278 static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves);
2279 static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves);
2280
2281 static int editor_hl_dx_boulderdash[] =
2282 {
2283   EL_CHAR('D'),
2284   EL_CHAR('X'),
2285   EL_CHAR('-'),
2286   EL_CHAR(' '),
2287
2288   EL_CHAR('B'),
2289   EL_CHAR('O'),
2290   EL_CHAR('U'),
2291   EL_CHAR('L'),
2292
2293   EL_CHAR('-'),
2294   EL_CHAR('D'),
2295   EL_CHAR('E'),
2296   EL_CHAR('R'),
2297
2298   EL_CHAR('D'),
2299   EL_CHAR('A'),
2300   EL_CHAR('S'),
2301   EL_CHAR('H'),
2302 };
2303
2304 static int editor_el_dx_boulderdash[] =
2305 {
2306   EL_SPRING,
2307   EL_TUBE_RIGHT_DOWN,
2308   EL_TUBE_HORIZONTAL_DOWN,
2309   EL_TUBE_LEFT_DOWN,
2310
2311   EL_TUBE_HORIZONTAL,
2312   EL_TUBE_VERTICAL_RIGHT,
2313   EL_TUBE_ANY,
2314   EL_TUBE_VERTICAL_LEFT,
2315
2316   EL_TUBE_VERTICAL,
2317   EL_TUBE_RIGHT_UP,
2318   EL_TUBE_HORIZONTAL_UP,
2319   EL_TUBE_LEFT_UP,
2320
2321   EL_TRAP,
2322   EL_DX_SUPABOMB,
2323   EL_EMPTY,
2324   EL_EMPTY
2325 };
2326 static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash);
2327 static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash);
2328
2329 static int editor_hl_chars[] =
2330 {
2331   EL_CHAR('T'),
2332   EL_CHAR('E'),
2333   EL_CHAR('X'),
2334   EL_CHAR('T'),
2335 };
2336
2337 static int editor_el_chars[] =
2338 {
2339   EL_CHAR(' '),
2340   EL_CHAR('!'),
2341   EL_CHAR('"'),
2342   EL_CHAR('#'),
2343
2344   EL_CHAR('$'),
2345   EL_CHAR('%'),
2346   EL_CHAR('&'),
2347   EL_CHAR('\''),
2348
2349   EL_CHAR('('),
2350   EL_CHAR(')'),
2351   EL_CHAR('*'),
2352   EL_CHAR('+'),
2353
2354   EL_CHAR(','),
2355   EL_CHAR('-'),
2356   EL_CHAR('.'),
2357   EL_CHAR('/'),
2358
2359   EL_CHAR('0'),
2360   EL_CHAR('1'),
2361   EL_CHAR('2'),
2362   EL_CHAR('3'),
2363
2364   EL_CHAR('4'),
2365   EL_CHAR('5'),
2366   EL_CHAR('6'),
2367   EL_CHAR('7'),
2368
2369   EL_CHAR('8'),
2370   EL_CHAR('9'),
2371   EL_CHAR(':'),
2372   EL_CHAR(';'),
2373
2374   EL_CHAR('<'),
2375   EL_CHAR('='),
2376   EL_CHAR('>'),
2377   EL_CHAR('?'),
2378
2379   EL_CHAR('@'),
2380   EL_CHAR('A'),
2381   EL_CHAR('B'),
2382   EL_CHAR('C'),
2383
2384   EL_CHAR('D'),
2385   EL_CHAR('E'),
2386   EL_CHAR('F'),
2387   EL_CHAR('G'),
2388
2389   EL_CHAR('H'),
2390   EL_CHAR('I'),
2391   EL_CHAR('J'),
2392   EL_CHAR('K'),
2393
2394   EL_CHAR('L'),
2395   EL_CHAR('M'),
2396   EL_CHAR('N'),
2397   EL_CHAR('O'),
2398
2399   EL_CHAR('P'),
2400   EL_CHAR('Q'),
2401   EL_CHAR('R'),
2402   EL_CHAR('S'),
2403
2404   EL_CHAR('T'),
2405   EL_CHAR('U'),
2406   EL_CHAR('V'),
2407   EL_CHAR('W'),
2408
2409   EL_CHAR('X'),
2410   EL_CHAR('Y'),
2411   EL_CHAR('Z'),
2412   EL_CHAR('['),
2413
2414   EL_CHAR('\\'),
2415   EL_CHAR(']'),
2416   EL_CHAR('^'),
2417   EL_CHAR('_'),
2418
2419   EL_CHAR('©'),
2420   EL_CHAR('Ä'),
2421   EL_CHAR('Ö'),
2422   EL_CHAR('Ãœ'),
2423
2424   EL_CHAR('°'),
2425   EL_CHAR('®'),
2426   EL_CHAR(FONT_ASCII_CURSOR),
2427   EL_CHAR(' ')
2428 };
2429 static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars);
2430 static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars);
2431
2432 static int editor_hl_custom[] =
2433 {
2434   EL_CHAR('C'),
2435   EL_CHAR('U'),
2436   EL_CHAR('S'),
2437   EL_CHAR('-'),
2438
2439   EL_CHAR('T'),
2440   EL_CHAR('O'),
2441   EL_CHAR('M'),
2442   EL_CHAR(' '),
2443
2444   EL_CHAR('E'),
2445   EL_CHAR('L'),
2446   EL_CHAR('E'),
2447   EL_CHAR('M'),
2448
2449   EL_CHAR('E'),
2450   EL_CHAR('N'),
2451   EL_CHAR('T'),
2452   EL_CHAR('S'),
2453 };
2454
2455 static int editor_el_custom[] =
2456 {
2457   EL_CUSTOM_START + 0,
2458   EL_CUSTOM_START + 1,
2459   EL_CUSTOM_START + 2,
2460   EL_CUSTOM_START + 3,
2461
2462   EL_CUSTOM_START + 4,
2463   EL_CUSTOM_START + 5,
2464   EL_CUSTOM_START + 6,
2465   EL_CUSTOM_START + 7,
2466
2467   EL_CUSTOM_START + 8,
2468   EL_CUSTOM_START + 9,
2469   EL_CUSTOM_START + 10,
2470   EL_CUSTOM_START + 11,
2471
2472   EL_CUSTOM_START + 12,
2473   EL_CUSTOM_START + 13,
2474   EL_CUSTOM_START + 14,
2475   EL_CUSTOM_START + 15,
2476
2477   EL_CUSTOM_START + 16,
2478   EL_CUSTOM_START + 17,
2479   EL_CUSTOM_START + 18,
2480   EL_CUSTOM_START + 19,
2481
2482   EL_CUSTOM_START + 20,
2483   EL_CUSTOM_START + 21,
2484   EL_CUSTOM_START + 22,
2485   EL_CUSTOM_START + 23,
2486
2487   EL_CUSTOM_START + 24,
2488   EL_CUSTOM_START + 25,
2489   EL_CUSTOM_START + 26,
2490   EL_CUSTOM_START + 27,
2491
2492   EL_CUSTOM_START + 28,
2493   EL_CUSTOM_START + 29,
2494   EL_CUSTOM_START + 30,
2495   EL_CUSTOM_START + 31,
2496
2497   EL_CUSTOM_START + 32,
2498   EL_CUSTOM_START + 33,
2499   EL_CUSTOM_START + 34,
2500   EL_CUSTOM_START + 35,
2501
2502   EL_CUSTOM_START + 36,
2503   EL_CUSTOM_START + 37,
2504   EL_CUSTOM_START + 38,
2505   EL_CUSTOM_START + 39,
2506
2507   EL_CUSTOM_START + 40,
2508   EL_CUSTOM_START + 41,
2509   EL_CUSTOM_START + 42,
2510   EL_CUSTOM_START + 43,
2511
2512   EL_CUSTOM_START + 44,
2513   EL_CUSTOM_START + 45,
2514   EL_CUSTOM_START + 46,
2515   EL_CUSTOM_START + 47,
2516
2517   EL_CUSTOM_START + 48,
2518   EL_CUSTOM_START + 49,
2519   EL_CUSTOM_START + 50,
2520   EL_CUSTOM_START + 51,
2521
2522   EL_CUSTOM_START + 52,
2523   EL_CUSTOM_START + 53,
2524   EL_CUSTOM_START + 54,
2525   EL_CUSTOM_START + 55,
2526
2527   EL_CUSTOM_START + 56,
2528   EL_CUSTOM_START + 57,
2529   EL_CUSTOM_START + 58,
2530   EL_CUSTOM_START + 59,
2531
2532   EL_CUSTOM_START + 60,
2533   EL_CUSTOM_START + 61,
2534   EL_CUSTOM_START + 62,
2535   EL_CUSTOM_START + 63,
2536
2537   EL_CUSTOM_START + 64,
2538   EL_CUSTOM_START + 65,
2539   EL_CUSTOM_START + 66,
2540   EL_CUSTOM_START + 67,
2541
2542   EL_CUSTOM_START + 68,
2543   EL_CUSTOM_START + 69,
2544   EL_CUSTOM_START + 70,
2545   EL_CUSTOM_START + 71,
2546
2547   EL_CUSTOM_START + 72,
2548   EL_CUSTOM_START + 73,
2549   EL_CUSTOM_START + 74,
2550   EL_CUSTOM_START + 75,
2551
2552   EL_CUSTOM_START + 76,
2553   EL_CUSTOM_START + 77,
2554   EL_CUSTOM_START + 78,
2555   EL_CUSTOM_START + 79,
2556
2557   EL_CUSTOM_START + 80,
2558   EL_CUSTOM_START + 81,
2559   EL_CUSTOM_START + 82,
2560   EL_CUSTOM_START + 83,
2561
2562   EL_CUSTOM_START + 84,
2563   EL_CUSTOM_START + 85,
2564   EL_CUSTOM_START + 86,
2565   EL_CUSTOM_START + 87,
2566
2567   EL_CUSTOM_START + 88,
2568   EL_CUSTOM_START + 89,
2569   EL_CUSTOM_START + 90,
2570   EL_CUSTOM_START + 91,
2571
2572   EL_CUSTOM_START + 92,
2573   EL_CUSTOM_START + 93,
2574   EL_CUSTOM_START + 94,
2575   EL_CUSTOM_START + 95,
2576
2577   EL_CUSTOM_START + 96,
2578   EL_CUSTOM_START + 97,
2579   EL_CUSTOM_START + 98,
2580   EL_CUSTOM_START + 99,
2581
2582   EL_CUSTOM_START + 100,
2583   EL_CUSTOM_START + 101,
2584   EL_CUSTOM_START + 102,
2585   EL_CUSTOM_START + 103,
2586
2587   EL_CUSTOM_START + 104,
2588   EL_CUSTOM_START + 105,
2589   EL_CUSTOM_START + 106,
2590   EL_CUSTOM_START + 107,
2591
2592   EL_CUSTOM_START + 108,
2593   EL_CUSTOM_START + 109,
2594   EL_CUSTOM_START + 110,
2595   EL_CUSTOM_START + 111,
2596
2597   EL_CUSTOM_START + 112,
2598   EL_CUSTOM_START + 113,
2599   EL_CUSTOM_START + 114,
2600   EL_CUSTOM_START + 115,
2601
2602   EL_CUSTOM_START + 116,
2603   EL_CUSTOM_START + 117,
2604   EL_CUSTOM_START + 118,
2605   EL_CUSTOM_START + 119,
2606
2607   EL_CUSTOM_START + 120,
2608   EL_CUSTOM_START + 121,
2609   EL_CUSTOM_START + 122,
2610   EL_CUSTOM_START + 123,
2611
2612   EL_CUSTOM_START + 124,
2613   EL_CUSTOM_START + 125,
2614   EL_CUSTOM_START + 126,
2615   EL_CUSTOM_START + 127
2616 };
2617 static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom);
2618 static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
2619
2620 static int editor_hl_custom_more[] =
2621 {
2622 };
2623
2624 static int editor_el_custom_more[] =
2625 {
2626   EL_CUSTOM_START + 128,
2627   EL_CUSTOM_START + 129,
2628   EL_CUSTOM_START + 130,
2629   EL_CUSTOM_START + 131,
2630
2631   EL_CUSTOM_START + 132,
2632   EL_CUSTOM_START + 133,
2633   EL_CUSTOM_START + 134,
2634   EL_CUSTOM_START + 135,
2635
2636   EL_CUSTOM_START + 136,
2637   EL_CUSTOM_START + 137,
2638   EL_CUSTOM_START + 138,
2639   EL_CUSTOM_START + 139,
2640
2641   EL_CUSTOM_START + 140,
2642   EL_CUSTOM_START + 141,
2643   EL_CUSTOM_START + 142,
2644   EL_CUSTOM_START + 143,
2645
2646   EL_CUSTOM_START + 144,
2647   EL_CUSTOM_START + 145,
2648   EL_CUSTOM_START + 146,
2649   EL_CUSTOM_START + 147,
2650
2651   EL_CUSTOM_START + 148,
2652   EL_CUSTOM_START + 149,
2653   EL_CUSTOM_START + 150,
2654   EL_CUSTOM_START + 151,
2655
2656   EL_CUSTOM_START + 152,
2657   EL_CUSTOM_START + 153,
2658   EL_CUSTOM_START + 154,
2659   EL_CUSTOM_START + 155,
2660
2661   EL_CUSTOM_START + 156,
2662   EL_CUSTOM_START + 157,
2663   EL_CUSTOM_START + 158,
2664   EL_CUSTOM_START + 159,
2665
2666   EL_CUSTOM_START + 160,
2667   EL_CUSTOM_START + 161,
2668   EL_CUSTOM_START + 162,
2669   EL_CUSTOM_START + 163,
2670
2671   EL_CUSTOM_START + 164,
2672   EL_CUSTOM_START + 165,
2673   EL_CUSTOM_START + 166,
2674   EL_CUSTOM_START + 167,
2675
2676   EL_CUSTOM_START + 168,
2677   EL_CUSTOM_START + 169,
2678   EL_CUSTOM_START + 170,
2679   EL_CUSTOM_START + 171,
2680
2681   EL_CUSTOM_START + 172,
2682   EL_CUSTOM_START + 173,
2683   EL_CUSTOM_START + 174,
2684   EL_CUSTOM_START + 175,
2685
2686   EL_CUSTOM_START + 176,
2687   EL_CUSTOM_START + 177,
2688   EL_CUSTOM_START + 178,
2689   EL_CUSTOM_START + 179,
2690
2691   EL_CUSTOM_START + 180,
2692   EL_CUSTOM_START + 181,
2693   EL_CUSTOM_START + 182,
2694   EL_CUSTOM_START + 183,
2695
2696   EL_CUSTOM_START + 184,
2697   EL_CUSTOM_START + 185,
2698   EL_CUSTOM_START + 186,
2699   EL_CUSTOM_START + 187,
2700
2701   EL_CUSTOM_START + 188,
2702   EL_CUSTOM_START + 189,
2703   EL_CUSTOM_START + 190,
2704   EL_CUSTOM_START + 191,
2705
2706   EL_CUSTOM_START + 192,
2707   EL_CUSTOM_START + 193,
2708   EL_CUSTOM_START + 194,
2709   EL_CUSTOM_START + 195,
2710
2711   EL_CUSTOM_START + 196,
2712   EL_CUSTOM_START + 197,
2713   EL_CUSTOM_START + 198,
2714   EL_CUSTOM_START + 199,
2715
2716   EL_CUSTOM_START + 200,
2717   EL_CUSTOM_START + 201,
2718   EL_CUSTOM_START + 202,
2719   EL_CUSTOM_START + 203,
2720
2721   EL_CUSTOM_START + 204,
2722   EL_CUSTOM_START + 205,
2723   EL_CUSTOM_START + 206,
2724   EL_CUSTOM_START + 207,
2725
2726   EL_CUSTOM_START + 208,
2727   EL_CUSTOM_START + 209,
2728   EL_CUSTOM_START + 210,
2729   EL_CUSTOM_START + 211,
2730
2731   EL_CUSTOM_START + 212,
2732   EL_CUSTOM_START + 213,
2733   EL_CUSTOM_START + 214,
2734   EL_CUSTOM_START + 215,
2735
2736   EL_CUSTOM_START + 216,
2737   EL_CUSTOM_START + 217,
2738   EL_CUSTOM_START + 218,
2739   EL_CUSTOM_START + 219,
2740
2741   EL_CUSTOM_START + 220,
2742   EL_CUSTOM_START + 221,
2743   EL_CUSTOM_START + 222,
2744   EL_CUSTOM_START + 223,
2745
2746   EL_CUSTOM_START + 224,
2747   EL_CUSTOM_START + 225,
2748   EL_CUSTOM_START + 226,
2749   EL_CUSTOM_START + 227,
2750
2751   EL_CUSTOM_START + 228,
2752   EL_CUSTOM_START + 229,
2753   EL_CUSTOM_START + 230,
2754   EL_CUSTOM_START + 231,
2755
2756   EL_CUSTOM_START + 232,
2757   EL_CUSTOM_START + 233,
2758   EL_CUSTOM_START + 234,
2759   EL_CUSTOM_START + 235,
2760
2761   EL_CUSTOM_START + 236,
2762   EL_CUSTOM_START + 237,
2763   EL_CUSTOM_START + 238,
2764   EL_CUSTOM_START + 239,
2765
2766   EL_CUSTOM_START + 240,
2767   EL_CUSTOM_START + 241,
2768   EL_CUSTOM_START + 242,
2769   EL_CUSTOM_START + 243,
2770
2771   EL_CUSTOM_START + 244,
2772   EL_CUSTOM_START + 245,
2773   EL_CUSTOM_START + 246,
2774   EL_CUSTOM_START + 247,
2775
2776   EL_CUSTOM_START + 248,
2777   EL_CUSTOM_START + 249,
2778   EL_CUSTOM_START + 250,
2779   EL_CUSTOM_START + 251,
2780
2781   EL_CUSTOM_START + 252,
2782   EL_CUSTOM_START + 253,
2783   EL_CUSTOM_START + 254,
2784   EL_CUSTOM_START + 255
2785 };
2786 static int num_editor_hl_custom_more = SIZEOF_ARRAY_INT(editor_hl_custom_more);
2787 static int num_editor_el_custom_more = SIZEOF_ARRAY_INT(editor_el_custom_more);
2788
2789 static int *editor_elements = NULL;     /* dynamically allocated */
2790 static int num_editor_elements = 0;     /* dynamically determined */
2791
2792 static struct
2793 {
2794   boolean *setup_value;
2795
2796   int *headline_list;
2797   int *headline_list_size;
2798
2799   int *element_list;
2800   int *element_list_size;
2801
2802   boolean last_setup_value;
2803 }
2804 editor_elements_info[] =
2805 {
2806   {
2807     &setup.editor.el_boulderdash,
2808     editor_hl_boulderdash,              &num_editor_hl_boulderdash,
2809     editor_el_boulderdash,              &num_editor_el_boulderdash
2810   },
2811   {
2812     &setup.editor.el_emerald_mine,
2813     editor_hl_emerald_mine,             &num_editor_hl_emerald_mine,
2814     editor_el_emerald_mine,             &num_editor_el_emerald_mine
2815   },
2816   {
2817     &setup.editor.el_more,
2818     editor_hl_more,                     &num_editor_hl_more,
2819     editor_el_more,                     &num_editor_el_more
2820   },
2821   {
2822     &setup.editor.el_sokoban,
2823     editor_hl_sokoban,                  &num_editor_hl_sokoban,
2824     editor_el_sokoban,                  &num_editor_el_sokoban
2825   },
2826   {
2827     &setup.editor.el_supaplex,
2828     editor_hl_supaplex,                 &num_editor_hl_supaplex,
2829     editor_el_supaplex,                 &num_editor_el_supaplex
2830   },
2831   {
2832     &setup.editor.el_diamond_caves,
2833     editor_hl_diamond_caves,            &num_editor_hl_diamond_caves,
2834     editor_el_diamond_caves,            &num_editor_el_diamond_caves
2835   },
2836   {
2837     &setup.editor.el_dx_boulderdash,
2838     editor_hl_dx_boulderdash,           &num_editor_hl_dx_boulderdash,
2839     editor_el_dx_boulderdash,           &num_editor_el_dx_boulderdash
2840   },
2841   {
2842     &setup.editor.el_chars,
2843     editor_hl_chars,                    &num_editor_hl_chars,
2844     editor_el_chars,                    &num_editor_el_chars
2845   },
2846   {
2847     &setup.editor.el_custom,
2848     editor_hl_custom,                   &num_editor_hl_custom,
2849     editor_el_custom,                   &num_editor_el_custom
2850   },
2851   {
2852     &setup.editor.el_custom_more,
2853     editor_hl_custom_more,              &num_editor_hl_custom_more,
2854     editor_el_custom_more,              &num_editor_el_custom_more
2855   },
2856   {
2857     NULL,
2858     NULL,                               NULL,
2859     NULL,                               NULL
2860   }
2861 };
2862
2863
2864 /*
2865   -----------------------------------------------------------------------------
2866   functions
2867   -----------------------------------------------------------------------------
2868 */
2869
2870 static void ReinitializeElementList()
2871 {
2872   int pos = 0;
2873   int i, j;
2874
2875   if (editor_elements != NULL)
2876     free(editor_elements);
2877
2878   num_editor_elements = 0;
2879
2880   /* determine size of element list */
2881   for (i=0; editor_elements_info[i].setup_value != NULL; i++)
2882   {
2883     if (*editor_elements_info[i].setup_value)
2884     {
2885       if (setup.editor.el_headlines)
2886         num_editor_elements += *editor_elements_info[i].headline_list_size;
2887
2888       num_editor_elements += *editor_elements_info[i].element_list_size;
2889     }
2890   }
2891
2892   if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
2893   {
2894     /* workaround: offer at least as many elements as element buttons exist */
2895     int list_nr = 1;    /* see above: editor_elements_info for Emerald Mine */
2896
2897     *editor_elements_info[list_nr].setup_value = TRUE;
2898     num_editor_elements += *editor_elements_info[list_nr].element_list_size;
2899   }
2900
2901   editor_elements = checked_malloc(num_editor_elements * sizeof(int));
2902
2903   /* fill element list */
2904   for (i=0; editor_elements_info[i].setup_value != NULL; i++)
2905   {
2906     if (*editor_elements_info[i].setup_value)
2907     {
2908       if (setup.editor.el_headlines)
2909         for (j=0; j < *editor_elements_info[i].headline_list_size; j++)
2910           editor_elements[pos++] = editor_elements_info[i].headline_list[j];
2911
2912       for (j=0; j < *editor_elements_info[i].element_list_size; j++)
2913         editor_elements[pos++] = editor_elements_info[i].element_list[j];
2914     }
2915   }
2916
2917   /* correct position of element list scrollbar */
2918   if (element_shift < 0)
2919     element_shift = 0;
2920   if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
2921     element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
2922 }
2923
2924 static void ReinitializeElementListButtons()
2925 {
2926   static boolean last_setup_value_headlines = FALSE;
2927   static boolean initialization_needed = TRUE;
2928   int i;
2929
2930   if (!initialization_needed)   /* check if editor element setup has changed */
2931   {
2932     if (last_setup_value_headlines != setup.editor.el_headlines)
2933       initialization_needed = TRUE;
2934
2935     for (i=0; editor_elements_info[i].setup_value != NULL; i++)
2936       if (editor_elements_info[i].last_setup_value !=
2937           *editor_elements_info[i].setup_value)
2938         initialization_needed = TRUE;
2939   }
2940
2941   if (!initialization_needed)
2942     return;
2943
2944   FreeLevelEditorGadgets();
2945   CreateLevelEditorGadgets();
2946
2947   /* store current setup values for next invocation of this function */
2948   last_setup_value_headlines = setup.editor.el_headlines;
2949   for (i=0; editor_elements_info[i].setup_value != NULL; i++)
2950     editor_elements_info[i].last_setup_value =
2951       *editor_elements_info[i].setup_value;
2952
2953   initialization_needed = FALSE;
2954 }
2955
2956 static int getMaxInfoTextLength()
2957 {
2958   return (SXSIZE / getFontWidth(FONT_TEXT_2));
2959 }
2960
2961 static int getTextWidthForGadget(char *text)
2962 {
2963   if (text == NULL)
2964     return 0;
2965
2966   return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
2967 }
2968
2969 static int getTextWidthForDrawingArea(char *text)
2970 {
2971   if (text == NULL)
2972     return 0;
2973
2974   return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
2975 }
2976
2977 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
2978 {
2979   return (gi->x + gi->width + getTextWidthForGadget(text));
2980 }
2981
2982 static char *getElementInfoText(int element)
2983 {
2984   char *info_text = NULL;
2985
2986   if (element < NUM_FILE_ELEMENTS)
2987   {
2988     if (strlen(element_info[element].description) > 0)
2989       info_text = element_info[element].description;
2990     else if (element_info[element].custom_description != NULL)
2991       info_text = element_info[element].custom_description;
2992     else if (element_info[element].editor_description != NULL)
2993       info_text = element_info[element].editor_description;
2994   }
2995
2996   if (info_text == NULL)
2997   {
2998     info_text = "unknown";
2999
3000     Error(ERR_WARN, "no element description for element %d", element);
3001   }
3002
3003   return info_text;
3004 }
3005
3006 static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
3007                               boolean input)
3008 {
3009   int border_graphic =
3010     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
3011   Bitmap *src_bitmap;
3012   int src_x, src_y;
3013   int num_mini_tilex = width / MINI_TILEX + 1;
3014   int num_mini_tiley = width / MINI_TILEY + 1;
3015   int x, y;
3016
3017   getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
3018
3019   for (y=0; y < num_mini_tiley; y++)
3020     for (x=0; x < num_mini_tilex; x++)
3021       BlitBitmap(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
3022                  dest_x - MINI_TILEX / 2 + x * MINI_TILEX,
3023                  dest_y - MINI_TILEY / 2 + y * MINI_TILEY);
3024
3025   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
3026 }
3027
3028 static void DrawDrawingArea(int id)
3029 {
3030   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
3031   int x, y;
3032
3033   if (id == ED_DRAWING_ID_RANDOM_BACKGROUND)
3034     DrawMiniGraphicExt(drawto, gi->x, gi->y,
3035                        el2edimg(random_placement_background_element));
3036   else if (id == ED_DRAWING_ID_AMOEBA_CONTENT)
3037     DrawMiniGraphicExt(drawto, gi->x, gi->y, el2edimg(level.amoeba_content));
3038   else if (id == ED_DRAWING_ID_CUSTOM_GRAPHIC)
3039     DrawMiniGraphicExt(drawto, gi->x, gi->y,
3040                        el2edimg(custom_element.gfx_element));
3041   else if (id == ED_DRAWING_ID_CUSTOM_CONTENT)
3042     for (y=0; y<3; y++)
3043       for (x=0; x<3; x++)
3044         DrawMiniGraphicExt(drawto,
3045                            gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
3046                            el2edimg(custom_element.content[x][y]));
3047   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TARGET)
3048     DrawMiniGraphicExt(drawto, gi->x, gi->y,
3049                        el2edimg(custom_element_change.target_element));
3050   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT)
3051     for (y=0; y < 3; y++)
3052       for (x=0; x < 3; x++)
3053         DrawMiniGraphicExt(drawto,
3054                            gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
3055                            el2edimg(custom_element_change.content[x][y]));
3056   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER)
3057     DrawMiniGraphicExt(drawto, gi->x, gi->y,
3058                        el2edimg(custom_element_change.trigger_element));
3059   else if (id >= ED_DRAWING_ID_ELEMENT_CONTENT_0 &&
3060            id <= ED_DRAWING_ID_ELEMENT_CONTENT_7)
3061   {
3062     int nr = id - ED_DRAWING_ID_ELEMENT_CONTENT_0;
3063
3064     for (y=0; y < 3; y++)
3065       for (x=0; x < 3; x++)
3066         DrawMiniGraphicExt(drawto,
3067                            gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
3068                            el2edimg(level.yamyam_content[nr][x][y]));
3069   }
3070 }
3071
3072 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
3073 {
3074   int x,y;
3075   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
3076   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
3077
3078   BlitBitmap(drawto, drawto,
3079              SX + (dx == -1 ? MINI_TILEX : 0),
3080              SY + (dy == -1 ? MINI_TILEY : 0),
3081              (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
3082              (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
3083              SX + (dx == +1 ? MINI_TILEX : 0),
3084              SY + (dy == +1 ? MINI_TILEY : 0));
3085   if (dx)
3086   {
3087     x = (dx == 1 ? 0 : ed_fieldx - 1);
3088     for(y=0; y<ed_fieldy; y++)
3089       DrawMiniElementOrWall(x, y, from_x, from_y);
3090   }
3091   else if (dy)
3092   {
3093     y = (dy == 1 ? 0 : ed_fieldy - 1);
3094     for(x=0; x<ed_fieldx; x++)
3095       DrawMiniElementOrWall(x, y, from_x, from_y);
3096   }
3097
3098   redraw_mask |= REDRAW_FIELD;
3099   BackToFront();
3100 }
3101
3102 static void CreateControlButtons()
3103 {
3104   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3105   struct GadgetInfo *gi;
3106   unsigned long event_mask;
3107   int i;
3108
3109   /* create toolbox buttons */
3110   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
3111   {
3112     int id = i;
3113     int width, height;
3114     int gd_xoffset, gd_yoffset;
3115     int gd_x1, gd_x2, gd_y1, gd_y2;
3116     int button_type;
3117     int radio_button_nr;
3118     boolean checked;
3119
3120     if (id == GADGET_ID_SINGLE_ITEMS ||
3121         id == GADGET_ID_CONNECTED_ITEMS ||
3122         id == GADGET_ID_LINE ||
3123         id == GADGET_ID_ARC ||
3124         id == GADGET_ID_TEXT ||
3125         id == GADGET_ID_RECTANGLE ||
3126         id == GADGET_ID_FILLED_BOX ||
3127         id == GADGET_ID_FLOOD_FILL ||
3128         id == GADGET_ID_GRAB_BRUSH ||
3129         id == GADGET_ID_PICK_ELEMENT)
3130     {
3131       button_type = GD_TYPE_RADIO_BUTTON;
3132       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
3133       checked = (id == drawing_function ? TRUE : FALSE);
3134       event_mask = GD_EVENT_PRESSED;
3135     }
3136     else
3137     {
3138       button_type = GD_TYPE_NORMAL_BUTTON;
3139       radio_button_nr = RADIO_NR_NONE;
3140       checked = FALSE;
3141
3142       if (id == GADGET_ID_WRAP_LEFT ||
3143           id == GADGET_ID_WRAP_RIGHT ||
3144           id == GADGET_ID_WRAP_UP ||
3145           id == GADGET_ID_WRAP_DOWN)
3146         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
3147       else
3148         event_mask = GD_EVENT_RELEASED;
3149     }
3150
3151     if (id < ED_NUM_CTRL1_BUTTONS)
3152     {
3153       int x = i % ED_CTRL1_BUTTONS_HORIZ;
3154       int y = i / ED_CTRL1_BUTTONS_HORIZ;
3155
3156       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
3157       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
3158       width = ED_CTRL1_BUTTON_XSIZE;
3159       height = ED_CTRL1_BUTTON_YSIZE;
3160     }
3161     else
3162     {
3163       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
3164       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
3165
3166       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
3167       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
3168       width = ED_CTRL2_BUTTON_XSIZE;
3169       height = ED_CTRL2_BUTTON_YSIZE;
3170     }
3171
3172     gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
3173     gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
3174     gd_y1  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
3175     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
3176
3177     gi = CreateGadget(GDI_CUSTOM_ID, id,
3178                       GDI_CUSTOM_TYPE_ID, i,
3179                       GDI_INFO_TEXT, control_info[i].text,
3180                       GDI_X, EX + gd_xoffset,
3181                       GDI_Y, EY + gd_yoffset,
3182                       GDI_WIDTH, width,
3183                       GDI_HEIGHT, height,
3184                       GDI_TYPE, button_type,
3185                       GDI_STATE, GD_BUTTON_UNPRESSED,
3186                       GDI_RADIO_NR, radio_button_nr,
3187                       GDI_CHECKED, checked,
3188                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
3189                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
3190                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
3191                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
3192                       GDI_EVENT_MASK, event_mask,
3193                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3194                       GDI_CALLBACK_ACTION, HandleControlButtons,
3195                       GDI_END);
3196
3197     if (gi == NULL)
3198       Error(ERR_EXIT, "cannot create gadget");
3199
3200     level_editor_gadget[id] = gi;
3201   }
3202
3203   /* create buttons for scrolling of drawing area and element list */
3204   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
3205   {
3206     int id = scrollbutton_info[i].gadget_id;
3207     int x, y, width, height;
3208     int gd_x1, gd_x2, gd_y1, gd_y2;
3209
3210     x = scrollbutton_info[i].x;
3211     y = scrollbutton_info[i].y;
3212
3213     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
3214
3215     if (id == GADGET_ID_SCROLL_LIST_UP ||
3216         id == GADGET_ID_SCROLL_LIST_DOWN)
3217     {
3218       x += DX;
3219       y += DY;
3220       width = ED_SCROLLBUTTON2_XSIZE;
3221       height = ED_SCROLLBUTTON2_YSIZE;
3222       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
3223       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
3224       gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE;
3225       gd_y2 = gd_y1;
3226     }
3227     else
3228     {
3229       x += SX;
3230       y += SY;
3231       width = ED_SCROLLBUTTON_XSIZE;
3232       height = ED_SCROLLBUTTON_YSIZE;
3233       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
3234       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
3235       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
3236       gd_y2 = gd_y1;
3237     }
3238
3239     gi = CreateGadget(GDI_CUSTOM_ID, id,
3240                       GDI_CUSTOM_TYPE_ID, i,
3241                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
3242                       GDI_X, x,
3243                       GDI_Y, y,
3244                       GDI_WIDTH, width,
3245                       GDI_HEIGHT, height,
3246                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3247                       GDI_STATE, GD_BUTTON_UNPRESSED,
3248                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
3249                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
3250                       GDI_EVENT_MASK, event_mask,
3251                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3252                       GDI_CALLBACK_ACTION, HandleControlButtons,
3253                       GDI_END);
3254
3255     if (gi == NULL)
3256       Error(ERR_EXIT, "cannot create gadget");
3257
3258     level_editor_gadget[id] = gi;
3259   }
3260
3261   /* create buttons for element list */
3262   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
3263   {
3264     Bitmap *deco_bitmap;
3265     int deco_x, deco_y, deco_xpos, deco_ypos;
3266     int gd_xoffset, gd_yoffset;
3267     int gd_x1, gd_x2, gd_y;
3268     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
3269     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
3270     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
3271     int element = editor_elements[i];
3272
3273     event_mask = GD_EVENT_RELEASED;
3274
3275     gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
3276     gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
3277
3278     gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE;
3279     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
3280     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
3281
3282     getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
3283     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
3284     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
3285
3286     gi = CreateGadget(GDI_CUSTOM_ID, id,
3287                       GDI_CUSTOM_TYPE_ID, i,
3288                       GDI_INFO_TEXT, getElementInfoText(element),
3289                       GDI_X, DX + gd_xoffset,
3290                       GDI_Y, DY + gd_yoffset,
3291                       GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
3292                       GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
3293                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3294                       GDI_STATE, GD_BUTTON_UNPRESSED,
3295                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3296                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3297                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3298                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3299                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3300                       GDI_DECORATION_SHIFTING, 1, 1,
3301                       GDI_EVENT_MASK, event_mask,
3302                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3303                       GDI_CALLBACK_ACTION, HandleControlButtons,
3304                       GDI_END);
3305
3306     if (gi == NULL)
3307       Error(ERR_EXIT, "cannot create gadget");
3308
3309     level_editor_gadget[id] = gi;
3310   }
3311 }
3312
3313 static void CreateCounterButtons()
3314 {
3315   int max_infotext_len = getMaxInfoTextLength();
3316   int i;
3317
3318   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
3319   {
3320     int j;
3321     int x = SX + counterbutton_info[i].x;       /* down count button */
3322     int y = SY + counterbutton_info[i].y;
3323
3324     /* determine horizontal position to the right of specified gadget */
3325     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
3326       x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
3327            ED_GADGET_TEXT_DISTANCE);
3328
3329     /* determine horizontal offset for leading text */
3330     if (counterbutton_info[i].text_left != NULL)
3331       x += getTextWidthForGadget(counterbutton_info[i].text_left);
3332
3333     for (j=0; j<2; j++)
3334     {
3335       Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3336       struct GadgetInfo *gi;
3337       int id = (j == 0 ?
3338                 counterbutton_info[i].gadget_id_down :
3339                 counterbutton_info[i].gadget_id_up);
3340       int gd_xoffset;
3341       int gd_x, gd_x1, gd_x2, gd_y;
3342       int x_size, y_size;
3343       unsigned long event_mask;
3344       char infotext[max_infotext_len + 1];
3345
3346       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
3347
3348       if (i == ED_COUNTER_ID_SELECT_LEVEL)
3349       {
3350         int sid = (j == 0 ?
3351                    ED_SCROLLBUTTON_ID_AREA_LEFT :
3352                    ED_SCROLLBUTTON_ID_AREA_RIGHT);
3353
3354         event_mask |= GD_EVENT_RELEASED;
3355
3356         if (j == 1)
3357           x += 2 * ED_GADGET_DISTANCE;
3358         y += ED_GADGET_DISTANCE;
3359
3360         gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].gd_x;
3361         gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
3362         gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].gd_y;
3363         x_size = ED_SCROLLBUTTON_XSIZE;
3364         y_size = ED_SCROLLBUTTON_YSIZE;
3365       }
3366       else
3367       {
3368         gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
3369         gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3370         gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3371         gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
3372         x_size = ED_BUTTON_COUNT_XSIZE;
3373         y_size = ED_BUTTON_COUNT_YSIZE;
3374       }
3375
3376       sprintf(infotext, "%s counter value by 1, 5 or 10",
3377               (j == 0 ? "decrease" : "increase"));
3378
3379       gi = CreateGadget(GDI_CUSTOM_ID, id,
3380                         GDI_CUSTOM_TYPE_ID, i,
3381                         GDI_INFO_TEXT, infotext,
3382                         GDI_X, x,
3383                         GDI_Y, y,
3384                         GDI_WIDTH, x_size,
3385                         GDI_HEIGHT, y_size,
3386                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3387                         GDI_STATE, GD_BUTTON_UNPRESSED,
3388                         GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3389                         GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3390                         GDI_EVENT_MASK, event_mask,
3391                         GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3392                         GDI_CALLBACK_ACTION, HandleCounterButtons,
3393                         GDI_END);
3394
3395       if (gi == NULL)
3396         Error(ERR_EXIT, "cannot create gadget");
3397
3398       level_editor_gadget[id] = gi;
3399       right_gadget_border[id] =
3400         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
3401
3402       x += gi->width + ED_GADGET_DISTANCE;      /* text count button */
3403
3404       if (j == 0)
3405       {
3406         int font_type = FONT_INPUT_1;
3407         int font_type_active = FONT_INPUT_1_ACTIVE;
3408         int gd_width = ED_WIN_COUNT_XSIZE;
3409
3410         id = counterbutton_info[i].gadget_id_text;
3411         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
3412
3413         if (i == ED_COUNTER_ID_SELECT_LEVEL)
3414         {
3415           font_type = FONT_LEVEL_NUMBER;
3416           font_type_active = FONT_LEVEL_NUMBER;
3417
3418           x += 2 * ED_GADGET_DISTANCE;
3419           y -= ED_GADGET_DISTANCE;
3420
3421           gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
3422           gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
3423           gd_width = ED_WIN_COUNT2_XSIZE;
3424         }
3425         else
3426         {
3427           gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
3428           gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
3429         }
3430
3431         gi = CreateGadget(GDI_CUSTOM_ID, id,
3432                           GDI_CUSTOM_TYPE_ID, i,
3433                           GDI_INFO_TEXT, "enter counter value",
3434                           GDI_X, x,
3435                           GDI_Y, y,
3436                           GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
3437                           GDI_NUMBER_VALUE, 0,
3438                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
3439                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
3440                           GDI_TEXT_SIZE, 3,
3441                           GDI_TEXT_FONT, font_type,
3442                           GDI_TEXT_FONT_ACTIVE, font_type_active,
3443                           GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
3444                           GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
3445                           GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
3446                           GDI_DESIGN_WIDTH, gd_width,
3447                           GDI_EVENT_MASK, event_mask,
3448                           GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3449                           GDI_CALLBACK_ACTION, HandleCounterButtons,
3450                           GDI_END);
3451
3452         if (gi == NULL)
3453           Error(ERR_EXIT, "cannot create gadget");
3454
3455         level_editor_gadget[id] = gi;
3456         right_gadget_border[id] =
3457           getRightGadgetBorder(gi, counterbutton_info[i].text_right);
3458
3459         x += gi->width + ED_GADGET_DISTANCE;    /* up count button */
3460       }
3461     }
3462   }
3463 }
3464
3465 static void CreateDrawingAreas()
3466 {
3467   int i;
3468
3469   for (i=0; i<ED_NUM_DRAWING_AREAS; i++)
3470   {
3471     struct GadgetInfo *gi;
3472     unsigned long event_mask;
3473     int id = drawingarea_info[i].gadget_id;
3474     int x = SX + drawingarea_info[i].x;
3475     int y = SY + drawingarea_info[i].y;
3476     int area_xsize = drawingarea_info[i].area_xsize;
3477     int area_ysize = drawingarea_info[i].area_ysize;
3478
3479     event_mask =
3480       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
3481       GD_EVENT_OFF_BORDERS;
3482
3483     /* determine horizontal position to the right of specified gadget */
3484     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
3485       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
3486            ED_DRAWINGAREA_TEXT_DISTANCE);
3487
3488     /* determine horizontal offset for leading text */
3489     if (drawingarea_info[i].text_left != NULL)
3490       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
3491
3492     gi = CreateGadget(GDI_CUSTOM_ID, id,
3493                       GDI_CUSTOM_TYPE_ID, i,
3494                       GDI_X, x,
3495                       GDI_Y, y,
3496                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
3497                       GDI_AREA_SIZE, area_xsize, area_ysize,
3498                       GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
3499                       GDI_EVENT_MASK, event_mask,
3500                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
3501                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
3502                       GDI_END);
3503
3504     if (gi == NULL)
3505       Error(ERR_EXIT, "cannot create gadget");
3506
3507     level_editor_gadget[id] = gi;
3508     right_gadget_border[id] =
3509       getRightGadgetBorder(gi, drawingarea_info[i].text_right);
3510   }
3511 }
3512
3513 static void CreateTextInputGadgets()
3514 {
3515   int max_infotext_len = getMaxInfoTextLength();
3516   int i;
3517
3518   for (i=0; i<ED_NUM_TEXTINPUT; i++)
3519   {
3520     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3521     int gd_x, gd_y;
3522     struct GadgetInfo *gi;
3523     unsigned long event_mask;
3524     char infotext[MAX_OUTPUT_LINESIZE + 1];
3525     int id = textinput_info[i].gadget_id;
3526
3527     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
3528
3529     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
3530     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
3531
3532     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
3533     infotext[max_infotext_len] = '\0';
3534
3535     gi = CreateGadget(GDI_CUSTOM_ID, id,
3536                       GDI_CUSTOM_TYPE_ID, i,
3537                       GDI_INFO_TEXT, infotext,
3538                       GDI_X, SX + textinput_info[i].x,
3539                       GDI_Y, SY + textinput_info[i].y,
3540                       GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC,
3541                       GDI_TEXT_VALUE, textinput_info[i].value,
3542                       GDI_TEXT_SIZE, textinput_info[i].size,
3543                       GDI_TEXT_FONT, FONT_INPUT_1,
3544                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
3545                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
3546                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
3547                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
3548                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
3549                       GDI_EVENT_MASK, event_mask,
3550                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3551                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
3552                       GDI_END);
3553
3554     if (gi == NULL)
3555       Error(ERR_EXIT, "cannot create gadget");
3556
3557     level_editor_gadget[id] = gi;
3558   }
3559 }
3560
3561 static void CreateTextAreaGadgets()
3562 {
3563   int max_infotext_len = getMaxInfoTextLength();
3564   int i;
3565
3566   for (i=0; i<ED_NUM_TEXTAREAS; i++)
3567   {
3568     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3569     int gd_x, gd_y;
3570     struct GadgetInfo *gi;
3571     unsigned long event_mask;
3572     char infotext[MAX_OUTPUT_LINESIZE + 1];
3573     int id = textarea_info[i].gadget_id;
3574     int area_xsize = textarea_info[i].xsize;
3575     int area_ysize = textarea_info[i].ysize;
3576
3577     event_mask = GD_EVENT_TEXT_LEAVING;
3578
3579     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
3580     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
3581
3582     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
3583     infotext[max_infotext_len] = '\0';
3584
3585     gi = CreateGadget(GDI_CUSTOM_ID, id,
3586                       GDI_CUSTOM_TYPE_ID, i,
3587                       GDI_INFO_TEXT, infotext,
3588                       GDI_X, SX + textarea_info[i].x,
3589                       GDI_Y, SY + textarea_info[i].y,
3590                       GDI_TYPE, GD_TYPE_TEXT_AREA,
3591                       GDI_AREA_SIZE, area_xsize, area_ysize,
3592                       GDI_TEXT_FONT, FONT_INPUT_1,
3593                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
3594                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
3595                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
3596                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
3597                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
3598                       GDI_EVENT_MASK, event_mask,
3599                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3600                       GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
3601                       GDI_END);
3602
3603     if (gi == NULL)
3604       Error(ERR_EXIT, "cannot create gadget");
3605
3606     level_editor_gadget[id] = gi;
3607   }
3608 }
3609
3610 static void CreateSelectboxGadgets()
3611 {
3612   int max_infotext_len = getMaxInfoTextLength();
3613   int i, j;
3614
3615   for (i=0; i<ED_NUM_SELECTBOX; i++)
3616   {
3617     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3618     int gd_x, gd_y;
3619     struct GadgetInfo *gi;
3620     unsigned long event_mask;
3621     char infotext[MAX_OUTPUT_LINESIZE + 1];
3622     int id = selectbox_info[i].gadget_id;
3623     int x = SX + selectbox_info[i].x;
3624     int y = SY + selectbox_info[i].y;
3625
3626     if (selectbox_info[i].size == -1)   /* dynamically determine size */
3627     {
3628       /* (we cannot use -1 for uninitialized values if we directly compare
3629          with results from strlen(), because the '<' and '>' operation will
3630          implicitely cast -1 to an unsigned integer value!) */
3631       selectbox_info[i].size = 0;
3632
3633       for (j=0; selectbox_info[i].options[j].text != NULL; j++)
3634         if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
3635           selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
3636
3637       selectbox_info[i].size++;         /* add one character empty space */
3638     }
3639
3640     event_mask = GD_EVENT_RELEASED |
3641       GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
3642
3643     gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
3644     gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
3645
3646     /* determine horizontal position to the right of specified gadget */
3647     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
3648       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
3649            ED_GADGET_TEXT_DISTANCE);
3650
3651     /* determine horizontal offset for leading text */
3652     if (selectbox_info[i].text_left != NULL)
3653       x += getTextWidthForGadget(selectbox_info[i].text_left);
3654
3655     sprintf(infotext, "Select %s", selectbox_info[i].infotext);
3656     infotext[max_infotext_len] = '\0';
3657
3658     gi = CreateGadget(GDI_CUSTOM_ID, id,
3659                       GDI_CUSTOM_TYPE_ID, i,
3660                       GDI_INFO_TEXT, infotext,
3661                       GDI_X, x,
3662                       GDI_Y, y,
3663                       GDI_TYPE, GD_TYPE_SELECTBOX,
3664                       GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
3665                       GDI_TEXT_SIZE, selectbox_info[i].size,
3666                       GDI_TEXT_FONT, FONT_INPUT_1,
3667                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
3668                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
3669                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
3670                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
3671                       GDI_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE,
3672                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
3673                       GDI_EVENT_MASK, event_mask,
3674                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3675                       GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
3676                       GDI_END);
3677
3678     if (gi == NULL)
3679       Error(ERR_EXIT, "cannot create gadget");
3680
3681     level_editor_gadget[id] = gi;
3682     right_gadget_border[id] =
3683       getRightGadgetBorder(gi, selectbox_info[i].text_right);
3684   }
3685 }
3686
3687 static void CreateTextbuttonGadgets()
3688 {
3689   int max_infotext_len = getMaxInfoTextLength();
3690   int i;
3691
3692   for (i=0; i<ED_NUM_TEXTBUTTONS; i++)
3693   {
3694     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3695     int gd_x1, gd_x2, gd_y1, gd_y2;
3696     struct GadgetInfo *gi;
3697     unsigned long event_mask;
3698     char infotext[MAX_OUTPUT_LINESIZE + 1];
3699     int id = textbutton_info[i].gadget_id;
3700     int x = SX + textbutton_info[i].x;
3701     int y = SY + textbutton_info[i].y;
3702
3703     if (textbutton_info[i].size == -1)  /* dynamically determine size */
3704       textbutton_info[i].size = strlen(textbutton_info[i].text);
3705
3706     event_mask = GD_EVENT_RELEASED;
3707
3708     if (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_ADVANCED)
3709     {
3710       gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
3711       gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
3712       gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS;
3713       gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS;
3714     }
3715     else
3716     {
3717       gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS;
3718       gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS;
3719       gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS;
3720       gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS;
3721     }
3722
3723     sprintf(infotext, "%s", textbutton_info[i].infotext);
3724     infotext[max_infotext_len] = '\0';
3725
3726     /* determine horizontal position to the right of specified gadget */
3727     if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
3728       x = (right_gadget_border[textbutton_info[i].gadget_id_align] +
3729            ED_GADGET_TEXT_DISTANCE);
3730
3731     /* determine horizontal offset for leading text */
3732     if (textbutton_info[i].text_left != NULL)
3733       x += getTextWidthForGadget(textbutton_info[i].text_left);
3734
3735     gi = CreateGadget(GDI_CUSTOM_ID, id,
3736                       GDI_CUSTOM_TYPE_ID, i,
3737                       GDI_INFO_TEXT, infotext,
3738                       GDI_X, x,
3739                       GDI_Y, y,
3740                       GDI_TYPE, GD_TYPE_TEXT_BUTTON,
3741                       GDI_TEXT_VALUE, textbutton_info[i].text,
3742                       GDI_TEXT_SIZE, textbutton_info[i].size,
3743                       GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE,
3744                       GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2,
3745                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
3746                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
3747                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
3748                       GDI_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE,
3749                       GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
3750                       GDI_DECORATION_SHIFTING, 1, 1,
3751                       GDI_EVENT_MASK, event_mask,
3752                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3753                       GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
3754                       GDI_END);
3755
3756     if (gi == NULL)
3757       Error(ERR_EXIT, "cannot create gadget");
3758
3759     level_editor_gadget[id] = gi;
3760     right_gadget_border[id] =
3761       getRightGadgetBorder(gi, textbutton_info[i].text_right);
3762   }
3763 }
3764
3765 static void CreateGraphicbuttonGadgets()
3766 {
3767   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3768   struct GadgetInfo *gi;
3769   unsigned long event_mask;
3770   int i;
3771
3772   /* create buttons for scrolling of drawing area and element list */
3773   for (i=0; i < ED_NUM_GRAPHICBUTTONS; i++)
3774   {
3775     int id = graphicbutton_info[i].gadget_id;
3776     int gd_x1, gd_x2, gd_y1, gd_y2;
3777     int x = SX + graphicbutton_info[i].x;
3778     int y = SY + graphicbutton_info[i].y;
3779
3780     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
3781
3782     gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
3783     gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
3784     gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
3785     gd_y2 = gd_y1;
3786
3787     /* determine horizontal position to the right of specified gadget */
3788     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
3789       x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
3790            ED_GADGET_TEXT_DISTANCE);
3791
3792     /* determine horizontal offset for leading text */
3793     if (graphicbutton_info[i].text_left != NULL)
3794       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
3795
3796     gi = CreateGadget(GDI_CUSTOM_ID, id,
3797                       GDI_CUSTOM_TYPE_ID, i,
3798                       GDI_INFO_TEXT, graphicbutton_info[i].infotext,
3799                       GDI_X, x,
3800                       GDI_Y, y,
3801                       GDI_WIDTH, graphicbutton_info[i].width,
3802                       GDI_HEIGHT, graphicbutton_info[i].height,
3803                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3804                       GDI_STATE, GD_BUTTON_UNPRESSED,
3805                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
3806                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
3807                       GDI_EVENT_MASK, event_mask,
3808                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3809                       GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
3810                       GDI_END);
3811
3812     if (gi == NULL)
3813       Error(ERR_EXIT, "cannot create gadget");
3814
3815     level_editor_gadget[id] = gi;
3816     right_gadget_border[id] =
3817       getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
3818   }
3819 }
3820
3821 static void CreateScrollbarGadgets()
3822 {
3823   int i;
3824
3825   for (i=0; i<ED_NUM_SCROLLBARS; i++)
3826   {
3827     int id = scrollbar_info[i].gadget_id;
3828     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3829     int gd_x1, gd_x2, gd_y1, gd_y2;
3830     struct GadgetInfo *gi;
3831     int items_max, items_visible, item_position;
3832     unsigned long event_mask;
3833
3834     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
3835     {
3836       items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
3837       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
3838       item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
3839     }
3840     else        /* drawing area scrollbars */
3841     {
3842       if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
3843       {
3844         items_max = MAX(lev_fieldx + 2, ed_fieldx);
3845         items_visible = ed_fieldx;
3846         item_position = 0;
3847       }
3848       else
3849       {
3850         items_max = MAX(lev_fieldy + 2, ed_fieldy);
3851         items_visible = ed_fieldy;
3852         item_position = 0;
3853       }
3854     }
3855
3856     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
3857
3858     gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].gd_x;
3859     gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
3860                       scrollbar_info[i].height : scrollbar_info[i].width));
3861     gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
3862     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
3863
3864     gi = CreateGadget(GDI_CUSTOM_ID, id,
3865                       GDI_CUSTOM_TYPE_ID, i,
3866                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
3867                       GDI_X, scrollbar_info[i].x,
3868                       GDI_Y, scrollbar_info[i].y,
3869                       GDI_WIDTH, scrollbar_info[i].width,
3870                       GDI_HEIGHT, scrollbar_info[i].height,
3871                       GDI_TYPE, scrollbar_info[i].type,
3872                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
3873                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
3874                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
3875                       GDI_STATE, GD_BUTTON_UNPRESSED,
3876                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
3877                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
3878                       GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
3879                       GDI_EVENT_MASK, event_mask,
3880                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3881                       GDI_CALLBACK_ACTION, HandleControlButtons,
3882                       GDI_END);
3883
3884     if (gi == NULL)
3885       Error(ERR_EXIT, "cannot create gadget");
3886
3887     level_editor_gadget[id] = gi;
3888   }
3889 }
3890
3891 static void CreateCheckbuttonGadgets()
3892 {
3893   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3894   struct GadgetInfo *gi;
3895   unsigned long event_mask;
3896   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
3897   int i;
3898
3899   event_mask = GD_EVENT_PRESSED;
3900
3901   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
3902   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
3903   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
3904   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
3905   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
3906
3907   for (i=0; i<ED_NUM_CHECKBUTTONS; i++)
3908   {
3909     int id = checkbutton_info[i].gadget_id;
3910     int x = SX + checkbutton_info[i].x;
3911     int y = SY + checkbutton_info[i].y;
3912
3913     if (id == GADGET_ID_STICK_ELEMENT)
3914       gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
3915     else
3916       gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
3917
3918     /* determine horizontal position to the right of specified gadget */
3919     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
3920       x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
3921            ED_GADGET_TEXT_DISTANCE);
3922
3923     /* determine horizontal offset for leading text */
3924     if (checkbutton_info[i].text_left != NULL)
3925       x += getTextWidthForGadget(checkbutton_info[i].text_left);
3926
3927     gi = CreateGadget(GDI_CUSTOM_ID, id,
3928                       GDI_CUSTOM_TYPE_ID, i,
3929                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
3930                       GDI_X, x,
3931                       GDI_Y, y,
3932                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
3933                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
3934                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
3935                       GDI_CHECKED, *checkbutton_info[i].value,
3936                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3937                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3938                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
3939                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
3940                       GDI_EVENT_MASK, event_mask,
3941                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
3942                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
3943                       GDI_END);
3944
3945     if (gi == NULL)
3946       Error(ERR_EXIT, "cannot create gadget");
3947
3948     level_editor_gadget[id] = gi;
3949     right_gadget_border[id] =
3950       getRightGadgetBorder(gi, checkbutton_info[i].text_right);
3951   }
3952 }
3953
3954 static void CreateRadiobuttonGadgets()
3955 {
3956   Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3957   struct GadgetInfo *gi;
3958   unsigned long event_mask;
3959   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
3960   int i;
3961
3962   event_mask = GD_EVENT_PRESSED;
3963
3964   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
3965   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
3966   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
3967   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
3968   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
3969
3970   for (i=0; i<ED_NUM_RADIOBUTTONS; i++)
3971   {
3972     int id = radiobutton_info[i].gadget_id;
3973     int x = SX + radiobutton_info[i].x;
3974     int y = SY + radiobutton_info[i].y;
3975
3976     int checked =
3977       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
3978
3979     /* determine horizontal position to the right of specified gadget */
3980     if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
3981       x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
3982            ED_GADGET_TEXT_DISTANCE);
3983
3984     /* determine horizontal offset for leading text */
3985     if (radiobutton_info[i].text_left != NULL)
3986       x += getTextWidthForGadget(radiobutton_info[i].text_left);
3987
3988     gi = CreateGadget(GDI_CUSTOM_ID, id,
3989                       GDI_CUSTOM_TYPE_ID, i,
3990                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
3991                       GDI_X, x,
3992                       GDI_Y, y,
3993                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
3994                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
3995                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
3996                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
3997                       GDI_CHECKED, checked,
3998                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3999                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4000                       GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
4001                       GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
4002                       GDI_EVENT_MASK, event_mask,
4003                       GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
4004                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
4005                       GDI_END);
4006
4007     if (gi == NULL)
4008       Error(ERR_EXIT, "cannot create gadget");
4009
4010     level_editor_gadget[id] = gi;
4011     right_gadget_border[id] =
4012       getRightGadgetBorder(gi, radiobutton_info[i].text_right);
4013   }
4014 }
4015
4016 void CreateLevelEditorGadgets()
4017 {
4018   int old_game_status = game_status;
4019
4020   /* setting 'game_status' is needed to get the right fonts for the editor */
4021   game_status = GAME_MODE_EDITOR;
4022
4023   ReinitializeElementList();
4024
4025   CreateControlButtons();
4026   CreateScrollbarGadgets();
4027
4028   /* order of function calls is important because of cross-references */
4029   CreateCheckbuttonGadgets();
4030   CreateCounterButtons();
4031   CreateRadiobuttonGadgets();
4032   CreateTextInputGadgets();
4033   CreateTextAreaGadgets();
4034   CreateSelectboxGadgets();
4035   CreateGraphicbuttonGadgets();
4036   CreateTextbuttonGadgets();
4037   CreateDrawingAreas();
4038
4039   game_status = old_game_status;
4040 }
4041
4042 void FreeLevelEditorGadgets()
4043 {
4044   int i;
4045
4046   for (i=0; i<NUM_EDITOR_GADGETS; i++)
4047     FreeGadget(level_editor_gadget[i]);
4048 }
4049
4050 static void MapCounterButtons(int id)
4051 {
4052   int gadget_id_down = counterbutton_info[id].gadget_id_down;
4053   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
4054   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
4055   struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
4056 #if 0
4057   char infotext[MAX_OUTPUT_LINESIZE + 1];
4058   int max_infotext_len = getMaxInfoTextLength();
4059   int xoffset_left = 0;
4060   int yoffset_left = ED_BORDER_SIZE;
4061   int xoffset_right = getCounterGadgetWidth();
4062   int yoffset_right = ED_BORDER_SIZE;
4063 #else
4064   int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
4065   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4066   int yoffset_above = MINI_TILEX + ED_GADGET_DISTANCE;
4067   int yoffset = ED_BORDER_SIZE;
4068   int x_left = gi_down->x - xoffset_left;
4069   int x_right = gi_up->x + gi_up->width + xoffset_right;
4070   int y_above = gi_down->y - yoffset_above;
4071   int x = gi_down->x;
4072   int y = gi_up->y + yoffset;
4073 #endif
4074
4075   if (counterbutton_info[id].text_above)
4076     DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
4077
4078   if (counterbutton_info[id].text_left)
4079     DrawText(x_left, y, counterbutton_info[id].text_left, FONT_TEXT_1);
4080
4081   if (counterbutton_info[id].text_right)
4082     DrawText(x_right, y, counterbutton_info[id].text_right, FONT_TEXT_1);
4083
4084   ModifyEditorCounter(id, *counterbutton_info[id].value);
4085
4086   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
4087   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
4088   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
4089 }
4090
4091 static void MapControlButtons()
4092 {
4093   int counter_id;
4094   int i;
4095
4096   /* map toolbox buttons */
4097   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
4098     MapGadget(level_editor_gadget[i]);
4099
4100   /* map buttons to select elements */
4101   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
4102     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
4103   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
4104   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
4105   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
4106
4107   /* map buttons to select level */
4108   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
4109   ModifyEditorCounterLimits(counter_id,
4110                             leveldir_current->first_level,
4111                             leveldir_current->last_level);
4112   MapCounterButtons(counter_id);
4113 }
4114
4115 static void MapDrawingArea(int id)
4116 {
4117   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
4118   int area_xsize = gi->drawing.area_xsize;
4119   int area_ysize = gi->drawing.area_ysize;
4120   int xoffset_left= getTextWidthForDrawingArea(drawingarea_info[id].text_left);
4121   int xoffset_below= getTextWidth(drawingarea_info[id].text_below,FONT_TEXT_1);
4122   int x_left  = gi->x - xoffset_left;
4123   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
4124   int x_below = gi->x + (gi->width - xoffset_below) / 2;
4125   int y_side  = gi->y + (gi->height - getFontHeight(FONT_TEXT_1)) / 2;
4126   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
4127
4128   if (drawingarea_info[id].text_left)
4129     DrawText(x_left, y_side, drawingarea_info[id].text_left, FONT_TEXT_1);
4130
4131   if (drawingarea_info[id].text_right)
4132     DrawText(x_right, y_side, drawingarea_info[id].text_right, FONT_TEXT_1);
4133
4134   if (drawingarea_info[id].text_below)
4135     DrawText(x_below, y_below, drawingarea_info[id].text_below, FONT_TEXT_1);
4136
4137   if (id != ED_DRAWING_ID_DRAWING_LEVEL)
4138   {
4139     DrawElementBorder(gi->x, gi->y,
4140                       area_xsize * MINI_TILEX, area_ysize * MINI_TILEY, TRUE);
4141
4142     DrawDrawingArea(id);
4143   }
4144
4145   MapGadget(gi);
4146 }
4147
4148 static void MapTextInputGadget(int id)
4149 {
4150   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
4151   int xoffset_above = 0;
4152   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
4153   int x_above = textinput_info[id].x + xoffset_above;
4154   int y_above = textinput_info[id].y + yoffset_above;
4155
4156   if (textinput_info[id].text_above)
4157     DrawTextF(x_above, y_above, FONT_TEXT_1, textinput_info[id].text_above);
4158
4159   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
4160
4161   MapGadget(gi);
4162 }
4163
4164 static void MapTextAreaGadget(int id)
4165 {
4166   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
4167   int xoffset_above = 0;
4168   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
4169   int x_above = textarea_info[id].x + xoffset_above;
4170   int y_above = textarea_info[id].y + yoffset_above;
4171
4172   if (textarea_info[id].text_above)
4173     DrawTextF(x_above, y_above, FONT_TEXT_1, textarea_info[id].text_above);
4174
4175   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
4176
4177   MapGadget(gi);
4178 }
4179
4180 static void MapSelectboxGadget(int id)
4181 {
4182   struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
4183   int xoffset_left = getTextWidthForGadget(selectbox_info[id].text_left);
4184   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4185   int yoffset = ED_BORDER_SIZE;
4186   int x_left = gi->x - xoffset_left;
4187   int x_right = gi->x + gi->width + xoffset_right;
4188   int y = gi->y + yoffset;
4189
4190   if (selectbox_info[id].text_left)
4191     DrawText(x_left, y, selectbox_info[id].text_left, FONT_TEXT_1);
4192
4193   if (selectbox_info[id].text_right)
4194     DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1);
4195
4196   ModifyEditorSelectbox(id, *selectbox_info[id].value);
4197
4198   MapGadget(gi);
4199 }
4200
4201 static void MapTextbuttonGadget(int id)
4202 {
4203   struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
4204   int xoffset_left = getTextWidthForGadget(textbutton_info[id].text_left);
4205   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4206   int yoffset = ED_BORDER_SIZE;
4207   int x_left = gi->x - xoffset_left;
4208   int x_right = gi->x + gi->width + xoffset_right;
4209   int y = gi->y + yoffset;
4210
4211   /* only show button to delete change pages when more than minimum pages */
4212   if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
4213       custom_element.num_change_pages == MIN_CHANGE_PAGES)
4214     return;
4215
4216   if (textbutton_info[id].text_left)
4217     DrawText(x_left, y, textbutton_info[id].text_left, FONT_TEXT_1);
4218
4219   if (textbutton_info[id].text_right)
4220     DrawText(x_right, y, textbutton_info[id].text_right, FONT_TEXT_1);
4221
4222   MapGadget(gi);
4223 }
4224
4225 static void MapGraphicbuttonGadget(int id)
4226 {
4227   struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id];
4228   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
4229   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4230   int yoffset = ED_BORDER_SIZE;
4231   int x_left = gi->x - xoffset_left;
4232   int x_right = gi->x + gi->width + xoffset_right;
4233   int y = gi->y + yoffset;
4234
4235   if (graphicbutton_info[id].text_left)
4236     DrawText(x_left, y, graphicbutton_info[id].text_left, FONT_TEXT_1);
4237
4238   if (graphicbutton_info[id].text_right)
4239     DrawText(x_right, y, graphicbutton_info[id].text_right, FONT_TEXT_1);
4240
4241   MapGadget(gi);
4242 }
4243
4244 static void MapRadiobuttonGadget(int id)
4245 {
4246   struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
4247   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
4248   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4249   int yoffset = ED_BORDER_SIZE;
4250   int x_left = gi->x - xoffset_left;
4251   int x_right = gi->x + gi->width + xoffset_right;
4252   int y = gi->y + yoffset;
4253   boolean checked =
4254     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
4255
4256   if (radiobutton_info[id].text_left)
4257     DrawText(x_left, y, radiobutton_info[id].text_left, FONT_TEXT_1);
4258
4259   if (radiobutton_info[id].text_right)
4260     DrawText(x_right, y, radiobutton_info[id].text_right, FONT_TEXT_1);
4261
4262   ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
4263
4264   MapGadget(gi);
4265 }
4266
4267 static void MapCheckbuttonGadget(int id)
4268 {
4269   struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
4270   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
4271   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
4272   int yoffset = ED_BORDER_SIZE;
4273   int x_left = gi->x - xoffset_left;
4274   int x_right = gi->x + gi->width + xoffset_right;
4275   int y = gi->y + yoffset;
4276
4277   /* special case needed for "sticky" gadget */
4278   ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value,
4279                GDI_Y, SY + checkbutton_info[id].y, GDI_END);
4280   y = gi->y + yoffset;
4281
4282   if (checkbutton_info[id].text_left)
4283     DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1);
4284
4285   if (checkbutton_info[id].text_right)
4286     DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1);
4287
4288   MapGadget(gi);
4289 }
4290
4291 static void MapMainDrawingArea()
4292 {
4293   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
4294   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
4295   int i;
4296
4297   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i<=ED_SCROLLBUTTON_ID_AREA_LAST; i++)
4298   {
4299     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
4300           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
4301          no_horizontal_scrollbar) ||
4302         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
4303           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
4304          no_vertical_scrollbar))
4305       continue;
4306
4307     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
4308   }
4309
4310   for (i=ED_SCROLLBAR_ID_AREA_FIRST; i<=ED_SCROLLBAR_ID_AREA_LAST; i++)
4311   {
4312     if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
4313         (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
4314       continue;
4315
4316     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
4317   }
4318
4319   MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
4320 }
4321
4322 static void UnmapDrawingArea(int id)
4323 {
4324   UnmapGadget(level_editor_gadget[id]);
4325 }
4326
4327 void UnmapLevelEditorWindowGadgets()
4328 {
4329   int i;
4330
4331   for (i=0; i<NUM_EDITOR_GADGETS; i++)
4332     if (level_editor_gadget[i]->x < SX + SXSIZE)
4333       UnmapGadget(level_editor_gadget[i]);
4334 }
4335
4336 void UnmapLevelEditorGadgets()
4337 {
4338   int i;
4339
4340   for (i=0; i<NUM_EDITOR_GADGETS; i++)
4341     UnmapGadget(level_editor_gadget[i]);
4342 }
4343
4344 static void ResetUndoBuffer()
4345 {
4346   undo_buffer_position = -1;
4347   undo_buffer_steps = -1;
4348   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
4349 }
4350
4351 static void DrawEditModeWindow()
4352 {
4353   ModifyEditorElementList();
4354   RedrawDrawingElements();
4355
4356   if (edit_mode == ED_MODE_INFO)
4357     DrawLevelInfoWindow();
4358   else if (edit_mode == ED_MODE_PROPERTIES)
4359     DrawPropertiesWindow();
4360   else  /* edit_mode == ED_MODE_DRAWING */
4361     DrawDrawingWindow();
4362 }
4363
4364 static boolean LevelChanged()
4365 {
4366   boolean level_changed = FALSE;
4367   int x, y;
4368
4369   for(y=0; y<lev_fieldy; y++) 
4370     for(x=0; x<lev_fieldx; x++)
4371       if (Feld[x][y] != level.field[x][y])
4372         level_changed = TRUE;
4373
4374   return level_changed;
4375 }
4376
4377 static boolean LevelContainsPlayer()
4378 {
4379   boolean player_found = FALSE;
4380   int x, y;
4381
4382   for(y=0; y<lev_fieldy; y++) 
4383     for(x=0; x<lev_fieldx; x++)
4384       if (Feld[x][y] == EL_PLAYER_1 ||
4385           Feld[x][y] == EL_SP_MURPHY) 
4386         player_found = TRUE;
4387
4388   return player_found;
4389 }
4390
4391 static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
4392                           short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
4393 {
4394   int x, y;
4395
4396   for(x=0; x<lev_fieldx; x++)
4397     for(y=0; y<lev_fieldy; y++) 
4398       dst[x][y] = src[x][y];
4399 }
4400
4401 static int setSelectboxValue(int selectbox_id, int new_value)
4402 {
4403   int new_index_value = 0;
4404   int i;
4405
4406   for(i=0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
4407     if (selectbox_info[selectbox_id].options[i].value == new_value)
4408       new_index_value = i;
4409
4410   *selectbox_info[selectbox_id].value =
4411     selectbox_info[selectbox_id].options[new_index_value].value;
4412
4413   return new_index_value;
4414 }
4415
4416 static void CopyCustomElementPropertiesToEditor(int element)
4417 {
4418   int i;
4419   int current_change_page = element_info[element].current_change_page;
4420
4421   /* dynamically (re)build selectbox for selecting change page */
4422   for (i=0; i < element_info[element].num_change_pages; i++)
4423   {
4424     sprintf(options_change_page_strings[i], "%d", i + 1);
4425
4426     options_change_page[i].value = i;
4427     options_change_page[i].text = options_change_page_strings[i];
4428   }
4429
4430   options_change_page[i].value = -1;
4431   options_change_page[i].text = NULL;
4432
4433   /* needed here to initialize combined element properties */
4434   InitElementPropertiesEngine(level.game_version);
4435
4436   element_info[element].change =
4437     &element_info[element].change_page[current_change_page];
4438
4439   custom_element = element_info[element];
4440   custom_element_change = *element_info[element].change;
4441
4442   /* needed to initially set selectbox value variables to reliable defaults */
4443   for (i=0; i < ED_NUM_SELECTBOX; i++)
4444     setSelectboxValue(i, *selectbox_info[i].value);
4445
4446   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
4447     custom_element_properties[i] = HAS_PROPERTY(element, i);
4448
4449   for (i=0; i < NUM_CHANGE_EVENTS; i++)
4450     custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
4451
4452   /* ---------- element settings: configure (custom elements) ------------- */
4453
4454   /* set accessible layer selectbox help value */
4455   custom_element.access_type =
4456     (IS_WALKABLE(element) ? EP_WALKABLE :
4457      IS_PASSABLE(element) ? EP_PASSABLE :
4458      custom_element.access_type);
4459   custom_element.access_layer =
4460     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
4461      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
4462      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
4463      custom_element.access_layer);
4464   custom_element_properties[EP_ACCESSIBLE] =
4465     (IS_ACCESSIBLE_OVER(element) ||
4466      IS_ACCESSIBLE_INSIDE(element) ||
4467      IS_ACCESSIBLE_UNDER(element));
4468
4469   /* set walk-to-object action selectbox help value */
4470   custom_element.walk_to_action =
4471     (IS_DIGGABLE(element) ? EP_DIGGABLE :
4472      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
4473      IS_DROPPABLE(element) ? EP_DROPPABLE :
4474      IS_PUSHABLE(element) ? EP_PUSHABLE :
4475      custom_element.walk_to_action);
4476   custom_element_properties[EP_WALK_TO_OBJECT] =
4477     (IS_DIGGABLE(element) ||
4478      IS_COLLECTIBLE_ONLY(element) ||
4479      IS_DROPPABLE(element) ||
4480      IS_PUSHABLE(element));
4481
4482   /* set smash targets selectbox help value */
4483   custom_element.smash_targets =
4484     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
4485      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
4486      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
4487      custom_element.smash_targets);
4488   custom_element_properties[EP_CAN_SMASH] =
4489     (CAN_SMASH_EVERYTHING(element) ||
4490      CAN_SMASH_ENEMIES(element) ||
4491      CAN_SMASH_PLAYER(element));
4492
4493   /* set deadliness selectbox help value */
4494   custom_element.deadliness =
4495     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
4496      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
4497      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
4498      custom_element.deadliness);
4499   custom_element_properties[EP_DEADLY] =
4500     (DONT_TOUCH(element) ||
4501      DONT_COLLIDE_WITH(element) ||
4502      DONT_RUN_INTO(element));
4503
4504   /* set consistency selectbox help value */
4505   custom_element.consistency =
4506     (IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
4507      CAN_EXPLODE_1X1(element) ? EP_CAN_EXPLODE_1X1 :
4508      CAN_EXPLODE_3X3(element) ? EP_CAN_EXPLODE_3X3 :
4509      custom_element.consistency);
4510   custom_element_properties[EP_EXPLODE_RESULT] =
4511     (IS_INDESTRUCTIBLE(element) ||
4512      CAN_EXPLODE_1X1(element) ||
4513      CAN_EXPLODE_3X3(element));
4514
4515   /* special case: sub-settings dependent from main setting */
4516   if (CAN_EXPLODE_BY_FIRE(element))
4517     custom_element.can_explode_by_fire = TRUE;
4518   if (CAN_EXPLODE_SMASHED(element))
4519     custom_element.can_explode_smashed = TRUE;
4520   if (CAN_EXPLODE_IMPACT(element))
4521     custom_element.can_explode_impact  = TRUE;
4522
4523   /* ---------- element settings: advanced (custom elements) --------------- */
4524
4525   /* set "change by direct action" selectbox help value */
4526   custom_element_change.direct_action =
4527     (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
4528      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
4529      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
4530      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
4531      HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION :
4532      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
4533      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
4534      custom_element_change.direct_action);
4535
4536   /* set "change by other element action" selectbox help value */
4537   custom_element_change.other_action =
4538     (
4539      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_TOUCHED) ? CE_OTHER_GETS_TOUCHED :
4540      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PRESSED) ? CE_OTHER_GETS_PRESSED :
4541      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PUSHED) ? CE_OTHER_GETS_PUSHED :
4542      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DIGGED) ? CE_OTHER_GETS_DIGGED :
4543      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
4544      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED :
4545      HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
4546      HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
4547      HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
4548      custom_element_change.other_action);
4549 }
4550
4551 static void CopyCustomElementPropertiesToGame(int element)
4552 {
4553   int i;
4554   int access_type_and_layer;
4555
4556   /* mark that this custom element has been modified */
4557   custom_element.modified_settings = TRUE;
4558
4559   if (level.use_custom_template)
4560   {
4561     if (Request("Copy and modify level tem- plate ?", REQ_ASK))
4562     {
4563       level.use_custom_template = FALSE;
4564       ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
4565                    GDI_CHECKED, FALSE, GDI_END);
4566     }
4567     else
4568     {
4569       LoadLevelTemplate(-1);    /* this resets all element modifications ... */
4570
4571       DrawEditModeWindow();     /* ... and copies them to 'custom_element' */
4572     }
4573   }
4574
4575   element_info[element] = custom_element;
4576   *element_info[element].change = custom_element_change;
4577
4578   /* ---------- element settings: configure (custom elements) ------------- */
4579
4580   /* set accessible property from checkbox and selectbox */
4581   custom_element_properties[EP_WALKABLE_OVER] = FALSE;
4582   custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
4583   custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
4584   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
4585   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
4586   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
4587   access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
4588                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
4589                            (custom_element.access_layer - EP_ACCESSIBLE_OVER));
4590   custom_element_properties[access_type_and_layer] =
4591     custom_element_properties[EP_ACCESSIBLE];
4592
4593   /* set walk-to-object property from checkbox and selectbox */
4594   custom_element_properties[EP_DIGGABLE] = FALSE;
4595   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
4596   custom_element_properties[EP_DROPPABLE] = FALSE;
4597   custom_element_properties[EP_PUSHABLE] = FALSE;
4598   custom_element_properties[custom_element.walk_to_action] =
4599     custom_element_properties[EP_WALK_TO_OBJECT];
4600
4601   /* set smash property from checkbox and selectbox */
4602   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
4603   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
4604   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
4605   custom_element_properties[custom_element.smash_targets] =
4606     custom_element_properties[EP_CAN_SMASH];
4607
4608   /* set deadliness property from checkbox and selectbox */
4609   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
4610   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
4611   custom_element_properties[EP_DONT_TOUCH] = FALSE;
4612   custom_element_properties[custom_element.deadliness] =
4613     custom_element_properties[EP_DEADLY];
4614
4615   /* set consistency property from checkbox and selectbox */
4616   custom_element_properties[EP_INDESTRUCTIBLE] = FALSE;
4617   custom_element_properties[EP_CAN_EXPLODE_1X1] = FALSE;
4618   custom_element_properties[EP_CAN_EXPLODE_3X3] = FALSE;
4619   custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = FALSE;
4620   custom_element_properties[EP_CAN_EXPLODE_SMASHED] = FALSE;
4621   custom_element_properties[EP_CAN_EXPLODE_IMPACT] = FALSE;
4622   custom_element_properties[custom_element.consistency] =
4623     custom_element_properties[EP_EXPLODE_RESULT];
4624
4625   /* special case: sub-settings dependent from main setting */
4626   if (custom_element_properties[EP_CAN_EXPLODE_3X3] ||
4627       custom_element_properties[EP_CAN_EXPLODE_1X1])
4628   {
4629     custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
4630       custom_element.can_explode_by_fire;
4631     custom_element_properties[EP_CAN_EXPLODE_SMASHED] =
4632       custom_element.can_explode_smashed;
4633     custom_element_properties[EP_CAN_EXPLODE_IMPACT] =
4634       custom_element.can_explode_impact;
4635   }
4636
4637   /* ---------- element settings: advanced (custom elements) --------------- */
4638
4639   /* set player change event from checkbox and selectbox */
4640   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
4641   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
4642   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
4643   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
4644   custom_element_change_events[CE_COLLISION] = FALSE;
4645   custom_element_change_events[CE_IMPACT] = FALSE;
4646   custom_element_change_events[CE_SMASHED] = FALSE;
4647   custom_element_change_events[custom_element_change.direct_action] =
4648     custom_element_change_events[CE_BY_DIRECT_ACTION];
4649
4650   /* set other element action change event from checkbox and selectbox */
4651   custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
4652   custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE;
4653   custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE;
4654   custom_element_change_events[CE_OTHER_GETS_TOUCHED] = FALSE;
4655   custom_element_change_events[CE_OTHER_GETS_PRESSED] = FALSE;
4656   custom_element_change_events[CE_OTHER_GETS_PUSHED] = FALSE;
4657   custom_element_change_events[CE_OTHER_GETS_DIGGED] = FALSE;
4658   custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
4659   custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE;
4660   custom_element_change_events[custom_element_change.other_action] =
4661     custom_element_change_events[CE_BY_OTHER_ACTION];
4662
4663   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
4664     SET_PROPERTY(element, i, custom_element_properties[i]);
4665
4666   for (i=0; i < NUM_CHANGE_EVENTS; i++)
4667     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
4668
4669   /* copy change events also to special level editor variable */
4670   custom_element = element_info[element];
4671   custom_element_change = *element_info[element].change;
4672 }
4673
4674 void DrawLevelEd()
4675 {
4676   CloseDoor(DOOR_CLOSE_ALL);
4677   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
4678
4679   if (level_editor_test_game)
4680   {
4681     CopyPlayfield(level.field, Feld);
4682     CopyPlayfield(FieldBackup, level.field);
4683
4684     level_editor_test_game = FALSE;
4685   }
4686   else
4687   {
4688     edit_mode = ED_MODE_DRAWING;
4689     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
4690
4691     ResetUndoBuffer();
4692
4693     level_xpos = -1;
4694     level_ypos = -1;
4695   }
4696
4697   /* copy default editor door content to main double buffer */
4698   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4699              DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
4700
4701 #if 0
4702   /* draw mouse button brush elements */
4703   RedrawDrawingElements();
4704 #endif
4705
4706   /* draw bigger door */
4707   DrawSpecialEditorDoor();
4708
4709   /* draw new control window */
4710   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4711              DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
4712
4713   redraw_mask |= REDRAW_ALL;
4714
4715   ReinitializeElementListButtons();     /* only needed after setup changes */
4716 #if 0
4717   ModifyEditorElementList();            /* may be needed for custom elements */
4718 #endif
4719
4720   UnmapTapeButtons();
4721   MapControlButtons();
4722
4723   DrawEditModeWindow();
4724
4725   /* copy actual editor door content to door double buffer for OpenDoor() */
4726   BlitBitmap(drawto, bitmap_db_door,
4727              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4728
4729   OpenDoor(DOOR_OPEN_1);
4730 }
4731
4732 static void AdjustDrawingAreaGadgets()
4733 {
4734   int ed_xsize = lev_fieldx + 2;
4735   int ed_ysize = lev_fieldy + 2;
4736   int max_ed_fieldx = MAX_ED_FIELDX;
4737   int max_ed_fieldy = MAX_ED_FIELDY;
4738   boolean horizontal_scrollbar_needed;
4739   boolean vertical_scrollbar_needed;
4740   int x, y, width, height;
4741   int xoffset, yoffset;
4742
4743   /* check if we need any scrollbars */
4744   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
4745   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
4746
4747   /* check if we have a smaller editor field because of scrollbars */
4748   if (horizontal_scrollbar_needed)
4749     max_ed_fieldy = MAX_ED_FIELDY - 1;
4750   if (vertical_scrollbar_needed)
4751     max_ed_fieldx = MAX_ED_FIELDX - 1;
4752
4753   /* check again if we now need more scrollbars because of less space */
4754   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
4755   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
4756
4757   /* check if editor field gets even smaller after adding new scrollbars */
4758   if (horizontal_scrollbar_needed)
4759     max_ed_fieldy = MAX_ED_FIELDY - 1;
4760   if (vertical_scrollbar_needed)
4761     max_ed_fieldx = MAX_ED_FIELDX - 1;
4762
4763   ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
4764   ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
4765
4766   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
4767                GDI_WIDTH, ed_fieldx * MINI_TILEX,
4768                GDI_HEIGHT, ed_fieldy * MINI_TILEY,
4769                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
4770                GDI_END);
4771
4772   xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
4773   yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
4774
4775   x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
4776   y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
4777
4778   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
4779   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
4780
4781   width = scrollbar_info[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
4782   height = scrollbar_info[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
4783
4784   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
4785                GDI_WIDTH, width,
4786                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
4787                GDI_END);
4788   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
4789                GDI_HEIGHT, height,
4790                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
4791                GDI_END);
4792 }
4793
4794 static void AdjustLevelScrollPosition()
4795 {
4796   if (level_xpos < -1)
4797     level_xpos = -1;
4798   if (level_xpos > lev_fieldx - ed_fieldx + 1)
4799     level_xpos = lev_fieldx - ed_fieldx + 1;
4800   if (lev_fieldx < ed_fieldx - 2)
4801     level_xpos = -1;
4802
4803   if (level_ypos < -1)
4804     level_ypos = -1;
4805   if (level_ypos > lev_fieldy - ed_fieldy + 1)
4806     level_ypos = lev_fieldy - ed_fieldy + 1;
4807   if (lev_fieldy < ed_fieldy - 2)
4808     level_ypos = -1;
4809 }
4810
4811 static void AdjustEditorScrollbar(int id)
4812 {
4813   struct GadgetInfo *gi = level_editor_gadget[id];
4814   int items_max, items_visible, item_position;
4815
4816   if (id == GADGET_ID_SCROLL_HORIZONTAL)
4817   {
4818     items_max = MAX(lev_fieldx + 2, ed_fieldx);
4819     items_visible = ed_fieldx;
4820     item_position = level_xpos + 1;
4821   }
4822   else
4823   {
4824     items_max = MAX(lev_fieldy + 2, ed_fieldy);
4825     items_visible = ed_fieldy;
4826     item_position = level_ypos + 1;
4827   }
4828
4829   if (item_position > items_max - items_visible)
4830     item_position = items_max - items_visible;
4831
4832   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
4833                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
4834 }
4835
4836 static void ModifyEditorCounter(int counter_id, int new_value)
4837 {
4838   int *counter_value = counterbutton_info[counter_id].value;
4839   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
4840   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
4841
4842   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
4843
4844   if (counter_value != NULL)
4845     *counter_value = gi->textinput.number_value;
4846 }
4847
4848 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
4849 {
4850   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
4851   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
4852
4853   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
4854 }
4855
4856 static void ModifyEditorSelectbox(int selectbox_id, int new_value)
4857 {
4858   int gadget_id = selectbox_info[selectbox_id].gadget_id;
4859   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
4860   int new_index_value = setSelectboxValue(selectbox_id, new_value);
4861
4862   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
4863 }
4864
4865 static void ModifyEditorElementList()
4866 {
4867   int i;
4868
4869   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
4870   {
4871     int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
4872     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
4873     struct GadgetDesign *gd = &gi->deco.design;
4874     int element = editor_elements[element_shift + i];
4875
4876     UnmapGadget(gi);
4877     getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
4878     ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
4879     MapGadget(gi);
4880   }
4881 }
4882
4883 static void PickDrawingElement(int button, int element)
4884 {
4885   if (button < 1 || button > 3)
4886     return;
4887
4888   if (button == 1)
4889   {
4890     new_element1 = element;
4891     DrawMiniGraphicExt(drawto,
4892                        DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
4893                        el2edimg(new_element1));
4894   }
4895   else if (button == 2)
4896   {
4897     new_element2 = element;
4898     DrawMiniGraphicExt(drawto,
4899                        DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
4900                        el2edimg(new_element2));
4901   }
4902   else
4903   {
4904     new_element3 = element;
4905     DrawMiniGraphicExt(drawto,
4906                        DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
4907                        el2edimg(new_element3));
4908   }
4909
4910   redraw_mask |= REDRAW_DOOR_1;
4911 }
4912
4913 static void RedrawDrawingElements()
4914 {
4915   PickDrawingElement(1, new_element1);
4916   PickDrawingElement(2, new_element2);
4917   PickDrawingElement(3, new_element3);
4918 }
4919
4920 static void DrawDrawingWindow()
4921 {
4922   stick_element_properties_window = FALSE;
4923
4924   SetMainBackgroundImage(IMG_UNDEFINED);
4925   ClearWindow();
4926   UnmapLevelEditorWindowGadgets();
4927
4928   AdjustDrawingAreaGadgets();
4929   AdjustLevelScrollPosition();
4930   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
4931   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
4932
4933   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
4934   MapMainDrawingArea();
4935 }
4936
4937 static void DrawLevelInfoWindow()
4938 {
4939   int i;
4940
4941   stick_element_properties_window = FALSE;
4942
4943   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
4944   ClearWindow();
4945   UnmapLevelEditorWindowGadgets();
4946
4947   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
4948            "Level Settings", FONT_TITLE_1);
4949   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
4950            "Editor Settings", FONT_TITLE_1);
4951
4952   /* draw counter gadgets */
4953   for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
4954     MapCounterButtons(i);
4955
4956   /* draw checkbutton gadgets */
4957   for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
4958     MapCheckbuttonGadget(i);
4959
4960   /* draw radiobutton gadgets */
4961   for (i=ED_RADIOBUTTON_ID_LEVEL_FIRST; i<=ED_RADIOBUTTON_ID_LEVEL_LAST; i++)
4962     MapRadiobuttonGadget(i);
4963
4964   /* draw text input gadgets */
4965   for (i=ED_TEXTINPUT_ID_LEVEL_FIRST; i<=ED_TEXTINPUT_ID_LEVEL_LAST; i++)
4966     MapTextInputGadget(i);
4967
4968   /* draw drawing area */
4969   MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
4970 }
4971
4972 static void DrawCustomContentArea()
4973 {
4974   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
4975   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
4976   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
4977   int x2 = right_gadget_border[GADGET_ID_CUSTOM_CONSISTENCY];
4978   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
4979   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
4980
4981   /* add distance for potential left text (without drawing area border) */
4982   x2 += getTextWidthForGadget(drawingarea_info[id].text_left);
4983
4984   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
4985
4986   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
4987 }
4988
4989 static void DrawCustomChangeContentArea()
4990 {
4991   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
4992   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
4993   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
4994   int x2 = right_gadget_border[GADGET_ID_CHANGE_POWER];
4995   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
4996   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
4997
4998   ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
4999
5000   MapDrawingArea(id);
5001 }
5002
5003 static void DrawElementContentAreas()
5004 {
5005   int x = SX + ED_AREA_YAMYAM_CONTENT_XPOS(3) + 4 * MINI_TILEX;
5006   int y = SY + ED_AREA_YAMYAM_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE;
5007   int i;
5008
5009   /* display counter to choose number of element content areas */
5010   MapCounterButtons(ED_COUNTER_ID_ELEMENT_CONTENT);
5011
5012   for (i=0; i < MAX_ELEMENT_CONTENTS; i++)
5013   {
5014     int id = ED_DRAWING_ID_ELEMENT_CONTENT_0 + i;
5015     int font_height = getFontHeight(FONT_TEXT_1);
5016
5017     if (i < level.num_yamyam_contents)
5018       MapDrawingArea(id);
5019     else
5020     {
5021       UnmapDrawingArea(id);
5022
5023       /* delete content areas in case of reducing number of them */
5024       DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
5025                      SY + drawingarea_info[id].y - MINI_TILEY / 2,
5026                      4 * MINI_TILEX,
5027                      4 * MINI_TILEX + ED_GADGET_TEXT_DISTANCE + font_height);
5028     }
5029   }
5030
5031   DrawText(x, y + 0 * MINI_TILEY, "content", FONT_TEXT_1);
5032   DrawText(x, y + 1 * MINI_TILEY, "when",    FONT_TEXT_1);
5033   DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1);
5034 }
5035
5036 static void DrawEnvelopeTextArea()
5037 {
5038   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
5039   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
5040
5041   UnmapGadget(gi);
5042   DrawBackground(gi->x, gi->y, gi->width, gi->height);
5043
5044   ModifyGadget(gi, GDI_AREA_SIZE, level.envelope_xsize, level.envelope_ysize,
5045                GDI_END);
5046   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
5047 }
5048
5049 char *getElementDescriptionFilename(int element)
5050 {
5051   char *docs_dir = options.docs_directory;
5052   char *elements_subdir = "elements";
5053   static char *filename = NULL;
5054   char basename[MAX_FILENAME_LEN];
5055
5056   if (filename != NULL)
5057     free(filename);
5058
5059   /* 1st try: look for element description file for exactly this element */
5060   sprintf(basename, "%s.txt", element_info[element].token_name);
5061   filename = getPath3(docs_dir, elements_subdir, basename);
5062   if (fileExists(filename))
5063     return filename;
5064
5065   free(filename);
5066
5067   /* 2nd try: look for element description file for this element's class */
5068   sprintf(basename, "%s.txt", element_info[element].class_name);
5069   filename = getPath3(docs_dir, elements_subdir, basename);
5070   if (fileExists(filename))
5071     return filename;
5072
5073   return NULL;
5074 }
5075
5076 static boolean PrintInfoText(char *text, int font_nr, int screen_line)
5077 {
5078   int font_height = getFontHeight(font_nr);
5079   int pad_x = ED_SETTINGS_XPOS(0);
5080   int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
5081   int sx = SX + pad_x;
5082   int sy = SY + pad_y;
5083   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
5084
5085   if (screen_line >= max_lines_per_screen)
5086     return FALSE;
5087
5088   DrawText(sx, sy + screen_line * font_height, text, font_nr);
5089
5090   return TRUE;
5091 }
5092
5093 static int PrintElementDescriptionFromFile(char *filename, int screen_line)
5094 {
5095   int font_nr = FONT_TEXT_2;
5096   int font_width = getFontWidth(font_nr);
5097   int pad_x = ED_SETTINGS_XPOS(0);
5098   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
5099   char line[MAX_LINE_LEN];
5100   char buffer[max_chars_per_line + 1];
5101   int buffer_len;
5102   int lines_printed = 0;
5103   FILE *file;
5104
5105   if (filename == NULL)
5106     return 0;
5107
5108   if (!(file = fopen(filename, MODE_READ)))
5109     return 0;
5110
5111   buffer[0] = '\0';
5112   buffer_len = 0;
5113
5114   while(!feof(file))
5115   {
5116     char *line_ptr, *word_ptr;
5117     boolean last_line_was_empty = TRUE;
5118
5119     /* read next line of input file */
5120     if (!fgets(line, MAX_LINE_LEN, file))
5121       break;
5122
5123     /* skip comments (lines directly beginning with '#') */
5124     if (line[0] == '#')
5125       continue;
5126
5127     /* cut trailing newline from input line */
5128     for (line_ptr = line; *line_ptr; line_ptr++)
5129     {
5130       if (*line_ptr == '\n' || *line_ptr == '\r')
5131       {
5132         *line_ptr = '\0';
5133         break;
5134       }
5135     }
5136
5137     if (strlen(line) == 0)              /* special case: force empty line */
5138       strcpy(line, "\n");
5139
5140     word_ptr = line;
5141
5142     while (*word_ptr)
5143     {
5144       boolean print_buffer = FALSE;
5145       int word_len;
5146
5147       /* skip leading whitespaces */
5148       while (*word_ptr == ' ' || *word_ptr == '\t')
5149         word_ptr++;
5150
5151       line_ptr = word_ptr;
5152       word_len = 0;
5153
5154       /* look for end of next word */
5155       while (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
5156       {
5157         line_ptr++;
5158         word_len++;
5159       }
5160
5161       if (word_len == 0)
5162       {
5163         continue;
5164       }
5165       else if (*word_ptr == '\n')       /* special case: force empty line */
5166       {
5167         if (buffer_len == 0)
5168           word_ptr++;
5169
5170         /* prevent printing of multiple empty lines */
5171         if (buffer_len > 0 || !last_line_was_empty)
5172           print_buffer = TRUE;
5173       }
5174       else if (word_len < max_chars_per_line - buffer_len)
5175       {
5176         /* word fits into text buffer -- add word */
5177
5178         if (buffer_len > 0)
5179           buffer[buffer_len++] = ' ';
5180
5181         strncpy(&buffer[buffer_len], word_ptr, word_len);
5182         buffer_len += word_len;
5183         buffer[buffer_len] = '\0';
5184         word_ptr += word_len;
5185       }
5186       else if (buffer_len > 0)
5187       {
5188         /* not enough space left for word in text buffer -- print buffer */
5189
5190         print_buffer = TRUE;
5191       }
5192       else
5193       {
5194         /* word does not fit at all into empty text buffer -- cut word */
5195
5196         strncpy(buffer, word_ptr, max_chars_per_line);
5197         buffer[max_chars_per_line] = '\0';
5198         word_ptr += max_chars_per_line;
5199         print_buffer = TRUE;
5200       }
5201
5202       if (print_buffer)
5203       {
5204         if (!PrintInfoText(buffer, font_nr, screen_line + lines_printed))
5205           return lines_printed;
5206
5207         last_line_was_empty = (buffer_len == 0);
5208         lines_printed++;
5209
5210         buffer[0] = '\0';
5211         buffer_len = 0;
5212         print_buffer = FALSE;
5213       }
5214     }
5215   }
5216
5217   fclose(file);
5218
5219   if (buffer_len > 0)
5220     if (PrintInfoText(buffer, font_nr, screen_line + lines_printed))
5221       lines_printed++;
5222
5223   return lines_printed;
5224 }
5225
5226 static void DrawPropertiesTabulatorGadgets()
5227 {
5228   struct GadgetInfo *gd_gi = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
5229   struct GadgetDesign *gd = &gd_gi->alt_design[GD_BUTTON_UNPRESSED];
5230   int gd_x = gd->x + gd_gi->border.width / 2;
5231   int gd_y = gd->y + gd_gi->height - 1;
5232   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
5233   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
5234   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
5235   int i;
5236
5237   /* draw additional "advanced" tabulator for custom elements */
5238   if (IS_CUSTOM_ELEMENT(properties_element))
5239     id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED;
5240
5241   for (i=id_first; i <= id_last; i++)
5242   {
5243     int gadget_id = textbutton_info[i].gadget_id;
5244     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
5245     boolean active = (i != edit_mode_properties);
5246
5247     /* draw background line below tabulator button */
5248     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width,1);
5249
5250     /* draw solid line below inactive tabulator buttons */
5251     if (!active && tab_color != BLACK_PIXEL)    /* black => transparent */
5252       FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,1, tab_color);
5253
5254     ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
5255     MapTextbuttonGadget(i);
5256   }
5257
5258   /* draw little border line below tabulator buttons */
5259   if (tab_color != BLACK_PIXEL)                 /* black => transparent */
5260     FillRectangle(drawto, gd_gi->x, gd_gi->y + gd_gi->height + 1,
5261                   3 * gd_gi->width + 2 * ED_GADGET_DISTANCE,
5262                   ED_GADGET_DISTANCE, tab_color);
5263 }
5264
5265 static void DrawPropertiesInfo()
5266 {
5267   static struct
5268   {
5269     int value;
5270     char *text;
5271   }
5272   properties[] =
5273   {
5274     /* configurable properties */
5275
5276     { EP_WALKABLE_OVER,         "- player can walk over it"             },
5277     { EP_WALKABLE_INSIDE,       "- player can walk inside it"           },
5278     { EP_WALKABLE_UNDER,        "- player can walk under it"            },
5279     { EP_PASSABLE_OVER,         "- player can pass over it"             },
5280     { EP_PASSABLE_INSIDE,       "- player can pass through it"          },
5281     { EP_PASSABLE_UNDER,        "- player can pass under it"            },
5282
5283     { EP_DIGGABLE,              "- can be digged away"                  },
5284     { EP_COLLECTIBLE,           "- can be collected"                    },
5285     { EP_DROPPABLE,             "- can be dropped after collecting"     },
5286     { EP_PUSHABLE,              "- can be pushed"                       },
5287
5288     { EP_CAN_MOVE,              "- can move"                            },
5289     { EP_CAN_FALL,              "- can fall"                            },
5290
5291     { EP_CAN_SMASH_PLAYER,      "- can smash player"                    },
5292 #if 0
5293     { EP_CAN_SMASH_ENEMIES,     "- can smash good and bad guys"         },
5294 #endif
5295     { EP_CAN_SMASH_EVERYTHING,  "- can smash everything smashable"      },
5296
5297     { EP_SLIPPERY,              "- slippery for falling objects"        },
5298     { EP_EM_SLIPPERY_WALL,      "- slippery for some gems (EM style)"   },
5299
5300     { EP_DONT_RUN_INTO,         "- deadly when running into"            },
5301     { EP_DONT_COLLIDE_WITH,     "- deadly when colliding with"          },
5302     { EP_DONT_TOUCH,            "- deadly when touching"                },
5303
5304     { EP_INDESTRUCTIBLE,        "- indestructible"                      },
5305
5306     { EP_CAN_EXPLODE_BY_FIRE,   "- can explode by fire or explosions"   },
5307     { EP_CAN_EXPLODE_SMASHED,   "- can explode when smashed"            },
5308     { EP_CAN_EXPLODE_IMPACT,    "- can explode on impact"               },
5309
5310     { EP_CAN_CHANGE,            "- can change to other element"         },
5311
5312     /* pre-defined properties */
5313     { EP_CAN_PASS_MAGIC_WALL,   "- can pass magic walls"                },
5314     { EP_HAS_CONTENT,           "- can contain other elements"          },
5315
5316     { -1,                       NULL                                    }
5317   };
5318   char *filename = getElementDescriptionFilename(properties_element);
5319   char *percentage_text = "In this level:";
5320   char *properties_text = "Standard properties:";
5321   float percentage;
5322   int num_elements_in_level;
5323   int num_standard_properties = 0;
5324   int font1_nr = FONT_TEXT_1;
5325   int font2_nr = FONT_TEXT_2;
5326   int font1_width = getFontWidth(font1_nr);
5327   int font2_height = getFontHeight(font2_nr);
5328   int pad_x = ED_SETTINGS_XPOS(0);
5329   int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
5330   int screen_line = 0;
5331   int i, x, y;
5332
5333   /* ----- print number of elements / percentage of this element in level */
5334
5335   num_elements_in_level = 0;
5336   for (y=0; y<lev_fieldy; y++) 
5337     for (x=0; x<lev_fieldx; x++)
5338       if (Feld[x][y] == properties_element)
5339         num_elements_in_level++;
5340   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
5341
5342   DrawTextF(pad_x, pad_y + screen_line * font2_height, font1_nr,
5343             percentage_text);
5344   DrawTextF(pad_x + strlen(percentage_text) * font1_width,
5345             pad_y + screen_line++ * font2_height, font2_nr,
5346             "%d (%.2f%%)", num_elements_in_level, percentage);
5347
5348   screen_line++;
5349
5350   /* ----- print standard properties of this element */
5351
5352   DrawTextF(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
5353             properties_text);
5354
5355   for (i=0; properties[i].value != -1; i++)
5356   {
5357     if (!HAS_PROPERTY(properties_element, properties[i].value))
5358       continue;
5359
5360     DrawTextF(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
5361               properties[i].text);
5362     num_standard_properties++;
5363   }
5364
5365   if (num_standard_properties == 0)
5366     DrawTextF(pad_x + strlen(properties_text) * font1_width,
5367               pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
5368
5369   screen_line++;
5370
5371   /* ----- print special description of this element */
5372
5373   PrintInfoText("Description:", FONT_TEXT_1, screen_line);
5374   if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
5375     PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
5376 }
5377
5378 #define TEXT_COLLECTING         "Score for collecting"
5379 #define TEXT_SMASHING           "Score for smashing"
5380 #define TEXT_CRACKING           "Score for cracking"
5381 #define TEXT_SPEED              "Speed of amoeba growth"
5382 #define TEXT_DURATION           "Duration when activated"
5383
5384 static struct
5385 {
5386   int element;
5387   int *value;
5388   char *text;
5389 } elements_with_counter[] =
5390 {
5391   { EL_EMERALD,         &level.score[SC_EMERALD],       TEXT_COLLECTING },
5392   { EL_BD_DIAMOND,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
5393   { EL_EMERALD_YELLOW,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
5394   { EL_EMERALD_RED,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
5395   { EL_EMERALD_PURPLE,  &level.score[SC_EMERALD],       TEXT_COLLECTING },
5396   { EL_SP_INFOTRON,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
5397   { EL_DIAMOND,         &level.score[SC_DIAMOND],       TEXT_COLLECTING },
5398   { EL_CRYSTAL,         &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
5399   { EL_PEARL,           &level.score[SC_PEARL],         TEXT_COLLECTING },
5400   { EL_BUG_RIGHT,       &level.score[SC_BUG],           TEXT_SMASHING   },
5401   { EL_BUG_UP,          &level.score[SC_BUG],           TEXT_SMASHING   },
5402   { EL_BUG_LEFT,        &level.score[SC_BUG],           TEXT_SMASHING   },
5403   { EL_BUG_DOWN,        &level.score[SC_BUG],           TEXT_SMASHING   },
5404   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],         TEXT_SMASHING   },
5405   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],         TEXT_SMASHING   },
5406   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],         TEXT_SMASHING   },
5407   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],         TEXT_SMASHING   },
5408   { EL_SP_ELECTRON,     &level.score[SC_BUG],           TEXT_SMASHING   },
5409   { EL_SPACESHIP_RIGHT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5410   { EL_SPACESHIP_UP,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5411   { EL_SPACESHIP_LEFT,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5412   { EL_SPACESHIP_DOWN,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5413   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5414   { EL_BD_FIREFLY_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5415   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5416   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5417   { EL_SP_SNIKSNAK,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
5418   { EL_YAMYAM,          &level.score[SC_YAMYAM],        TEXT_SMASHING   },
5419   { EL_DARK_YAMYAM,     &level.score[SC_YAMYAM],        TEXT_SMASHING   },
5420   { EL_ROBOT,           &level.score[SC_ROBOT],         TEXT_SMASHING   },
5421   { EL_PACMAN_RIGHT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
5422   { EL_PACMAN_UP,       &level.score[SC_PACMAN],        TEXT_SMASHING   },
5423   { EL_PACMAN_LEFT,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
5424   { EL_PACMAN_DOWN,     &level.score[SC_PACMAN],        TEXT_SMASHING   },
5425   { EL_NUT,             &level.score[SC_NUT],           TEXT_CRACKING   },
5426   { EL_DYNAMITE,        &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
5427   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
5428   { EL_DYNABOMB_INCREASE_SIZE,  &level.score[SC_DYNAMITE],TEXT_COLLECTING },
5429   { EL_DYNABOMB_INCREASE_POWER, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
5430   { EL_SHIELD_NORMAL,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
5431   { EL_SHIELD_DEADLY,   &level.score[SC_SHIELD],        TEXT_COLLECTING },
5432   { EL_EXTRA_TIME,      &level.score[SC_TIME_BONUS],    TEXT_COLLECTING },
5433   { EL_KEY_1,           &level.score[SC_KEY],           TEXT_COLLECTING },
5434   { EL_KEY_2,           &level.score[SC_KEY],           TEXT_COLLECTING },
5435   { EL_KEY_3,           &level.score[SC_KEY],           TEXT_COLLECTING },
5436   { EL_KEY_4,           &level.score[SC_KEY],           TEXT_COLLECTING },
5437   { EL_EM_KEY_1_FILE,   &level.score[SC_KEY],           TEXT_COLLECTING },
5438   { EL_EM_KEY_2_FILE,   &level.score[SC_KEY],           TEXT_COLLECTING },
5439   { EL_EM_KEY_3_FILE,   &level.score[SC_KEY],           TEXT_COLLECTING },
5440   { EL_EM_KEY_4_FILE,   &level.score[SC_KEY],           TEXT_COLLECTING },
5441   { EL_AMOEBA_WET,      &level.amoeba_speed,            TEXT_SPEED      },
5442   { EL_AMOEBA_DRY,      &level.amoeba_speed,            TEXT_SPEED      },
5443   { EL_AMOEBA_FULL,     &level.amoeba_speed,            TEXT_SPEED      },
5444   { EL_BD_AMOEBA,       &level.amoeba_speed,            TEXT_SPEED      },
5445   { EL_MAGIC_WALL,      &level.time_magic_wall,         TEXT_DURATION   },
5446   { EL_ROBOT_WHEEL,     &level.time_wheel,              TEXT_DURATION   },
5447   { -1,                 NULL,                           NULL            }
5448 };
5449
5450 static boolean checkPropertiesConfig()
5451 {
5452   int i;
5453
5454   if (IS_GEM(properties_element) ||
5455       IS_CUSTOM_ELEMENT(properties_element) ||
5456       HAS_CONTENT(properties_element) ||
5457       properties_element == EL_ENVELOPE)
5458     return TRUE;
5459   else
5460     for (i=0; elements_with_counter[i].element != -1; i++)
5461       if (elements_with_counter[i].element == properties_element)
5462         return TRUE;
5463
5464   return FALSE;
5465 }
5466
5467 static void DrawPropertiesConfig()
5468 {
5469   int i;
5470
5471   if (!checkPropertiesConfig())
5472   {
5473     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
5474
5475     return;
5476   }
5477
5478   /* check if there are elements where a score can be chosen for */
5479   for (i=0; elements_with_counter[i].element != -1; i++)
5480   {
5481     if (elements_with_counter[i].element == properties_element)
5482     {
5483       int counter_id = ED_COUNTER_ID_ELEMENT_SCORE;
5484
5485       counterbutton_info[counter_id].value = elements_with_counter[i].value;
5486       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
5487       MapCounterButtons(counter_id);
5488
5489       break;
5490     }
5491   }
5492
5493   if (HAS_CONTENT(properties_element))
5494   {
5495     /* draw stickybutton gadget */
5496     i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
5497     checkbutton_info[i].y = ED_COUNTER_YPOS(4);
5498     MapCheckbuttonGadget(i);
5499
5500     if (IS_AMOEBOID(properties_element))
5501       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
5502     else
5503       DrawElementContentAreas();
5504   }
5505
5506   if (IS_GEM(properties_element))
5507     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
5508
5509   if (properties_element == EL_ENVELOPE)
5510   {
5511     /* display counter to choose size of envelope text area */
5512     MapCounterButtons(ED_COUNTER_ID_ENVELOPE_XSIZE);
5513     MapCounterButtons(ED_COUNTER_ID_ENVELOPE_YSIZE);
5514
5515     DrawEnvelopeTextArea();
5516   }
5517
5518   if (IS_CUSTOM_ELEMENT(properties_element))
5519   {
5520     /* draw stickybutton gadget */
5521     i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
5522     checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
5523     MapCheckbuttonGadget(i);
5524
5525     /* draw checkbutton gadgets */
5526     for (i =  ED_CHECKBUTTON_ID_CUSTOM_FIRST;
5527          i <= ED_CHECKBUTTON_ID_CUSTOM_LAST; i++)
5528       MapCheckbuttonGadget(i);
5529
5530     /* draw counter gadgets */
5531     for (i=ED_COUNTER_ID_CUSTOM_FIRST; i<=ED_COUNTER_ID_CUSTOM_LAST; i++)
5532       MapCounterButtons(i);
5533
5534     /* draw selectbox gadgets */
5535     for (i=ED_SELECTBOX_ID_CUSTOM_FIRST; i <= ED_SELECTBOX_ID_CUSTOM_LAST; i++)
5536       MapSelectboxGadget(i);
5537
5538     /* draw drawing area gadgets */
5539     DrawCustomContentArea();
5540
5541     /* draw text input gadgets */
5542     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
5543   }
5544 }
5545
5546 static void DrawPropertiesAdvancedDrawingAreas()
5547 {
5548   MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
5549   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
5550   MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
5551
5552   DrawCustomChangeContentArea();
5553
5554   redraw_mask |= REDRAW_FIELD;
5555 }
5556
5557 static void DrawPropertiesAdvanced()
5558 {
5559   int i;
5560
5561   /* draw stickybutton gadget */
5562   i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
5563   checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
5564   MapCheckbuttonGadget(i);
5565
5566   /* draw checkbutton gadgets */
5567   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
5568        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
5569     MapCheckbuttonGadget(i);
5570
5571   /* draw counter gadgets */
5572   for (i=ED_COUNTER_ID_CHANGE_FIRST; i<=ED_COUNTER_ID_CHANGE_LAST; i++)
5573     MapCounterButtons(i);
5574
5575   /* draw selectbox gadgets */
5576   for (i=ED_SELECTBOX_ID_CHANGE_FIRST; i<=ED_SELECTBOX_ID_CHANGE_LAST; i++)
5577     MapSelectboxGadget(i);
5578
5579   /* draw textbutton gadgets */
5580   for (i=ED_TEXTBUTTON_ID_CHANGE_FIRST; i<=ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
5581     MapTextbuttonGadget(i);
5582
5583   /* draw graphicbutton gadgets */
5584   for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
5585        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
5586     MapGraphicbuttonGadget(i);
5587
5588   /* draw drawing area gadgets */
5589   DrawPropertiesAdvancedDrawingAreas();
5590 }
5591
5592 static void DrawElementName(int x, int y, int element)
5593 {
5594   char *element_name = getElementInfoText(element);
5595   int font_nr = FONT_TEXT_1;
5596   int font_width = getFontWidth(font_nr);
5597   int font_height = getFontHeight(font_nr);
5598   int max_text_width = SXSIZE - x - ED_SETTINGS_XPOS(0);
5599   int max_chars_per_line = max_text_width / font_width;
5600   char buffer[max_chars_per_line + 1];
5601
5602   if (strlen(element_name) <= max_chars_per_line)
5603     DrawTextF(x, y, font_nr, element_name);
5604   else
5605   {
5606     int next_pos = max_chars_per_line;
5607
5608     strncpy(buffer, element_name, max_chars_per_line);
5609     buffer[max_chars_per_line] = '\0';
5610
5611     if (element_name[max_chars_per_line] == ' ')
5612       next_pos++;
5613     else
5614     {
5615       int i;
5616
5617       for (i = max_chars_per_line - 1; i >= 0; i--)
5618         if (buffer[i] == ' ')
5619           break;
5620
5621       if (strlen(&element_name[i + 1]) <= max_chars_per_line)
5622       {
5623         buffer[i] = '\0';
5624         next_pos = i + 1;
5625       }
5626     }
5627
5628     DrawTextF(x, y - font_height / 2, font_nr, buffer);
5629
5630     strncpy(buffer, &element_name[next_pos], max_chars_per_line);
5631     buffer[max_chars_per_line] = '\0';
5632
5633     DrawTextF(x, y + font_height / 2, font_nr, buffer);
5634   }
5635 }
5636
5637 static void DrawPropertiesWindow()
5638 {
5639   int xstart = 2;
5640   int ystart = 4;
5641
5642   stick_element_properties_window = FALSE;
5643
5644   /* make sure that previous properties edit mode exists for this element */
5645   if (edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED &&
5646       !IS_CUSTOM_ELEMENT(properties_element))
5647     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
5648
5649   if (IS_CUSTOM_ELEMENT(properties_element))
5650     CopyCustomElementPropertiesToEditor(properties_element);
5651
5652   UnmapLevelEditorWindowGadgets();
5653
5654   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
5655   ClearWindow();
5656
5657   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
5658            "Element Settings", FONT_TITLE_1);
5659
5660   DrawElementBorder(SX + xstart * MINI_TILEX,
5661                     SY + ystart * MINI_TILEY + MINI_TILEY / 2,
5662                     TILEX, TILEY, FALSE);
5663   DrawGraphicAnimationExt(drawto,
5664                           SX + xstart * MINI_TILEX,
5665                           SY + ystart * MINI_TILEY + MINI_TILEY / 2,
5666                           el2img(properties_element), -1, NO_MASKING);
5667
5668   FrameCounter = 0;     /* restart animation frame counter */
5669
5670   DrawElementName((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
5671                   properties_element);
5672
5673   DrawPropertiesTabulatorGadgets();
5674
5675   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
5676     DrawPropertiesInfo();
5677   else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG)
5678     DrawPropertiesConfig();
5679   else  /* edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED */
5680     DrawPropertiesAdvanced();
5681 }
5682
5683 static void UpdateCustomElementGraphicGadgets()
5684 {
5685   ModifyEditorElementList();
5686   RedrawDrawingElements();
5687
5688   if (edit_mode == ED_MODE_PROPERTIES &&
5689       edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED)
5690     DrawPropertiesAdvancedDrawingAreas();
5691 }
5692
5693 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
5694 {
5695   int lx = sx + level_xpos;
5696   int ly = sy + level_ypos;
5697
5698   DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
5699
5700   if (change_level)
5701     Feld[lx][ly] = element;
5702 }
5703
5704 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
5705                      int element, boolean change_level)
5706 {
5707   if (from_y == to_y)                   /* horizontal line */
5708   {
5709     int x;
5710     int y = from_y;
5711
5712     if (from_x > to_x)
5713       swap_numbers(&from_x, &to_x);
5714
5715     for (x=from_x; x<=to_x; x++)
5716       DrawLineElement(x, y, element, change_level);
5717   }
5718   else if (from_x == to_x)              /* vertical line */
5719   {
5720     int x = from_x;
5721     int y;
5722
5723     if (from_y > to_y)
5724       swap_numbers(&from_y, &to_y);
5725
5726     for (y=from_y; y<=to_y; y++)
5727       DrawLineElement(x, y, element, change_level);
5728   }
5729   else                                  /* diagonal line */
5730   {
5731     int len_x = ABS(to_x - from_x);
5732     int len_y = ABS(to_y - from_y);
5733     int x, y;
5734
5735     if (len_y < len_x)                  /* a < 1 */
5736     {
5737       float a = (float)len_y / (float)len_x;
5738
5739       if (from_x > to_x)
5740         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
5741
5742       for (x=0; x<=len_x; x++)
5743       {
5744         y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
5745         DrawLineElement(from_x + x, from_y + y, element, change_level);
5746       }
5747     }
5748     else                                /* a >= 1 */
5749     {
5750       float a = (float)len_x / (float)len_y;
5751
5752       if (from_y > to_y)
5753         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
5754
5755       for (y=0; y<=len_y; y++)
5756       {
5757         x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
5758         DrawLineElement(from_x + x, from_y + y, element, change_level);
5759       }
5760     }
5761   }
5762 }
5763
5764 static void DrawBox(int from_x, int from_y, int to_x, int to_y,
5765                     int element, boolean change_level)
5766 {
5767   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
5768   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
5769   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
5770   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
5771 }
5772
5773 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
5774                           int element, boolean change_level)
5775 {
5776   int y;
5777
5778   if (from_y > to_y)
5779     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
5780
5781   for (y=from_y; y<=to_y; y++)
5782     DrawLine(from_x, y, to_x, y, element, change_level);
5783 }
5784
5785 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
5786                        int element, boolean change_level)
5787 {
5788   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
5789   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
5790   int len_x = ABS(to_x - from_x);
5791   int len_y = ABS(to_y - from_y);
5792   int radius, x, y;
5793
5794   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
5795
5796   /* not optimal (some points get drawn twice) but simple,
5797      and fast enough for the few points we are drawing */
5798
5799   for (x=0; x<=radius; x++)
5800   {
5801     int sx, sy, lx, ly;
5802
5803     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
5804
5805     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
5806     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
5807     lx = sx + level_xpos;
5808     ly = sy + level_ypos;
5809
5810     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
5811       DrawLineElement(sx, sy, element, change_level);
5812   }
5813
5814   for (y=0; y<=radius; y++)
5815   {
5816     int sx, sy, lx, ly;
5817
5818     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
5819
5820     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
5821     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
5822     lx = sx + level_xpos;
5823     ly = sy + level_ypos;
5824
5825     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
5826       DrawLineElement(sx, sy, element, change_level);
5827   }
5828 }
5829
5830 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
5831                     int element, boolean change_level)
5832 {
5833   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
5834   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
5835
5836   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
5837 }
5838
5839 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
5840 #if DRAW_CIRCLES_BUTTON_AVAILABLE
5841 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
5842                        int element, boolean change_level)
5843 {
5844   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
5845   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
5846   int mirror_to_x2 = from_x - (to_x2 - from_x);
5847   int mirror_to_y2 = from_y - (to_y2 - from_y);
5848
5849   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
5850   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
5851   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
5852   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
5853 }
5854 #endif
5855
5856 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
5857 {
5858   int from_sx, from_sy;
5859   int to_sx, to_sy;
5860
5861   if (from_x > to_x)
5862     swap_numbers(&from_x, &to_x);
5863
5864   if (from_y > to_y)
5865     swap_numbers(&from_y, &to_y);
5866
5867   from_sx = SX + from_x * MINI_TILEX;
5868   from_sy = SY + from_y * MINI_TILEY;
5869   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
5870   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
5871
5872   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
5873   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
5874   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
5875   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
5876
5877   if (from_x == to_x && from_y == to_y)
5878     MarkTileDirty(from_x/2, from_y/2);
5879   else
5880     redraw_mask |= REDRAW_FIELD;
5881 }
5882
5883 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
5884                        int element, boolean change_level)
5885 {
5886   if (element == -1 || change_level)
5887     DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
5888   else
5889     DrawAreaBorder(from_x, from_y, to_x, to_y);
5890 }
5891
5892 /* values for CopyBrushExt() */
5893 #define CB_AREA_TO_BRUSH        0
5894 #define CB_BRUSH_TO_CURSOR      1
5895 #define CB_BRUSH_TO_LEVEL       2
5896 #define CB_DELETE_OLD_CURSOR    3
5897
5898 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
5899                          int button, int mode)
5900 {
5901   static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
5902   static int brush_width, brush_height;
5903   static int last_cursor_x = -1, last_cursor_y = -1;
5904   static boolean delete_old_brush;
5905   int new_element = BUTTON_ELEMENT(button);
5906   int x, y;
5907
5908   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
5909     return;
5910
5911   if (mode == CB_AREA_TO_BRUSH)
5912   {
5913     int from_lx, from_ly;
5914
5915     if (from_x > to_x)
5916       swap_numbers(&from_x, &to_x);
5917
5918     if (from_y > to_y)
5919       swap_numbers(&from_y, &to_y);
5920
5921     brush_width = to_x - from_x + 1;
5922     brush_height = to_y - from_y + 1;
5923
5924     from_lx = from_x + level_xpos;
5925     from_ly = from_y + level_ypos;
5926
5927     for (y=0; y<brush_height; y++)
5928     {
5929       for (x=0; x<brush_width; x++)
5930       {
5931         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
5932
5933         if (button != 1)
5934           DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
5935       }
5936     }
5937
5938     if (button != 1)
5939       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
5940
5941     delete_old_brush = FALSE;
5942   }
5943   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
5944            mode == CB_BRUSH_TO_LEVEL)
5945   {
5946     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
5947     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
5948     int cursor_from_x = cursor_x - brush_width / 2;
5949     int cursor_from_y = cursor_y - brush_height / 2;
5950     int border_from_x = cursor_x, border_from_y = cursor_y;
5951     int border_to_x = cursor_x, border_to_y = cursor_y;
5952
5953     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
5954       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
5955
5956     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
5957         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
5958     {
5959       delete_old_brush = FALSE;
5960       return;
5961     }
5962
5963     for (y=0; y<brush_height; y++)
5964     {
5965       for (x=0; x<brush_width; x++)
5966       {
5967         int sx = cursor_from_x + x;
5968         int sy = cursor_from_y + y;
5969         int lx = sx + level_xpos;
5970         int ly = sy + level_ypos;
5971         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
5972         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
5973                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
5974                        brush_buffer[x][y] : new_element);
5975
5976         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
5977         {
5978           if (sx < border_from_x)
5979             border_from_x = sx;
5980           else if (sx > border_to_x)
5981             border_to_x = sx;
5982           if (sy < border_from_y)
5983             border_from_y = sy;
5984           else if (sy > border_to_y)
5985             border_to_y = sy;
5986
5987           DrawLineElement(sx, sy, element, change_level);
5988         }
5989       }
5990     }
5991
5992     if (mode != CB_DELETE_OLD_CURSOR)
5993       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
5994
5995     last_cursor_x = cursor_x;
5996     last_cursor_y = cursor_y;
5997     delete_old_brush = TRUE;
5998   }
5999 }
6000
6001 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
6002                             int button)
6003 {
6004   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
6005 }
6006
6007 static void CopyBrushToLevel(int x, int y, int button)
6008 {
6009   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
6010 }
6011
6012 static void CopyBrushToCursor(int x, int y)
6013 {
6014   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
6015 }
6016
6017 static void DeleteBrushFromCursor()
6018 {
6019   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
6020 }
6021
6022 static void FloodFill(int from_x, int from_y, int fill_element)
6023 {
6024   int i,x,y;
6025   int old_element;
6026   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
6027   static int safety = 0;
6028
6029   /* check if starting field still has the desired content */
6030   if (Feld[from_x][from_y] == fill_element)
6031     return;
6032
6033   safety++;
6034
6035   if (safety > lev_fieldx*lev_fieldy)
6036     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
6037
6038   old_element = Feld[from_x][from_y];
6039   Feld[from_x][from_y] = fill_element;
6040
6041   for(i=0;i<4;i++)
6042   {
6043     x = from_x + check[i][0];
6044     y = from_y + check[i][1];
6045
6046     if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
6047       FloodFill(x, y, fill_element);
6048   }
6049
6050   safety--;
6051 }
6052
6053 /* values for DrawLevelText() modes */
6054 #define TEXT_INIT               0
6055 #define TEXT_SETCURSOR          1
6056 #define TEXT_WRITECHAR          2
6057 #define TEXT_BACKSPACE          3
6058 #define TEXT_NEWLINE            4
6059 #define TEXT_END                5
6060 #define TEXT_QUERY_TYPING       6
6061
6062 static int DrawLevelText(int sx, int sy, char letter, int mode)
6063 {
6064   static short delete_buffer[MAX_LEV_FIELDX];
6065   static int start_sx, start_sy;
6066   static int last_sx, last_sy;
6067   static boolean typing = FALSE;
6068   int letter_element = EL_CHAR_ASCII0 + letter;
6069   int lx = 0, ly = 0;
6070
6071   /* map lower case letters to upper case and convert special characters */
6072   if (letter >= 'a' && letter <= 'z')
6073     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
6074   else if (letter == 'ä' || letter == 'Ä')
6075     letter_element = EL_CHAR_AUMLAUT;
6076   else if (letter == 'ö' || letter == 'Ö')
6077     letter_element = EL_CHAR_OUMLAUT;
6078   else if (letter == 'ü' || letter == 'Ãœ')
6079     letter_element = EL_CHAR_UUMLAUT;
6080   else if (letter == '^')
6081     letter_element = EL_CHAR_COPYRIGHT;
6082   else
6083     letter_element = EL_CHAR_ASCII0 + letter;
6084
6085   if (mode != TEXT_INIT)
6086   {
6087     if (!typing)
6088       return FALSE;
6089
6090     if (mode != TEXT_SETCURSOR)
6091     {
6092       sx = last_sx;
6093       sy = last_sy;
6094     }
6095
6096     lx = last_sx + level_xpos;
6097     ly = last_sy + level_ypos;
6098   }
6099
6100   switch (mode)
6101   {
6102     case TEXT_INIT:
6103       if (typing)
6104         DrawLevelText(0, 0, 0, TEXT_END);
6105
6106       typing = TRUE;
6107       start_sx = last_sx = sx;
6108       start_sy = last_sy = sy;
6109       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
6110       break;
6111
6112     case TEXT_SETCURSOR:
6113       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
6114       DrawAreaBorder(sx, sy, sx, sy);
6115       last_sx = sx;
6116       last_sy = sy;
6117       break;
6118
6119     case TEXT_WRITECHAR:
6120       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
6121       {
6122         delete_buffer[sx - start_sx] = Feld[lx][ly];
6123         Feld[lx][ly] = letter_element;
6124
6125         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
6126           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
6127         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
6128           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
6129         else
6130           DrawLevelText(0, 0, 0, TEXT_END);
6131       }
6132       break;
6133
6134     case TEXT_BACKSPACE:
6135       if (sx > start_sx)
6136       {
6137         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
6138         DrawMiniElement(sx - 1, sy, Feld[lx - 1][ly]);
6139         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
6140       }
6141       break;
6142
6143     case TEXT_NEWLINE:
6144       if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
6145         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
6146       else
6147         DrawLevelText(0, 0, 0, TEXT_END);
6148       break;
6149
6150     case TEXT_END:
6151       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6152       DrawMiniElement(sx, sy, Feld[lx][ly]);
6153       typing = FALSE;
6154       break;
6155
6156     case TEXT_QUERY_TYPING:
6157       break;
6158
6159     default:
6160       break;
6161   }
6162
6163   return typing;
6164 }
6165
6166 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
6167                           int element, boolean change_level)
6168 {
6169   int lx = sx + level_xpos;
6170   int ly = sy + level_ypos;
6171
6172   if (element == -1)
6173     DrawMiniElement(sx, sy, Feld[lx][ly]);
6174   else
6175     DrawAreaBorder(sx, sy, sx, sy);
6176 }
6177
6178 static void CopyLevelToUndoBuffer(int mode)
6179 {
6180   static boolean accumulated_undo = FALSE;
6181   boolean new_undo_buffer_position = TRUE;
6182   int last_border_element;
6183   int x, y;
6184
6185   switch (mode)
6186   {
6187     case UNDO_IMMEDIATE:
6188       accumulated_undo = FALSE;
6189       break;
6190
6191     case UNDO_ACCUMULATE:
6192       if (accumulated_undo)
6193         new_undo_buffer_position = FALSE;
6194       accumulated_undo = TRUE;
6195       break;
6196
6197     default:
6198       break;
6199   }
6200
6201   if (new_undo_buffer_position)
6202   {
6203     /* new position in undo buffer ring */
6204     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
6205
6206     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
6207       undo_buffer_steps++;
6208   }
6209
6210   for(x=0; x<lev_fieldx; x++)
6211     for(y=0; y<lev_fieldy; y++)
6212       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
6213
6214   /* check if drawing operation forces change of border style */
6215   last_border_element = BorderElement;
6216   SetBorderElement();
6217   if (BorderElement != last_border_element)
6218     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6219 }
6220
6221 static void RandomPlacement(int new_element)
6222 {
6223   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
6224   int num_free_positions;
6225   int num_percentage;
6226   int num_elements;
6227   int x, y;
6228
6229   /* determine number of free positions for the new elements */
6230   /* (maybe this statement should be formatted a bit more readable...) */
6231   num_free_positions = 0;
6232   for (x=0; x<lev_fieldx; x++)
6233     for (y=0; y<lev_fieldy; y++)
6234       if ((free_position[x][y] =
6235            ((random_placement_background_restricted &&
6236              Feld[x][y] == random_placement_background_element) ||
6237             (!random_placement_background_restricted &&
6238              Feld[x][y] != new_element))) == TRUE)
6239         num_free_positions++;
6240
6241   /* determine number of new elements to place there */
6242   num_percentage = num_free_positions * random_placement_value / 100;
6243   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
6244                   num_percentage : random_placement_value);
6245
6246   /* if not more free positions than elements to place, fill whole level */
6247   if (num_elements >= num_free_positions)
6248   {
6249     for (x=0; x<lev_fieldx; x++)
6250       for (y=0; y<lev_fieldy; y++)
6251         Feld[x][y] = new_element;
6252
6253     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6254     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6255     return;
6256   }
6257
6258   while (num_elements > 0)
6259   {
6260     x = RND(lev_fieldx);
6261     y = RND(lev_fieldy);
6262
6263     /* don't place element at the same position twice */
6264     if (free_position[x][y])
6265     {
6266       free_position[x][y] = FALSE;
6267       Feld[x][y] = new_element;
6268       num_elements--;
6269     }
6270   }
6271
6272   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6273   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6274 }
6275
6276 void WrapLevel(int dx, int dy)
6277 {
6278   int wrap_dx = lev_fieldx - dx;
6279   int wrap_dy = lev_fieldy - dy;
6280   int x, y;
6281
6282   for(x=0; x<lev_fieldx; x++)
6283     for(y=0; y<lev_fieldy; y++)
6284       FieldBackup[x][y] = Feld[x][y];
6285
6286   for(x=0; x<lev_fieldx; x++)
6287     for(y=0; y<lev_fieldy; y++)
6288       Feld[x][y] =
6289         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
6290
6291   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6292   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
6293 }
6294
6295 static void HandleDrawingAreas(struct GadgetInfo *gi)
6296 {
6297   static boolean started_inside_drawing_area = FALSE;
6298   int id = gi->custom_id;
6299   boolean button_press_event;
6300   boolean button_release_event;
6301   boolean inside_drawing_area = !gi->event.off_borders;
6302   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
6303   int actual_drawing_function;
6304   int button = gi->event.button;
6305   int new_element = BUTTON_ELEMENT(button);
6306   int sx = gi->event.x, sy = gi->event.y;
6307   int min_sx = 0, min_sy = 0;
6308   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
6309   int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
6310   int lx = 0, ly = 0;
6311   int min_lx = 0, min_ly = 0;
6312   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
6313   int x, y;
6314
6315   /* handle info callback for each invocation of action callback */
6316   gi->callback_info(gi);
6317
6318   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
6319   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
6320
6321   /* make sure to stay inside drawing area boundaries */
6322   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
6323   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
6324
6325   if (draw_level)
6326   {
6327     /* get positions inside level field */
6328     lx = sx + level_xpos;
6329     ly = sy + level_ypos;
6330
6331     if (!IN_LEV_FIELD(lx, ly))
6332       inside_drawing_area = FALSE;
6333
6334     /* make sure to stay inside level field boundaries */
6335     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
6336     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
6337
6338     /* correct drawing area positions accordingly */
6339     sx = lx - level_xpos;
6340     sy = ly - level_ypos;
6341   }
6342
6343   if (button_press_event)
6344     started_inside_drawing_area = inside_drawing_area;
6345
6346   if (!started_inside_drawing_area)
6347     return;
6348
6349   if (!button && !button_release_event)
6350     return;
6351
6352   /* automatically switch to 'single item' drawing mode, if needed */
6353   actual_drawing_function =
6354     (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
6355      drawing_function : GADGET_ID_SINGLE_ITEMS);
6356
6357   /* clicking into drawing area with pressed Control key picks element */
6358   if (GetKeyModState() & KMOD_Control)
6359     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
6360
6361   switch (actual_drawing_function)
6362   {
6363     case GADGET_ID_SINGLE_ITEMS:
6364       if (draw_level)
6365       {
6366         if (button_release_event)
6367         {
6368           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6369
6370           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
6371               !inside_drawing_area)
6372             DeleteBrushFromCursor();
6373         }
6374
6375         if (!button)
6376           break;
6377
6378         if (draw_with_brush)
6379         {
6380           if (!button_release_event)
6381             CopyBrushToLevel(sx, sy, button);
6382         }
6383         else if (new_element != Feld[lx][ly])
6384         {
6385           if (new_element == EL_PLAYER_1)
6386           {
6387             /* remove player at old position */
6388             for(y=0; y<lev_fieldy; y++)
6389             {
6390               for(x=0; x<lev_fieldx; x++)
6391               {
6392                 if (Feld[x][y] == EL_PLAYER_1)
6393                 {
6394                   Feld[x][y] = EL_EMPTY;
6395                   if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
6396                       y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
6397                     DrawMiniElement(x - level_xpos, y - level_ypos,
6398                                     EL_EMPTY);
6399                 }
6400               }
6401             }
6402           }
6403
6404           Feld[lx][ly] = new_element;
6405           DrawMiniElement(sx, sy, new_element);
6406         }
6407       }
6408       else
6409       {
6410         if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
6411           DrawMiniGraphicExt(drawto,
6412                              gi->x + sx * MINI_TILEX,
6413                              gi->y + sy * MINI_TILEY,
6414                              el2edimg(new_element));
6415         else
6416           DrawGraphicExt(drawto,
6417                          gi->x + sx * TILEX,
6418                          gi->y + sy * TILEY,
6419                          el2img(new_element), 0);
6420
6421         if (id == GADGET_ID_AMOEBA_CONTENT)
6422           level.amoeba_content = new_element;
6423         else if (id == GADGET_ID_CUSTOM_GRAPHIC)
6424         {
6425           new_element = GFX_ELEMENT(new_element);
6426           custom_element.gfx_element = new_element;
6427
6428           CopyCustomElementPropertiesToGame(properties_element);
6429
6430           UpdateCustomElementGraphicGadgets();
6431
6432           FrameCounter = 0;     /* restart animation frame counter */
6433         }
6434         else if (id == GADGET_ID_CUSTOM_CONTENT)
6435         {
6436           custom_element.content[sx][sy] = new_element;
6437
6438           CopyCustomElementPropertiesToGame(properties_element);
6439         }
6440         else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
6441         {
6442           custom_element_change.target_element = new_element;
6443
6444           CopyCustomElementPropertiesToGame(properties_element);
6445         }
6446         else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
6447         {
6448           custom_element_change.content[sx][sy] = new_element;
6449
6450           CopyCustomElementPropertiesToGame(properties_element);
6451         }
6452         else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
6453         {
6454           custom_element_change.trigger_element = new_element;
6455
6456           CopyCustomElementPropertiesToGame(properties_element);
6457         }
6458         else if (id == GADGET_ID_RANDOM_BACKGROUND)
6459           random_placement_background_element = new_element;
6460         else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
6461                  id <= GADGET_ID_ELEMENT_CONTENT_7)
6462           level.yamyam_content[id - GADGET_ID_ELEMENT_CONTENT_0][sx][sy] =
6463             new_element;
6464       }
6465       break;
6466
6467     case GADGET_ID_CONNECTED_ITEMS:
6468       {
6469         static int last_sx = -1;
6470         static int last_sy = -1;
6471
6472         if (button_release_event)
6473           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6474
6475         if (button)
6476         {
6477           if (!button_press_event)
6478             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
6479
6480           last_sx = sx;
6481           last_sy = sy;
6482         }
6483       }
6484       break;
6485
6486     case GADGET_ID_LINE:
6487     case GADGET_ID_ARC:
6488     case GADGET_ID_RECTANGLE:
6489     case GADGET_ID_FILLED_BOX:
6490     case GADGET_ID_GRAB_BRUSH:
6491     case GADGET_ID_TEXT:
6492       {
6493         static int last_sx = -1;
6494         static int last_sy = -1;
6495         static int start_sx = -1;
6496         static int start_sy = -1;
6497         void (*draw_func)(int, int, int, int, int, boolean);
6498
6499         if (drawing_function == GADGET_ID_LINE)
6500           draw_func = DrawLine;
6501         else if (drawing_function == GADGET_ID_ARC)
6502           draw_func = DrawArc;
6503         else if (drawing_function == GADGET_ID_RECTANGLE)
6504           draw_func = DrawBox;
6505         else if (drawing_function == GADGET_ID_FILLED_BOX)
6506           draw_func = DrawFilledBox;
6507         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
6508           draw_func = SelectArea;
6509         else /* (drawing_function == GADGET_ID_TEXT) */
6510           draw_func = SetTextCursor;
6511
6512         if (button_press_event)
6513         {
6514           draw_func(sx, sy, sx, sy, new_element, FALSE);
6515           start_sx = last_sx = sx;
6516           start_sy = last_sy = sy;
6517
6518           if (drawing_function == GADGET_ID_TEXT)
6519             DrawLevelText(0, 0, 0, TEXT_END);
6520         }
6521         else if (button_release_event)
6522         {
6523           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
6524           if (drawing_function == GADGET_ID_GRAB_BRUSH)
6525           {
6526             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
6527             CopyBrushToCursor(sx, sy);
6528             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
6529                           MB_LEFTBUTTON);
6530             draw_with_brush = TRUE;
6531           }
6532           else if (drawing_function == GADGET_ID_TEXT)
6533             DrawLevelText(sx, sy, 0, TEXT_INIT);
6534           else
6535             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6536         }
6537         else if (last_sx != sx || last_sy != sy)
6538         {
6539           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
6540           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
6541           last_sx = sx;
6542           last_sy = sy;
6543         }
6544       }
6545       break;
6546
6547     case GADGET_ID_FLOOD_FILL:
6548       if (button_press_event && Feld[lx][ly] != new_element)
6549       {
6550         FloodFill(lx, ly, new_element);
6551         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6552         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
6553       }
6554       break;
6555
6556     case GADGET_ID_PICK_ELEMENT:
6557       if (button_release_event)
6558         ClickOnGadget(level_editor_gadget[last_drawing_function],
6559                       MB_LEFTBUTTON);
6560       else if (draw_level)
6561         PickDrawingElement(button, Feld[lx][ly]);
6562       else if (id == GADGET_ID_AMOEBA_CONTENT)
6563         PickDrawingElement(button, level.amoeba_content);
6564       else if (id == GADGET_ID_CUSTOM_GRAPHIC)
6565         PickDrawingElement(button, custom_element.gfx_element);
6566       else if (id == GADGET_ID_CUSTOM_CONTENT)
6567         PickDrawingElement(button, custom_element.content[sx][sy]);
6568       else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
6569         PickDrawingElement(button, custom_element_change.target_element);
6570       else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
6571         PickDrawingElement(button, custom_element_change.content[sx][sy]);
6572       else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
6573         PickDrawingElement(button, custom_element_change.trigger_element);
6574       else if (id == GADGET_ID_RANDOM_BACKGROUND)
6575         PickDrawingElement(button, random_placement_background_element);
6576       else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
6577                id <= GADGET_ID_ELEMENT_CONTENT_7)
6578       {
6579         int i = id - GADGET_ID_ELEMENT_CONTENT_0;
6580
6581         PickDrawingElement(button, level.yamyam_content[i][sx][sy]);
6582       }
6583
6584       break;
6585
6586     default:
6587       break;
6588   }
6589 }
6590
6591 static void HandleCounterButtons(struct GadgetInfo *gi)
6592 {
6593   int gadget_id = gi->custom_id;
6594   int counter_id = gi->custom_type_id;
6595   int button = gi->event.button;
6596   int *counter_value = counterbutton_info[counter_id].value;
6597   int step = BUTTON_STEPSIZE(button) *
6598     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
6599
6600   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
6601   {
6602     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
6603     boolean released = (gi->event.type == GD_EVENT_RELEASED);
6604     boolean level_changed = LevelChanged();
6605
6606     if ((level_changed && pressed) || (!level_changed && released))
6607       return;
6608
6609     if (level_changed && !Request("Level has changed! Discard changes ?",
6610                                   REQ_ASK))
6611     {
6612       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
6613         ModifyEditorCounter(counter_id, *counter_value);
6614       return;
6615     }
6616   }
6617
6618   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
6619     *counter_value = gi->textinput.number_value;
6620   else
6621     ModifyEditorCounter(counter_id, *counter_value + step);
6622
6623   switch (counter_id)
6624   {
6625     case ED_COUNTER_ID_ELEMENT_CONTENT:
6626       DrawElementContentAreas();
6627       break;
6628
6629     case ED_COUNTER_ID_ENVELOPE_XSIZE:
6630     case ED_COUNTER_ID_ENVELOPE_YSIZE:
6631       DrawEnvelopeTextArea();
6632       break;
6633
6634     case ED_COUNTER_ID_LEVEL_XSIZE:
6635     case ED_COUNTER_ID_LEVEL_YSIZE:
6636       lev_fieldx = level.fieldx;
6637       lev_fieldy = level.fieldy;
6638       break;
6639
6640     case ED_COUNTER_ID_SELECT_LEVEL:
6641       LoadLevel(level_nr);
6642       TapeErase();
6643       ResetUndoBuffer();
6644       DrawEditModeWindow();
6645       break;
6646
6647     default:
6648       break;
6649   }
6650
6651   if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
6652        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
6653       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
6654        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
6655     CopyCustomElementPropertiesToGame(properties_element);
6656 }
6657
6658 static void HandleTextInputGadgets(struct GadgetInfo *gi)
6659 {
6660   int type_id = gi->custom_type_id;
6661
6662   strcpy(textinput_info[type_id].value, gi->textinput.value);
6663
6664   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
6665   {
6666     CopyCustomElementPropertiesToGame(properties_element);
6667
6668     ModifyEditorElementList();  /* update changed button info text */
6669   }
6670 }
6671
6672 static void HandleTextAreaGadgets(struct GadgetInfo *gi)
6673 {
6674   int type_id = gi->custom_type_id;
6675
6676   strcpy(textarea_info[type_id].value, gi->textarea.value);
6677 }
6678
6679 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
6680 {
6681   int type_id = gi->custom_type_id;
6682
6683   *selectbox_info[type_id].value =
6684     selectbox_info[type_id].options[gi->selectbox.index].value;
6685
6686   if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
6687   {
6688     element_info[properties_element].current_change_page = gi->selectbox.index;
6689
6690     DrawPropertiesWindow();
6691   }
6692   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
6693             type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
6694            (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
6695             type_id <= ED_SELECTBOX_ID_CHANGE_LAST))
6696     CopyCustomElementPropertiesToGame(properties_element);
6697 }
6698
6699 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
6700 {
6701   int type_id = gi->custom_type_id;
6702   int i;
6703
6704   if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST &&
6705       type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST)
6706   {
6707     edit_mode_properties = gi->custom_type_id;
6708
6709     DrawPropertiesWindow();
6710   }
6711   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
6712   {
6713     boolean new_template = (!LevelFileExists(-1));
6714
6715     if (new_template ||
6716         Request("Save this tem- plate and kill the old ?", REQ_ASK))
6717       SaveLevelTemplate();
6718
6719     if (new_template)
6720       Request("Tem- plate saved !", REQ_CONFIRM);
6721   }
6722   else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE &&
6723            custom_element.num_change_pages < MAX_CHANGE_PAGES)
6724   {
6725     struct ElementInfo *ei = &element_info[properties_element];
6726
6727     setElementChangePages(ei, ei->num_change_pages + 1);
6728
6729     /* set new change page to be new current change page */
6730     ei->current_change_page = ei->num_change_pages - 1;
6731     ei->change = &ei->change_page[ei->current_change_page];
6732
6733     setElementChangeInfoToDefaults(ei->change);
6734
6735     DrawPropertiesWindow();
6736   }
6737   else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE &&
6738            custom_element.num_change_pages > MIN_CHANGE_PAGES)
6739   {
6740     struct ElementInfo *ei = &element_info[properties_element];
6741
6742     /* copy all change pages after change page to be deleted */
6743     for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++)
6744       ei->change_page[i] = ei->change_page[i + 1];
6745
6746     setElementChangePages(ei, ei->num_change_pages - 1);
6747
6748     DrawPropertiesWindow();
6749   }
6750 }
6751
6752 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
6753 {
6754   int type_id = gi->custom_type_id;
6755
6756   if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ||
6757       type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
6758   {
6759     struct ElementInfo *ei = &element_info[properties_element];
6760     int step = BUTTON_STEPSIZE(gi->event.button);
6761
6762     step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1);
6763     ei->current_change_page += step;
6764
6765     if (ei->current_change_page < 0)
6766       ei->current_change_page = 0;
6767     else if (ei->current_change_page >= ei->num_change_pages)
6768       ei->current_change_page = ei->num_change_pages - 1;
6769
6770     DrawPropertiesWindow();
6771   }
6772 }
6773
6774 static void HandleRadiobuttons(struct GadgetInfo *gi)
6775 {
6776   *radiobutton_info[gi->custom_type_id].value =
6777     radiobutton_info[gi->custom_type_id].checked_value;
6778 }
6779
6780 static void HandleCheckbuttons(struct GadgetInfo *gi)
6781 {
6782   int type_id = gi->custom_type_id;
6783
6784   *checkbutton_info[type_id].value ^= TRUE;
6785
6786   if ((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
6787        type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
6788       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
6789        type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
6790        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
6791   {
6792     CopyCustomElementPropertiesToGame(properties_element);
6793   }
6794
6795   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
6796   {
6797     UpdateCustomElementGraphicGadgets();
6798   }
6799   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
6800   {
6801     if (level.use_custom_template && !LevelFileExists(-1))
6802     {
6803       Request("No level tem- plate found !", REQ_CONFIRM);
6804
6805       level.use_custom_template = FALSE;
6806       ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
6807
6808       return;
6809     }
6810
6811     LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
6812
6813     DrawEditModeWindow();
6814   }
6815 }
6816
6817 static void HandleControlButtons(struct GadgetInfo *gi)
6818 {
6819   int id = gi->custom_id;
6820   int button = gi->event.button;
6821   int step = BUTTON_STEPSIZE(button);
6822   int new_element = BUTTON_ELEMENT(button);
6823   int x, y;
6824
6825   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
6826     DrawLevelText(0, 0, 0, TEXT_END);
6827
6828   if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_PROPERTIES &&
6829       id != GADGET_ID_PICK_ELEMENT && edit_mode != ED_MODE_DRAWING &&
6830       drawing_function != GADGET_ID_PICK_ELEMENT &&
6831       !(GetKeyModState() & KMOD_Control))
6832   {
6833     DrawDrawingWindow();
6834     edit_mode = ED_MODE_DRAWING;
6835   }
6836
6837   switch (id)
6838   {
6839     case GADGET_ID_SCROLL_LEFT:
6840       if (level_xpos >= 0)
6841       {
6842         if (lev_fieldx < ed_fieldx - 2)
6843           break;
6844
6845         level_xpos -= step;
6846         if (level_xpos < -1)
6847           level_xpos = -1;
6848         if (button == 1)
6849           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
6850         else
6851           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6852
6853         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
6854                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
6855       }
6856       break;
6857
6858     case GADGET_ID_SCROLL_RIGHT:
6859       if (level_xpos <= lev_fieldx - ed_fieldx)
6860       {
6861         if (lev_fieldx < ed_fieldx - 2)
6862           break;
6863
6864         level_xpos += step;
6865         if (level_xpos > lev_fieldx - ed_fieldx + 1)
6866           level_xpos = lev_fieldx - ed_fieldx + 1;
6867         if (button == 1)
6868           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
6869         else
6870           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6871
6872         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
6873                      GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
6874       }
6875       break;
6876
6877     case GADGET_ID_SCROLL_UP:
6878       if (level_ypos >= 0)
6879       {
6880         if (lev_fieldy < ed_fieldy - 2)
6881           break;
6882
6883         level_ypos -= step;
6884         if (level_ypos < -1)
6885           level_ypos = -1;
6886         if (button == 1)
6887           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
6888         else
6889           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6890
6891         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
6892                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
6893       }
6894       break;
6895
6896     case GADGET_ID_SCROLL_DOWN:
6897       if (level_ypos <= lev_fieldy - ed_fieldy)
6898       {
6899         if (lev_fieldy < ed_fieldy - 2)
6900           break;
6901
6902         level_ypos += step;
6903         if (level_ypos > lev_fieldy - ed_fieldy + 1)
6904           level_ypos = lev_fieldy - ed_fieldy + 1;
6905         if (button == 1)
6906           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
6907         else
6908           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6909
6910         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
6911                      GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
6912       }
6913       break;
6914
6915     case GADGET_ID_SCROLL_HORIZONTAL:
6916       level_xpos = gi->event.item_position - 1;
6917       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6918       break;
6919
6920     case GADGET_ID_SCROLL_VERTICAL:
6921       level_ypos = gi->event.item_position - 1;
6922       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
6923       break;
6924
6925     case GADGET_ID_SCROLL_LIST_UP:
6926     case GADGET_ID_SCROLL_LIST_DOWN:
6927     case GADGET_ID_SCROLL_LIST_VERTICAL:
6928       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
6929         element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
6930       else
6931       {
6932         step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
6933         element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
6934
6935         if (element_shift < 0)
6936           element_shift = 0;
6937         if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
6938           element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
6939
6940         ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
6941                      GDI_SCROLLBAR_ITEM_POSITION,
6942                      element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
6943       }
6944
6945       ModifyEditorElementList();
6946
6947       break;
6948
6949     case GADGET_ID_WRAP_LEFT:
6950       WrapLevel(-step, 0);
6951       break;
6952
6953     case GADGET_ID_WRAP_RIGHT:
6954       WrapLevel(step, 0);
6955       break;
6956
6957     case GADGET_ID_WRAP_UP:
6958       WrapLevel(0, -step);
6959       break;
6960
6961     case GADGET_ID_WRAP_DOWN:
6962       WrapLevel(0, step);
6963       break;
6964
6965     case GADGET_ID_SINGLE_ITEMS:
6966     case GADGET_ID_CONNECTED_ITEMS:
6967     case GADGET_ID_LINE:
6968     case GADGET_ID_ARC:
6969     case GADGET_ID_TEXT:
6970     case GADGET_ID_RECTANGLE:
6971     case GADGET_ID_FILLED_BOX:
6972     case GADGET_ID_FLOOD_FILL:
6973     case GADGET_ID_GRAB_BRUSH:
6974     case GADGET_ID_PICK_ELEMENT:
6975       if (drawing_function != GADGET_ID_PICK_ELEMENT)
6976         last_drawing_function = drawing_function;
6977       drawing_function = id;
6978       draw_with_brush = FALSE;
6979       break;
6980
6981     case GADGET_ID_RANDOM_PLACEMENT:
6982       RandomPlacement(new_element);
6983       break;
6984
6985     case GADGET_ID_PROPERTIES:
6986       if (edit_mode != ED_MODE_PROPERTIES)
6987       {
6988         properties_element = new_element;
6989         DrawPropertiesWindow();
6990         edit_mode = ED_MODE_PROPERTIES;
6991       }
6992       else
6993       {
6994         DrawDrawingWindow();
6995         edit_mode = ED_MODE_DRAWING;
6996       }
6997       break;
6998
6999     case GADGET_ID_UNDO:
7000       if (undo_buffer_steps == 0)
7001       {
7002         Request("Undo buffer empty !", REQ_CONFIRM);
7003         break;
7004       }
7005
7006       if (edit_mode != ED_MODE_DRAWING)
7007       {
7008         DrawDrawingWindow();
7009         edit_mode = ED_MODE_DRAWING;
7010       }
7011
7012       undo_buffer_position =
7013         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
7014       undo_buffer_steps--;
7015
7016       for(x=0; x<lev_fieldx; x++)
7017         for(y=0; y<lev_fieldy; y++)
7018           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
7019       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos,level_ypos);
7020       break;
7021
7022     case GADGET_ID_INFO:
7023       if (edit_mode != ED_MODE_INFO)
7024       {
7025         DrawLevelInfoWindow();
7026         edit_mode = ED_MODE_INFO;
7027       }
7028       else
7029       {
7030         DrawDrawingWindow();
7031         edit_mode = ED_MODE_DRAWING;
7032       }
7033       break;
7034
7035     case GADGET_ID_CLEAR:
7036       if (edit_mode != ED_MODE_DRAWING)
7037       {
7038         DrawDrawingWindow();
7039         edit_mode = ED_MODE_DRAWING;
7040       }
7041
7042       for(x=0; x<MAX_LEV_FIELDX; x++) 
7043         for(y=0; y<MAX_LEV_FIELDY; y++) 
7044           Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
7045       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
7046
7047       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
7048       break;
7049
7050     case GADGET_ID_SAVE:
7051       if (leveldir_current->readonly)
7052       {
7053         Request("This level is read only !", REQ_CONFIRM);
7054         break;
7055       }
7056
7057       if (!LevelContainsPlayer)
7058         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
7059       else
7060       {
7061         boolean new_level = (!LevelFileExists(level_nr));
7062
7063         if (new_level ||
7064             Request("Save this level and kill the old ?", REQ_ASK))
7065         {
7066           CopyPlayfield(Feld, level.field);
7067
7068           SaveLevel(level_nr);
7069         }
7070
7071         if (new_level)
7072           Request("Level saved !", REQ_CONFIRM);
7073       }
7074       break;
7075
7076     case GADGET_ID_TEST:
7077       if (!LevelContainsPlayer)
7078         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
7079       else
7080       {
7081         if (LevelChanged())
7082           level.game_version = GAME_VERSION_ACTUAL;
7083
7084         CopyPlayfield(level.field, FieldBackup);
7085         CopyPlayfield(Feld, level.field);
7086
7087         UnmapLevelEditorGadgets();
7088         UndrawSpecialEditorDoor();
7089
7090         CloseDoor(DOOR_CLOSE_ALL);
7091
7092         DrawCompleteVideoDisplay();
7093
7094         if (setup.autorecord)
7095           TapeStartRecording();
7096
7097         level_editor_test_game = TRUE;
7098         game_status = GAME_MODE_PLAYING;
7099
7100         InitGame();
7101       }
7102       break;
7103
7104     case GADGET_ID_EXIT:
7105       RequestExitLevelEditor(TRUE);     /* if level has changed, ask user */
7106       break;
7107
7108     default:
7109       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
7110           id <= GADGET_ID_ELEMENTLIST_LAST)
7111       {
7112         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
7113         int new_element = editor_elements[element_position + element_shift];
7114
7115         PickDrawingElement(button, new_element);
7116
7117         if (!stick_element_properties_window &&
7118             drawing_function != GADGET_ID_PICK_ELEMENT &&
7119             !(GetKeyModState() & KMOD_Control))
7120         {
7121           properties_element = new_element;
7122           if (edit_mode == ED_MODE_PROPERTIES)
7123             DrawPropertiesWindow();
7124         }
7125
7126         if (drawing_function == GADGET_ID_PICK_ELEMENT)
7127           ClickOnGadget(level_editor_gadget[last_drawing_function],
7128                         MB_LEFTBUTTON);
7129       }
7130 #ifdef DEBUG
7131       else if (gi->event.type == GD_EVENT_PRESSED)
7132         printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
7133       else if (gi->event.type == GD_EVENT_RELEASED)
7134         printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
7135       else if (gi->event.type == GD_EVENT_MOVING)
7136         printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
7137       else
7138         printf("default: HandleControlButtons: ? (id == %d)\n", id);
7139 #endif
7140       break;
7141   }
7142 }
7143
7144 void HandleLevelEditorKeyInput(Key key)
7145 {
7146   char letter = getCharFromKey(key);
7147   int button = MB_LEFTBUTTON;
7148
7149   if (drawing_function == GADGET_ID_TEXT &&
7150       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
7151   {
7152     if (letter)
7153       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
7154     else if (key == KSYM_Delete || key == KSYM_BackSpace)
7155       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
7156     else if (key == KSYM_Return)
7157       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
7158     else if (key == KSYM_Escape)
7159       DrawLevelText(0, 0, 0, TEXT_END);
7160   }
7161   else if (button_status == MB_RELEASED)
7162   {
7163     int i, id = GADGET_ID_NONE;
7164
7165     switch (key)
7166     {
7167       case KSYM_Left:
7168         id = GADGET_ID_SCROLL_LEFT;
7169         break;
7170       case KSYM_Right:
7171         id = GADGET_ID_SCROLL_RIGHT;
7172         break;
7173       case KSYM_Up:
7174         id = GADGET_ID_SCROLL_UP;
7175         break;
7176       case KSYM_Down:
7177         id = GADGET_ID_SCROLL_DOWN;
7178         break;
7179       case KSYM_Page_Up:
7180         id = GADGET_ID_SCROLL_LIST_UP;
7181         button = MB_RIGHTBUTTON;
7182         break;
7183       case KSYM_Page_Down:
7184         id = GADGET_ID_SCROLL_LIST_DOWN;
7185         button = MB_RIGHTBUTTON;
7186         break;
7187
7188       case KSYM_Escape:
7189         if (edit_mode == ED_MODE_DRAWING)
7190         {
7191           RequestExitLevelEditor(setup.ask_on_escape);
7192         }
7193         else
7194         {
7195           DrawDrawingWindow();
7196           edit_mode = ED_MODE_DRAWING;
7197         }
7198         break;
7199
7200       default:
7201         break;
7202     }
7203
7204     if (id != GADGET_ID_NONE)
7205       ClickOnGadget(level_editor_gadget[id], button);
7206     else if (letter == '.')
7207       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
7208     else if (key == KSYM_Return || key == setup.shortcut.toggle_pause)
7209       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
7210     else
7211       for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
7212         if (letter && letter == control_info[i].shortcut)
7213           if (!anyTextGadgetActive())
7214             ClickOnGadget(level_editor_gadget[i], button);
7215   }
7216 }
7217
7218 void HandleLevelEditorIdle()
7219 {
7220   static unsigned long action_delay = 0;
7221   unsigned long action_delay_value = GameFrameDelay;
7222   int xpos = 1, ypos = 2;
7223
7224   if (edit_mode != ED_MODE_PROPERTIES)
7225     return;
7226
7227   if (!DelayReached(&action_delay, action_delay_value))
7228     return;
7229
7230   DrawGraphicAnimationExt(drawto,
7231                           SX + xpos * TILEX,
7232                           SY + ypos * TILEY + MINI_TILEY / 2,
7233                           el2img(properties_element), -1, NO_MASKING);
7234
7235   MarkTileDirty(xpos, ypos);
7236   MarkTileDirty(xpos, ypos + 1);
7237
7238   FrameCounter++;       /* increase animation frame counter */
7239 }
7240
7241 void ClearEditorGadgetInfoText()
7242 {
7243   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
7244 }
7245
7246 void HandleEditorGadgetInfoText(void *ptr)
7247 {
7248   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
7249   char infotext[MAX_OUTPUT_LINESIZE + 1];
7250   char shortcut[MAX_OUTPUT_LINESIZE + 1];
7251   int max_infotext_len = getMaxInfoTextLength();
7252
7253   if (game_status != GAME_MODE_EDITOR)
7254     return;
7255
7256   ClearEditorGadgetInfoText();
7257
7258   if (gi->event.type == GD_EVENT_INFO_LEAVING)
7259     return;
7260
7261   /* misuse this function to delete brush cursor, if needed */
7262   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
7263     DeleteBrushFromCursor();
7264
7265   if (gi == NULL || gi->info_text == NULL)
7266     return;
7267
7268   strncpy(infotext, gi->info_text, max_infotext_len);
7269   infotext[max_infotext_len] = '\0';
7270
7271   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
7272   {
7273     int key = control_info[gi->custom_id].shortcut;
7274
7275     if (key)
7276     {
7277       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)      /* special case 1 */
7278         sprintf(shortcut, " ('.' or '%c')", key);
7279       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT) /* special case 2 */
7280         sprintf(shortcut, " ('%c' or 'Ctrl')", key);
7281       else if (gi->custom_id == GADGET_ID_TEST)         /* special case 3 */
7282         sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
7283       else                                              /* normal case */
7284         sprintf(shortcut, " ('%s%c')",
7285                 (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
7286
7287       if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
7288         strcat(infotext, shortcut);
7289     }
7290   }
7291
7292   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2);
7293 }
7294
7295 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
7296 {
7297   static int start_lx, start_ly;
7298   char *infotext;
7299   int id = gi->custom_id;
7300   int sx = gi->event.x;
7301   int sy = gi->event.y;
7302   int lx = sx + level_xpos;
7303   int ly = sy + level_ypos;
7304   int min_sx = 0, min_sy = 0;
7305   int max_sx = gi->drawing.area_xsize - 1;
7306   int max_sy = gi->drawing.area_ysize - 1;
7307   int actual_drawing_function = drawing_function;
7308
7309   /* pressed Control key: simulate picking element */
7310   if (GetKeyModState() & KMOD_Control)
7311     actual_drawing_function = GADGET_ID_PICK_ELEMENT;
7312
7313   ClearEditorGadgetInfoText();
7314
7315   if (gi->event.type == GD_EVENT_INFO_LEAVING)
7316     return;
7317
7318   /* make sure to stay inside drawing area boundaries */
7319   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
7320   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
7321
7322   if (id == GADGET_ID_DRAWING_LEVEL)
7323   {
7324     if (button_status)
7325     {
7326       int min_lx = 0, min_ly = 0;
7327       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
7328
7329       /* get positions inside level field */
7330       lx = sx + level_xpos;
7331       ly = sy + level_ypos;
7332
7333       /* make sure to stay inside level field boundaries */
7334       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
7335       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
7336
7337       /* correct drawing area positions accordingly */
7338       sx = lx - level_xpos;
7339       sy = ly - level_ypos;
7340     }
7341
7342     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
7343     {
7344       if (button_status)        /* if (gi->state == GD_BUTTON_PRESSED) */
7345       {
7346         if (gi->event.type == GD_EVENT_PRESSED)
7347         {
7348           start_lx = lx;
7349           start_ly = ly;
7350         }
7351
7352         switch (actual_drawing_function)
7353         {
7354           case GADGET_ID_SINGLE_ITEMS:
7355             infotext = "Drawing single items";
7356             break;
7357           case GADGET_ID_CONNECTED_ITEMS:
7358             infotext = "Drawing connected items";
7359             break;
7360           case GADGET_ID_LINE:
7361             infotext = "Drawing line";
7362             break;
7363           case GADGET_ID_ARC:
7364             infotext = "Drawing arc";
7365             break;
7366           case GADGET_ID_TEXT:
7367             infotext = "Setting text cursor";
7368             break;
7369           case GADGET_ID_RECTANGLE:
7370             infotext = "Drawing rectangle";
7371             break;
7372           case GADGET_ID_FILLED_BOX:
7373             infotext = "Drawing filled box";
7374             break;
7375           case GADGET_ID_FLOOD_FILL:
7376             infotext = "Flood fill";
7377             break;
7378           case GADGET_ID_GRAB_BRUSH:
7379             infotext = "Grabbing brush";
7380             break;
7381           case GADGET_ID_PICK_ELEMENT:
7382             infotext = "Picking element";
7383             break;
7384
7385           default:
7386             infotext = "Drawing position";
7387             break;
7388         }
7389
7390         if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
7391           DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7392                     "%s: %d, %d", infotext, lx, ly);
7393         else
7394           DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7395                     "%s: %d, %d", infotext,
7396                     ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
7397       }
7398       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
7399         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7400                   "%s", getElementInfoText(Feld[lx][ly]));
7401       else
7402         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7403                   "Level position: %d, %d", lx, ly);
7404     }
7405
7406     /* misuse this function to draw brush cursor, if needed */
7407     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
7408     {
7409       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
7410         CopyBrushToCursor(sx, sy);
7411       else
7412         DeleteBrushFromCursor();
7413     }
7414   }
7415   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
7416   {
7417     if (id == GADGET_ID_AMOEBA_CONTENT)
7418       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7419                 getElementInfoText(level.amoeba_content));
7420     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
7421       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7422                 getElementInfoText(custom_element.gfx_element));
7423     else if (id == GADGET_ID_CUSTOM_CONTENT)
7424       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7425                 getElementInfoText(custom_element.content[sx][sy]));
7426     else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
7427       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7428                 getElementInfoText(custom_element_change.target_element));
7429     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
7430       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7431                 getElementInfoText(custom_element_change.content[sx][sy]));
7432     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
7433       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7434                 getElementInfoText(custom_element_change.trigger_element));
7435     else if (id == GADGET_ID_RANDOM_BACKGROUND)
7436       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7437                 getElementInfoText(random_placement_background_element));
7438     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
7439              id <= GADGET_ID_ELEMENT_CONTENT_7)
7440     {
7441       int i = id - GADGET_ID_ELEMENT_CONTENT_0;
7442
7443       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
7444                 getElementInfoText(level.yamyam_content[i][sx][sy]));
7445     }
7446   }
7447   else
7448   {
7449     if (id == GADGET_ID_AMOEBA_CONTENT)
7450       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7451                 "Amoeba content");
7452     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
7453       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7454                 "Custom graphic element");
7455     else if (id == GADGET_ID_CUSTOM_CONTENT)
7456       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7457                 "Custom element content position: %d, %d", sx, sy);
7458     else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
7459       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7460                 "New element after change");
7461     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
7462       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7463                 "New extended elements after change");
7464     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
7465       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7466                 "Other element triggering change");
7467     else if (id == GADGET_ID_RANDOM_BACKGROUND)
7468       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7469                 "Random placement background");
7470     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
7471              id <= GADGET_ID_ELEMENT_CONTENT_7)
7472       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
7473                 "Content area %d position: %d, %d",
7474                 id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
7475   }
7476 }
7477
7478 void RequestExitLevelEditor(boolean ask_if_level_has_changed)
7479 {
7480   if (!ask_if_level_has_changed ||
7481       !LevelChanged() ||
7482       Request("Level has changed! Exit without saving ?",
7483               REQ_ASK | REQ_STAY_OPEN))
7484   {
7485     CloseDoor(DOOR_CLOSE_1);
7486     /*
7487     CloseDoor(DOOR_CLOSE_ALL);
7488     */
7489     game_status = GAME_MODE_MAIN;
7490     DrawMainMenu();
7491   }
7492   else
7493   {
7494     CloseDoor(DOOR_CLOSE_1);
7495     BlitBitmap(bitmap_db_door, bitmap_db_door,
7496                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
7497                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
7498     OpenDoor(DOOR_OPEN_1);
7499   }
7500 }