ee201420d2029dd184f33028da5db76702b1e0e0
[rocksndiamonds.git] / src / editor.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  editor.c                                                *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "editor.h"
17 #include "screens.h"
18 #include "tools.h"
19 #include "misc.h"
20 #include "buttons.h"
21 #include "files.h"
22 #include "game.h"
23 #include "tape.h"
24
25 /* positions in the level editor */
26 #define ED_WIN_MB_LEFT_XPOS             7
27 #define ED_WIN_MB_LEFT_YPOS             6
28 #define ED_WIN_LEVELNR_XPOS             77
29 #define ED_WIN_LEVELNR_YPOS             7
30 #define ED_WIN_MB_MIDDLE_XPOS           7
31 #define ED_WIN_MB_MIDDLE_YPOS           258
32 #define ED_WIN_MB_RIGHT_XPOS            77
33 #define ED_WIN_MB_RIGHT_YPOS            258
34
35 /* other constants for the editor */
36 #define ED_SCROLL_NO                    0
37 #define ED_SCROLL_LEFT                  1
38 #define ED_SCROLL_RIGHT                 2
39 #define ED_SCROLL_UP                    4
40 #define ED_SCROLL_DOWN                  8
41
42 /* screens in the level editor */
43 #define ED_MODE_DRAWING                 0
44 #define ED_MODE_INFO                    1
45 #define ED_MODE_PROPERTIES              2
46
47 /* how many steps can be cancelled */
48 #define NUM_UNDO_STEPS                  (10 + 1)
49
50 /* values for elements with score */
51 #define MIN_SCORE                       0
52 #define MAX_SCORE                       255
53
54 /* values for the control window */
55 #define ED_CTRL_BUTTONS_GFX_YPOS        236
56 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS    142
57
58 #define ED_CTRL1_BUTTONS_HORIZ          4
59 #define ED_CTRL1_BUTTONS_VERT           4
60 #define ED_CTRL1_BUTTON_XSIZE           22
61 #define ED_CTRL1_BUTTON_YSIZE           22
62 #define ED_CTRL1_BUTTONS_XPOS           6
63 #define ED_CTRL1_BUTTONS_YPOS           6
64 #define ED_CTRL2_BUTTONS_HORIZ          3
65 #define ED_CTRL2_BUTTONS_VERT           2
66 #define ED_CTRL2_BUTTON_XSIZE           30
67 #define ED_CTRL2_BUTTON_YSIZE           20
68 #define ED_CTRL2_BUTTONS_XPOS           5
69 #define ED_CTRL2_BUTTONS_YPOS           99
70 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
71 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
72 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
73
74 /* values for the element list */
75 #define ED_ELEMENTLIST_UP_XPOS          35
76 #define ED_ELEMENTLIST_UP_YPOS          5
77 #define ED_ELEMENTLIST_UP_ALT_YPOS      140
78 #define ED_ELEMENTLIST_DOWN_XPOS        35
79 #define ED_ELEMENTLIST_DOWN_YPOS        250
80 #define ED_ELEMENTLIST_DOWN_ALT_YPOS    165
81 #define ED_ELEMENTLIST_UPDOWN_XSIZE     30
82 #define ED_ELEMENTLIST_UPDOWN_YSIZE     25
83 #define ED_ELEMENTLIST_XPOS             6
84 #define ED_ELEMENTLIST_YPOS             30
85 #define ED_ELEMENTLIST_ALT_YPOS         190
86 #define ED_ELEMENTLIST_XSIZE            22
87 #define ED_ELEMENTLIST_YSIZE            22
88 #define ED_ELEMENTLIST_BUTTONS_HORIZ    4
89 #define ED_ELEMENTLIST_BUTTONS_VERT     10
90 #define ED_NUM_ELEMENTLIST_BUTTONS      (ED_ELEMENTLIST_BUTTONS_HORIZ * \
91                                          ED_ELEMENTLIST_BUTTONS_VERT)
92
93 /* values for the setting windows */
94 #define ED_SETTINGS_XPOS                (MINI_TILEX + 8)
95 #define ED_SETTINGS2_XPOS               MINI_TILEX
96 #define ED_SETTINGS_YPOS                MINI_TILEY
97 #define ED_SETTINGS2_YPOS               (ED_SETTINGS_YPOS + 12 * TILEY - 2)
98
99 /* values for counter gadgets */
100 #define ED_COUNT_ELEM_SCORE_XPOS        ED_SETTINGS_XPOS
101 #define ED_COUNT_ELEM_SCORE_YPOS        (14 * MINI_TILEY)
102 #define ED_COUNT_ELEM_CONTENT_XPOS      ED_SETTINGS_XPOS
103 #define ED_COUNT_ELEM_CONTENT_YPOS      (19 * MINI_TILEY)
104
105 #define ED_COUNTER_YSTART               (ED_SETTINGS_YPOS + 2 * TILEY)
106 #define ED_COUNTER_YDISTANCE            (3 * MINI_TILEY)
107 #define ED_COUNTER_YPOS(n)              (ED_COUNTER_YSTART + \
108                                          n * ED_COUNTER_YDISTANCE)
109 #define ED_COUNTER2_YPOS(n)             (ED_COUNTER_YSTART + \
110                                          n * ED_COUNTER_YDISTANCE - 2)
111 /* standard distances */
112 #define ED_BORDER_SIZE                  3
113 #define ED_GADGET_DISTANCE              2
114
115 /* values for element content drawing areas */
116 #define ED_AREA_ELEM_CONTENT_XPOS       ( 2 * MINI_TILEX)
117 #define ED_AREA_ELEM_CONTENT_YPOS       (22 * MINI_TILEY)
118
119 /* values for random placement background drawing area */
120 #define ED_AREA_RANDOM_BACKGROUND_XPOS  (29 * MINI_TILEX)
121 #define ED_AREA_RANDOM_BACKGROUND_YPOS  (31 * MINI_TILEY)
122
123 /* values for scrolling gadgets */
124 #define ED_SCROLLBUTTON_XPOS            24
125 #define ED_SCROLLBUTTON_YPOS            0
126 #define ED_SCROLLBAR_XPOS               24
127 #define ED_SCROLLBAR_YPOS               64
128
129 #define ED_SCROLLBUTTON_XSIZE           16
130 #define ED_SCROLLBUTTON_YSIZE           16
131
132 #define ED_SCROLL_UP_XPOS               (SXSIZE - ED_SCROLLBUTTON_XSIZE)
133 #define ED_SCROLL_UP_YPOS               (0)
134 #define ED_SCROLL_DOWN_XPOS             ED_SCROLL_UP_XPOS
135 #define ED_SCROLL_DOWN_YPOS             (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
136 #define ED_SCROLL_LEFT_XPOS             (0)
137 #define ED_SCROLL_LEFT_YPOS             (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
138 #define ED_SCROLL_RIGHT_XPOS            (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
139 #define ED_SCROLL_RIGHT_YPOS            ED_SCROLL_LEFT_YPOS
140 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
141 #define ED_SCROLL_HORIZONTAL_YPOS       ED_SCROLL_LEFT_YPOS
142 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
143 #define ED_SCROLL_HORIZONTAL_YSIZE      ED_SCROLLBUTTON_YSIZE
144 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
145 #define ED_SCROLL_VERTICAL_YPOS   (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
146 #define ED_SCROLL_VERTICAL_XSIZE        ED_SCROLLBUTTON_XSIZE
147 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
148
149 /* values for checkbutton gadgets */
150 #define ED_CHECKBUTTON_XSIZE            ED_BUTTON_COUNT_XSIZE
151 #define ED_CHECKBUTTON_YSIZE            ED_BUTTON_COUNT_YSIZE
152 #define ED_CHECKBUTTON_UNCHECKED_XPOS   ED_BUTTON_MINUS_XPOS
153 #define ED_CHECKBUTTON_CHECKED_XPOS     ED_BUTTON_PLUS_XPOS
154 #define ED_CHECKBUTTON_YPOS             (ED_BUTTON_MINUS_YPOS + 22)
155 #define ED_STICKYBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 88)
156
157 /* some positions in the editor control window */
158 #define ED_BUTTON_ELEM_XPOS     6
159 #define ED_BUTTON_ELEM_YPOS     30
160 #define ED_BUTTON_ELEM_XSIZE    22
161 #define ED_BUTTON_ELEM_YSIZE    22
162
163 #define ED_BUTTON_MINUS_XPOS    2
164 #define ED_BUTTON_MINUS_YPOS    ED_BUTTON_COUNT_YPOS
165 #define ED_BUTTON_MINUS_XSIZE   ED_BUTTON_COUNT_XSIZE
166 #define ED_BUTTON_MINUS_YSIZE   ED_BUTTON_COUNT_YSIZE
167 #define ED_BUTTON_PLUS_XPOS     (ED_WIN_COUNT_XPOS + ED_WIN_COUNT_XSIZE + 2)
168 #define ED_BUTTON_PLUS_YPOS     ED_BUTTON_COUNT_YPOS
169 #define ED_BUTTON_PLUS_XSIZE    ED_BUTTON_COUNT_XSIZE
170 #define ED_BUTTON_PLUS_YSIZE    ED_BUTTON_COUNT_YSIZE
171
172 /* editor gadget identifiers */
173
174 /* drawing toolbox buttons */
175 #define GADGET_ID_NONE                  -1
176 #define GADGET_ID_SINGLE_ITEMS          0
177 #define GADGET_ID_CONNECTED_ITEMS       1
178 #define GADGET_ID_LINE                  2
179 #define GADGET_ID_ARC                   3
180 #define GADGET_ID_RECTANGLE             4
181 #define GADGET_ID_FILLED_BOX            5
182 #define GADGET_ID_WRAP_UP               6
183 #define GADGET_ID_TEXT                  7
184 #define GADGET_ID_FLOOD_FILL            8
185 #define GADGET_ID_WRAP_LEFT             9
186 #define GADGET_ID_PROPERTIES            10
187 #define GADGET_ID_WRAP_RIGHT            11
188 #define GADGET_ID_RANDOM_PLACEMENT      12
189 #define GADGET_ID_GRAB_BRUSH            13
190 #define GADGET_ID_WRAP_DOWN             14
191 #define GADGET_ID_PICK_ELEMENT          15
192 #define GADGET_ID_UNDO                  16
193 #define GADGET_ID_INFO                  17
194 #define GADGET_ID_SAVE                  18
195 #define GADGET_ID_CLEAR                 19
196 #define GADGET_ID_TEST                  20
197 #define GADGET_ID_EXIT                  21
198
199 /* counter button identifiers */
200 #define GADGET_ID_ELEM_SCORE_DOWN       22
201 #define GADGET_ID_ELEM_SCORE_TEXT       23
202 #define GADGET_ID_ELEM_SCORE_UP         24
203 #define GADGET_ID_ELEM_CONTENT_DOWN     25
204 #define GADGET_ID_ELEM_CONTENT_TEXT     26
205 #define GADGET_ID_ELEM_CONTENT_UP       27
206 #define GADGET_ID_LEVEL_XSIZE_DOWN      28
207 #define GADGET_ID_LEVEL_XSIZE_TEXT      29
208 #define GADGET_ID_LEVEL_XSIZE_UP        30
209 #define GADGET_ID_LEVEL_YSIZE_DOWN      31
210 #define GADGET_ID_LEVEL_YSIZE_TEXT      32
211 #define GADGET_ID_LEVEL_YSIZE_UP        33
212 #define GADGET_ID_LEVEL_RANDOM_DOWN     34
213 #define GADGET_ID_LEVEL_RANDOM_TEXT     35
214 #define GADGET_ID_LEVEL_RANDOM_UP       36
215 #define GADGET_ID_LEVEL_COLLECT_DOWN    37
216 #define GADGET_ID_LEVEL_COLLECT_TEXT    38
217 #define GADGET_ID_LEVEL_COLLECT_UP      39
218 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN  40
219 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT  41
220 #define GADGET_ID_LEVEL_TIMELIMIT_UP    42
221 #define GADGET_ID_LEVEL_TIMESCORE_DOWN  43
222 #define GADGET_ID_LEVEL_TIMESCORE_TEXT  44
223 #define GADGET_ID_LEVEL_TIMESCORE_UP    45
224
225 /* drawing area identifiers */
226 #define GADGET_ID_DRAWING_LEVEL 46
227 #define GADGET_ID_ELEM_CONTENT_0        47
228 #define GADGET_ID_ELEM_CONTENT_1        48
229 #define GADGET_ID_ELEM_CONTENT_2        49
230 #define GADGET_ID_ELEM_CONTENT_3        50
231 #define GADGET_ID_ELEM_CONTENT_4        51
232 #define GADGET_ID_ELEM_CONTENT_5        52
233 #define GADGET_ID_ELEM_CONTENT_6        53
234 #define GADGET_ID_ELEM_CONTENT_7        54
235 #define GADGET_ID_AMOEBA_CONTENT        55
236
237 /* text input identifiers */
238 #define GADGET_ID_LEVEL_NAME            56
239 #define GADGET_ID_LEVEL_AUTHOR          57
240
241 /* gadgets for scrolling of drawing area */
242 #define GADGET_ID_SCROLL_UP             58
243 #define GADGET_ID_SCROLL_DOWN           59
244 #define GADGET_ID_SCROLL_LEFT           60
245 #define GADGET_ID_SCROLL_RIGHT          61
246 #define GADGET_ID_SCROLL_HORIZONTAL     62
247 #define GADGET_ID_SCROLL_VERTICAL       63
248
249 /* gadgets for scrolling element list */
250 #define GADGET_ID_ELEMENTLIST_UP        64
251 #define GADGET_ID_ELEMENTLIST_DOWN      65
252
253 /* gadgets for buttons in element list */
254 #define GADGET_ID_ELEMENTLIST_FIRST     66
255 #define GADGET_ID_ELEMENTLIST_LAST      105
256
257 /* buttons for level settings */
258 #define GADGET_ID_RANDOM_PERCENTAGE     106
259 #define GADGET_ID_RANDOM_QUANTITY       107
260 #define GADGET_ID_RANDOM_RESTRICTED     108
261 #define GADGET_ID_DOUBLE_SPEED          109
262 #define GADGET_ID_GRAVITY               110
263 #define GADGET_ID_STICK_ELEMENT         111
264
265 /* another drawing area for random placement */
266 #define GADGET_ID_RANDOM_BACKGROUND     112
267
268 #define NUM_EDITOR_GADGETS              113
269
270 /* radio button numbers */
271 #define RADIO_NR_NONE                   0
272 #define RADIO_NR_DRAWING_TOOLBOX        1
273 #define RADIO_NR_RANDOM_ELEMENTS        2
274
275 /* values for counter gadgets */
276 #define ED_COUNTER_ID_ELEM_SCORE        0
277 #define ED_COUNTER_ID_ELEM_CONTENT      1
278 #define ED_COUNTER_ID_LEVEL_XSIZE       2
279 #define ED_COUNTER_ID_LEVEL_YSIZE       3
280 #define ED_COUNTER_ID_LEVEL_COLLECT     4
281 #define ED_COUNTER_ID_LEVEL_TIMELIMIT   5
282 #define ED_COUNTER_ID_LEVEL_TIMESCORE   6
283 #define ED_COUNTER_ID_LEVEL_RANDOM      7
284
285 #define ED_NUM_COUNTERBUTTONS           8
286
287 #define ED_COUNTER_ID_LEVEL_FIRST       ED_COUNTER_ID_LEVEL_XSIZE
288 #define ED_COUNTER_ID_LEVEL_LAST        ED_COUNTER_ID_LEVEL_RANDOM
289
290 /* values for scrollbutton gadgets */
291 #define ED_SCROLLBUTTON_ID_AREA_UP      0
292 #define ED_SCROLLBUTTON_ID_AREA_DOWN    1
293 #define ED_SCROLLBUTTON_ID_AREA_LEFT    2
294 #define ED_SCROLLBUTTON_ID_AREA_RIGHT   3
295 #define ED_SCROLLBUTTON_ID_LIST_UP      4
296 #define ED_SCROLLBUTTON_ID_LIST_DOWN    5
297
298 #define ED_NUM_SCROLLBUTTONS            6
299
300 #define ED_SCROLLBUTTON_ID_AREA_FIRST   ED_SCROLLBUTTON_ID_AREA_UP
301 #define ED_SCROLLBUTTON_ID_AREA_LAST    ED_SCROLLBUTTON_ID_AREA_RIGHT
302
303 /* values for scrollbar gadgets */
304 #define ED_SCROLLBAR_ID_HORIZONTAL      0
305 #define ED_SCROLLBAR_ID_VERTICAL        1
306
307 #define ED_NUM_SCROLLBARS               2
308
309 /* values for text input gadgets */
310 #define ED_TEXTINPUT_ID_LEVEL_NAME      0
311 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR    1
312
313 #define ED_NUM_TEXTINPUT                2
314
315 #define ED_TEXTINPUT_ID_LEVEL_FIRST     ED_TEXTINPUT_ID_LEVEL_NAME
316 #define ED_TEXTINPUT_ID_LEVEL_LAST      ED_TEXTINPUT_ID_LEVEL_AUTHOR
317
318 /* values for checkbutton gadgets */
319 #define ED_CHECKBUTTON_ID_DOUBLE_SPEED          0
320 #define ED_CHECKBUTTON_ID_GRAVITY               1
321 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED     2
322 #define ED_CHECKBUTTON_ID_STICK_ELEMENT         3
323
324 #define ED_NUM_CHECKBUTTONS                     4
325
326 #define ED_CHECKBUTTON_ID_LEVEL_FIRST   ED_CHECKBUTTON_ID_DOUBLE_SPEED
327 #define ED_CHECKBUTTON_ID_LEVEL_LAST    ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
328
329 /* values for radiobutton gadgets */
330 #define ED_RADIOBUTTON_ID_PERCENTAGE    0
331 #define ED_RADIOBUTTON_ID_QUANTITY      1
332
333 #define ED_NUM_RADIOBUTTONS             2
334
335 #define ED_RADIOBUTTON_ID_LEVEL_FIRST   ED_RADIOBUTTON_ID_PERCENTAGE
336 #define ED_RADIOBUTTON_ID_LEVEL_LAST    ED_RADIOBUTTON_ID_QUANTITY
337
338 /* values for CopyLevelToUndoBuffer() */
339 #define UNDO_IMMEDIATE                  0
340 #define UNDO_ACCUMULATE                 1
341
342 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
343 #define INFOTEXT_XPOS                   SX
344 #define INFOTEXT_YPOS                   (SY + SYSIZE - MINI_TILEX + 2)
345 #define INFOTEXT_XSIZE                  SXSIZE
346 #define INFOTEXT_YSIZE                  MINI_TILEX
347 #define MAX_INFOTEXT_LEN                (SXSIZE / FONT2_XSIZE)
348
349 static struct
350 {
351   char shortcut;
352   char *text;
353 } control_info[ED_NUM_CTRL_BUTTONS] =
354 {
355   { 's', "draw single items" },
356   { 'd', "draw connected items" },
357   { 'l', "draw lines" },
358   { 'a', "draw arcs" },
359   { 'r', "draw outline rectangles" },
360   { 'R', "draw filled rectangles" },
361   { '\0', "wrap (rotate) level up" },
362   { 't', "enter text elements" },
363   { 'f', "flood fill" },
364   { '\0', "wrap (rotate) level left" },
365   { '?', "properties of drawing element" },
366   { '\0', "wrap (rotate) level right" },
367   { '\0', "random element placement" },
368   { 'b', "grab brush" },
369   { '\0', "wrap (rotate) level down" },
370   { ',', "pick drawing element" },
371   { 'U', "undo last operation" },
372   { 'I', "level properties" },
373   { 'S', "save level" },
374   { 'C', "clear level" },
375   { 'T', "test level" },
376   { 'E', "exit level editor" }
377 };
378
379 /* values for random placement */
380 #define RANDOM_USE_PERCENTAGE           0
381 #define RANDOM_USE_QUANTITY             1
382
383 static int random_placement_value = 10;
384 static int random_placement_method = RANDOM_USE_QUANTITY;
385 static int random_placement_background_element = EL_ERDREICH;
386 static boolean random_placement_background_restricted = FALSE;
387 static boolean stick_element_properties_window = FALSE;
388
389 static struct
390 {
391   int x, y;
392   int min_value, max_value;
393   int gadget_id_down, gadget_id_up;
394   int gadget_id_text;
395   int *value;
396   char *infotext_above, *infotext_right;
397 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
398 {
399   {
400     ED_COUNT_ELEM_SCORE_XPOS,           ED_COUNT_ELEM_SCORE_YPOS,
401     MIN_SCORE,                          MAX_SCORE,
402     GADGET_ID_ELEM_SCORE_DOWN,          GADGET_ID_ELEM_SCORE_UP,
403     GADGET_ID_ELEM_SCORE_TEXT,
404     NULL,                               /* will be set when used */
405     "element score",                    NULL
406   },
407   {
408     ED_COUNT_ELEM_CONTENT_XPOS,         ED_COUNT_ELEM_CONTENT_YPOS,
409     MIN_ELEMENT_CONTENTS,               MAX_ELEMENT_CONTENTS,
410     GADGET_ID_ELEM_CONTENT_DOWN,        GADGET_ID_ELEM_CONTENT_UP,
411     GADGET_ID_ELEM_CONTENT_TEXT,
412     &level.num_yam_contents,
413     "element content",                  NULL
414   },
415   {
416     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(2),
417     MIN_LEV_FIELDX,                     MAX_LEV_FIELDX,
418     GADGET_ID_LEVEL_XSIZE_DOWN,         GADGET_ID_LEVEL_XSIZE_UP,
419     GADGET_ID_LEVEL_XSIZE_TEXT,
420     &level.fieldx,
421     "playfield size",                   "width",
422   },
423   {
424     ED_SETTINGS_XPOS + 2 * DXSIZE,      ED_COUNTER_YPOS(2),
425     MIN_LEV_FIELDY,                     MAX_LEV_FIELDY,
426     GADGET_ID_LEVEL_YSIZE_DOWN,         GADGET_ID_LEVEL_YSIZE_UP,
427     GADGET_ID_LEVEL_YSIZE_TEXT,
428     &level.fieldy,
429     NULL,                               "height",
430   },
431   {
432     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(3),
433     0,                                  999,
434     GADGET_ID_LEVEL_COLLECT_DOWN,       GADGET_ID_LEVEL_COLLECT_UP,
435     GADGET_ID_LEVEL_COLLECT_TEXT,
436     &level.gems_needed,
437     "number of emeralds to collect",    NULL
438   },
439   {
440     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(4),
441     0,                                  999,
442     GADGET_ID_LEVEL_TIMELIMIT_DOWN,     GADGET_ID_LEVEL_TIMELIMIT_UP,
443     GADGET_ID_LEVEL_TIMELIMIT_TEXT,
444     &level.time,
445     "time available to solve level",    "(0 => no time limit)"
446   },
447   {
448     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(5),
449     0,                                  255,
450     GADGET_ID_LEVEL_TIMESCORE_DOWN,     GADGET_ID_LEVEL_TIMESCORE_UP,
451     GADGET_ID_LEVEL_TIMESCORE_TEXT,
452     &level.score[SC_ZEITBONUS],
453     "score for each 10 seconds left",   NULL
454   },
455   {
456     ED_SETTINGS_XPOS,                   ED_COUNTER2_YPOS(8),
457     1,                                  100,
458     GADGET_ID_LEVEL_RANDOM_DOWN,        GADGET_ID_LEVEL_RANDOM_UP,
459     GADGET_ID_LEVEL_RANDOM_TEXT,
460     &random_placement_value,
461     "random element placement",         "in"
462   }
463 };
464
465 static struct
466 {
467   int x, y;
468   int gadget_id;
469   int size;
470   char *value;
471   char *infotext;
472 } textinput_info[ED_NUM_TEXTINPUT] =
473 {
474   {
475     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(0),
476     GADGET_ID_LEVEL_NAME,
477     MAX_LEVEL_NAME_LEN,
478     level.name,
479     "Title"
480   },
481   {
482     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(1),
483     GADGET_ID_LEVEL_AUTHOR,
484     MAX_LEVEL_AUTHOR_LEN,
485     level.author,
486     "Author"
487   }
488 };
489
490 static struct
491 {
492   int xpos, ypos;
493   int x, y;
494   int gadget_id;
495   char *infotext;
496 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
497 {
498   {
499     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
500     ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,
501     GADGET_ID_SCROLL_UP,
502     "scroll level editing area up"
503   },
504   {
505     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
506     ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,
507     GADGET_ID_SCROLL_DOWN,
508     "scroll level editing area down"
509   },
510   {
511     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
512     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
513     GADGET_ID_SCROLL_LEFT,
514     "scroll level editing area left"
515   },
516   {
517     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
518     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
519     GADGET_ID_SCROLL_RIGHT,
520     "scroll level editing area right"
521   },
522   {
523     ED_ELEMENTLIST_UP_XPOS, ED_ELEMENTLIST_UP_ALT_YPOS,
524     ED_ELEMENTLIST_UP_XPOS, ED_ELEMENTLIST_UP_YPOS,
525     GADGET_ID_ELEMENTLIST_UP,
526     "scroll element list up ('Page Up')"
527   },
528   {
529     ED_ELEMENTLIST_DOWN_XPOS, ED_ELEMENTLIST_DOWN_ALT_YPOS,
530     ED_ELEMENTLIST_DOWN_XPOS, ED_ELEMENTLIST_DOWN_YPOS,
531     GADGET_ID_ELEMENTLIST_DOWN,
532     "scroll element list down ('Page Down')"
533   }
534 };
535
536 static struct
537 {
538   int xpos, ypos;
539   int x, y;
540   int width, height;
541   int type;
542   int gadget_id;
543   char *infotext;
544 } scrollbar_info[ED_NUM_SCROLLBARS] =
545 {
546   {
547     ED_SCROLLBAR_XPOS,          ED_SCROLLBAR_YPOS,
548     ED_SCROLL_HORIZONTAL_XPOS,  ED_SCROLL_HORIZONTAL_YPOS,
549     ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
550     GD_TYPE_SCROLLBAR_HORIZONTAL,
551     GADGET_ID_SCROLL_HORIZONTAL,
552     "scroll level editing area horizontally"
553   },
554   {
555     ED_SCROLLBAR_XPOS,          ED_SCROLLBAR_YPOS,
556     ED_SCROLL_VERTICAL_XPOS,    ED_SCROLL_VERTICAL_YPOS,
557     ED_SCROLL_VERTICAL_XSIZE,   ED_SCROLL_VERTICAL_YSIZE,
558     GD_TYPE_SCROLLBAR_VERTICAL,
559     GADGET_ID_SCROLL_VERTICAL,
560     "scroll level editing area vertically"
561   }
562 };
563
564 static struct
565 {
566   int x, y;
567   int gadget_id;
568   int radio_button_nr;
569   int *value;
570   int checked_value;
571   char *text, *infotext;
572 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
573 {
574   {
575     ED_SETTINGS_XPOS + 160,             ED_COUNTER2_YPOS(8),
576     GADGET_ID_RANDOM_PERCENTAGE,
577     RADIO_NR_RANDOM_ELEMENTS,
578     &random_placement_method,           RANDOM_USE_PERCENTAGE,
579     "percentage",                       "use percentage for random elements"
580   },
581   {
582     ED_SETTINGS_XPOS + 340,             ED_COUNTER2_YPOS(8),
583     GADGET_ID_RANDOM_QUANTITY,
584     RADIO_NR_RANDOM_ELEMENTS,
585     &random_placement_method,           RANDOM_USE_QUANTITY,
586     "quantity",                         "use quantity for random elements"
587   }
588 };
589
590 static struct
591 {
592   int x, y;
593   int gadget_id;
594   boolean *value;
595   char *text, *infotext;
596 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
597 {
598   {
599     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(6) - MINI_TILEY,
600     GADGET_ID_DOUBLE_SPEED,
601     &level.double_speed,
602     "double speed movement",            "set movement speed of player"
603   },
604   {
605     ED_SETTINGS_XPOS + 340,             ED_COUNTER_YPOS(6) - MINI_TILEY,
606     GADGET_ID_GRAVITY,
607     &level.gravity,
608     "gravity",                          "set level gravity"
609   },
610   {
611     ED_SETTINGS_XPOS,                   ED_COUNTER2_YPOS(9) - MINI_TILEY,
612     GADGET_ID_RANDOM_RESTRICTED,
613     &random_placement_background_restricted,
614     "restrict random placement to",     "set random placement restriction"
615   },
616   {
617     ED_SETTINGS_XPOS,                   ED_COUNTER_YPOS(4),
618     GADGET_ID_STICK_ELEMENT,
619     &stick_element_properties_window,
620     "stick window to edit content",     "stick window to edit content"
621   }
622 };
623
624 /* maximal size of level editor drawing area */
625 #define MAX_ED_FIELDX           (2 * SCR_FIELDX)
626 #define MAX_ED_FIELDY           (2 * SCR_FIELDY - 1)
627
628 /* actual size of level editor drawing area */
629 static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
630
631 /* actual position of level editor drawing area in level playfield */
632 static int level_xpos = -1, level_ypos = -1;
633
634 #define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldx)
635
636 /* drawing elements on the three mouse buttons */
637 static int new_element1 = EL_MAUERWERK;
638 static int new_element2 = EL_LEERRAUM;
639 static int new_element3 = EL_ERDREICH;
640
641 #define BUTTON_ELEMENT(button) (button == 1 ? new_element1 : \
642                                 button == 2 ? new_element2 : \
643                                 button == 3 ? new_element3 : EL_LEERRAUM)
644 #define BUTTON_STEPSIZE(button) (button == 1 ? 1 : button == 2 ? 5 : 10)
645
646 /* forward declaration for internal use */
647 static void DrawDrawingWindow();
648 static void DrawLevelInfoWindow();
649 static void DrawPropertiesWindow();
650 static void CopyLevelToUndoBuffer(int);
651 static void HandleDrawingAreas(struct GadgetInfo *);
652 static void HandleCounterButtons(struct GadgetInfo *);
653 static void HandleTextInputGadgets(struct GadgetInfo *);
654 static void HandleRadiobuttons(struct GadgetInfo *);
655 static void HandleCheckbuttons(struct GadgetInfo *);
656 static void HandleControlButtons(struct GadgetInfo *);
657 static void HandleDrawingAreaInfo(struct GadgetInfo *);
658
659 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
660
661 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
662 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
663 static boolean draw_with_brush = FALSE;
664 static int properties_element = 0;
665
666 static short ElementContent[MAX_ELEMENT_CONTENTS][3][3];
667 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
668 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
669 static int undo_buffer_position = 0;
670 static int undo_buffer_steps = 0;
671
672 static int edit_mode;
673
674 static int counter_xsize = DXSIZE + FONT2_XSIZE - 2 * ED_GADGET_DISTANCE;
675
676 int element_shift = 0;
677
678 int editor_element[] =
679 {
680   EL_CHAR('B'),
681   EL_CHAR('O'),
682   EL_CHAR('U'),
683   EL_CHAR('L'),
684
685   EL_CHAR_MINUS,
686   EL_CHAR('D'),
687   EL_CHAR('E'),
688   EL_CHAR('R'),
689
690   EL_CHAR('D'),
691   EL_CHAR('A'),
692   EL_CHAR('S'),
693   EL_CHAR('H'),
694
695   EL_SPIELFIGUR,
696   EL_LEERRAUM,
697   EL_ERDREICH,
698   EL_BETON,
699
700   EL_FELSBODEN,
701   EL_SIEB2_INAKTIV,
702   EL_AUSGANG_ZU,
703   EL_AUSGANG_AUF,
704
705   EL_EDELSTEIN_BD,
706   EL_BUTTERFLY_O,
707   EL_FIREFLY_O,
708   EL_FELSBROCKEN,
709
710   EL_BUTTERFLY_L,
711   EL_FIREFLY_L,
712   EL_BUTTERFLY_R,
713   EL_FIREFLY_R,
714
715   EL_AMOEBE_BD,
716   EL_BUTTERFLY_U,
717   EL_FIREFLY_U,
718   EL_LEERRAUM,
719
720   EL_CHAR('E'),
721   EL_CHAR('M'),
722   EL_CHAR('E'),
723   EL_CHAR_MINUS,
724
725   EL_CHAR('R'),
726   EL_CHAR('A'),
727   EL_CHAR('L'),
728   EL_CHAR('D'),
729
730   EL_CHAR('M'),
731   EL_CHAR('I'),
732   EL_CHAR('N'),
733   EL_CHAR('E'),
734
735   EL_SPIELER1,
736   EL_SPIELER2,
737   EL_SPIELER3,
738   EL_SPIELER4,
739
740   EL_SPIELFIGUR,
741   EL_LEERRAUM,
742   EL_ERDREICH,
743   EL_FELSBROCKEN,
744
745   EL_BETON,
746   EL_MAUERWERK,
747   EL_FELSBODEN,
748   EL_SIEB_INAKTIV,
749
750   EL_EDELSTEIN,
751   EL_DIAMANT,
752   EL_KOKOSNUSS,
753   EL_BOMBE,
754
755   EL_ERZ_EDEL,
756   EL_ERZ_DIAM,
757   EL_MORAST_LEER,
758   EL_MORAST_VOLL,
759
760   EL_DYNAMIT_AUS,
761   EL_DYNAMIT,
762   EL_AUSGANG_ZU,
763   EL_AUSGANG_AUF,
764
765   EL_MAMPFER,
766   EL_KAEFER_O,
767   EL_FLIEGER_O,
768   EL_ROBOT,
769
770   EL_KAEFER_L,
771   EL_FLIEGER_L,
772   EL_KAEFER_R,
773   EL_FLIEGER_R,
774
775   EL_ABLENK_AUS,
776   EL_KAEFER_U,
777   EL_FLIEGER_U,
778   EL_UNSICHTBAR,
779
780   EL_BADEWANNE1,
781   EL_SALZSAEURE,
782   EL_BADEWANNE2,
783   EL_LEERRAUM,
784
785   EL_BADEWANNE3,
786   EL_BADEWANNE4,
787   EL_BADEWANNE5,
788   EL_LEERRAUM,
789
790   EL_TROPFEN,
791   EL_AMOEBE_TOT,
792   EL_AMOEBE_NASS,
793   EL_AMOEBE_NORM,
794
795   EL_EM_KEY_1_FILE,
796   EL_EM_KEY_2_FILE,
797   EL_EM_KEY_3_FILE,
798   EL_EM_KEY_4_FILE,
799
800   EL_EM_GATE_1,
801   EL_EM_GATE_2,
802   EL_EM_GATE_3,
803   EL_EM_GATE_4,
804
805   EL_EM_GATE_1X,
806   EL_EM_GATE_2X,
807   EL_EM_GATE_3X,
808   EL_EM_GATE_4X,
809
810   EL_CHAR('M'),
811   EL_CHAR('O'),
812   EL_CHAR('R'),
813   EL_CHAR('E'),
814
815   EL_SCHLUESSEL1,
816   EL_SCHLUESSEL2,
817   EL_SCHLUESSEL3,
818   EL_SCHLUESSEL4,
819
820   EL_PFORTE1,
821   EL_PFORTE2,
822   EL_PFORTE3,
823   EL_PFORTE4,
824
825   EL_PFORTE1X,
826   EL_PFORTE2X,
827   EL_PFORTE3X,
828   EL_PFORTE4X,
829
830   EL_PFEIL_L,
831   EL_PFEIL_R,
832   EL_PFEIL_O,
833   EL_PFEIL_U,
834
835   EL_AMOEBE_VOLL,
836   EL_EDELSTEIN_GELB,
837   EL_EDELSTEIN_ROT,
838   EL_EDELSTEIN_LILA,
839
840   EL_ERZ_EDEL_BD,
841   EL_ERZ_EDEL_GELB,
842   EL_ERZ_EDEL_ROT,
843   EL_ERZ_EDEL_LILA,
844
845   EL_LIFE,
846   EL_PACMAN_O,
847   EL_ZEIT_VOLL,
848   EL_ZEIT_LEER,
849
850   EL_PACMAN_L,
851   EL_MAMPFER2,
852   EL_PACMAN_R,
853   EL_MAUER_LEBT,
854
855   EL_LIFE_ASYNC,
856   EL_PACMAN_U,
857   EL_BIRNE_AUS,
858   EL_BIRNE_EIN,
859
860   EL_DYNABOMB_NR,
861   EL_DYNABOMB_SZ,
862   EL_DYNABOMB_XL,
863   EL_BADEWANNE,
864
865   EL_MAULWURF,
866   EL_PINGUIN,
867   EL_SCHWEIN,
868   EL_DRACHE,
869
870   EL_SONDE,
871   EL_MAUER_X,
872   EL_MAUER_Y,
873   EL_MAUER_XY,
874
875   EL_INVISIBLE_STEEL,
876   EL_UNSICHTBAR,
877   EL_SPEED_PILL,
878   EL_BLACK_ORB,
879
880   EL_CHAR('S'),
881   EL_CHAR('O'),
882   EL_CHAR('K'),
883   EL_CHAR('O'),
884
885   EL_CHAR_MINUS,
886   EL_CHAR('B'),
887   EL_CHAR('A'),
888   EL_CHAR('N'),
889
890   EL_SOKOBAN_OBJEKT,
891   EL_SOKOBAN_FELD_LEER,
892   EL_SOKOBAN_FELD_VOLL,
893   EL_BETON,
894
895   EL_LEERRAUM,
896   EL_LEERRAUM,
897   EL_LEERRAUM,
898   EL_LEERRAUM,
899
900   EL_CHAR('S'),
901   EL_CHAR('U'),
902   EL_CHAR('P'),
903   EL_CHAR('A'),
904
905   EL_CHAR('P'),
906   EL_CHAR('L'),
907   EL_CHAR('E'),
908   EL_CHAR('X'),
909
910   EL_SP_EMPTY,
911   EL_SP_ZONK,
912   EL_SP_BASE,
913   EL_SP_MURPHY,
914
915   EL_SP_INFOTRON,
916   EL_SP_CHIP_SINGLE,
917   EL_SP_HARD_GRAY,
918   EL_SP_EXIT,
919
920   EL_SP_DISK_ORANGE,
921   EL_SP_PORT1_RIGHT,
922   EL_SP_PORT1_DOWN,
923   EL_SP_PORT1_LEFT,
924
925   EL_SP_PORT1_UP,
926   EL_SP_PORT2_RIGHT,
927   EL_SP_PORT2_DOWN,
928   EL_SP_PORT2_LEFT,
929
930   EL_SP_PORT2_UP,
931   EL_SP_SNIKSNAK,
932   EL_SP_DISK_YELLOW,
933   EL_SP_TERMINAL,
934
935   EL_SP_DISK_RED,
936   EL_SP_PORT_Y,
937   EL_SP_PORT_X,
938   EL_SP_PORT_XY,
939
940   EL_SP_ELECTRON,
941   EL_SP_BUG,
942   EL_SP_CHIP_LEFT,
943   EL_SP_CHIP_RIGHT,
944
945   EL_SP_HARD_BASE1,
946   EL_SP_HARD_GREEN,
947   EL_SP_HARD_BLUE,
948   EL_SP_HARD_RED,
949
950   EL_SP_HARD_YELLOW,
951   EL_SP_HARD_BASE2,
952   EL_SP_HARD_BASE3,
953   EL_SP_HARD_BASE4,
954
955   EL_SP_HARD_BASE5,
956   EL_SP_HARD_BASE6,
957   EL_SP_CHIP_UPPER,
958   EL_SP_CHIP_LOWER,
959
960   /*
961   EL_CHAR('D'),
962   EL_CHAR('Y'),
963   EL_CHAR('N'),
964   EL_CHAR('A'),
965
966   EL_CHAR('B'),
967   EL_CHAR('L'),
968   EL_CHAR('A'),
969   EL_CHAR('S'),
970
971   EL_CHAR_MINUS,
972   EL_CHAR('T'),
973   EL_CHAR('E'),
974   EL_CHAR('R'),
975   */
976
977   EL_LEERRAUM,
978   EL_LEERRAUM,
979   EL_LEERRAUM,
980   EL_LEERRAUM,
981
982   EL_CHAR(' '),
983   EL_CHAR('!'),
984   EL_CHAR('"'),
985   EL_CHAR('#'),
986
987   EL_CHAR('$'),
988   EL_CHAR('%'),
989   EL_CHAR('&'),
990   EL_CHAR('\''),
991
992   EL_CHAR('('),
993   EL_CHAR(')'),
994   EL_CHAR('*'),
995   EL_CHAR('+'),
996
997   EL_CHAR(','),
998   EL_CHAR('-'),
999   EL_CHAR('.'),
1000   EL_CHAR('/'),
1001
1002   EL_CHAR('0'),
1003   EL_CHAR('1'),
1004   EL_CHAR('2'),
1005   EL_CHAR('3'),
1006
1007   EL_CHAR('4'),
1008   EL_CHAR('5'),
1009   EL_CHAR('6'),
1010   EL_CHAR('7'),
1011
1012   EL_CHAR('8'),
1013   EL_CHAR('9'),
1014   EL_CHAR(':'),
1015   EL_CHAR(';'),
1016
1017   EL_CHAR('<'),
1018   EL_CHAR('='),
1019   EL_CHAR('>'),
1020   EL_CHAR('?'),
1021
1022   EL_CHAR('@'),
1023   EL_CHAR('A'),
1024   EL_CHAR('B'),
1025   EL_CHAR('C'),
1026
1027   EL_CHAR('D'),
1028   EL_CHAR('E'),
1029   EL_CHAR('F'),
1030   EL_CHAR('G'),
1031
1032   EL_CHAR('H'),
1033   EL_CHAR('I'),
1034   EL_CHAR('J'),
1035   EL_CHAR('K'),
1036
1037   EL_CHAR('L'),
1038   EL_CHAR('M'),
1039   EL_CHAR('N'),
1040   EL_CHAR('O'),
1041
1042   EL_CHAR('P'),
1043   EL_CHAR('Q'),
1044   EL_CHAR('R'),
1045   EL_CHAR('S'),
1046
1047   EL_CHAR('T'),
1048   EL_CHAR('U'),
1049   EL_CHAR('V'),
1050   EL_CHAR('W'),
1051
1052   EL_CHAR('X'),
1053   EL_CHAR('Y'),
1054   EL_CHAR('Z'),
1055   EL_CHAR('Ä'),
1056
1057   EL_CHAR('Ö'),
1058   EL_CHAR('Ãœ'),
1059   EL_CHAR('^'),
1060   EL_CHAR(' ')
1061 };
1062 int elements_in_list = sizeof(editor_element)/sizeof(int);
1063
1064 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
1065 {
1066   int x,y;
1067   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
1068   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
1069
1070   XCopyArea(display, drawto, drawto, gc,
1071             SX + (dx == -1 ? MINI_TILEX : 0),
1072             SY + (dy == -1 ? MINI_TILEY : 0),
1073             (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
1074             (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
1075             SX + (dx == +1 ? MINI_TILEX : 0),
1076             SY + (dy == +1 ? MINI_TILEY : 0));
1077   if (dx)
1078   {
1079     x = (dx == 1 ? 0 : ed_fieldx - 1);
1080     for(y=0; y<ed_fieldy; y++)
1081       DrawMiniElementOrWall(x, y, from_x, from_y);
1082   }
1083   else if (dy)
1084   {
1085     y = (dy == 1 ? 0 : ed_fieldy - 1);
1086     for(x=0; x<ed_fieldx; x++)
1087       DrawMiniElementOrWall(x, y, from_x, from_y);
1088   }
1089
1090   redraw_mask |= REDRAW_FIELD;
1091   BackToFront();
1092 }
1093
1094 static void CreateControlButtons()
1095 {
1096   Pixmap gd_pixmap = pix[PIX_DOOR];
1097   struct GadgetInfo *gi;
1098   unsigned long event_mask;
1099   int i;
1100
1101   /* create toolbox buttons */
1102   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1103   {
1104     int id = i;
1105     int width, height;
1106     int gd_xoffset, gd_yoffset;
1107     int gd_x1, gd_x2, gd_y1, gd_y2;
1108     int button_type;
1109     int radio_button_nr;
1110     boolean checked;
1111
1112     if (id == GADGET_ID_SINGLE_ITEMS ||
1113         id == GADGET_ID_CONNECTED_ITEMS ||
1114         id == GADGET_ID_LINE ||
1115         id == GADGET_ID_ARC ||
1116         id == GADGET_ID_TEXT ||
1117         id == GADGET_ID_RECTANGLE ||
1118         id == GADGET_ID_FILLED_BOX ||
1119         id == GADGET_ID_FLOOD_FILL ||
1120         id == GADGET_ID_GRAB_BRUSH ||
1121         id == GADGET_ID_PICK_ELEMENT)
1122     {
1123       button_type = GD_TYPE_RADIO_BUTTON;
1124       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
1125       checked = (id == drawing_function ? TRUE : FALSE);
1126       event_mask = GD_EVENT_PRESSED;
1127     }
1128     else
1129     {
1130       button_type = GD_TYPE_NORMAL_BUTTON;
1131       radio_button_nr = RADIO_NR_NONE;
1132       checked = FALSE;
1133
1134       if (id == GADGET_ID_WRAP_LEFT ||
1135           id == GADGET_ID_WRAP_RIGHT ||
1136           id == GADGET_ID_WRAP_UP ||
1137           id == GADGET_ID_WRAP_DOWN)
1138         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1139       else
1140         event_mask = GD_EVENT_RELEASED;
1141     }
1142
1143     if (id < ED_NUM_CTRL1_BUTTONS)
1144     {
1145       int x = i % ED_CTRL1_BUTTONS_HORIZ;
1146       int y = i / ED_CTRL1_BUTTONS_HORIZ;
1147
1148       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
1149       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
1150       width = ED_CTRL1_BUTTON_XSIZE;
1151       height = ED_CTRL1_BUTTON_YSIZE;
1152     }
1153     else
1154     {
1155       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
1156       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
1157
1158       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
1159       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
1160       width = ED_CTRL2_BUTTON_XSIZE;
1161       height = ED_CTRL2_BUTTON_YSIZE;
1162     }
1163
1164     gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
1165     gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
1166     gd_y1  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
1167     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
1168
1169     gi = CreateGadget(GDI_CUSTOM_ID, id,
1170                       GDI_CUSTOM_TYPE_ID, i,
1171                       GDI_INFO_TEXT, control_info[i].text,
1172                       GDI_X, EX + gd_xoffset,
1173                       GDI_Y, EY + gd_yoffset,
1174                       GDI_WIDTH, width,
1175                       GDI_HEIGHT, height,
1176                       GDI_TYPE, button_type,
1177                       GDI_STATE, GD_BUTTON_UNPRESSED,
1178                       GDI_RADIO_NR, radio_button_nr,
1179                       GDI_CHECKED, checked,
1180                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1181                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
1182                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
1183                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1184                       GDI_EVENT_MASK, event_mask,
1185                       GDI_CALLBACK_ACTION, HandleControlButtons,
1186                       GDI_END);
1187
1188     if (gi == NULL)
1189       Error(ERR_EXIT, "cannot create gadget");
1190
1191     level_editor_gadget[id] = gi;
1192   }
1193
1194   /* create buttons for scrolling of drawing area and element list */
1195   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1196   {
1197     int id = scrollbutton_info[i].gadget_id;
1198     int x, y, width, height;
1199     int gd_x1, gd_x2, gd_y1, gd_y2;
1200
1201     x = scrollbutton_info[i].x;
1202     y = scrollbutton_info[i].y;
1203
1204     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1205
1206     if (id == GADGET_ID_ELEMENTLIST_UP ||
1207         id == GADGET_ID_ELEMENTLIST_DOWN)
1208     {
1209       x += DX;
1210       y += DY;
1211       width = ED_ELEMENTLIST_UPDOWN_XSIZE;
1212       height = ED_ELEMENTLIST_UPDOWN_YSIZE;
1213       gd_x1 = DOOR_GFX_PAGEX6 + scrollbutton_info[i].xpos;
1214       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].y;
1215       gd_x2 = gd_x1;
1216       gd_y2 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
1217     }
1218     else
1219     {
1220       x += SX;
1221       y += SY;
1222       width = ED_SCROLLBUTTON_XSIZE;
1223       height = ED_SCROLLBUTTON_YSIZE;
1224       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
1225       gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
1226       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1227       gd_y2 = gd_y1;
1228     }
1229
1230     gi = CreateGadget(GDI_CUSTOM_ID, id,
1231                       GDI_CUSTOM_TYPE_ID, i,
1232                       GDI_INFO_TEXT, scrollbutton_info[i].infotext,
1233                       GDI_X, x,
1234                       GDI_Y, y,
1235                       GDI_WIDTH, width,
1236                       GDI_HEIGHT, height,
1237                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1238                       GDI_STATE, GD_BUTTON_UNPRESSED,
1239                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1240                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1241                       GDI_EVENT_MASK, event_mask,
1242                       GDI_CALLBACK_ACTION, HandleControlButtons,
1243                       GDI_END);
1244
1245     if (gi == NULL)
1246       Error(ERR_EXIT, "cannot create gadget");
1247
1248     level_editor_gadget[id] = gi;
1249   }
1250
1251   /* create buttons for element list */
1252   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
1253   {
1254     Pixmap deco_pixmap;
1255     int deco_x, deco_y, deco_xpos, deco_ypos;
1256     int gd_xoffset, gd_yoffset;
1257     int gd_x, gd_y1, gd_y2;
1258     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
1259     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
1260     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
1261
1262     event_mask = GD_EVENT_RELEASED;
1263
1264     gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
1265     gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
1266
1267     gd_x = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
1268     gd_y1 = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
1269     gd_y2 = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_ALT_YPOS;
1270
1271     getMiniGraphicSource(el2gfx(editor_element[i]),
1272                          &deco_pixmap, &deco_x, &deco_y);
1273     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
1274     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
1275
1276     gi = CreateGadget(GDI_CUSTOM_ID, id,
1277                       GDI_CUSTOM_TYPE_ID, i,
1278                       GDI_INFO_TEXT, element_info[editor_element[i]],
1279                       GDI_X, DX + gd_xoffset,
1280                       GDI_Y, DY + gd_yoffset,
1281                       GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
1282                       GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
1283                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1284                       GDI_STATE, GD_BUTTON_UNPRESSED,
1285                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y1,
1286                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y2,
1287                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
1288                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
1289                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
1290                       GDI_DECORATION_SHIFTING, 1, 1,
1291                       GDI_EVENT_MASK, event_mask,
1292                       GDI_CALLBACK_ACTION, HandleControlButtons,
1293                       GDI_END);
1294
1295     if (gi == NULL)
1296       Error(ERR_EXIT, "cannot create gadget");
1297
1298     level_editor_gadget[id] = gi;
1299   }
1300 }
1301
1302 static void CreateCounterButtons()
1303 {
1304   int i;
1305
1306   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
1307   {
1308     int j;
1309     int xpos = SX + counterbutton_info[i].x;    /* xpos of down count button */
1310     int ypos = SY + counterbutton_info[i].y;
1311
1312     for (j=0; j<2; j++)
1313     {
1314       Pixmap gd_pixmap = pix[PIX_DOOR];
1315       struct GadgetInfo *gi;
1316       int id = (j == 0 ?
1317                 counterbutton_info[i].gadget_id_down :
1318                 counterbutton_info[i].gadget_id_up);
1319       int gd_xoffset;
1320       int gd_x, gd_x1, gd_x2, gd_y;
1321       unsigned long event_mask;
1322       char infotext[MAX_INFOTEXT_LEN + 1];
1323
1324       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1325
1326       gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
1327       gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
1328       gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
1329       gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
1330
1331       sprintf(infotext, "%s counter value by 1, 5 or 10",
1332               (j == 0 ? "decrease" : "increase"));
1333
1334       gi = CreateGadget(GDI_CUSTOM_ID, id,
1335                         GDI_CUSTOM_TYPE_ID, i,
1336                         GDI_INFO_TEXT, infotext,
1337                         GDI_X, xpos,
1338                         GDI_Y, ypos,
1339                         GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
1340                         GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
1341                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1342                         GDI_STATE, GD_BUTTON_UNPRESSED,
1343                         GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
1344                         GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
1345                         GDI_EVENT_MASK, event_mask,
1346                         GDI_CALLBACK_ACTION, HandleCounterButtons,
1347                         GDI_END);
1348
1349       if (gi == NULL)
1350         Error(ERR_EXIT, "cannot create gadget");
1351
1352       level_editor_gadget[id] = gi;
1353       xpos += gi->width + ED_GADGET_DISTANCE;   /* xpos of text count button */
1354
1355       if (j == 0)
1356       {
1357         id = counterbutton_info[i].gadget_id_text;
1358         event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1359
1360         gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1361         gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1362
1363         gi = CreateGadget(GDI_CUSTOM_ID, id,
1364                           GDI_CUSTOM_TYPE_ID, i,
1365                           GDI_INFO_TEXT, "enter counter value",
1366                           GDI_X, xpos,
1367                           GDI_Y, ypos,
1368                           GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC,
1369                           GDI_NUMBER_VALUE, 0,
1370                           GDI_NUMBER_MIN, counterbutton_info[i].min_value,
1371                           GDI_NUMBER_MAX, counterbutton_info[i].max_value,
1372                           GDI_TEXT_SIZE, 3,
1373                           GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
1374                           GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
1375                           GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1376                           GDI_EVENT_MASK, event_mask,
1377                           GDI_CALLBACK_ACTION, HandleCounterButtons,
1378                           GDI_END);
1379
1380         if (gi == NULL)
1381           Error(ERR_EXIT, "cannot create gadget");
1382
1383         level_editor_gadget[id] = gi;
1384         xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of up count button */
1385       }
1386     }
1387   }
1388 }
1389
1390 static void CreateDrawingAreas()
1391 {
1392   struct GadgetInfo *gi;
1393   unsigned long event_mask;
1394   int id;
1395   int i;
1396
1397   event_mask =
1398     GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
1399     GD_EVENT_OFF_BORDERS;
1400
1401   /* one for the level drawing area ... */
1402   id = GADGET_ID_DRAWING_LEVEL;
1403   gi = CreateGadget(GDI_CUSTOM_ID, id,
1404                     GDI_X, SX,
1405                     GDI_Y, SY,
1406                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
1407                     GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
1408                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1409                     GDI_EVENT_MASK, event_mask,
1410                     GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1411                     GDI_CALLBACK_ACTION, HandleDrawingAreas,
1412                     GDI_END);
1413
1414   if (gi == NULL)
1415     Error(ERR_EXIT, "cannot create gadget");
1416
1417   level_editor_gadget[id] = gi;
1418
1419   /* ... up to eight areas for element content ... */
1420   for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
1421   {
1422     int gx = SX + ED_AREA_ELEM_CONTENT_XPOS + 5 * (i % 4) * MINI_TILEX;
1423     int gy = SX + ED_AREA_ELEM_CONTENT_YPOS + 6 * (i / 4) * MINI_TILEY;
1424
1425     id = GADGET_ID_ELEM_CONTENT_0 + i;
1426     gi = CreateGadget(GDI_CUSTOM_ID, id,
1427                       GDI_CUSTOM_TYPE_ID, i,
1428                       GDI_X, gx,
1429                       GDI_Y, gy,
1430                       GDI_WIDTH, 3 * MINI_TILEX,
1431                       GDI_HEIGHT, 3 * MINI_TILEY,
1432                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
1433                       GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1434                       GDI_EVENT_MASK, event_mask,
1435                       GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1436                       GDI_CALLBACK_ACTION, HandleDrawingAreas,
1437                       GDI_END);
1438
1439     if (gi == NULL)
1440       Error(ERR_EXIT, "cannot create gadget");
1441
1442     level_editor_gadget[id] = gi;
1443   }
1444
1445   /* ... one for the amoeba content */
1446   id = GADGET_ID_AMOEBA_CONTENT;
1447   gi = CreateGadget(GDI_CUSTOM_ID, id,
1448                     GDI_X, SX + ED_AREA_ELEM_CONTENT_XPOS,
1449                     GDI_Y, SY + ED_AREA_ELEM_CONTENT_YPOS,
1450                     GDI_WIDTH, MINI_TILEX,
1451                     GDI_HEIGHT, MINI_TILEY,
1452                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
1453                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1454                     GDI_EVENT_MASK, event_mask,
1455                     GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1456                     GDI_CALLBACK_ACTION, HandleDrawingAreas,
1457                     GDI_END);
1458
1459   if (gi == NULL)
1460     Error(ERR_EXIT, "cannot create gadget");
1461
1462   level_editor_gadget[id] = gi;
1463
1464   /* ... and one for random placement background restrictions */
1465
1466   id = GADGET_ID_RANDOM_BACKGROUND;
1467   gi = CreateGadget(GDI_CUSTOM_ID, id,
1468                     GDI_X, SX + ED_AREA_RANDOM_BACKGROUND_XPOS,
1469                     GDI_Y, SY + ED_AREA_RANDOM_BACKGROUND_YPOS,
1470                     GDI_WIDTH, MINI_TILEX,
1471                     GDI_HEIGHT, MINI_TILEY,
1472                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
1473                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1474                     GDI_EVENT_MASK, event_mask,
1475                     GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1476                     GDI_CALLBACK_ACTION, HandleDrawingAreas,
1477                     GDI_END);
1478
1479   if (gi == NULL)
1480     Error(ERR_EXIT, "cannot create gadget");
1481
1482   level_editor_gadget[id] = gi;
1483 }
1484
1485 static void CreateTextInputGadgets()
1486 {
1487   int i;
1488
1489   for (i=0; i<ED_NUM_TEXTINPUT; i++)
1490   {
1491     Pixmap gd_pixmap = pix[PIX_DOOR];
1492     int gd_x, gd_y;
1493     struct GadgetInfo *gi;
1494     unsigned long event_mask;
1495     char infotext[1024];
1496     int id = textinput_info[i].gadget_id;
1497
1498     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1499
1500     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1501     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1502
1503     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
1504     infotext[MAX_INFOTEXT_LEN] = '\0';
1505
1506     gi = CreateGadget(GDI_CUSTOM_ID, id,
1507                       GDI_CUSTOM_TYPE_ID, i,
1508                       GDI_INFO_TEXT, infotext,
1509                       GDI_X, SX + textinput_info[i].x,
1510                       GDI_Y, SY + textinput_info[i].y,
1511                       GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC,
1512                       GDI_TEXT_VALUE, textinput_info[i].value,
1513                       GDI_TEXT_SIZE, textinput_info[i].size,
1514                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
1515                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
1516                       GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1517                       GDI_EVENT_MASK, event_mask,
1518                       GDI_CALLBACK_ACTION, HandleTextInputGadgets,
1519                       GDI_END);
1520
1521     if (gi == NULL)
1522       Error(ERR_EXIT, "cannot create gadget");
1523
1524     level_editor_gadget[id] = gi;
1525   }
1526 }
1527
1528 static void CreateScrollbarGadgets()
1529 {
1530   int i;
1531
1532   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1533   {
1534     int id = scrollbar_info[i].gadget_id;
1535     Pixmap gd_pixmap = pix[PIX_DOOR];
1536     int gd_x1, gd_x2, gd_y1, gd_y2;
1537     struct GadgetInfo *gi;
1538     int items_max, items_visible, item_position;
1539     unsigned long event_mask;
1540
1541     if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1542     {
1543       items_max = MAX(lev_fieldx + 2, ed_fieldx);
1544       items_visible = ed_fieldx;
1545       item_position = 0;
1546     }
1547     else
1548     {
1549       items_max = MAX(lev_fieldy + 2, ed_fieldy);
1550       items_visible = ed_fieldy;
1551       item_position = 0;
1552     }
1553
1554     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
1555
1556     gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
1557     gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1558     gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1559     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1560
1561     gi = CreateGadget(GDI_CUSTOM_ID, id,
1562                       GDI_CUSTOM_TYPE_ID, i,
1563                       GDI_INFO_TEXT, scrollbar_info[i].infotext,
1564                       GDI_X, SX + scrollbar_info[i].x,
1565                       GDI_Y, SY + scrollbar_info[i].y,
1566                       GDI_WIDTH, scrollbar_info[i].width,
1567                       GDI_HEIGHT, scrollbar_info[i].height,
1568                       GDI_TYPE, scrollbar_info[i].type,
1569                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
1570                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1571                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
1572                       GDI_STATE, GD_BUTTON_UNPRESSED,
1573                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1574                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1575                       GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1576                       GDI_EVENT_MASK, event_mask,
1577                       GDI_CALLBACK_ACTION, HandleControlButtons,
1578                       GDI_END);
1579
1580     if (gi == NULL)
1581       Error(ERR_EXIT, "cannot create gadget");
1582
1583     level_editor_gadget[id] = gi;
1584   }
1585 }
1586
1587 static void CreateCheckbuttonGadgets()
1588 {
1589   Pixmap gd_pixmap = pix[PIX_DOOR];
1590   struct GadgetInfo *gi;
1591   unsigned long event_mask;
1592   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
1593   boolean checked;
1594   int i;
1595
1596   event_mask = GD_EVENT_PRESSED;
1597
1598   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
1599   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
1600   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
1601   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
1602   gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
1603
1604   for (i=0; i<ED_NUM_RADIOBUTTONS; i++)
1605   {
1606     int id = radiobutton_info[i].gadget_id;
1607
1608     checked =
1609       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
1610
1611     gi = CreateGadget(GDI_CUSTOM_ID, id,
1612                       GDI_CUSTOM_TYPE_ID, i,
1613                       GDI_INFO_TEXT, radiobutton_info[i].infotext,
1614                       GDI_X, SX + radiobutton_info[i].x,
1615                       GDI_Y, SY + radiobutton_info[i].y,
1616                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
1617                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
1618                       GDI_TYPE, GD_TYPE_RADIO_BUTTON,
1619                       GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
1620                       GDI_CHECKED, checked,
1621                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
1622                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
1623                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x3, gd_y,
1624                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x4, gd_y,
1625                       GDI_EVENT_MASK, event_mask,
1626                       GDI_CALLBACK_ACTION, HandleRadiobuttons,
1627                       GDI_END);
1628
1629     if (gi == NULL)
1630       Error(ERR_EXIT, "cannot create gadget");
1631
1632     level_editor_gadget[id] = gi;
1633   }
1634
1635   for (i=0; i<ED_NUM_CHECKBUTTONS; i++)
1636   {
1637     int id = checkbutton_info[i].gadget_id;
1638
1639     if (id == GADGET_ID_STICK_ELEMENT)
1640       gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
1641     else
1642       gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
1643
1644     gi = CreateGadget(GDI_CUSTOM_ID, id,
1645                       GDI_CUSTOM_TYPE_ID, i,
1646                       GDI_INFO_TEXT, checkbutton_info[i].infotext,
1647                       GDI_X, SX + checkbutton_info[i].x,
1648                       GDI_Y, SY + checkbutton_info[i].y,
1649                       GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
1650                       GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
1651                       GDI_TYPE, GD_TYPE_CHECK_BUTTON,
1652                       GDI_CHECKED, *checkbutton_info[i].value,
1653                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
1654                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
1655                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x3, gd_y,
1656                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x4, gd_y,
1657                       GDI_EVENT_MASK, event_mask,
1658                       GDI_CALLBACK_ACTION, HandleCheckbuttons,
1659                       GDI_END);
1660
1661     if (gi == NULL)
1662       Error(ERR_EXIT, "cannot create gadget");
1663
1664     level_editor_gadget[id] = gi;
1665   }
1666 }
1667
1668 void CreateLevelEditorGadgets()
1669 {
1670   CreateControlButtons();
1671   CreateCounterButtons();
1672   CreateDrawingAreas();
1673   CreateTextInputGadgets();
1674   CreateScrollbarGadgets();
1675   CreateCheckbuttonGadgets();
1676 }
1677
1678 static void MapControlButtons()
1679 {
1680   int i;
1681
1682   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1683     MapGadget(level_editor_gadget[i]);
1684   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
1685     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
1686   MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_UP]);
1687   MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_DOWN]);
1688 }
1689
1690 static void MapCounterButtons(int id)
1691 {
1692   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
1693   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
1694   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
1695 }
1696
1697 static void MapDrawingArea(int id)
1698 {
1699   MapGadget(level_editor_gadget[id]);
1700 }
1701
1702 static void MapTextInputGadget(int id)
1703 {
1704   MapGadget(level_editor_gadget[textinput_info[id].gadget_id]);
1705 }
1706
1707 static void MapRadiobuttonGadget(int id)
1708 {
1709   MapGadget(level_editor_gadget[radiobutton_info[id].gadget_id]);
1710 }
1711
1712 static void MapCheckbuttonGadget(int id)
1713 {
1714   MapGadget(level_editor_gadget[checkbutton_info[id].gadget_id]);
1715 }
1716
1717 static void MapMainDrawingArea()
1718 {
1719   boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
1720   boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
1721   int i;
1722
1723   for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i<=ED_SCROLLBUTTON_ID_AREA_LAST; i++)
1724   {
1725     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
1726           i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
1727          no_horizontal_scrollbar) ||
1728         ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
1729           i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
1730          no_vertical_scrollbar))
1731       continue;
1732
1733     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1734   }
1735
1736   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1737   {
1738     if ((i == ED_SCROLLBAR_ID_HORIZONTAL && no_horizontal_scrollbar) ||
1739         (i == ED_SCROLLBAR_ID_VERTICAL && no_vertical_scrollbar))
1740       continue;
1741
1742     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1743   }
1744
1745   MapDrawingArea(GADGET_ID_DRAWING_LEVEL);
1746 }
1747
1748 static void UnmapDrawingArea(int id)
1749 {
1750   UnmapGadget(level_editor_gadget[id]);
1751 }
1752
1753 void UnmapLevelEditorWindowGadgets()
1754 {
1755   int i;
1756
1757   for (i=0; i<NUM_EDITOR_GADGETS; i++)
1758     if (level_editor_gadget[i]->x < DX)
1759       UnmapGadget(level_editor_gadget[i]);
1760 }
1761
1762 void UnmapLevelEditorGadgets()
1763 {
1764   int i;
1765
1766   for (i=0; i<NUM_EDITOR_GADGETS; i++)
1767     UnmapGadget(level_editor_gadget[i]);
1768 }
1769
1770 void DrawLevelEd()
1771 {
1772   edit_mode = ED_MODE_DRAWING;
1773
1774   CloseDoor(DOOR_CLOSE_ALL);
1775   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1776
1777   if (level_editor_test_game)
1778   {
1779     int x, y;
1780
1781     for(x=0; x<lev_fieldx; x++)
1782       for(y=0; y<lev_fieldy; y++)
1783         Feld[x][y] = Ur[x][y];
1784
1785     for(x=0; x<lev_fieldx; x++)
1786       for(y=0; y<lev_fieldy; y++)
1787         Ur[x][y] = FieldBackup[x][y];
1788
1789     level_editor_test_game = FALSE;
1790   }
1791   else
1792   {
1793     level_xpos = -1;
1794     level_ypos = -1;
1795     undo_buffer_position = -1;
1796     undo_buffer_steps = -1;
1797     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1798   }
1799
1800   /* copy default editor door content to main double buffer */
1801   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1802             DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
1803
1804   /* draw mouse button brush elements */
1805   DrawMiniGraphicExt(drawto, gc,
1806                      DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
1807                      el2gfx(new_element1));
1808   DrawMiniGraphicExt(drawto, gc,
1809                      DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
1810                      el2gfx(new_element2));
1811   DrawMiniGraphicExt(drawto, gc,
1812                      DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
1813                      el2gfx(new_element3));
1814
1815   /* draw level number */
1816   DrawTextExt(pix[PIX_DB_DOOR], gc,
1817               DOOR_GFX_PAGEX2 + ED_WIN_LEVELNR_XPOS,
1818               DOOR_GFX_PAGEY1 + ED_WIN_LEVELNR_YPOS,
1819               int2str(level_nr, 2), FS_SMALL, FC_SPECIAL1);
1820   /* copy level number to fit into level number field */
1821   XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1822             DOOR_GFX_PAGEX2 + ED_WIN_LEVELNR_XPOS + 3,
1823             DOOR_GFX_PAGEY1 + ED_WIN_LEVELNR_YPOS,
1824             7, FONT3_YSIZE,
1825             DX + ED_WIN_LEVELNR_XPOS,
1826             DY + ED_WIN_LEVELNR_YPOS);
1827   XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1828             DOOR_GFX_PAGEX2 + ED_WIN_LEVELNR_XPOS + 14,
1829             DOOR_GFX_PAGEY1 + ED_WIN_LEVELNR_YPOS,
1830             7, FONT3_YSIZE,
1831             DX + ED_WIN_LEVELNR_XPOS + 9,
1832             DY + ED_WIN_LEVELNR_YPOS);
1833
1834   /* draw bigger door */
1835   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1836             DOOR_GFX_PAGEX7, 0,
1837             108, 64,
1838             EX - 4, EY - 12);
1839
1840   /* draw new control window */
1841   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1842             DOOR_GFX_PAGEX8, 236,
1843             EXSIZE, EYSIZE,
1844             EX, EY);
1845
1846   redraw_mask |= REDRAW_ALL;
1847
1848   MapControlButtons();
1849
1850   /* copy actual editor door content to door double buffer for OpenDoor() */
1851   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1852             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1853
1854   DrawDrawingWindow();
1855   FadeToFront();
1856
1857   OpenDoor(DOOR_OPEN_1);
1858
1859   /*
1860   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1861   */
1862 }
1863
1864 static void AdjustDrawingAreaGadgets()
1865 {
1866   int ed_xsize = lev_fieldx + 2;
1867   int ed_ysize = lev_fieldy + 2;
1868   int max_ed_fieldx = MAX_ED_FIELDX;
1869   int max_ed_fieldy = MAX_ED_FIELDY;
1870   boolean horizontal_scrollbar_needed;
1871   boolean vertical_scrollbar_needed;
1872   int x, y, width, height;
1873   int xoffset, yoffset;
1874
1875   /* check if we need any scrollbars */
1876   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
1877   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
1878
1879   /* check if we have a smaller editor field because of scrollbars */
1880   if (horizontal_scrollbar_needed)
1881     max_ed_fieldy = MAX_ED_FIELDY - 1;
1882   if (vertical_scrollbar_needed)
1883     max_ed_fieldx = MAX_ED_FIELDX - 1;
1884
1885   /* check again if we now need more scrollbars because of less space */
1886   horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
1887   vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
1888
1889   /* check if editor field gets even smaller after adding new scrollbars */
1890   if (horizontal_scrollbar_needed)
1891     max_ed_fieldy = MAX_ED_FIELDY - 1;
1892   if (vertical_scrollbar_needed)
1893     max_ed_fieldx = MAX_ED_FIELDX - 1;
1894
1895   ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
1896   ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
1897
1898   ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
1899                GDI_WIDTH, ed_fieldx * MINI_TILEX,
1900                GDI_HEIGHT, ed_fieldy * MINI_TILEY,
1901                GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
1902                GDI_END);
1903
1904   xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
1905   yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
1906
1907   x = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
1908   y = SX + scrollbutton_info[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
1909
1910   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
1911   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
1912
1913   width = scrollbar_info[ED_SCROLLBAR_ID_HORIZONTAL].width + xoffset;
1914   height = scrollbar_info[ED_SCROLLBAR_ID_VERTICAL].height + yoffset;
1915
1916   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
1917                GDI_WIDTH, width,
1918                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
1919                GDI_END);
1920   ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
1921                GDI_HEIGHT, height,
1922                GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
1923                GDI_END);
1924 }
1925
1926 static void AdjustLevelScrollPosition()
1927 {
1928   if (level_xpos < -1)
1929     level_xpos = -1;
1930   if (level_xpos > lev_fieldx - ed_fieldx + 1)
1931     level_xpos = lev_fieldx - ed_fieldx + 1;
1932   if (lev_fieldx < ed_fieldx - 2)
1933     level_xpos = -1;
1934
1935   if (level_ypos < -1)
1936     level_ypos = -1;
1937   if (level_ypos > lev_fieldy - ed_fieldy + 1)
1938     level_ypos = lev_fieldy - ed_fieldy + 1;
1939   if (lev_fieldy < ed_fieldy - 2)
1940     level_ypos = -1;
1941 }
1942
1943 static void AdjustEditorScrollbar(int id)
1944 {
1945   struct GadgetInfo *gi = level_editor_gadget[id];
1946   int items_max, items_visible, item_position;
1947
1948   if (id == GADGET_ID_SCROLL_HORIZONTAL)
1949   {
1950     items_max = MAX(lev_fieldx + 2, ed_fieldx);
1951     items_visible = ed_fieldx;
1952     item_position = level_xpos + 1;
1953   }
1954   else
1955   {
1956     items_max = MAX(lev_fieldy + 2, ed_fieldy);
1957     items_visible = ed_fieldy;
1958     item_position = level_ypos + 1;
1959   }
1960
1961   if (item_position > items_max - items_visible)
1962     item_position = items_max - items_visible;
1963
1964   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1965                GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1966 }
1967
1968 static void ModifyEditorTextInput(int textinput_id, char *new_text)
1969 {
1970   int gadget_id = textinput_info[textinput_id].gadget_id;
1971   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1972
1973   ModifyGadget(gi, GDI_TEXT_VALUE, new_text, GDI_END);
1974 }
1975
1976 static void ModifyEditorCounter(int counter_id, int new_value)
1977 {
1978   int *counter_value = counterbutton_info[counter_id].value;
1979   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
1980   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1981
1982   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
1983
1984   if (counter_value != NULL)
1985     *counter_value = gi->text.number_value;
1986 }
1987
1988 static void PickDrawingElement(int button, int element)
1989 {
1990   if (button < 1 || button > 3)
1991     return;
1992
1993   if (button == 1)
1994   {
1995     new_element1 = element;
1996     DrawMiniGraphicExt(drawto, gc,
1997                        DX + ED_WIN_MB_LEFT_XPOS,
1998                        DY + ED_WIN_MB_LEFT_YPOS,
1999                        el2gfx(new_element1));
2000   }
2001   else if (button == 2)
2002   {
2003     new_element2 = element;
2004     DrawMiniGraphicExt(drawto, gc,
2005                        DX + ED_WIN_MB_MIDDLE_XPOS,
2006                        DY + ED_WIN_MB_MIDDLE_YPOS,
2007                        el2gfx(new_element2));
2008   }
2009   else
2010   {
2011     new_element3 = element;
2012     DrawMiniGraphicExt(drawto, gc,
2013                        DX + ED_WIN_MB_RIGHT_XPOS,
2014                        DY + ED_WIN_MB_RIGHT_YPOS,
2015                        el2gfx(new_element3));
2016   }
2017
2018   redraw_mask |= REDRAW_DOOR_1;
2019 }
2020
2021 static void DrawDrawingWindow()
2022 {
2023   ClearWindow();
2024   UnmapLevelEditorWindowGadgets();
2025   AdjustDrawingAreaGadgets();
2026   AdjustLevelScrollPosition();
2027   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
2028   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
2029   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2030   MapMainDrawingArea();
2031 }
2032
2033 static void DrawRandomPlacementBackgroundArea()
2034 {
2035   int area_x = ED_AREA_RANDOM_BACKGROUND_XPOS / MINI_TILEX;
2036   int area_y = ED_AREA_RANDOM_BACKGROUND_YPOS / MINI_TILEY;
2037   int area_sx = SX + ED_AREA_RANDOM_BACKGROUND_XPOS;
2038   int area_sy = SY + ED_AREA_RANDOM_BACKGROUND_YPOS;
2039   int x, y;
2040
2041   ElementContent[0][0][0] = random_placement_background_element;
2042
2043   /* draw decorative border for the object */
2044   for (y=0; y<2; y++)
2045     for (x=0; x<2; x++)
2046       DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2047
2048   XFillRectangle(display, drawto, gc,
2049                  area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2050                  MINI_TILEX + 2, MINI_TILEY + 2);
2051
2052   /* copy border to the right location */
2053   XCopyArea(display, drawto, drawto, gc,
2054             area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2055             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2056
2057   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2058
2059   MapDrawingArea(GADGET_ID_RANDOM_BACKGROUND);
2060 }
2061
2062 static void DrawLevelInfoWindow()
2063 {
2064   char infotext[1024];
2065   int xoffset_above = 0;
2066   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
2067   int xoffset_right = counter_xsize;
2068   int yoffset_right = ED_BORDER_SIZE;
2069   int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
2070   int yoffset_right2 = ED_BORDER_SIZE;
2071   int font_color = FC_GREEN;
2072   int i, x, y;
2073
2074   ClearWindow();
2075   UnmapLevelEditorWindowGadgets();
2076
2077   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
2078            "Level Settings", FS_BIG, FC_YELLOW);
2079   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
2080            "Editor Settings", FS_BIG, FC_YELLOW);
2081
2082   /* draw counter gadgets */
2083   for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
2084   {
2085     if (counterbutton_info[i].infotext_above)
2086     {
2087       x = counterbutton_info[i].x + xoffset_above;
2088       y = counterbutton_info[i].y + yoffset_above;
2089
2090       sprintf(infotext, "%s:", counterbutton_info[i].infotext_above);
2091       infotext[MAX_INFOTEXT_LEN] = '\0';
2092       DrawTextF(x, y, font_color, infotext);
2093     }
2094
2095     if (counterbutton_info[i].infotext_right)
2096     {
2097       x = counterbutton_info[i].x + xoffset_right;
2098       y = counterbutton_info[i].y + yoffset_right;
2099
2100       sprintf(infotext, "%s", counterbutton_info[i].infotext_right);
2101       infotext[MAX_INFOTEXT_LEN] = '\0';
2102       DrawTextF(x, y, font_color, infotext);
2103     }
2104
2105     ModifyEditorCounter(i, *counterbutton_info[i].value);
2106     MapCounterButtons(i);
2107   }
2108
2109   /* draw text input gadgets */
2110   for (i=ED_TEXTINPUT_ID_LEVEL_FIRST; i<=ED_TEXTINPUT_ID_LEVEL_LAST; i++)
2111   {
2112     x = textinput_info[i].x + xoffset_above;
2113     y = textinput_info[i].y + yoffset_above;
2114
2115     sprintf(infotext, "%s:", textinput_info[i].infotext);
2116     infotext[MAX_INFOTEXT_LEN] = '\0';
2117
2118     DrawTextF(x, y, font_color, infotext);
2119     ModifyEditorTextInput(i, textinput_info[i].value);
2120     MapTextInputGadget(i);
2121   }
2122
2123   /* draw radiobutton gadgets */
2124   for (i=ED_RADIOBUTTON_ID_LEVEL_FIRST; i<=ED_RADIOBUTTON_ID_LEVEL_LAST; i++)
2125   {
2126     boolean checked =
2127       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
2128
2129     x = radiobutton_info[i].x + xoffset_right2;
2130     y = radiobutton_info[i].y + yoffset_right2;
2131
2132     DrawTextF(x, y, font_color, radiobutton_info[i].text);
2133     ModifyGadget(level_editor_gadget[radiobutton_info[i].gadget_id],
2134                  GDI_CHECKED, checked, GDI_END);
2135     MapRadiobuttonGadget(i);
2136   }
2137
2138   /* draw checkbutton gadgets */
2139   for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
2140   {
2141     x = checkbutton_info[i].x + xoffset_right2;
2142     y = checkbutton_info[i].y + yoffset_right2;
2143
2144     DrawTextF(x, y, font_color, checkbutton_info[i].text);
2145     ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
2146                  GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
2147     MapCheckbuttonGadget(i);
2148   }
2149
2150   /* draw drawing area */
2151   DrawRandomPlacementBackgroundArea();
2152 }
2153
2154 static void DrawAmoebaContentArea()
2155 {
2156   int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
2157   int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
2158   int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
2159   int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
2160   int font_color = FC_GREEN;
2161   int x, y;
2162
2163   ElementContent[0][0][0] = level.amoeba_content;
2164
2165   /* draw decorative border for the object */
2166   for (y=0; y<2; y++)
2167     for (x=0; x<2; x++)
2168       DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2169
2170   XFillRectangle(display, drawto, gc,
2171                  area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2172                  MINI_TILEX + 2, MINI_TILEY + 2);
2173
2174   /* copy border to the right location */
2175   XCopyArea(display, drawto, drawto, gc,
2176             area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2177             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2178
2179   DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2180            FS_SMALL, font_color);
2181
2182   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2183
2184   MapDrawingArea(GADGET_ID_AMOEBA_CONTENT);
2185 }
2186
2187 static void DrawElementContentAreas()
2188 {
2189   int counter_id = ED_COUNTER_ID_ELEM_CONTENT;
2190   int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
2191   int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
2192   int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
2193   int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
2194   int xoffset_right = counter_xsize;
2195   int yoffset_right = ED_BORDER_SIZE;
2196   int font_color = FC_GREEN;
2197   int i, x, y;
2198
2199   for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
2200     for (y=0; y<3; y++)
2201       for (x=0; x<3; x++)
2202         ElementContent[i][x][y] = level.yam_content[i][x][y];
2203
2204   for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
2205     UnmapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
2206
2207   /* display counter to choose number of element content areas */
2208   x = counterbutton_info[counter_id].x + xoffset_right;
2209   y = counterbutton_info[counter_id].y + yoffset_right;
2210   DrawTextF(x, y, font_color, "number of content areas");
2211
2212   ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
2213   MapCounterButtons(counter_id);
2214
2215   /* delete content areas in case of reducing number of them */
2216   XFillRectangle(display, backbuffer, gc,
2217                  SX, area_sy - MINI_TILEX,
2218                  SXSIZE, 12 * MINI_TILEY);
2219
2220   /* draw some decorative border for the objects */
2221   for (i=0; i<level.num_yam_contents; i++)
2222   {
2223     for (y=0; y<4; y++)
2224       for (x=0; x<4; x++)
2225         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2226                         EL_ERDREICH);
2227
2228     XFillRectangle(display, drawto, gc,
2229                    area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2230                    area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2231                    3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2232   }
2233
2234   /* copy border to the right location */
2235   XCopyArea(display, drawto, drawto, gc,
2236             area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 11 * MINI_TILEY,
2237             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2238
2239   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2240            "Content", FS_SMALL, font_color);
2241   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2242            "when", FS_SMALL, font_color);
2243   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2244            "smashed", FS_SMALL, font_color);
2245
2246   for (i=0; i<level.num_yam_contents; i++)
2247   {
2248     for (y=0; y<3; y++)
2249       for (x=0; x<3; x++)
2250         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2251                         ElementContent[i][x][y]);
2252
2253     DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2254               area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2255               font_color, "%d", i + 1);
2256   }
2257
2258   for (i=0; i<level.num_yam_contents; i++)
2259     MapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
2260 }
2261
2262 #define TEXT_COLLECTING         "Score for collecting"
2263 #define TEXT_SMASHING           "Score for smashing"
2264 #define TEXT_CRACKING           "Score for cracking"
2265 #define TEXT_SPEED              "Speed of amoeba growth"
2266 #define TEXT_DURATION           "Duration when activated"
2267
2268 static void DrawPropertiesWindow()
2269 {
2270   int counter_id = ED_COUNTER_ID_ELEM_SCORE;
2271   int num_elements_in_level;
2272   float percentage;
2273   int xoffset_right = counter_xsize;
2274   int yoffset_right = ED_BORDER_SIZE;
2275   int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
2276   int yoffset_right2 = ED_BORDER_SIZE;
2277   int xstart = 2;
2278   int ystart = 4;
2279   int font_color = FC_GREEN;
2280   int i, x, y;
2281   static struct
2282   {
2283     int element;
2284     int *value;
2285     char *text;
2286   } elements_with_counter[] =
2287   {
2288     { EL_EDELSTEIN,     &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
2289     { EL_EDELSTEIN_BD,  &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
2290     { EL_EDELSTEIN_GELB,&level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
2291     { EL_EDELSTEIN_ROT, &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
2292     { EL_EDELSTEIN_LILA,&level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
2293     { EL_DIAMANT,       &level.score[SC_DIAMANT],       TEXT_COLLECTING },
2294     { EL_KAEFER_R,      &level.score[SC_KAEFER],        TEXT_SMASHING },
2295     { EL_KAEFER_O,      &level.score[SC_KAEFER],        TEXT_SMASHING },
2296     { EL_KAEFER_L,      &level.score[SC_KAEFER],        TEXT_SMASHING },
2297     { EL_KAEFER_U,      &level.score[SC_KAEFER],        TEXT_SMASHING },
2298     { EL_BUTTERFLY_R,   &level.score[SC_KAEFER],        TEXT_SMASHING },
2299     { EL_BUTTERFLY_O,   &level.score[SC_KAEFER],        TEXT_SMASHING },
2300     { EL_BUTTERFLY_L,   &level.score[SC_KAEFER],        TEXT_SMASHING },
2301     { EL_BUTTERFLY_U,   &level.score[SC_KAEFER],        TEXT_SMASHING },
2302     { EL_FLIEGER_R,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2303     { EL_FLIEGER_O,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2304     { EL_FLIEGER_L,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2305     { EL_FLIEGER_U,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2306     { EL_FIREFLY_R,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2307     { EL_FIREFLY_O,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2308     { EL_FIREFLY_L,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2309     { EL_FIREFLY_U,     &level.score[SC_FLIEGER],       TEXT_SMASHING },
2310     { EL_MAMPFER,       &level.score[SC_MAMPFER],       TEXT_SMASHING },
2311     { EL_MAMPFER2,      &level.score[SC_MAMPFER],       TEXT_SMASHING },
2312     { EL_ROBOT,         &level.score[SC_ROBOT],         TEXT_SMASHING },
2313     { EL_PACMAN_R,      &level.score[SC_PACMAN],        TEXT_SMASHING },
2314     { EL_PACMAN_O,      &level.score[SC_PACMAN],        TEXT_SMASHING },
2315     { EL_PACMAN_L,      &level.score[SC_PACMAN],        TEXT_SMASHING },
2316     { EL_PACMAN_U,      &level.score[SC_PACMAN],        TEXT_SMASHING },
2317     { EL_KOKOSNUSS,     &level.score[SC_KOKOSNUSS],     TEXT_CRACKING },
2318     { EL_DYNAMIT_AUS,   &level.score[SC_DYNAMIT],       TEXT_COLLECTING },
2319     { EL_SCHLUESSEL1,   &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2320     { EL_SCHLUESSEL2,   &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2321     { EL_SCHLUESSEL3,   &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2322     { EL_SCHLUESSEL4,   &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2323     { EL_EM_KEY_1_FILE, &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2324     { EL_EM_KEY_2_FILE, &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2325     { EL_EM_KEY_3_FILE, &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2326     { EL_EM_KEY_4_FILE, &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
2327     { EL_AMOEBE_NASS,   &level.amoeba_speed,            TEXT_SPEED },
2328     { EL_AMOEBE_NORM,   &level.amoeba_speed,            TEXT_SPEED },
2329     { EL_AMOEBE_VOLL,   &level.amoeba_speed,            TEXT_SPEED },
2330     { EL_AMOEBE_BD,     &level.amoeba_speed,            TEXT_SPEED },
2331     { EL_SIEB_INAKTIV,  &level.time_magic_wall,         TEXT_DURATION },
2332     { EL_ABLENK_AUS,    &level.time_wheel,              TEXT_DURATION },
2333     { -1, NULL, NULL }
2334   };
2335
2336   ClearWindow();
2337   UnmapLevelEditorWindowGadgets();
2338
2339   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
2340            "Element Settings", FS_BIG, FC_YELLOW);
2341
2342   /* draw some decorative border for the object */
2343   for (y=0; y<3; y++)
2344     for (x=0; x<3; x++)
2345       DrawMiniElement(xstart + x , ystart + y, EL_ERDREICH);
2346
2347   XFillRectangle(display, drawto, gc,
2348                  SX + xstart * MINI_TILEX + MINI_TILEX/2 - 1,
2349                  SY + ystart * MINI_TILEY + MINI_TILEY/2 - 1,
2350                  TILEX + 2, TILEY + 2);
2351
2352   /* copy border to the right location */
2353   XCopyArea(display, drawto, drawto, gc,
2354             SX + xstart * MINI_TILEX,
2355             SY + ystart * MINI_TILEY,
2356             2 * TILEX, 2 * TILEY,
2357             SX + xstart * MINI_TILEX - MINI_TILEX/2,
2358             SY + ystart * MINI_TILEY - MINI_TILEY/2);
2359
2360   DrawGraphic(xstart/2, ystart/2, el2gfx(properties_element));
2361
2362   /* copy the whole stuff to the definitive location */
2363   XCopyArea(display, drawto, drawto, gc,
2364             SX + xstart * MINI_TILEX - MINI_TILEX/2,
2365             SY + ystart * MINI_TILEY - MINI_TILEY,
2366             2 * TILEX, 2 * TILEY,
2367             SX + xstart * MINI_TILEX - MINI_TILEX/2,
2368             SY + ystart * MINI_TILEY - MINI_TILEY/2);
2369
2370   DrawTextF((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
2371             font_color, element_info[properties_element]);
2372
2373   num_elements_in_level = 0;
2374   for (y=0; y<lev_fieldy; y++) 
2375     for (x=0; x<lev_fieldx; x++)
2376       if (Feld[x][y] == properties_element)
2377         num_elements_in_level++;
2378   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
2379
2380   DrawTextF(ED_SETTINGS_XPOS, 5 * TILEY, font_color, "In this level:");
2381   DrawTextF(ED_SETTINGS_XPOS + 15 * FONT2_XSIZE, 5 * TILEY, FC_YELLOW,
2382             "%d (%.2f%%)", num_elements_in_level, percentage);
2383
2384   /* check if there are elements where a score can be chosen for */
2385   for (i=0; elements_with_counter[i].element != -1; i++)
2386   {
2387     if (elements_with_counter[i].element == properties_element)
2388     {
2389       int x = counterbutton_info[counter_id].x + xoffset_right;
2390       int y = counterbutton_info[counter_id].y + yoffset_right;
2391
2392       counterbutton_info[counter_id].value = elements_with_counter[i].value;
2393       DrawTextF(x, y, font_color, elements_with_counter[i].text);
2394
2395       ModifyEditorCounter(counter_id,  *counterbutton_info[counter_id].value);
2396       MapCounterButtons(counter_id);
2397       break;
2398     }
2399   }
2400
2401   if (HAS_CONTENT(properties_element))
2402   {
2403     /* draw stickybutton gadget */
2404     i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
2405     x = checkbutton_info[i].x + xoffset_right2;
2406     y = checkbutton_info[i].y + yoffset_right2;
2407
2408     DrawTextF(x, y, font_color, checkbutton_info[i].text);
2409     ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
2410                  GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
2411     MapCheckbuttonGadget(i);
2412
2413     if (IS_AMOEBOID(properties_element))
2414       DrawAmoebaContentArea();
2415     else
2416       DrawElementContentAreas();
2417   }
2418 }
2419
2420 static void swap_numbers(int *i1, int *i2)
2421 {
2422   int help = *i1;
2423
2424   *i1 = *i2;
2425   *i2 = help;
2426 }
2427
2428 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2429 {
2430   int help_x = *x1;
2431   int help_y = *y1;
2432
2433   *x1 = *x2;
2434   *x2 = help_x;
2435
2436   *y1 = *y2;
2437   *y2 = help_y;
2438 }
2439
2440 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2441 {
2442   int lx = sx + level_xpos;
2443   int ly = sy + level_ypos;
2444
2445   DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2446
2447   if (change_level)
2448     Feld[lx][ly] = element;
2449 }
2450
2451 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2452                      int element, boolean change_level)
2453 {
2454   if (from_y == to_y)                   /* horizontal line */
2455   {
2456     int x;
2457     int y = from_y;
2458
2459     if (from_x > to_x)
2460       swap_numbers(&from_x, &to_x);
2461
2462     for (x=from_x; x<=to_x; x++)
2463       DrawLineElement(x, y, element, change_level);
2464   }
2465   else if (from_x == to_x)              /* vertical line */
2466   {
2467     int x = from_x;
2468     int y;
2469
2470     if (from_y > to_y)
2471       swap_numbers(&from_y, &to_y);
2472
2473     for (y=from_y; y<=to_y; y++)
2474       DrawLineElement(x, y, element, change_level);
2475   }
2476   else                                  /* diagonal line */
2477   {
2478     int len_x = ABS(to_x - from_x);
2479     int len_y = ABS(to_y - from_y);
2480     int x, y;
2481
2482     if (len_y < len_x)                  /* a < 1 */
2483     {
2484       float a = (float)len_y / (float)len_x;
2485
2486       if (from_x > to_x)
2487         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2488
2489       for (x=0; x<=len_x; x++)
2490       {
2491         y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2492         DrawLineElement(from_x + x, from_y + y, element, change_level);
2493       }
2494     }
2495     else                                /* a >= 1 */
2496     {
2497       float a = (float)len_x / (float)len_y;
2498
2499       if (from_y > to_y)
2500         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2501
2502       for (y=0; y<=len_y; y++)
2503       {
2504         x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2505         DrawLineElement(from_x + x, from_y + y, element, change_level);
2506       }
2507     }
2508   }
2509 }
2510
2511 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2512                           int element, boolean change_level)
2513 {
2514   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2515   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2516   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2517   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2518 }
2519
2520 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2521                           int element, boolean change_level)
2522 {
2523   int y;
2524
2525   if (from_y > to_y)
2526     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2527
2528   for (y=from_y; y<=to_y; y++)
2529     DrawLine(from_x, y, to_x, y, element, change_level);
2530 }
2531
2532 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
2533                        int element, boolean change_level)
2534 {
2535   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
2536   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
2537   int len_x = ABS(to_x - from_x);
2538   int len_y = ABS(to_y - from_y);
2539   int radius, x, y;
2540
2541   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
2542
2543   /* not optimal (some points get drawn twice) but simple,
2544      and fast enough for the few points we are drawing */
2545
2546   for (x=0; x<=radius; x++)
2547   {
2548     int sx, sy, lx, ly;
2549
2550     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
2551
2552     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
2553     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
2554     lx = sx + level_xpos;
2555     ly = sy + level_ypos;
2556
2557     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2558       DrawLineElement(sx, sy, element, change_level);
2559   }
2560
2561   for (y=0; y<=radius; y++)
2562   {
2563     int sx, sy, lx, ly;
2564
2565     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
2566
2567     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
2568     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
2569     lx = sx + level_xpos;
2570     ly = sy + level_ypos;
2571
2572     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2573       DrawLineElement(sx, sy, element, change_level);
2574   }
2575 }
2576
2577 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
2578                     int element, boolean change_level)
2579 {
2580   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
2581   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
2582
2583   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
2584 }
2585
2586 #define DRAW_CIRCLES_BUTTON_AVAILABLE   0
2587 #if DRAW_CIRCLES_BUTTON_AVAILABLE
2588 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
2589                        int element, boolean change_level)
2590 {
2591   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
2592   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
2593   int mirror_to_x2 = from_x - (to_x2 - from_x);
2594   int mirror_to_y2 = from_y - (to_y2 - from_y);
2595
2596   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
2597   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
2598   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
2599   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
2600 }
2601 #endif
2602
2603 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2604 {
2605   int from_sx, from_sy;
2606   int to_sx, to_sy;
2607
2608   if (from_x > to_x)
2609     swap_numbers(&from_x, &to_x);
2610
2611   if (from_y > to_y)
2612     swap_numbers(&from_y, &to_y);
2613
2614   from_sx = SX + from_x * MINI_TILEX;
2615   from_sy = SY + from_y * MINI_TILEY;
2616   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2617   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2618
2619   XSetForeground(display, gc, WhitePixel(display, screen));
2620
2621   XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2622   XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2623   XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2624   XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2625
2626   XSetForeground(display, gc, BlackPixel(display, screen));
2627
2628   if (from_x == to_x && from_y == to_y)
2629     MarkTileDirty(from_x/2, from_y/2);
2630   else
2631     redraw_mask |= REDRAW_FIELD;
2632 }
2633
2634 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2635                        int element, boolean change_level)
2636 {
2637   if (element == -1 || change_level)
2638     DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2639   else
2640     DrawAreaBorder(from_x, from_y, to_x, to_y);
2641 }
2642
2643 /* values for CopyBrushExt() */
2644 #define CB_AREA_TO_BRUSH        0
2645 #define CB_BRUSH_TO_CURSOR      1
2646 #define CB_BRUSH_TO_LEVEL       2
2647 #define CB_DELETE_OLD_CURSOR    3
2648
2649 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
2650                          int button, int mode)
2651 {
2652   static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
2653   static int brush_width, brush_height;
2654   static int last_cursor_x = -1, last_cursor_y = -1;
2655   static boolean delete_old_brush;
2656   int new_element = BUTTON_ELEMENT(button);
2657   int x, y;
2658
2659   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
2660     return;
2661
2662   if (mode == CB_AREA_TO_BRUSH)
2663   {
2664     int from_lx, from_ly;
2665
2666     if (from_x > to_x)
2667       swap_numbers(&from_x, &to_x);
2668
2669     if (from_y > to_y)
2670       swap_numbers(&from_y, &to_y);
2671
2672     brush_width = to_x - from_x + 1;
2673     brush_height = to_y - from_y + 1;
2674
2675     from_lx = from_x + level_xpos;
2676     from_ly = from_y + level_ypos;
2677
2678     for (y=0; y<brush_height; y++)
2679     {
2680       for (x=0; x<brush_width; x++)
2681       {
2682         brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
2683
2684         if (button != 1)
2685           DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
2686       }
2687     }
2688
2689     if (button != 1)
2690       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2691
2692     delete_old_brush = FALSE;
2693   }
2694   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
2695            mode == CB_BRUSH_TO_LEVEL)
2696   {
2697     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
2698     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
2699     int cursor_from_x = cursor_x - brush_width / 2;
2700     int cursor_from_y = cursor_y - brush_height / 2;
2701     int border_from_x = cursor_x, border_from_y = cursor_y;
2702     int border_to_x = cursor_x, border_to_y = cursor_y;
2703
2704     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
2705       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2706
2707     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
2708         !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
2709     {
2710       delete_old_brush = FALSE;
2711       return;
2712     }
2713
2714     for (y=0; y<brush_height; y++)
2715     {
2716       for (x=0; x<brush_width; x++)
2717       {
2718         int sx = cursor_from_x + x;
2719         int sy = cursor_from_y + y;
2720         int lx = sx + level_xpos;
2721         int ly = sy + level_ypos;
2722         boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
2723         int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
2724                        mode == CB_BRUSH_TO_CURSOR || button == 1 ?
2725                        brush_buffer[x][y] : new_element);
2726
2727         if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2728         {
2729           if (sx < border_from_x)
2730             border_from_x = sx;
2731           else if (sx > border_to_x)
2732             border_to_x = sx;
2733           if (sy < border_from_y)
2734             border_from_y = sy;
2735           else if (sy > border_to_y)
2736             border_to_y = sy;
2737
2738           DrawLineElement(sx, sy, element, change_level);
2739         }
2740       }
2741     }
2742
2743     if (mode != CB_DELETE_OLD_CURSOR)
2744       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
2745
2746     last_cursor_x = cursor_x;
2747     last_cursor_y = cursor_y;
2748     delete_old_brush = TRUE;
2749   }
2750 }
2751
2752 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
2753                             int button)
2754 {
2755   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
2756 }
2757
2758 static void CopyBrushToLevel(int x, int y, int button)
2759 {
2760   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
2761 }
2762
2763 static void CopyBrushToCursor(int x, int y)
2764 {
2765   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
2766 }
2767
2768 static void DeleteBrushFromCursor()
2769 {
2770   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2771 }
2772
2773 static void FloodFill(int from_x, int from_y, int fill_element)
2774 {
2775   int i,x,y;
2776   int old_element;
2777   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2778   static int safety = 0;
2779
2780   /* check if starting field still has the desired content */
2781   if (Feld[from_x][from_y] == fill_element)
2782     return;
2783
2784   safety++;
2785
2786   if (safety > lev_fieldx*lev_fieldy)
2787     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2788
2789   old_element = Feld[from_x][from_y];
2790   Feld[from_x][from_y] = fill_element;
2791
2792   for(i=0;i<4;i++)
2793   {
2794     x = from_x + check[i][0];
2795     y = from_y + check[i][1];
2796
2797     if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2798       FloodFill(x, y, fill_element);
2799   }
2800
2801   safety--;
2802 }
2803
2804 /* values for DrawLevelText() modes */
2805 #define TEXT_INIT               0
2806 #define TEXT_SETCURSOR          1
2807 #define TEXT_WRITECHAR          2
2808 #define TEXT_BACKSPACE          3
2809 #define TEXT_NEWLINE            4
2810 #define TEXT_END                5
2811 #define TEXT_QUERY_TYPING       6
2812
2813 static int DrawLevelText(int sx, int sy, char letter, int mode)
2814 {
2815   static short delete_buffer[MAX_LEV_FIELDX];
2816   static int start_sx, start_sy;
2817   static int last_sx, last_sy;
2818   static boolean typing = FALSE;
2819   int letter_element = EL_CHAR_ASCII0 + letter;
2820   int lx = 0, ly = 0;
2821
2822   /* map lower case letters to upper case and convert special characters */
2823   if (letter >= 'a' && letter <= 'z')
2824     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
2825   else if (letter == 'ä' || letter == 'Ä')
2826     letter_element = EL_CHAR_AE;
2827   else if (letter == 'ö' || letter == 'Ö')
2828     letter_element = EL_CHAR_OE;
2829   else if (letter == 'ü' || letter == 'Ãœ')
2830     letter_element = EL_CHAR_UE;
2831   else if (letter == '^')
2832     letter_element = EL_CHAR_COPY;
2833   else
2834     letter_element = EL_CHAR_ASCII0 + letter;
2835
2836   if (mode != TEXT_INIT)
2837   {
2838     if (!typing)
2839       return FALSE;
2840
2841     if (mode != TEXT_SETCURSOR)
2842     {
2843       sx = last_sx;
2844       sy = last_sy;
2845     }
2846
2847     lx = last_sx + level_xpos;
2848     ly = last_sy + level_ypos;
2849   }
2850
2851   switch (mode)
2852   {
2853     case TEXT_INIT:
2854       if (typing)
2855         DrawLevelText(0, 0, 0, TEXT_END);
2856
2857       typing = TRUE;
2858       start_sx = last_sx = sx;
2859       start_sy = last_sy = sy;
2860       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2861       break;
2862
2863     case TEXT_SETCURSOR:
2864       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2865       DrawAreaBorder(sx, sy, sx, sy);
2866       last_sx = sx;
2867       last_sy = sy;
2868       break;
2869
2870     case TEXT_WRITECHAR:
2871       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2872       {
2873         delete_buffer[sx - start_sx] = Feld[lx][ly];
2874         Feld[lx][ly] = letter_element;
2875
2876         if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
2877           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2878         else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
2879           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2880         else
2881           DrawLevelText(0, 0, 0, TEXT_END);
2882       }
2883       break;
2884
2885     case TEXT_BACKSPACE:
2886       if (sx > start_sx)
2887       {
2888         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2889         DrawMiniElement(sx - 1, sy, Feld[lx - 1][ly]);
2890         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2891       }
2892       break;
2893
2894     case TEXT_NEWLINE:
2895       if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
2896         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2897       else
2898         DrawLevelText(0, 0, 0, TEXT_END);
2899       break;
2900
2901     case TEXT_END:
2902       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2903       DrawMiniElement(sx, sy, Feld[lx][ly]);
2904       typing = FALSE;
2905       break;
2906
2907     case TEXT_QUERY_TYPING:
2908       break;
2909
2910     default:
2911       break;
2912   }
2913
2914   return typing;
2915 }
2916
2917 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
2918                           int element, boolean change_level)
2919 {
2920   int lx = sx + level_xpos;
2921   int ly = sy + level_ypos;
2922
2923   if (element == -1)
2924     DrawMiniElement(sx, sy, Feld[lx][ly]);
2925   else
2926     DrawAreaBorder(sx, sy, sx, sy);
2927 }
2928
2929 static void CopyLevelToUndoBuffer(int mode)
2930 {
2931   static boolean accumulated_undo = FALSE;
2932   boolean new_undo_buffer_position = TRUE;
2933   int last_border_element;
2934   int x, y;
2935
2936   switch (mode)
2937   {
2938     case UNDO_IMMEDIATE:
2939       accumulated_undo = FALSE;
2940       break;
2941
2942     case UNDO_ACCUMULATE:
2943       if (accumulated_undo)
2944         new_undo_buffer_position = FALSE;
2945       accumulated_undo = TRUE;
2946       break;
2947
2948     default:
2949       break;
2950   }
2951
2952   if (new_undo_buffer_position)
2953   {
2954     /* new position in undo buffer ring */
2955     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2956
2957     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2958       undo_buffer_steps++;
2959   }
2960
2961   for(x=0; x<lev_fieldx; x++)
2962     for(y=0; y<lev_fieldy; y++)
2963       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2964
2965   /* check if change of border style was forced by drawing operation */
2966   last_border_element = BorderElement;
2967   SetBorderElement();
2968   if (BorderElement != last_border_element)
2969     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2970
2971 #if 0
2972 #ifdef DEBUG
2973   printf("level saved to undo buffer\n");
2974 #endif
2975 #endif
2976 }
2977
2978 static void RandomPlacement(int new_element)
2979 {
2980   static boolean free_position[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
2981   int num_free_positions;
2982   int num_percentage;
2983   int num_elements;
2984   int x, y;
2985
2986   /* determine number of free positions for the new elements */
2987   /* (maybe this statement should be formatted a bit more readable...) */
2988   num_free_positions = 0;
2989   for (x=0; x<lev_fieldx; x++)
2990     for (y=0; y<lev_fieldy; y++)
2991       if ((free_position[x][y] =
2992            ((random_placement_background_restricted &&
2993              Feld[x][y] == random_placement_background_element) ||
2994             (!random_placement_background_restricted &&
2995              Feld[x][y] != new_element))) == TRUE)
2996         num_free_positions++;
2997
2998   /* determine number of new elements to place there */
2999   num_percentage = num_free_positions * random_placement_value / 100;
3000   num_elements = (random_placement_method == RANDOM_USE_PERCENTAGE ?
3001                   num_percentage : random_placement_value);
3002
3003   /* if not more free positions than elements to place, fill whole level */
3004   if (num_elements >= num_free_positions)
3005   {
3006     for (x=0; x<lev_fieldx; x++)
3007       for (y=0; y<lev_fieldy; y++)
3008         Feld[x][y] = new_element;
3009
3010     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3011     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3012     return;
3013   }
3014
3015   while (num_elements > 0)
3016   {
3017     x = RND(lev_fieldx);
3018     y = RND(lev_fieldy);
3019
3020     /* don't place element at the same position twice */
3021     if (free_position[x][y])
3022     {
3023       free_position[x][y] = FALSE;
3024       Feld[x][y] = new_element;
3025       num_elements--;
3026     }
3027   }
3028
3029   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3030   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3031 }
3032
3033 void WrapLevel(int dx, int dy)
3034 {
3035   int wrap_dx = lev_fieldx - dx;
3036   int wrap_dy = lev_fieldy - dy;
3037   int x, y;
3038
3039   for(x=0; x<lev_fieldx; x++)
3040     for(y=0; y<lev_fieldy; y++)
3041       FieldBackup[x][y] = Feld[x][y];
3042
3043   for(x=0; x<lev_fieldx; x++)
3044     for(y=0; y<lev_fieldy; y++)
3045       Feld[x][y] =
3046         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
3047
3048   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3049   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
3050 }
3051
3052 static void HandleDrawingAreas(struct GadgetInfo *gi)
3053 {
3054   static boolean started_inside_drawing_area = FALSE;
3055   int id = gi->custom_id;
3056   boolean button_press_event;
3057   boolean button_release_event;
3058   boolean inside_drawing_area = !gi->event.off_borders;
3059   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
3060   int actual_drawing_function;
3061   int button = gi->event.button;
3062   int new_element = BUTTON_ELEMENT(button);
3063   int sx = gi->event.x, sy = gi->event.y;
3064   int min_sx = 0, min_sy = 0;
3065   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
3066   int lx = 0, ly = 0;
3067   int min_lx = 0, min_ly = 0;
3068   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
3069   int x, y;
3070
3071   /* handle info callback for each invocation of action callback */
3072   gi->callback_info(gi);
3073
3074   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
3075   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
3076
3077   /* make sure to stay inside drawing area boundaries */
3078   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
3079   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
3080
3081   if (draw_level)
3082   {
3083     /* get positions inside level field */
3084     lx = sx + level_xpos;
3085     ly = sy + level_ypos;
3086
3087     if (!IN_LEV_FIELD(lx, ly))
3088       inside_drawing_area = FALSE;
3089
3090     /* make sure to stay inside level field boundaries */
3091     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
3092     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
3093
3094     /* correct drawing area positions accordingly */
3095     sx = lx - level_xpos;
3096     sy = ly - level_ypos;
3097   }
3098
3099   if (button_press_event)
3100     started_inside_drawing_area = inside_drawing_area;
3101
3102   if (!started_inside_drawing_area)
3103     return;
3104
3105   if (!button && !button_release_event)
3106     return;
3107
3108   /* automatically switch to 'single item' drawing mode, if needed */
3109   actual_drawing_function =
3110     (draw_level ? drawing_function : GADGET_ID_SINGLE_ITEMS);
3111
3112   switch (actual_drawing_function)
3113   {
3114     case GADGET_ID_SINGLE_ITEMS:
3115       if (draw_level)
3116       {
3117         if (button_release_event)
3118         {
3119           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3120
3121           if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
3122               !inside_drawing_area)
3123             DeleteBrushFromCursor();
3124         }
3125
3126         if (!button)
3127           break;
3128
3129         if (draw_with_brush)
3130         {
3131           if (!button_release_event)
3132             CopyBrushToLevel(sx, sy, button);
3133         }
3134         else if (new_element != Feld[lx][ly])
3135         {
3136           if (new_element == EL_SPIELFIGUR)
3137           {
3138             /* remove player at old position */
3139             for(y=0; y<lev_fieldy; y++)
3140             {
3141               for(x=0; x<lev_fieldx; x++)
3142               {
3143                 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
3144                 {
3145                   Feld[x][y] = EL_LEERRAUM;
3146                   if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
3147                       y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
3148                     DrawMiniElement(x - level_xpos, y - level_ypos,
3149                                     EL_LEERRAUM);
3150                 }
3151               }
3152             }
3153           }
3154
3155           Feld[lx][ly] = new_element;
3156           DrawMiniElement(sx, sy, new_element);
3157         }
3158       }
3159       else
3160       {
3161         DrawMiniGraphicExt(drawto, gc,
3162                            gi->x + sx * MINI_TILEX,
3163                            gi->y + sy * MINI_TILEY,
3164                            el2gfx(new_element));
3165         DrawMiniGraphicExt(window, gc,
3166                            gi->x + sx * MINI_TILEX,
3167                            gi->y + sy * MINI_TILEY,
3168                            el2gfx(new_element));
3169
3170         if (id == GADGET_ID_AMOEBA_CONTENT)
3171           level.amoeba_content = new_element;
3172         else if (id == GADGET_ID_RANDOM_BACKGROUND)
3173           random_placement_background_element = new_element;
3174         else if (id >= GADGET_ID_ELEM_CONTENT_0 &&
3175                  id <= GADGET_ID_ELEM_CONTENT_7)
3176           level.yam_content[id - GADGET_ID_ELEM_CONTENT_0][sx][sy] =
3177             new_element;
3178       }
3179       break;
3180
3181     case GADGET_ID_CONNECTED_ITEMS:
3182       {
3183         static int last_sx = -1;
3184         static int last_sy = -1;
3185
3186         if (button_release_event)
3187           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3188
3189         if (button)
3190         {
3191           if (!button_press_event)
3192             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
3193
3194           last_sx = sx;
3195           last_sy = sy;
3196         }
3197       }
3198       break;
3199
3200     case GADGET_ID_LINE:
3201     case GADGET_ID_ARC:
3202     case GADGET_ID_RECTANGLE:
3203     case GADGET_ID_FILLED_BOX:
3204     case GADGET_ID_GRAB_BRUSH:
3205     case GADGET_ID_TEXT:
3206       {
3207         static int last_sx = -1;
3208         static int last_sy = -1;
3209         static int start_sx = -1;
3210         static int start_sy = -1;
3211         void (*draw_func)(int, int, int, int, int, boolean);
3212
3213         if (drawing_function == GADGET_ID_LINE)
3214           draw_func = DrawLine;
3215         else if (drawing_function == GADGET_ID_ARC)
3216           draw_func = DrawArc;
3217         else if (drawing_function == GADGET_ID_RECTANGLE)
3218           draw_func = DrawRectangle;
3219         else if (drawing_function == GADGET_ID_FILLED_BOX)
3220           draw_func = DrawFilledBox;
3221         else if (drawing_function == GADGET_ID_GRAB_BRUSH)
3222           draw_func = SelectArea;
3223         else /* (drawing_function == GADGET_ID_TEXT) */
3224           draw_func = SetTextCursor;
3225
3226         if (button_press_event)
3227         {
3228           draw_func(sx, sy, sx, sy, new_element, FALSE);
3229           start_sx = last_sx = sx;
3230           start_sy = last_sy = sy;
3231
3232           if (drawing_function == GADGET_ID_TEXT)
3233             DrawLevelText(0, 0, 0, TEXT_END);
3234         }
3235         else if (button_release_event)
3236         {
3237           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
3238           if (drawing_function == GADGET_ID_GRAB_BRUSH)
3239           {
3240             CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
3241             CopyBrushToCursor(sx, sy);
3242             ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],MB_LEFT);
3243             draw_with_brush = TRUE;
3244           }
3245           else if (drawing_function == GADGET_ID_TEXT)
3246             DrawLevelText(sx, sy, 0, TEXT_INIT);
3247           else
3248             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3249         }
3250         else if (last_sx != sx || last_sy != sy)
3251         {
3252           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
3253           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
3254           last_sx = sx;
3255           last_sy = sy;
3256         }
3257       }
3258       break;
3259
3260     case GADGET_ID_FLOOD_FILL:
3261       if (button_press_event && Feld[lx][ly] != new_element)
3262       {
3263         FloodFill(lx, ly, new_element);
3264         DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3265         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3266       }
3267       break;
3268
3269     case GADGET_ID_PICK_ELEMENT:
3270       if (button_release_event)
3271         ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFT);
3272       else
3273         PickDrawingElement(button, Feld[lx][ly]);
3274
3275       break;
3276
3277     default:
3278       break;
3279   }
3280 }
3281
3282 static void HandleCounterButtons(struct GadgetInfo *gi)
3283 {
3284   int gadget_id = gi->custom_id;
3285   int counter_id = gi->custom_type_id;
3286   int button = gi->event.button;
3287   int *counter_value = counterbutton_info[counter_id].value;
3288   int step = BUTTON_STEPSIZE(button) *
3289     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
3290
3291   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
3292     *counter_value = gi->text.number_value;
3293   else
3294     ModifyEditorCounter(counter_id, *counter_value + step);
3295
3296   if (counter_id == ED_COUNTER_ID_ELEM_CONTENT)
3297     DrawElementContentAreas();
3298   else if (counter_id == ED_COUNTER_ID_LEVEL_XSIZE)
3299     lev_fieldx = level.fieldx;
3300   else if (counter_id == ED_COUNTER_ID_LEVEL_YSIZE)
3301     lev_fieldy = level.fieldy;
3302 }
3303
3304 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3305 {
3306   strcpy(textinput_info[gi->custom_type_id].value, gi->text.value);
3307 }
3308
3309 static void HandleRadiobuttons(struct GadgetInfo *gi)
3310 {
3311   *radiobutton_info[gi->custom_type_id].value =
3312     radiobutton_info[gi->custom_type_id].checked_value;
3313 }
3314
3315 static void HandleCheckbuttons(struct GadgetInfo *gi)
3316 {
3317   *checkbutton_info[gi->custom_type_id].value ^= TRUE;
3318 }
3319
3320 static void HandleControlButtons(struct GadgetInfo *gi)
3321 {
3322   int id = gi->custom_id;
3323   int button = gi->event.button;
3324   int step = BUTTON_STEPSIZE(button);
3325   int new_element = BUTTON_ELEMENT(button);
3326   int player_present = FALSE;
3327   int level_changed = FALSE;
3328   int i, x, y;
3329
3330   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
3331     DrawLevelText(0, 0, 0, TEXT_END);
3332
3333   if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_PROPERTIES &&
3334       edit_mode != ED_MODE_DRAWING)
3335   {
3336     DrawDrawingWindow();
3337     edit_mode = ED_MODE_DRAWING;
3338   }
3339
3340   switch (id)
3341   {
3342     case GADGET_ID_SCROLL_LEFT:
3343       if (level_xpos >= 0)
3344       {
3345         int gadget_id = GADGET_ID_SCROLL_HORIZONTAL;
3346         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3347
3348         if (lev_fieldx < ed_fieldx - 2)
3349           break;
3350
3351         level_xpos -= step;
3352         if (level_xpos < -1)
3353           level_xpos = -1;
3354         if (button == 1)
3355           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3356         else
3357           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3358
3359         ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
3360       }
3361       break;
3362
3363     case GADGET_ID_SCROLL_RIGHT:
3364       if (level_xpos <= lev_fieldx - ed_fieldx)
3365       {
3366         int gadget_id = GADGET_ID_SCROLL_HORIZONTAL;
3367         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3368
3369         if (lev_fieldx < ed_fieldx - 2)
3370           break;
3371
3372         level_xpos += step;
3373         if (level_xpos > lev_fieldx - ed_fieldx + 1)
3374           level_xpos = lev_fieldx - ed_fieldx + 1;
3375         if (button == 1)
3376           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3377         else
3378           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3379
3380         ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
3381       }
3382       break;
3383
3384     case GADGET_ID_SCROLL_UP:
3385       if (level_ypos >= 0)
3386       {
3387         int gadget_id = GADGET_ID_SCROLL_VERTICAL;
3388         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3389
3390         if (lev_fieldy < ed_fieldy - 2)
3391           break;
3392
3393         level_ypos -= step;
3394         if (level_ypos < -1)
3395           level_ypos = -1;
3396         if (button == 1)
3397           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3398         else
3399           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3400
3401         ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
3402       }
3403       break;
3404
3405     case GADGET_ID_SCROLL_DOWN:
3406       if (level_ypos <= lev_fieldy - ed_fieldy)
3407       {
3408         int gadget_id = GADGET_ID_SCROLL_VERTICAL;
3409         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3410
3411         if (lev_fieldy < ed_fieldy - 2)
3412           break;
3413
3414         level_ypos += step;
3415         if (level_ypos > lev_fieldy - ed_fieldy + 1)
3416           level_ypos = lev_fieldy - ed_fieldy + 1;
3417         if (button == 1)
3418           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3419         else
3420           DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3421
3422         ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
3423       }
3424       break;
3425
3426     case GADGET_ID_SCROLL_HORIZONTAL:
3427       level_xpos = gi->event.item_position - 1;
3428       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3429       break;
3430
3431     case GADGET_ID_SCROLL_VERTICAL:
3432       level_ypos = gi->event.item_position - 1;
3433       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3434       break;
3435
3436     case GADGET_ID_ELEMENTLIST_UP:
3437     case GADGET_ID_ELEMENTLIST_DOWN:
3438       step *= (id == GADGET_ID_ELEMENTLIST_UP ? -1 : +1);
3439       element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
3440
3441       if (element_shift < 0)
3442         element_shift = 0;
3443       if (element_shift > elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS)
3444         element_shift = elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS;
3445
3446       for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
3447       {
3448         int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
3449         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3450         struct GadgetDesign *gd = &gi->deco.design;
3451         int element = editor_element[element_shift + i];
3452
3453         UnmapGadget(gi);
3454         getMiniGraphicSource(el2gfx(element), &gd->pixmap, &gd->x, &gd->y);
3455         ModifyGadget(gi, GDI_INFO_TEXT, element_info[element], GDI_END);
3456         MapGadget(gi);
3457       }
3458       break;
3459
3460     case GADGET_ID_WRAP_LEFT:
3461       WrapLevel(-step, 0);
3462       break;
3463
3464     case GADGET_ID_WRAP_RIGHT:
3465       WrapLevel(step, 0);
3466       break;
3467
3468     case GADGET_ID_WRAP_UP:
3469       WrapLevel(0, -step);
3470       break;
3471
3472     case GADGET_ID_WRAP_DOWN:
3473       WrapLevel(0, step);
3474       break;
3475
3476     case GADGET_ID_SINGLE_ITEMS:
3477     case GADGET_ID_CONNECTED_ITEMS:
3478     case GADGET_ID_LINE:
3479     case GADGET_ID_ARC:
3480     case GADGET_ID_TEXT:
3481     case GADGET_ID_RECTANGLE:
3482     case GADGET_ID_FILLED_BOX:
3483     case GADGET_ID_FLOOD_FILL:
3484     case GADGET_ID_GRAB_BRUSH:
3485     case GADGET_ID_PICK_ELEMENT:
3486       last_drawing_function = drawing_function;
3487       drawing_function = id;
3488       draw_with_brush = FALSE;
3489       break;
3490
3491     case GADGET_ID_RANDOM_PLACEMENT:
3492       RandomPlacement(new_element);
3493       break;
3494
3495     case GADGET_ID_PROPERTIES:
3496       if (edit_mode != ED_MODE_PROPERTIES)
3497       {
3498         properties_element = new_element;
3499         DrawPropertiesWindow();
3500         edit_mode = ED_MODE_PROPERTIES;
3501       }
3502       else
3503       {
3504         DrawDrawingWindow();
3505         edit_mode = ED_MODE_DRAWING;
3506       }
3507       break;
3508
3509     case GADGET_ID_UNDO:
3510       if (undo_buffer_steps == 0)
3511       {
3512         Request("Undo buffer empty !", REQ_CONFIRM);
3513         break;
3514       }
3515
3516       undo_buffer_position =
3517         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3518       undo_buffer_steps--;
3519
3520       for(x=0; x<lev_fieldx; x++)
3521         for(y=0; y<lev_fieldy; y++)
3522           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3523       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos,level_ypos);
3524       break;
3525
3526     case GADGET_ID_INFO:
3527       if (edit_mode != ED_MODE_INFO)
3528       {
3529         DrawLevelInfoWindow();
3530         edit_mode = ED_MODE_INFO;
3531       }
3532       else
3533       {
3534         DrawDrawingWindow();
3535         edit_mode = ED_MODE_DRAWING;
3536       }
3537       break;
3538
3539     case GADGET_ID_CLEAR:
3540       for(x=0; x<MAX_LEV_FIELDX; x++) 
3541         for(y=0; y<MAX_LEV_FIELDY; y++) 
3542           Feld[x][y] = (button == 1 ? EL_LEERRAUM : new_element);
3543       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
3544
3545       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3546       break;
3547
3548     case GADGET_ID_SAVE:
3549       if (leveldir[leveldir_nr].readonly)
3550       {
3551         Request("This level is read only !", REQ_CONFIRM);
3552         break;
3553       }
3554
3555       for(y=0; y<lev_fieldy; y++) 
3556         for(x=0; x<lev_fieldx; x++)
3557           if (Feld[x][y] != Ur[x][y])
3558             level_changed = TRUE;
3559
3560       for(y=0; y<lev_fieldy; y++) 
3561         for(x=0; x<lev_fieldx; x++)
3562           if (Feld[x][y] == EL_SPIELFIGUR ||
3563               Feld[x][y] == EL_SPIELER1 ||
3564               Feld[x][y] == EL_SP_MURPHY) 
3565             player_present = TRUE;
3566
3567       if (!player_present)
3568         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3569       else
3570       {
3571         if (Request("Save this level and kill the old ?", REQ_ASK))
3572         {
3573           for(x=0; x<lev_fieldx; x++)
3574             for(y=0; y<lev_fieldy; y++) 
3575               Ur[x][y] = Feld[x][y];
3576           SaveLevel(level_nr);
3577         }
3578       }
3579       break;
3580
3581     case GADGET_ID_TEST:
3582       for(y=0; y<lev_fieldy; y++) 
3583         for(x=0; x<lev_fieldx; x++)
3584           if (Feld[x][y] == EL_SPIELFIGUR ||
3585               Feld[x][y] == EL_SPIELER1 ||
3586               Feld[x][y] == EL_SP_MURPHY) 
3587             player_present = TRUE;
3588
3589       if (!player_present)
3590         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3591       else
3592       {
3593         for(x=0; x<lev_fieldx; x++)
3594           for(y=0; y<lev_fieldy; y++)
3595             FieldBackup[x][y] = Ur[x][y];
3596
3597         for(x=0; x<lev_fieldx; x++)
3598           for(y=0; y<lev_fieldy; y++)
3599             Ur[x][y] = Feld[x][y];
3600
3601         UnmapLevelEditorGadgets();
3602
3603         /* draw smaller door */
3604         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3605                   DOOR_GFX_PAGEX7, 64,
3606                   108, 64,
3607                   EX - 4, EY - 12);
3608         redraw_mask |= REDRAW_ALL;
3609
3610         CloseDoor(DOOR_CLOSE_ALL);
3611
3612         DrawCompleteVideoDisplay();
3613
3614         if (setup.autorecord)
3615           TapeStartRecording();
3616
3617         level_editor_test_game = TRUE;
3618         game_status = PLAYING;
3619
3620         InitGame();
3621       }
3622       break;
3623
3624     case GADGET_ID_EXIT:
3625       for(y=0; y<lev_fieldy; y++) 
3626         for(x=0; x<lev_fieldx; x++)
3627           if (Feld[x][y] != Ur[x][y])
3628             level_changed = TRUE;
3629
3630       if (!level_changed ||
3631           Request("Level has changed! Exit without saving ?",
3632                   REQ_ASK | REQ_STAY_OPEN))
3633       {
3634         CloseDoor(DOOR_CLOSE_1);
3635
3636         /*
3637         CloseDoor(DOOR_CLOSE_ALL);
3638         */
3639
3640         /* draw smaller door */
3641         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3642                   DOOR_GFX_PAGEX7, 64,
3643                   108, 64,
3644                   EX - 4, EY - 12);
3645         redraw_mask |= REDRAW_ALL;
3646
3647         game_status = MAINMENU;
3648         DrawMainMenu();
3649       }
3650       else
3651       {
3652         CloseDoor(DOOR_CLOSE_1);
3653         XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3654                   DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3655                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3656         OpenDoor(DOOR_OPEN_1);
3657       }
3658       break;
3659
3660     default:
3661       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
3662           id <= GADGET_ID_ELEMENTLIST_LAST)
3663       {
3664         int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
3665         int new_element = editor_element[element_position + element_shift];
3666
3667         PickDrawingElement(button, new_element);
3668
3669         if (!HAS_CONTENT(properties_element) ||
3670             !stick_element_properties_window)
3671         {
3672           properties_element = new_element;
3673           if (edit_mode == ED_MODE_PROPERTIES)
3674             DrawPropertiesWindow();
3675         }
3676
3677         if (drawing_function == GADGET_ID_PICK_ELEMENT)
3678           ClickOnGadget(level_editor_gadget[last_drawing_function], MB_LEFT);
3679       }
3680 #ifdef DEBUG
3681       else if (gi->event.type == GD_EVENT_PRESSED)
3682         printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
3683       else if (gi->event.type == GD_EVENT_RELEASED)
3684         printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
3685       else if (gi->event.type == GD_EVENT_MOVING)
3686         printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
3687       else
3688         printf("default: HandleControlButtons: ? (id == %d)\n", id);
3689 #endif
3690       break;
3691   }
3692 }
3693
3694 void HandleLevelEditorKeyInput(KeySym key)
3695 {
3696   char letter = getCharFromKeySym(key);
3697   int button = MB_LEFT;
3698
3699   if (drawing_function == GADGET_ID_TEXT &&
3700       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
3701   {
3702     if (letter)
3703       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3704     else if (key == XK_Delete || key == XK_BackSpace)
3705       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3706     else if (key == XK_Return)
3707       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3708   }
3709   else if (button_status == MB_RELEASED)
3710   {
3711     int i, id;
3712
3713     switch (key)
3714     {
3715       case XK_Left:
3716         id = GADGET_ID_SCROLL_LEFT;
3717         break;
3718       case XK_Right:
3719         id = GADGET_ID_SCROLL_RIGHT;
3720         break;
3721       case XK_Up:
3722         id = GADGET_ID_SCROLL_UP;
3723         break;
3724       case XK_Down:
3725         id = GADGET_ID_SCROLL_DOWN;
3726         break;
3727       case XK_Page_Up:
3728         id = GADGET_ID_ELEMENTLIST_UP;
3729         button = 3;
3730         break;
3731       case XK_Page_Down:
3732         id = GADGET_ID_ELEMENTLIST_DOWN;
3733         button = 3;
3734         break;
3735
3736       default:
3737         id = GADGET_ID_NONE;
3738         break;
3739     }
3740
3741     if (id != GADGET_ID_NONE)
3742       ClickOnGadget(level_editor_gadget[id], button);
3743     else if (letter == '.')
3744       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
3745     else
3746       for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
3747         if (letter && letter == control_info[i].shortcut)
3748           if (!anyTextGadgetActive())
3749             ClickOnGadget(level_editor_gadget[i], button);
3750   }
3751 }
3752
3753 void ClearEditorGadgetInfoText()
3754 {
3755   XFillRectangle(display, drawto, gc,
3756                  INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
3757   redraw_mask |= REDRAW_FIELD;
3758 }
3759
3760 void HandleEditorGadgetInfoText(void *ptr)
3761 {
3762   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
3763   char infotext[MAX_INFOTEXT_LEN + 1];
3764   char shortcut[20];
3765
3766   ClearEditorGadgetInfoText();
3767
3768   /* misuse this function to delete brush cursor, if needed */
3769   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
3770     DeleteBrushFromCursor();
3771
3772   if (gi == NULL || gi->info_text == NULL)
3773     return;
3774
3775   strncpy(infotext, gi->info_text, MAX_INFOTEXT_LEN);
3776   infotext[MAX_INFOTEXT_LEN] = '\0';
3777
3778   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
3779   {
3780     int key = control_info[gi->custom_id].shortcut;
3781
3782     if (key)
3783     {
3784       sprintf(shortcut, " ('%s%c')",
3785               (key >= 'A' && key <= 'Z' ? "Shift-" :
3786                gi->custom_id == GADGET_ID_SINGLE_ITEMS ? ".' or '" : ""),
3787               key);
3788
3789       if (strlen(infotext) + strlen(shortcut) <= MAX_INFOTEXT_LEN)
3790         strcat(infotext, shortcut);
3791     }
3792   }
3793
3794   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
3795 }
3796
3797 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
3798 {
3799   static int start_lx, start_ly;
3800   char *infotext;
3801   int id = gi->custom_id;
3802   int sx = gi->event.x;
3803   int sy = gi->event.y;
3804   int lx = sx + level_xpos;
3805   int ly = sy + level_ypos;
3806   int min_sx = 0, min_sy = 0;
3807   int max_sx = gi->drawing.area_xsize - 1;
3808   int max_sy = gi->drawing.area_ysize - 1;
3809
3810   ClearEditorGadgetInfoText();
3811
3812   /* make sure to stay inside drawing area boundaries */
3813   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
3814   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
3815
3816   if (id == GADGET_ID_DRAWING_LEVEL)
3817   {
3818     if (button_status)
3819     {
3820       int min_lx = 0, min_ly = 0;
3821       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
3822
3823       /* get positions inside level field */
3824       lx = sx + level_xpos;
3825       ly = sy + level_ypos;
3826
3827       /* make sure to stay inside level field boundaries */
3828       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
3829       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
3830
3831       /* correct drawing area positions accordingly */
3832       sx = lx - level_xpos;
3833       sy = ly - level_ypos;
3834     }
3835
3836     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
3837     {
3838       if (button_status)        /* if (gi->state == GD_BUTTON_PRESSED) */
3839       {
3840         if (gi->event.type == GD_EVENT_PRESSED)
3841         {
3842           start_lx = lx;
3843           start_ly = ly;
3844         }
3845
3846         switch (drawing_function)
3847         {
3848           case GADGET_ID_SINGLE_ITEMS:
3849             infotext = "Drawing single items";
3850             break;
3851           case GADGET_ID_CONNECTED_ITEMS:
3852             infotext = "Drawing connected items";
3853             break;
3854           case GADGET_ID_LINE:
3855             infotext = "Drawing line";
3856             break;
3857           case GADGET_ID_ARC:
3858             infotext = "Drawing arc";
3859             break;
3860           case GADGET_ID_TEXT:
3861             infotext = "Setting text cursor";
3862             break;
3863           case GADGET_ID_RECTANGLE:
3864             infotext = "Drawing rectangle";
3865             break;
3866           case GADGET_ID_FILLED_BOX:
3867             infotext = "Drawing filled box";
3868             break;
3869           case GADGET_ID_FLOOD_FILL:
3870             infotext = "Flood fill";
3871             break;
3872           case GADGET_ID_GRAB_BRUSH:
3873             infotext = "Grabbing brush";
3874             break;
3875           case GADGET_ID_PICK_ELEMENT:
3876             infotext = "Picking element";
3877             break;
3878
3879           default:
3880             infotext = "Drawing position";
3881             break;
3882         }
3883
3884         if (drawing_function == GADGET_ID_PICK_ELEMENT)
3885           DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3886                     "%s: %d, %d", infotext, lx, ly);
3887         else
3888           DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3889                     "%s: %d, %d", infotext,
3890                     ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
3891       }
3892       else if (drawing_function == GADGET_ID_PICK_ELEMENT)
3893         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3894                   "%s", element_info[Feld[lx][ly]]);
3895       else
3896         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3897                   "Level position: %d, %d", lx, ly);
3898     }
3899
3900     /* misuse this function to draw brush cursor, if needed */
3901     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
3902     {
3903       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
3904         CopyBrushToCursor(sx, sy);
3905       else
3906         DeleteBrushFromCursor();
3907     }
3908   }
3909   else if (id == GADGET_ID_AMOEBA_CONTENT)
3910     DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3911               "Amoeba content");
3912   else if (id == GADGET_ID_RANDOM_BACKGROUND)
3913     DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3914               "Random placement background");
3915   else
3916     DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3917               "Content area %d position: %d, %d",
3918               id - GADGET_ID_ELEM_CONTENT_0 + 1, sx, sy);
3919 }