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