rnd-19990124-2
[rocksndiamonds.git] / src / buttons.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 *  buttons.c                                               *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #include "buttons.h"
17 #include "tools.h"
18 #include "misc.h"
19 #include "editor.h"
20 #include "tape.h"
21
22 /* some positions in the video tape control window */
23 #define VIDEO_BUTTON_EJECT_XPOS (VIDEO_CONTROL_XPOS + 0 * VIDEO_BUTTON_XSIZE)
24 #define VIDEO_BUTTON_STOP_XPOS  (VIDEO_CONTROL_XPOS + 1 * VIDEO_BUTTON_XSIZE)
25 #define VIDEO_BUTTON_PAUSE_XPOS (VIDEO_CONTROL_XPOS + 2 * VIDEO_BUTTON_XSIZE)
26 #define VIDEO_BUTTON_REC_XPOS   (VIDEO_CONTROL_XPOS + 3 * VIDEO_BUTTON_XSIZE)
27 #define VIDEO_BUTTON_PLAY_XPOS  (VIDEO_CONTROL_XPOS + 4 * VIDEO_BUTTON_XSIZE)
28 #define VIDEO_BUTTON_ANY_YPOS   (VIDEO_CONTROL_YPOS)
29 #define VIDEO_DATE_LABEL_XPOS   (VIDEO_DISPLAY1_XPOS)
30 #define VIDEO_DATE_LABEL_YPOS   (VIDEO_DISPLAY1_YPOS)
31 #define VIDEO_DATE_LABEL_XSIZE  (VIDEO_DISPLAY_XSIZE)
32 #define VIDEO_DATE_LABEL_YSIZE  (VIDEO_DISPLAY_YSIZE)
33 #define VIDEO_DATE_XPOS         (VIDEO_DISPLAY1_XPOS+1)
34 #define VIDEO_DATE_YPOS         (VIDEO_DISPLAY1_YPOS+14)
35 #define VIDEO_DATE_XSIZE        (VIDEO_DISPLAY_XSIZE)
36 #define VIDEO_DATE_YSIZE        16
37 #define VIDEO_REC_LABEL_XPOS    (VIDEO_DISPLAY2_XPOS)
38 #define VIDEO_REC_LABEL_YPOS    (VIDEO_DISPLAY2_YPOS)
39 #define VIDEO_REC_LABEL_XSIZE   20
40 #define VIDEO_REC_LABEL_YSIZE   12
41 #define VIDEO_REC_SYMBOL_XPOS   (VIDEO_DISPLAY2_XPOS+20)
42 #define VIDEO_REC_SYMBOL_YPOS   (VIDEO_DISPLAY2_YPOS)
43 #define VIDEO_REC_SYMBOL_XSIZE  16
44 #define VIDEO_REC_SYMBOL_YSIZE  16
45 #define VIDEO_PLAY_LABEL_XPOS   (VIDEO_DISPLAY2_XPOS+65)
46 #define VIDEO_PLAY_LABEL_YPOS   (VIDEO_DISPLAY2_YPOS)
47 #define VIDEO_PLAY_LABEL_XSIZE  22
48 #define VIDEO_PLAY_LABEL_YSIZE  12
49 #define VIDEO_PLAY_SYMBOL_XPOS  (VIDEO_DISPLAY2_XPOS+52)
50 #define VIDEO_PLAY_SYMBOL_YPOS  (VIDEO_DISPLAY2_YPOS)
51 #define VIDEO_PLAY_SYMBOL_XSIZE 11
52 #define VIDEO_PLAY_SYMBOL_YSIZE 13
53 #define VIDEO_PAUSE_LABEL_XPOS  (VIDEO_DISPLAY2_XPOS)
54 #define VIDEO_PAUSE_LABEL_YPOS  (VIDEO_DISPLAY2_YPOS+20)
55 #define VIDEO_PAUSE_LABEL_XSIZE 35
56 #define VIDEO_PAUSE_LABEL_YSIZE 8
57 #define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS+35)
58 #define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
59 #define VIDEO_PAUSE_SYMBOL_XSIZE 17
60 #define VIDEO_PAUSE_SYMBOL_YSIZE 13
61 #define VIDEO_TIME_XPOS         (VIDEO_DISPLAY2_XPOS+38)
62 #define VIDEO_TIME_YPOS         (VIDEO_DISPLAY2_YPOS+14)
63 #define VIDEO_TIME_XSIZE        50
64 #define VIDEO_TIME_YSIZE        16
65
66 /* special */
67 #define VIDEO_PBEND_LABEL_XPOS  6
68 #define VIDEO_PBEND_LABEL_YPOS  220
69 #define VIDEO_PBEND_LABEL_XSIZE 35
70 #define VIDEO_PBEND_LABEL_YSIZE 30
71
72 #define ON_VIDEO_BUTTON(x,y)    ((x)>=(VX+VIDEO_CONTROL_XPOS) &&        \
73                                  (x)< (VX+VIDEO_CONTROL_XPOS +          \
74                                        VIDEO_CONTROL_XSIZE) &&          \
75                                  (y)>=(VY+VIDEO_CONTROL_YPOS) &&        \
76                                  (y)< (VY+VIDEO_CONTROL_YPOS +          \
77                                        VIDEO_CONTROL_YSIZE))
78 #define VIDEO_BUTTON(x)         (((x)-(VX+VIDEO_CONTROL_XPOS))/VIDEO_BUTTON_XSIZE)
79
80 #define VIDEO_STATE_OFF         (VIDEO_STATE_PLAY_OFF   |       \
81                                  VIDEO_STATE_REC_OFF    |       \
82                                  VIDEO_STATE_PAUSE_OFF  |       \
83                                  VIDEO_STATE_FFWD_OFF   |       \
84                                  VIDEO_STATE_PBEND_OFF  |       \
85                                  VIDEO_STATE_DATE_OFF   |       \
86                                  VIDEO_STATE_TIME_OFF)
87 #define VIDEO_PRESS_OFF         (VIDEO_PRESS_PLAY_OFF   |       \
88                                  VIDEO_PRESS_REC_OFF    |       \
89                                  VIDEO_PRESS_PAUSE_OFF  |       \
90                                  VIDEO_PRESS_STOP_OFF   |       \
91                                  VIDEO_PRESS_EJECT_OFF)
92 #define VIDEO_ALL_OFF           (VIDEO_STATE_OFF | VIDEO_PRESS_OFF)
93
94 #define VIDEO_STATE_ON          (VIDEO_STATE_PLAY_ON    |       \
95                                  VIDEO_STATE_REC_ON     |       \
96                                  VIDEO_STATE_PAUSE_ON   |       \
97                                  VIDEO_STATE_FFWD_ON    |       \
98                                  VIDEO_STATE_PBEND_ON   |       \
99                                  VIDEO_STATE_DATE_ON    |       \
100                                  VIDEO_STATE_TIME_ON)
101 #define VIDEO_PRESS_ON          (VIDEO_PRESS_PLAY_ON    |       \
102                                  VIDEO_PRESS_REC_ON     |       \
103                                  VIDEO_PRESS_PAUSE_ON   |       \
104                                  VIDEO_PRESS_STOP_ON    |       \
105                                  VIDEO_PRESS_EJECT_ON)
106 #define VIDEO_ALL_ON            (VIDEO_STATE_ON | VIDEO_PRESS_ON)
107
108 #define VIDEO_STATE             (VIDEO_STATE_ON | VIDEO_STATE_OFF)
109 #define VIDEO_PRESS             (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
110 #define VIDEO_ALL               (VIDEO_ALL_ON | VIDEO_ALL_OFF)
111
112
113 /* some positions in the sound control window */
114 #define SOUND_BUTTON_XSIZE      30
115 #define SOUND_BUTTON_YSIZE      30
116 #define SOUND_CONTROL_XPOS      5
117 #define SOUND_CONTROL_YPOS      245
118 #define SOUND_CONTROL_XSIZE      (3*SOUND_BUTTON_XSIZE)
119 #define SOUND_CONTROL_YSIZE      (1*SOUND_BUTTON_YSIZE)
120 #define SOUND_BUTTON_MUSIC_XPOS  (SOUND_CONTROL_XPOS + 0 * SOUND_BUTTON_XSIZE)
121 #define SOUND_BUTTON_LOOPS_XPOS  (SOUND_CONTROL_XPOS + 1 * SOUND_BUTTON_XSIZE)
122 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_CONTROL_XPOS + 2 * SOUND_BUTTON_XSIZE)
123 #define SOUND_BUTTON_ANY_YPOS    (SOUND_CONTROL_YPOS)
124
125 #define ON_SOUND_BUTTON(x,y)    ((x)>=(DX+SOUND_CONTROL_XPOS) &&        \
126                                  (x)< (DX+SOUND_CONTROL_XPOS +          \
127                                        SOUND_CONTROL_XSIZE) &&          \
128                                  (y)>=(DY+SOUND_CONTROL_YPOS) &&        \
129                                  (y)< (DY+SOUND_CONTROL_YPOS +          \
130                                        SOUND_CONTROL_YSIZE))
131 #define SOUND_BUTTON(x)         (((x)-(DX+SOUND_CONTROL_XPOS))/SOUND_BUTTON_XSIZE)
132
133 /* some positions in the game control window */
134 #define GAME_BUTTON_STOP_XPOS   (GAME_CONTROL_XPOS + 0 * GAME_BUTTON_XSIZE)
135 #define GAME_BUTTON_STOP_YPOS   (GAME_CONTROL_YPOS)
136 #define GAME_BUTTON_PAUSE_XPOS  (GAME_CONTROL_XPOS + 1 * GAME_BUTTON_XSIZE)
137 #define GAME_BUTTON_PAUSE_YPOS  (GAME_CONTROL_YPOS)
138 #define GAME_BUTTON_PLAY_XPOS   (GAME_CONTROL_XPOS + 2 * GAME_BUTTON_XSIZE)
139 #define GAME_BUTTON_PLAY_YPOS   (GAME_CONTROL_YPOS)
140 #define GAME_BUTTON_ANY_YPOS    (GAME_CONTROL_YPOS)
141
142 #define ON_GAME_BUTTON(x,y)     ((x)>=(DX+GAME_CONTROL_XPOS) && \
143                                  (x)< (DX+GAME_CONTROL_XPOS +           \
144                                        GAME_CONTROL_XSIZE) &&           \
145                                  (y)>=(DY+GAME_CONTROL_YPOS) && \
146                                  (y)< (DY+GAME_CONTROL_YPOS +           \
147                                        GAME_CONTROL_YSIZE))
148 #define GAME_BUTTON(x)          (((x)-(DX+GAME_CONTROL_XPOS))/GAME_BUTTON_XSIZE)
149
150 /* some positions in the asking window */
151 #define OK_BUTTON_XPOS          2
152 #define OK_BUTTON_YPOS          250
153 #define OK_BUTTON_GFX_YPOS      0
154 #define OK_BUTTON_XSIZE         46
155 #define OK_BUTTON_YSIZE         28
156 #define NO_BUTTON_XPOS          52
157 #define NO_BUTTON_YPOS          OK_BUTTON_YPOS
158 #define NO_BUTTON_XSIZE         OK_BUTTON_XSIZE
159 #define NO_BUTTON_YSIZE         OK_BUTTON_YSIZE
160 #define CONFIRM_BUTTON_XPOS     2
161 #define CONFIRM_BUTTON_GFX_YPOS 30
162 #define CONFIRM_BUTTON_YPOS     OK_BUTTON_YPOS
163 #define CONFIRM_BUTTON_XSIZE    96
164 #define CONFIRM_BUTTON_YSIZE    OK_BUTTON_YSIZE
165
166 #define ON_YESNO_BUTTON(x,y)    (((x)>=(DX+OK_BUTTON_XPOS) &&           \
167                                   (x)< (DX+OK_BUTTON_XPOS +             \
168                                         OK_BUTTON_XSIZE) &&             \
169                                   (y)>=(DY+OK_BUTTON_YPOS) &&           \
170                                   (y)< (DY+OK_BUTTON_YPOS +             \
171                                         OK_BUTTON_YSIZE)) ||            \
172                                  ((x)>=(DX+NO_BUTTON_XPOS) &&           \
173                                   (x)< (DX+NO_BUTTON_XPOS +             \
174                                         NO_BUTTON_XSIZE) &&             \
175                                   (y)>=(DY+NO_BUTTON_YPOS) &&           \
176                                   (y)< (DY+NO_BUTTON_YPOS +             \
177                                         NO_BUTTON_YSIZE)))
178 #define ON_CONFIRM_BUTTON(x,y)  (((x)>=(DX+CONFIRM_BUTTON_XPOS) &&      \
179                                   (x)< (DX+CONFIRM_BUTTON_XPOS +        \
180                                         CONFIRM_BUTTON_XSIZE) &&        \
181                                   (y)>=(DY+CONFIRM_BUTTON_YPOS) &&      \
182                                   (y)< (DY+CONFIRM_BUTTON_YPOS +        \
183                                         CONFIRM_BUTTON_YSIZE)))
184 #define YESNO_BUTTON(x)         (((x)-(DX+OK_BUTTON_XPOS))/OK_BUTTON_XSIZE)
185
186 /* some positions in the choose player window */
187 #define PLAYER_BUTTON_XSIZE     30
188 #define PLAYER_BUTTON_YSIZE     30
189 #define PLAYER_BUTTON_GFX_XPOS  5
190 #define PLAYER_BUTTON_GFX_YPOS  (215-30)
191 #define PLAYER_CONTROL_XPOS     (5 + PLAYER_BUTTON_XSIZE/2)
192 #define PLAYER_CONTROL_YPOS     (215 - PLAYER_BUTTON_YSIZE/2)
193 #define PLAYER_CONTROL_XSIZE    (2*PLAYER_BUTTON_XSIZE)
194 #define PLAYER_CONTROL_YSIZE    (2*PLAYER_BUTTON_YSIZE)
195 #define PLAYER_BUTTON_1_XPOS    (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE)
196 #define PLAYER_BUTTON_2_XPOS    (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE)
197 #define PLAYER_BUTTON_3_XPOS    (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE)
198 #define PLAYER_BUTTON_4_XPOS    (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE)
199 #define PLAYER_BUTTON_1_YPOS    (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE)
200 #define PLAYER_BUTTON_2_YPOS    (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE)
201 #define PLAYER_BUTTON_3_YPOS    (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE)
202 #define PLAYER_BUTTON_4_YPOS    (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE)
203
204 #define ON_PLAYER_BUTTON(x,y)   ((x)>=(DX+PLAYER_CONTROL_XPOS) &&       \
205                                  (x)< (DX+PLAYER_CONTROL_XPOS +         \
206                                        PLAYER_CONTROL_XSIZE) &&         \
207                                  (y)>=(DY+PLAYER_CONTROL_YPOS) &&       \
208                                  (y)< (DY+PLAYER_CONTROL_YPOS +         \
209                                        PLAYER_CONTROL_YSIZE))
210 #define PLAYER_BUTTON(x,y)      ((((x)-(DX+PLAYER_CONTROL_XPOS)) /      \
211                                   PLAYER_BUTTON_XSIZE) + 2 *            \
212                                  (((y)-(DY+PLAYER_CONTROL_YPOS)) /      \
213                                   PLAYER_BUTTON_YSIZE))
214
215
216 /* some definitions for the editor control window */
217
218 #define ON_EDIT_BUTTON(x,y)     (((x)>=(VX+ED_BUTTON_CTRL_XPOS) &&      \
219                                   (x)< (VX+ED_BUTTON_CTRL_XPOS +        \
220                                         ED_BUTTON_CTRL_XSIZE) &&        \
221                                   (y)>=(VY+ED_BUTTON_CTRL_YPOS) &&      \
222                                   (y)< (VY+ED_BUTTON_CTRL_YPOS +        \
223                                         ED_BUTTON_CTRL_YSIZE +          \
224                                         ED_BUTTON_FILL_YSIZE)) ||       \
225                                  ((x)>=(VX+ED_BUTTON_LEFT_XPOS) &&      \
226                                   (x)< (VX+ED_BUTTON_LEFT_XPOS +        \
227                                         ED_BUTTON_LEFT_XSIZE +          \
228                                         ED_BUTTON_UP_XSIZE +            \
229                                         ED_BUTTON_RIGHT_XSIZE) &&       \
230                                   (y)>=(VY+ED_BUTTON_LEFT_YPOS) &&      \
231                                   (y)< (VY+ED_BUTTON_LEFT_YPOS +        \
232                                         ED_BUTTON_LEFT_YSIZE)) ||       \
233                                  ((x)>=(VX+ED_BUTTON_UP_XPOS) &&        \
234                                   (x)< (VX+ED_BUTTON_UP_XPOS +          \
235                                         ED_BUTTON_UP_XSIZE) &&          \
236                                   (y)>=(VY+ED_BUTTON_UP_YPOS) &&        \
237                                   (y)< (VY+ED_BUTTON_UP_YPOS +          \
238                                         ED_BUTTON_UP_YSIZE +            \
239                                         ED_BUTTON_DOWN_YSIZE)))
240
241 #define ON_CTRL_BUTTON(x,y)     ((x)>=(VX+ED_BUTTON_EDIT_XPOS) &&       \
242                                  (x)< (VX+ED_BUTTON_EDIT_XPOS +         \
243                                        ED_BUTTON_EDIT_XSIZE) &&         \
244                                  (y)>=(VY+ED_BUTTON_EDIT_YPOS) &&       \
245                                  (y)< (VY+ED_BUTTON_EDIT_YPOS +         \
246                                        ED_BUTTON_EDIT_YSIZE +           \
247                                        ED_BUTTON_CLEAR_YSIZE +          \
248                                        ED_BUTTON_UNDO_YSIZE +           \
249                                        ED_BUTTON_EXIT_YSIZE))
250
251 #define ON_ELEM_BUTTON(x,y)     (((x)>=(DX+ED_BUTTON_EUP_XPOS) &&       \
252                                   (x)< (DX+ED_BUTTON_EUP_XPOS +         \
253                                         ED_BUTTON_EUP_XSIZE) &&         \
254                                   (y)>=(DY+ED_BUTTON_EUP_YPOS) &&       \
255                                   (y)< (DY+ED_BUTTON_EUP_YPOS +         \
256                                         ED_BUTTON_EUP_YSIZE)) ||        \
257                                  ((x)>=(DX+ED_BUTTON_EDOWN_XPOS) &&     \
258                                   (x)< (DX+ED_BUTTON_EDOWN_XPOS +       \
259                                         ED_BUTTON_EDOWN_XSIZE) &&       \
260                                   (y)>=(DY+ED_BUTTON_EDOWN_YPOS) &&     \
261                                   (y)< (DY+ED_BUTTON_EDOWN_YPOS +       \
262                                         ED_BUTTON_EDOWN_YSIZE)) ||      \
263                                  ((x)>=(DX+ED_BUTTON_ELEM_XPOS) &&      \
264                                   (x)< (DX+ED_BUTTON_ELEM_XPOS +        \
265                                         MAX_ELEM_X*ED_BUTTON_ELEM_XSIZE) && \
266                                   (y)>=(DY+ED_BUTTON_ELEM_YPOS) &&      \
267                                   (y)< (DY+ED_BUTTON_ELEM_YPOS +        \
268                                         MAX_ELEM_Y*ED_BUTTON_ELEM_YSIZE)))
269
270 #define ON_COUNT_BUTTON(x,y)    (((((x)>=ED_COUNT_GADGET_XPOS &&        \
271                                     (x)<(ED_COUNT_GADGET_XPOS +         \
272                                          ED_BUTTON_MINUS_XSIZE)) ||     \
273                                    ((x)>=(ED_COUNT_GADGET_XPOS +        \
274                                           (ED_BUTTON_PLUS_XPOS -        \
275                                            ED_BUTTON_MINUS_XPOS)) &&    \
276                                     (x)<(ED_COUNT_GADGET_XPOS +         \
277                                          (ED_BUTTON_PLUS_XPOS -         \
278                                           ED_BUTTON_MINUS_XPOS) +       \
279                                          ED_BUTTON_PLUS_XSIZE))) &&     \
280                                   ((y)>=ED_COUNT_GADGET_YPOS &&         \
281                                    (y)<(ED_COUNT_GADGET_YPOS +          \
282                                         16*ED_COUNT_GADGET_YSIZE)) &&   \
283                                   (((y)-ED_COUNT_GADGET_YPOS) %         \
284                                    ED_COUNT_GADGET_YSIZE) <             \
285                                   ED_BUTTON_MINUS_YSIZE) ||             \
286                                  ((((x)>=ED_SIZE_GADGET_XPOS &&         \
287                                     (x)<(ED_SIZE_GADGET_XPOS +          \
288                                          ED_BUTTON_MINUS_XSIZE)) ||     \
289                                    ((x)>=(ED_SIZE_GADGET_XPOS +         \
290                                           (ED_BUTTON_PLUS_XPOS -        \
291                                            ED_BUTTON_MINUS_XPOS)) &&    \
292                                     (x)<(ED_SIZE_GADGET_XPOS +          \
293                                          (ED_BUTTON_PLUS_XPOS -         \
294                                           ED_BUTTON_MINUS_XPOS) +       \
295                                          ED_BUTTON_PLUS_XSIZE))) &&     \
296                                   ((y)>=ED_SIZE_GADGET_YPOS &&          \
297                                    (y)<(ED_SIZE_GADGET_YPOS +           \
298                                         2*ED_SIZE_GADGET_YSIZE)) &&     \
299                                   (((y)-ED_SIZE_GADGET_YPOS) %          \
300                                    ED_SIZE_GADGET_YSIZE) <              \
301                                   ED_BUTTON_MINUS_YSIZE))
302
303 #define EDIT_BUTTON(x,y)        (((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
304                                          ED_BUTTON_CTRL_YSIZE)) ? 0 :   \
305                                  ((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
306                                          ED_BUTTON_CTRL_YSIZE +         \
307                                          ED_BUTTON_FILL_YSIZE)) ? 1 :   \
308                                  ((x) < (VX + ED_BUTTON_LEFT_XPOS +     \
309                                          ED_BUTTON_LEFT_XSIZE) ? 2 :    \
310                                   (x) > (VX + ED_BUTTON_LEFT_XPOS +     \
311                                          ED_BUTTON_LEFT_XSIZE +         \
312                                          ED_BUTTON_UP_XSIZE) ? 5 :      \
313                                   3+(((y)-(VY + ED_BUTTON_CTRL_YPOS +   \
314                                            ED_BUTTON_CTRL_YSIZE +       \
315                                            ED_BUTTON_FILL_YSIZE)) /     \
316                                      ED_BUTTON_UP_YSIZE)))
317
318 #define CTRL_BUTTON(x,y)        (((y) < (VY + ED_BUTTON_EDIT_YPOS +     \
319                                          ED_BUTTON_EDIT_YSIZE)) ? 0 :   \
320                                  1+(((y)-(VY + ED_BUTTON_EDIT_YPOS +    \
321                                          ED_BUTTON_EDIT_YSIZE)) /       \
322                                     ED_BUTTON_CLEAR_YSIZE))
323
324 #define ELEM_BUTTON(x,y)        (((y) < (DY + ED_BUTTON_EUP_YPOS +      \
325                                          ED_BUTTON_EUP_YSIZE)) ? 0 :    \
326                                  ((y) > (DY + ED_BUTTON_EDOWN_YPOS)) ? 1 : \
327                                  2+(((y) - (DY + ED_BUTTON_ELEM_YPOS)) /   \
328                                  ED_BUTTON_ELEM_YSIZE)*MAX_ELEM_X +     \
329                                  ((x) - (DX + ED_BUTTON_ELEM_XPOS)) /   \
330                                  ED_BUTTON_ELEM_XSIZE)
331
332 #define COUNT_BUTTON(x,y)       ((x) < ED_SIZE_GADGET_XPOS ?            \
333                                  ((((y) - ED_COUNT_GADGET_YPOS) /       \
334                                    ED_COUNT_GADGET_YSIZE)*2 +           \
335                                   ((x) < (ED_COUNT_GADGET_XPOS +        \
336                                           ED_BUTTON_MINUS_XSIZE) ? 0 : 1)) : \
337                                  32+((((y) - ED_SIZE_GADGET_YPOS) /     \
338                                       ED_SIZE_GADGET_YSIZE)*2 +         \
339                                      ((x) < (ED_SIZE_GADGET_XPOS +      \
340                                              ED_BUTTON_MINUS_XSIZE) ? 0 : 1)))
341
342 /****************************************************************/
343 /********** drawing buttons and corresponding displays **********/
344 /****************************************************************/
345
346 void OLD_DrawVideoDisplay(unsigned long state, unsigned long value)
347 {
348   int i;
349   int part_label = 0, part_symbol = 1;
350   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
351   static char *monatsname[12] =
352   {
353     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
354     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
355   };
356   static int video_pos[5][2][4] =
357   {
358     {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
359        VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE },
360      { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
361        VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }},
362
363     {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
364        VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE },
365      { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
366        VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }},
367
368     {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
369        VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE },
370      { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
371        VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }},
372
373     {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
374        VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE },
375      { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
376        VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }},
377
378     {{ 0,0,
379        0,0 },
380      { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
381        VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }}
382   };
383
384   if (state & VIDEO_STATE_PBEND_OFF)
385   {
386     int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
387
388     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
389               cx + VIDEO_REC_LABEL_XPOS,
390               cy + VIDEO_REC_LABEL_YPOS,
391               VIDEO_PBEND_LABEL_XSIZE,
392               VIDEO_PBEND_LABEL_YSIZE,
393               VX + VIDEO_REC_LABEL_XPOS,
394               VY + VIDEO_REC_LABEL_YPOS);
395   }
396
397   for(i=0;i<10;i++)
398   {
399     if (state & (1<<i))
400     {
401       int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
402
403       if (i%2)                  /* i ungerade => STATE_ON / PRESS_OFF */
404         cx = DOOR_GFX_PAGEX4;
405       else
406         cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
407
408       if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
409         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
410                   cx + video_pos[pos][part_label][xpos],
411                   cy + video_pos[pos][part_label][ypos],
412                   video_pos[pos][part_label][xsize],
413                   video_pos[pos][part_label][ysize],
414                   VX + video_pos[pos][part_label][xpos],
415                   VY + video_pos[pos][part_label][ypos]);
416       if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
417         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
418                   cx + video_pos[pos][part_symbol][xpos],
419                   cy + video_pos[pos][part_symbol][ypos],
420                   video_pos[pos][part_symbol][xsize],
421                   video_pos[pos][part_symbol][ysize],
422                   VX + video_pos[pos][part_symbol][xpos],
423                   VY + video_pos[pos][part_symbol][ypos]);
424     }
425   }
426
427   if (state & VIDEO_STATE_FFWD_ON)
428   {
429     int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
430
431     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
432               cx + VIDEO_PLAY_SYMBOL_XPOS,
433               cy + VIDEO_PLAY_SYMBOL_YPOS,
434               VIDEO_PLAY_SYMBOL_XSIZE - 2,
435               VIDEO_PLAY_SYMBOL_YSIZE,
436               VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
437               VY + VIDEO_PLAY_SYMBOL_YPOS);
438   }
439
440   if (state & VIDEO_STATE_PBEND_ON)
441   {
442     int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
443
444     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
445               cx + VIDEO_PBEND_LABEL_XPOS,
446               cy + VIDEO_PBEND_LABEL_YPOS,
447               VIDEO_PBEND_LABEL_XSIZE,
448               VIDEO_PBEND_LABEL_YSIZE,
449               VX + VIDEO_REC_LABEL_XPOS,
450               VY + VIDEO_REC_LABEL_YPOS);
451   }
452
453   if (state & VIDEO_STATE_DATE_ON)
454   {
455     int tag = value % 100;
456     int monat = (value/100) % 100;
457     int jahr = (value/10000);
458
459     DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
460              int2str(tag,2),FS_SMALL,FC_SPECIAL1);
461     DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
462              monatsname[monat],FS_SMALL,FC_SPECIAL1);
463     DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
464              int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
465   }
466
467   if (state & VIDEO_STATE_TIME_ON)
468   {
469     int min = value / 60;
470     int sec = value % 60;
471
472     DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
473              int2str(min,2),FS_SMALL,FC_SPECIAL1);
474     DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
475              int2str(sec,2),FS_SMALL,FC_SPECIAL1);
476   }
477
478   if (state & VIDEO_STATE_DATE)
479     redraw_mask |= REDRAW_VIDEO_1;
480   if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
481     redraw_mask |= REDRAW_VIDEO_2;
482   if (state & VIDEO_PRESS)
483     redraw_mask |= REDRAW_VIDEO_3;
484 }
485
486 void DrawVideoDisplay(unsigned long state, unsigned long value)
487 {
488   int i;
489   int part_label = 0, part_symbol = 1;
490   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
491   static char *monatsname[12] =
492   {
493     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
494     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
495   };
496   static int video_pos[10][2][4] =
497   {
498     {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
499        VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE },
500      { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
501        VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }},
502
503     {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
504        VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE },
505      { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
506        VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }},
507
508     {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
509        VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE },
510      { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
511        VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }},
512
513     {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
514        VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE },
515      { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
516        VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }},
517
518     {{ 0,0,
519        0,0 },
520      { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
521        VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }},
522
523     {{ VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS,
524        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
525      { 0,0,
526        0,0 }},
527
528     {{ VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS,
529        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
530      { 0,0,
531        0,0 }},
532
533     {{ VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS,
534        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
535      { 0,0,
536        0,0 }},
537
538     {{ VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS,
539        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
540      { 0,0,
541        0,0 }},
542
543     {{ VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS,
544        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
545      { 0,0,
546        0,0 }}
547   };
548
549   if (state & VIDEO_STATE_PBEND_OFF)
550   {
551     int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
552
553     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
554               cx + VIDEO_REC_LABEL_XPOS,
555               cy + VIDEO_REC_LABEL_YPOS,
556               VIDEO_PBEND_LABEL_XSIZE,
557               VIDEO_PBEND_LABEL_YSIZE,
558               VX + VIDEO_REC_LABEL_XPOS,
559               VY + VIDEO_REC_LABEL_YPOS);
560   }
561
562   for(i=0;i<20;i++)
563   {
564     if (state & (1<<i))
565     {
566       int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
567
568       if (i%2)                  /* i ungerade => STATE_ON / PRESS_OFF */
569         cx = DOOR_GFX_PAGEX4;
570       else
571         cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
572
573       if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
574         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
575                   cx + video_pos[pos][part_label][xpos],
576                   cy + video_pos[pos][part_label][ypos],
577                   video_pos[pos][part_label][xsize],
578                   video_pos[pos][part_label][ysize],
579                   VX + video_pos[pos][part_label][xpos],
580                   VY + video_pos[pos][part_label][ypos]);
581       if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
582         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
583                   cx + video_pos[pos][part_symbol][xpos],
584                   cy + video_pos[pos][part_symbol][ypos],
585                   video_pos[pos][part_symbol][xsize],
586                   video_pos[pos][part_symbol][ysize],
587                   VX + video_pos[pos][part_symbol][xpos],
588                   VY + video_pos[pos][part_symbol][ypos]);
589     }
590   }
591
592   if (state & VIDEO_STATE_FFWD_ON)
593   {
594     int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
595
596     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
597               cx + VIDEO_PLAY_SYMBOL_XPOS,
598               cy + VIDEO_PLAY_SYMBOL_YPOS,
599               VIDEO_PLAY_SYMBOL_XSIZE - 2,
600               VIDEO_PLAY_SYMBOL_YSIZE,
601               VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
602               VY + VIDEO_PLAY_SYMBOL_YPOS);
603   }
604
605   if (state & VIDEO_STATE_PBEND_ON)
606   {
607     int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
608
609     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
610               cx + VIDEO_PBEND_LABEL_XPOS,
611               cy + VIDEO_PBEND_LABEL_YPOS,
612               VIDEO_PBEND_LABEL_XSIZE,
613               VIDEO_PBEND_LABEL_YSIZE,
614               VX + VIDEO_REC_LABEL_XPOS,
615               VY + VIDEO_REC_LABEL_YPOS);
616   }
617
618   if (state & VIDEO_STATE_DATE_ON)
619   {
620     int tag = value % 100;
621     int monat = (value/100) % 100;
622     int jahr = (value/10000);
623
624     DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
625              int2str(tag,2),FS_SMALL,FC_SPECIAL1);
626     DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
627              monatsname[monat],FS_SMALL,FC_SPECIAL1);
628     DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
629              int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
630   }
631
632   if (state & VIDEO_STATE_TIME_ON)
633   {
634     int min = value / 60;
635     int sec = value % 60;
636
637     DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
638              int2str(min,2),FS_SMALL,FC_SPECIAL1);
639     DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
640              int2str(sec,2),FS_SMALL,FC_SPECIAL1);
641   }
642
643   if (state & VIDEO_STATE_DATE)
644     redraw_mask |= REDRAW_VIDEO_1;
645   if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
646     redraw_mask |= REDRAW_VIDEO_2;
647   if (state & VIDEO_PRESS)
648     redraw_mask |= REDRAW_VIDEO_3;
649 }
650
651 void DrawCompleteVideoDisplay()
652 {
653   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
654             DOOR_GFX_PAGEX3,DOOR_GFX_PAGEY2, VXSIZE,VYSIZE, VX,VY);
655   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
656             DOOR_GFX_PAGEX4+VIDEO_CONTROL_XPOS,
657             DOOR_GFX_PAGEY2+VIDEO_CONTROL_YPOS,
658             VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
659             VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
660
661   DrawVideoDisplay(VIDEO_ALL_OFF,0);
662   if (tape.date && tape.length)
663   {
664     DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
665     DrawVideoDisplay(VIDEO_STATE_TIME_ON,tape.length_seconds);
666   }
667
668   XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
669             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
670 }
671
672 void DrawSoundDisplay(unsigned long state)
673 {
674   int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
675
676   pos = (state & BUTTON_SOUND_MUSIC ? SOUND_BUTTON_MUSIC_XPOS :
677          state & BUTTON_SOUND_LOOPS ? SOUND_BUTTON_LOOPS_XPOS :
678          SOUND_BUTTON_SIMPLE_XPOS);
679
680   if (state & BUTTON_ON)
681     cy -= SOUND_BUTTON_YSIZE;
682
683   if (state & BUTTON_PRESSED)
684     cx = DOOR_GFX_PAGEX3;
685
686   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
687             cx + pos,cy + SOUND_BUTTON_ANY_YPOS,
688             SOUND_BUTTON_XSIZE,SOUND_BUTTON_YSIZE,
689             DX + pos,DY + SOUND_BUTTON_ANY_YPOS);
690
691   redraw_mask |= REDRAW_DOOR_1;
692 }
693
694 void DrawGameButton(unsigned long state)
695 {
696   int pos, cx = DOOR_GFX_PAGEX4, cy = -GAME_BUTTON_YSIZE;
697
698   pos = (state & BUTTON_GAME_STOP ? GAME_BUTTON_STOP_XPOS :
699          state & BUTTON_GAME_PAUSE ? GAME_BUTTON_PAUSE_XPOS :
700          GAME_BUTTON_PLAY_XPOS);
701
702   if (state & BUTTON_PRESSED)
703     cx = DOOR_GFX_PAGEX3;
704
705   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
706             cx + pos,cy + GAME_BUTTON_ANY_YPOS,
707             GAME_BUTTON_XSIZE,GAME_BUTTON_YSIZE,
708             DX + pos,DY + GAME_BUTTON_ANY_YPOS);
709
710   redraw_mask |= REDRAW_DOOR_1;
711 }
712
713 void DrawYesNoButton(unsigned long state, int mode)
714 {
715   Drawable dest_drawto;
716   int dest_xoffset, dest_yoffset;
717   int xpos, cx = DOOR_GFX_PAGEX4;
718
719   if (mode == DB_INIT)
720   {
721     dest_drawto = pix[PIX_DB_DOOR];
722     dest_xoffset = DOOR_GFX_PAGEX1;
723     dest_yoffset = 0;
724   }
725   else
726   {
727     dest_drawto = drawto;
728     dest_xoffset = DX;
729     dest_yoffset = DY;
730   }
731
732   xpos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS);
733
734   if (state & BUTTON_PRESSED)
735     cx = DOOR_GFX_PAGEX3;
736
737   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
738             cx + xpos, OK_BUTTON_GFX_YPOS,
739             OK_BUTTON_XSIZE, OK_BUTTON_YSIZE,
740             dest_xoffset + xpos, dest_yoffset + OK_BUTTON_YPOS);
741
742   redraw_mask |= REDRAW_DOOR_1;
743 }
744
745 void DrawConfirmButton(unsigned long state, int mode)
746 {
747   Drawable dest_drawto;
748   int dest_xoffset, dest_yoffset;
749   int cx = DOOR_GFX_PAGEX4;
750
751   if (mode == DB_INIT)
752   {
753     dest_drawto = pix[PIX_DB_DOOR];
754     dest_xoffset = DOOR_GFX_PAGEX1;
755     dest_yoffset = 0;
756   }
757   else
758   {
759     dest_drawto = drawto;
760     dest_xoffset = DX;
761     dest_yoffset = DY;
762   }
763
764   if (state & BUTTON_PRESSED)
765     cx = DOOR_GFX_PAGEX3;
766
767   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
768             cx + CONFIRM_BUTTON_XPOS, CONFIRM_BUTTON_GFX_YPOS,
769             CONFIRM_BUTTON_XSIZE, CONFIRM_BUTTON_YSIZE,
770             dest_xoffset + CONFIRM_BUTTON_XPOS,
771             dest_yoffset + CONFIRM_BUTTON_YPOS);
772
773   redraw_mask |= REDRAW_DOOR_1;
774 }
775
776 void DrawPlayerButton(unsigned long state, int mode)
777 {
778   Drawable dest_drawto;
779   int dest_xoffset, dest_yoffset;
780   int graphic = GFX_SPIELER1;   /* default */
781   int graphic_offset = (PLAYER_BUTTON_XSIZE - TILEX/2)/2;
782   int xpos, ypos;
783   int cx = DOOR_GFX_PAGEX4, cy = 0;
784
785   if (mode == DB_INIT)
786   {
787     dest_drawto = pix[PIX_DB_DOOR];
788     dest_xoffset = DOOR_GFX_PAGEX1;
789     dest_yoffset = 0;
790   }
791   else
792   {
793     dest_drawto = drawto;
794     dest_xoffset = DX;
795     dest_yoffset = DY;
796   }
797
798   if (state & BUTTON_PLAYER_1)
799     graphic = GFX_SPIELER1;
800   else if (state & BUTTON_PLAYER_2)
801     graphic = GFX_SPIELER2;
802   else if (state & BUTTON_PLAYER_3)
803     graphic = GFX_SPIELER3;
804   else if (state & BUTTON_PLAYER_4)
805     graphic = GFX_SPIELER4;
806
807   xpos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_3 ?
808           PLAYER_BUTTON_1_XPOS : PLAYER_BUTTON_2_XPOS);
809   ypos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_2 ?
810           PLAYER_BUTTON_1_YPOS : PLAYER_BUTTON_3_YPOS);
811
812   if (state & BUTTON_PRESSED)
813   {
814     cx = DOOR_GFX_PAGEX3;
815     graphic_offset += 1;
816   }
817
818   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
819             cx + PLAYER_BUTTON_GFX_XPOS, cy + PLAYER_BUTTON_GFX_YPOS,
820             PLAYER_BUTTON_XSIZE, PLAYER_BUTTON_YSIZE,
821             dest_xoffset + xpos, dest_yoffset + ypos);
822   DrawMiniGraphicExt(dest_drawto,gc,
823                      dest_xoffset + xpos + graphic_offset,
824                      dest_yoffset + ypos + graphic_offset,
825                      graphic);
826
827   redraw_mask |= REDRAW_DOOR_1;
828 }
829
830 /* several buttons in the level editor */
831
832 void DrawEditButton(unsigned long state)
833 {
834   int i;
835   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
836   int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY2;
837   static int edit_pos[6][4] =
838   {
839    {ED_BUTTON_CTRL_XPOS,ED_BUTTON_CTRL_YPOS,
840     ED_BUTTON_CTRL_XSIZE,ED_BUTTON_CTRL_YSIZE},
841
842    {ED_BUTTON_FILL_XPOS,ED_BUTTON_FILL_YPOS,
843     ED_BUTTON_FILL_XSIZE,ED_BUTTON_FILL_YSIZE},
844
845    {ED_BUTTON_LEFT_XPOS,ED_BUTTON_LEFT_YPOS,
846     ED_BUTTON_LEFT_XSIZE,ED_BUTTON_LEFT_YSIZE},
847
848    {ED_BUTTON_UP_XPOS,ED_BUTTON_UP_YPOS,
849     ED_BUTTON_UP_XSIZE,ED_BUTTON_UP_YSIZE},
850
851    {ED_BUTTON_DOWN_XPOS,ED_BUTTON_DOWN_YPOS,
852     ED_BUTTON_DOWN_XSIZE,ED_BUTTON_DOWN_YSIZE},
853
854    {ED_BUTTON_RIGHT_XPOS,ED_BUTTON_RIGHT_YPOS,
855     ED_BUTTON_RIGHT_XSIZE,ED_BUTTON_RIGHT_YSIZE}
856   };
857
858   if (state & ED_BUTTON_PRESSED)
859     cx = DOOR_GFX_PAGEX5;
860
861   for(i=0;i<6;i++)
862   {
863     if (state & (1<<i))
864       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
865                 cx + edit_pos[i][xpos],
866                 cy + edit_pos[i][ypos],
867                 edit_pos[i][xsize],
868                 edit_pos[i][ysize],
869                 VX + edit_pos[i][xpos],
870                 VY + edit_pos[i][ypos]);
871   }
872
873   redraw_mask |= REDRAW_DOOR_2;
874 }
875
876 void DrawCtrlButton(unsigned long state)
877 {
878   int i;
879   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
880   int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY1+80;
881   static int edit_pos[4][4] =
882   {
883    {ED_BUTTON_EDIT_XPOS,ED_BUTTON_EDIT_YPOS,
884     ED_BUTTON_EDIT_XSIZE,ED_BUTTON_EDIT_YSIZE},
885
886    {ED_BUTTON_CLEAR_XPOS,ED_BUTTON_CLEAR_YPOS,
887     ED_BUTTON_CLEAR_XSIZE,ED_BUTTON_CLEAR_YSIZE},
888
889    {ED_BUTTON_UNDO_XPOS,ED_BUTTON_UNDO_YPOS,
890     ED_BUTTON_UNDO_XSIZE,ED_BUTTON_UNDO_YSIZE},
891
892    {ED_BUTTON_EXIT_XPOS,ED_BUTTON_EXIT_YPOS,
893     ED_BUTTON_EXIT_XSIZE,ED_BUTTON_EXIT_YSIZE}
894   };
895
896   if (state & ED_BUTTON_PRESSED)
897     cx = DOOR_GFX_PAGEX3;
898
899   for(i=0;i<4;i++)
900   {
901     if (state & (1<<(i+6)))
902       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
903                 cx + edit_pos[i][xpos],
904                 cy + edit_pos[i][ypos],
905                 edit_pos[i][xsize],
906                 edit_pos[i][ysize],
907                 VX + edit_pos[i][xpos],
908                 VY + edit_pos[i][ypos]);
909   }
910
911   redraw_mask |= REDRAW_DOOR_2;
912 }
913
914 void DrawElemButton(int button_nr, int button_state)
915 {
916   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
917   int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
918   int from_x, from_y, to_x,to_y, size_x, size_y;
919   static int edit_pos[3][4] =
920   {
921    {ED_BUTTON_EUP_XPOS,ED_BUTTON_EUP_YPOS,
922     ED_BUTTON_EUP_XSIZE,ED_BUTTON_EUP_YSIZE},
923
924    {ED_BUTTON_EDOWN_XPOS,ED_BUTTON_EDOWN_YPOS,
925     ED_BUTTON_EDOWN_XSIZE,ED_BUTTON_EDOWN_YSIZE},
926
927    {ED_BUTTON_ELEM_XPOS,ED_BUTTON_ELEM_YPOS,
928     ED_BUTTON_ELEM_XSIZE,ED_BUTTON_ELEM_YSIZE}
929   };
930
931   if (button_nr<ED_BUTTON_ELEM)
932   {
933     int pos = button_nr;
934
935     from_x = cx + edit_pos[pos][xpos];
936     from_y = cy + edit_pos[pos][ypos];
937     size_x = edit_pos[pos][xsize];
938     size_y = edit_pos[pos][ysize];
939     to_x   = DX + edit_pos[pos][xpos];
940     to_y   = DY + edit_pos[pos][ypos];
941
942     if (button_state & ED_BUTTON_PRESSED)
943     {
944       if (button_nr==ED_BUTTON_EUP)
945         from_y = cy + ED_BUTTON_EUP_Y2POS;
946       else
947         from_y = cy + ED_BUTTON_EDOWN_Y2POS;
948     }
949
950     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
951               from_x,from_y, size_x,size_y, to_x,to_y);
952   }
953   else
954   {
955     int pos = ED_BUTTON_ELEM;
956     int elem_pos = button_nr-ED_BUTTON_ELEM;
957     int x = elem_pos % MAX_ELEM_X;
958     int y = elem_pos / MAX_ELEM_X;
959     int graphic;
960     int shift = 0;
961
962     if (elem_pos+element_shift < elements_in_list)
963       graphic = el2gfx(editor_element[elem_pos+element_shift]);
964     else
965       graphic = GFX_LEERRAUM;
966
967     from_x = cx + edit_pos[pos][xpos];
968     from_y = cy + edit_pos[pos][ypos];
969     size_x = edit_pos[pos][xsize];
970     size_y = edit_pos[pos][ysize];
971     to_x   = DX + edit_pos[pos][xpos] + x * ED_BUTTON_ELEM_XSIZE;
972     to_y   = DY + edit_pos[pos][ypos] + y * ED_BUTTON_ELEM_YSIZE;
973
974     if (button_state & ED_BUTTON_PRESSED)
975     {
976       from_y = ED_BUTTON_ELEM_Y2POS;
977       shift = 1;
978     }
979
980     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
981               from_x,from_y, size_x,size_y, to_x,to_y);
982
983     DrawMiniGraphicExt(drawto,gc,
984                        DX+ED_BUTTON_ELEM_XPOS+3+shift + 
985                        (elem_pos % MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
986                        DY+ED_BUTTON_ELEM_YPOS+3+shift +
987                        (elem_pos / MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
988                        graphic);
989   }
990
991   redraw_mask |= REDRAW_DOOR_1;
992 }
993
994 void DrawCountButton(int button_nr, int button_state)
995 {
996   int from_x, from_y, to_x,to_y, size_x, size_y;
997
998   from_x =
999     DOOR_GFX_PAGEX4+(button_nr%2 ? ED_BUTTON_PLUS_XPOS : ED_BUTTON_MINUS_XPOS);
1000   from_y = DOOR_GFX_PAGEY1 + ED_BUTTON_MINUS_YPOS;
1001   size_x = ED_BUTTON_MINUS_XSIZE;
1002   size_y = ED_BUTTON_MINUS_YSIZE;
1003   to_x = (button_nr<32 ? ED_COUNT_GADGET_XPOS : ED_SIZE_GADGET_XPOS);
1004   if (button_nr % 2)
1005     to_x += (ED_BUTTON_PLUS_XPOS - ED_BUTTON_MINUS_XPOS);
1006   to_y = (button_nr<32 ? ED_COUNT_GADGET_YPOS : ED_SIZE_GADGET_YPOS) +
1007     ((button_nr<32 ? button_nr : button_nr-32)/2)*ED_COUNT_GADGET_YSIZE;
1008
1009   if (button_state & ED_BUTTON_PRESSED)
1010     from_x -= DXSIZE;
1011
1012   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1013             from_x,from_y, size_x,size_y, to_x,to_y);
1014   XCopyArea(display,pix[PIX_DOOR],window,gc,
1015             from_x,from_y, size_x,size_y, to_x,to_y);
1016 }
1017
1018 /**********************************************************************/
1019 /********** checking buttons (and redrawing them, if needed) **********/
1020 /**********************************************************************/
1021
1022 int CheckVideoButtons(int mx, int my, int button)
1023 {
1024   int return_code = 0;
1025   static int choice = -1;
1026   static boolean pressed = FALSE;
1027   static int video_button[5] =
1028   {
1029     VIDEO_PRESS_EJECT_ON,
1030     VIDEO_PRESS_STOP_ON,
1031     VIDEO_PRESS_PAUSE_ON,
1032     VIDEO_PRESS_REC_ON,
1033     VIDEO_PRESS_PLAY_ON
1034   };
1035
1036   if (button)
1037   {
1038     if (!motion_status)         /* Maustaste neu gedrückt */
1039     {
1040       if (ON_VIDEO_BUTTON(mx,my))
1041       {
1042         choice = VIDEO_BUTTON(mx);
1043         pressed = TRUE;
1044         DrawVideoDisplay(video_button[choice],0);
1045       }
1046     }
1047     else                        /* Mausbewegung bei gedrückter Maustaste */
1048     {
1049       if ((!ON_VIDEO_BUTTON(mx,my) || VIDEO_BUTTON(mx)!=choice) &&
1050           choice>=0 && pressed)
1051       {
1052         pressed = FALSE;
1053         DrawVideoDisplay(video_button[choice]<<1,0);
1054       }
1055       else if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && !pressed)
1056       {
1057         pressed = TRUE;
1058         DrawVideoDisplay(video_button[choice],0);
1059       }
1060     }
1061   }
1062   else                          /* Maustaste wieder losgelassen */
1063   {
1064     if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && pressed)
1065     {
1066       DrawVideoDisplay(video_button[choice]<<1,0);
1067       return_code = choice+1;
1068       choice = -1;
1069       pressed = FALSE;
1070     }
1071     else
1072     {
1073       choice = -1;
1074       pressed = FALSE;
1075     }
1076   }
1077
1078   BackToFront();
1079   return(return_code);
1080 }
1081
1082 int CheckSoundButtons(int mx, int my, int button)
1083 {
1084   int return_code = 0;
1085   static int choice = -1;
1086   static boolean pressed = FALSE;
1087   int sound_state[3];
1088
1089   sound_state[0] = BUTTON_SOUND_MUSIC  | (BUTTON_ON * setup.sound_music);
1090   sound_state[1] = BUTTON_SOUND_LOOPS  | (BUTTON_ON * setup.sound_loops);
1091   sound_state[2] = BUTTON_SOUND_SIMPLE | (BUTTON_ON * setup.sound_simple);
1092
1093   if (button)
1094   {
1095     if (!motion_status)         /* Maustaste neu gedrückt */
1096     {
1097       if (ON_SOUND_BUTTON(mx,my))
1098       {
1099         choice = SOUND_BUTTON(mx);
1100         pressed = TRUE;
1101         DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
1102       }
1103     }
1104     else                        /* Mausbewegung bei gedrückter Maustaste */
1105     {
1106       if ((!ON_SOUND_BUTTON(mx,my) || SOUND_BUTTON(mx)!=choice) &&
1107           choice>=0 && pressed)
1108       {
1109         pressed = FALSE;
1110         DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
1111       }
1112       else if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && !pressed)
1113       {
1114         pressed = TRUE;
1115         DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
1116       }
1117     }
1118   }
1119   else                          /* Maustaste wieder losgelassen */
1120   {
1121     if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && pressed)
1122     {
1123       DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
1124       return_code = 1<<choice;
1125       choice = -1;
1126       pressed = FALSE;
1127     }
1128     else
1129     {
1130       choice = -1;
1131       pressed = FALSE;
1132     }
1133   }
1134
1135   BackToFront();
1136   return(return_code);
1137 }
1138
1139 int CheckGameButtons(int mx, int my, int button)
1140 {
1141   int return_code = 0;
1142   static int choice = -1;
1143   static boolean pressed = FALSE;
1144   int game_state[3] =
1145   {
1146     BUTTON_GAME_STOP,
1147     BUTTON_GAME_PAUSE,
1148     BUTTON_GAME_PLAY
1149   };
1150
1151   if (button)
1152   {
1153     if (!motion_status)         /* Maustaste neu gedrückt */
1154     {
1155       if (ON_GAME_BUTTON(mx,my))
1156       {
1157         choice = GAME_BUTTON(mx);
1158         pressed = TRUE;
1159         DrawGameButton(game_state[choice] | BUTTON_PRESSED);
1160       }
1161     }
1162     else                        /* Mausbewegung bei gedrückter Maustaste */
1163     {
1164       if ((!ON_GAME_BUTTON(mx,my) || GAME_BUTTON(mx)!=choice) &&
1165           choice>=0 && pressed)
1166       {
1167         pressed = FALSE;
1168         DrawGameButton(game_state[choice] | BUTTON_RELEASED);
1169       }
1170       else if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && !pressed)
1171       {
1172         pressed = TRUE;
1173         DrawGameButton(game_state[choice] | BUTTON_PRESSED);
1174       }
1175     }
1176   }
1177   else                          /* Maustaste wieder losgelassen */
1178   {
1179     if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && pressed)
1180     {
1181       DrawGameButton(game_state[choice] | BUTTON_RELEASED);
1182       return_code = 1<<choice;
1183       choice = -1;
1184       pressed = FALSE;
1185     }
1186     else
1187     {
1188       choice = -1;
1189       pressed = FALSE;
1190     }
1191   }
1192
1193   BackToFront();
1194   return(return_code);
1195 }
1196
1197 int CheckYesNoButtons(int mx, int my, int button)
1198 {
1199   int return_code = 0;
1200   static int choice = -1;
1201   static boolean pressed = FALSE;
1202   static int yesno_button[5] =
1203   {
1204     BUTTON_OK,
1205     BUTTON_NO
1206   };
1207
1208   if (button)
1209   {
1210     if (!motion_status)         /* Maustaste neu gedrückt */
1211     {
1212       if (ON_YESNO_BUTTON(mx,my))
1213       {
1214         choice = YESNO_BUTTON(mx);
1215         pressed = TRUE;
1216         DrawYesNoButton(yesno_button[choice] | BUTTON_PRESSED, DB_NORMAL);
1217       }
1218     }
1219     else                        /* Mausbewegung bei gedrückter Maustaste */
1220     {
1221       if ((!ON_YESNO_BUTTON(mx,my) || YESNO_BUTTON(mx)!=choice) &&
1222           choice>=0 && pressed)
1223       {
1224         pressed = FALSE;
1225         DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL);
1226       }
1227       else if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && !pressed)
1228       {
1229         pressed = TRUE;
1230         DrawYesNoButton(yesno_button[choice] | BUTTON_PRESSED, DB_NORMAL);
1231       }
1232     }
1233   }
1234   else                          /* Maustaste wieder losgelassen */
1235   {
1236     if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && pressed)
1237     {
1238       DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL);
1239       return_code = choice+1;
1240       choice = -1;
1241       pressed = FALSE;
1242     }
1243     else
1244     {
1245       choice = -1;
1246       pressed = FALSE;
1247     }
1248   }
1249
1250   BackToFront();
1251   return(return_code);
1252 }
1253
1254 int CheckConfirmButton(int mx, int my, int button)
1255 {
1256   int return_code = 0;
1257   static int choice = -1;
1258   static boolean pressed = FALSE;
1259
1260   if (button)
1261   {
1262     if (!motion_status)         /* Maustaste neu gedrückt */
1263     {
1264       if (ON_CONFIRM_BUTTON(mx,my))
1265       {
1266         choice = 0;
1267         pressed = TRUE;
1268         DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL);
1269       }
1270     }
1271     else                        /* Mausbewegung bei gedrückter Maustaste */
1272     {
1273       if (!ON_CONFIRM_BUTTON(mx,my) && choice>=0 && pressed)
1274       {
1275         pressed = FALSE;
1276         DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL);
1277       }
1278       else if (ON_CONFIRM_BUTTON(mx,my) && !pressed)
1279       {
1280         pressed = TRUE;
1281         DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL);
1282       }
1283     }
1284   }
1285   else                          /* Maustaste wieder losgelassen */
1286   {
1287     if (ON_CONFIRM_BUTTON(mx,my) && pressed)
1288     {
1289       DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL);
1290       return_code = BUTTON_CONFIRM;
1291       choice = -1;
1292       pressed = FALSE;
1293     }
1294     else
1295     {
1296       choice = -1;
1297       pressed = FALSE;
1298     }
1299   }
1300
1301   BackToFront();
1302   return(return_code);
1303 }
1304
1305 int CheckPlayerButtons(int mx, int my, int button)
1306 {
1307   int return_code = 0;
1308   static int choice = -1;
1309   static boolean pressed = FALSE;
1310   int player_state[4] =
1311   {
1312     BUTTON_PLAYER_1,
1313     BUTTON_PLAYER_2,
1314     BUTTON_PLAYER_3,
1315     BUTTON_PLAYER_4
1316   };
1317
1318   if (button)
1319   {
1320     if (!motion_status)         /* Maustaste neu gedrückt */
1321     {
1322       if (ON_PLAYER_BUTTON(mx,my))
1323       {
1324         choice = PLAYER_BUTTON(mx,my);
1325         pressed = TRUE;
1326         DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL);
1327       }
1328     }
1329     else                        /* Mausbewegung bei gedrückter Maustaste */
1330     {
1331       if ((!ON_PLAYER_BUTTON(mx,my) || PLAYER_BUTTON(mx,my)!=choice) &&
1332           choice>=0 && pressed)
1333       {
1334         pressed = FALSE;
1335         DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL);
1336       }
1337       else if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && !pressed)
1338       {
1339         pressed = TRUE;
1340         DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL);
1341       }
1342     }
1343   }
1344   else                          /* Maustaste wieder losgelassen */
1345   {
1346     if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && pressed)
1347     {
1348       DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL);
1349       return_code = player_state[choice];
1350       choice = -1;
1351       pressed = FALSE;
1352     }
1353     else
1354     {
1355       choice = -1;
1356       pressed = FALSE;
1357     }
1358   }
1359
1360   BackToFront();
1361   return(return_code);
1362 }
1363
1364 /* several buttons in the level editor */
1365
1366 int CheckEditButtons(int mx, int my, int button)
1367 {
1368   int return_code = 0;
1369   static int choice = -1;
1370   static boolean pressed = FALSE;
1371   static int edit_button[6] =
1372   {
1373     ED_BUTTON_CTRL,
1374     ED_BUTTON_FILL,
1375     ED_BUTTON_LEFT,
1376     ED_BUTTON_UP,
1377     ED_BUTTON_DOWN,
1378     ED_BUTTON_RIGHT
1379   };
1380
1381   if (button)
1382   {
1383     if (!motion_status)         /* Maustaste neu gedrückt */
1384     {
1385       if (ON_EDIT_BUTTON(mx,my))
1386       {
1387         choice = EDIT_BUTTON(mx,my);
1388         pressed = TRUE;
1389         DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
1390         if (edit_button[choice]!=ED_BUTTON_CTRL &&
1391             edit_button[choice]!=ED_BUTTON_FILL)
1392           return_code = 1<<choice;
1393       }
1394     }
1395     else                        /* Mausbewegung bei gedrückter Maustaste */
1396     {
1397       if ((!ON_EDIT_BUTTON(mx,my) || EDIT_BUTTON(mx,my)!=choice) &&
1398           choice>=0 && pressed)
1399       {
1400         pressed = FALSE;
1401         DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
1402       }
1403       else if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice)
1404       {
1405         if (!pressed)
1406           DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
1407         pressed = TRUE;
1408         if (edit_button[choice]!=ED_BUTTON_CTRL &&
1409             edit_button[choice]!=ED_BUTTON_FILL)
1410           return_code = 1<<choice;
1411       }
1412     }
1413   }
1414   else                          /* Maustaste wieder losgelassen */
1415   {
1416     if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice && pressed)
1417     {
1418       DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
1419       if (edit_button[choice]==ED_BUTTON_CTRL ||
1420           edit_button[choice]==ED_BUTTON_FILL)
1421         return_code = 1<<choice;
1422       choice = -1;
1423       pressed = FALSE;
1424     }
1425     else
1426     {
1427       choice = -1;
1428       pressed = FALSE;
1429     }
1430   }
1431
1432   BackToFront();
1433   return(return_code);
1434 }
1435
1436 int CheckCtrlButtons(int mx, int my, int button)
1437 {
1438   int return_code = 0;
1439   static int choice = -1;
1440   static boolean pressed = FALSE;
1441   static int ctrl_button[4] =
1442   {
1443     ED_BUTTON_EDIT,
1444     ED_BUTTON_CLEAR,
1445     ED_BUTTON_UNDO,
1446     ED_BUTTON_EXIT
1447   };
1448
1449   if (button)
1450   {
1451     if (!motion_status)         /* Maustaste neu gedrückt */
1452     {
1453       if (ON_CTRL_BUTTON(mx,my))
1454       {
1455         choice = CTRL_BUTTON(mx,my);
1456         pressed = TRUE;
1457         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
1458       }
1459     }
1460     else                        /* Mausbewegung bei gedrückter Maustaste */
1461     {
1462       if ((!ON_CTRL_BUTTON(mx,my) || CTRL_BUTTON(mx,my)!=choice) &&
1463           choice>=0 && pressed)
1464       {
1465         pressed = FALSE;
1466         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
1467       }
1468       else if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && !pressed)
1469       {
1470         pressed = TRUE;
1471         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
1472       }
1473     }
1474   }
1475   else                          /* Maustaste wieder losgelassen */
1476   {
1477     if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && pressed)
1478     {
1479       DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
1480       return_code = 1<<(choice+6);
1481       choice = -1;
1482       pressed = FALSE;
1483     }
1484     else
1485     {
1486       choice = -1;
1487       pressed = FALSE;
1488     }
1489   }
1490
1491   BackToFront();
1492   return(return_code);
1493 }
1494
1495 int CheckElemButtons(int mx, int my, int button)
1496 {
1497   int return_code = -1;
1498   static int choice = -1;
1499   static boolean pressed = FALSE;
1500
1501   if (button)
1502   {
1503     if (!motion_status)         /* Maustaste neu gedrückt */
1504     {
1505       if (ON_ELEM_BUTTON(mx,my))
1506       {
1507         choice = ELEM_BUTTON(mx,my);
1508         pressed = TRUE;
1509         DrawElemButton(choice,ED_BUTTON_PRESSED);
1510         if (choice==ED_BUTTON_EUP ||
1511             choice==ED_BUTTON_EDOWN)
1512           return_code = choice;
1513       }
1514     }
1515     else                        /* Mausbewegung bei gedrückter Maustaste */
1516     {
1517       if ((!ON_ELEM_BUTTON(mx,my) || ELEM_BUTTON(mx,my)!=choice) &&
1518           choice>=0 && pressed)
1519       {
1520         pressed = FALSE;
1521         DrawElemButton(choice,ED_BUTTON_RELEASED);
1522       }
1523       else if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice)
1524       {
1525         if (!pressed)
1526           DrawElemButton(choice,ED_BUTTON_PRESSED);
1527         pressed = TRUE;
1528         if (choice==ED_BUTTON_EUP ||
1529             choice==ED_BUTTON_EDOWN)
1530           return_code = choice;
1531       }
1532     }
1533   }
1534   else                          /* Maustaste wieder losgelassen */
1535   {
1536     if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice && pressed)
1537     {
1538       DrawElemButton(choice,ED_BUTTON_RELEASED);
1539       if (choice!=ED_BUTTON_EUP &&
1540           choice!=ED_BUTTON_EDOWN)
1541         return_code = choice;
1542       choice = -1;
1543       pressed = FALSE;
1544     }
1545     else
1546     {
1547       choice = -1;
1548       pressed = FALSE;
1549     }
1550   }
1551
1552   BackToFront();
1553   return(return_code);
1554 }
1555
1556 int CheckCountButtons(int mx, int my, int button)
1557 {
1558   int return_code = -1;
1559   static int choice = -1;
1560   static boolean pressed = FALSE;
1561
1562   if (button)
1563   {
1564     if (!motion_status)         /* Maustaste neu gedrückt */
1565     {
1566       if (ON_COUNT_BUTTON(mx,my))
1567       {
1568         choice = COUNT_BUTTON(mx,my);
1569         pressed = TRUE;
1570         DrawCountButton(choice,ED_BUTTON_PRESSED);
1571         return_code = choice;
1572       }
1573     }
1574     else                        /* Mausbewegung bei gedrückter Maustaste */
1575     {
1576       if ((!ON_COUNT_BUTTON(mx,my) || COUNT_BUTTON(mx,my)!=choice) &&
1577           choice>=0 && pressed)
1578       {
1579         pressed = FALSE;
1580         DrawCountButton(choice,ED_BUTTON_RELEASED);
1581       }
1582       else if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice)
1583       {
1584         if (!pressed)
1585           DrawCountButton(choice,ED_BUTTON_PRESSED);
1586         pressed = TRUE;
1587         return_code = choice;
1588       }
1589     }
1590   }
1591   else                          /* Maustaste wieder losgelassen */
1592   {
1593     if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice && pressed)
1594     {
1595       DrawCountButton(choice,ED_BUTTON_RELEASED);
1596       choice = -1;
1597       pressed = FALSE;
1598     }
1599     else
1600     {
1601       choice = -1;
1602       pressed = FALSE;
1603     }
1604   }
1605
1606   BackToFront();
1607   return(return_code);
1608 }
1609
1610
1611 /* NEW GADGET STUFF -------------------------------------------------------- */
1612
1613
1614 static struct GadgetInfo *gadget_list_first_entry = NULL;
1615 static struct GadgetInfo *gadget_list_last_entry = NULL;
1616 static int next_free_gadget_id = 1;
1617 static boolean gadget_id_wrapped = FALSE;
1618
1619 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
1620 {
1621   struct GadgetInfo *gi = gadget_list_first_entry;
1622
1623   while (gi && gi->id != id)
1624     gi = gi->next;
1625
1626   return gi;
1627 }
1628
1629 static int getNewGadgetID()
1630 {
1631   int id = next_free_gadget_id++;
1632
1633   if (next_free_gadget_id <= 0)         /* counter overrun */
1634   {
1635     gadget_id_wrapped = TRUE;           /* now we must check each ID */
1636     next_free_gadget_id = 0;
1637   }
1638
1639   if (gadget_id_wrapped)
1640   {
1641     next_free_gadget_id++;
1642     while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
1643       next_free_gadget_id++;
1644   }
1645
1646   if (next_free_gadget_id <= 0)         /* cannot get new gadget id */
1647     Error(ERR_EXIT, "too much gadgets -- this should not happen");
1648
1649   return id;
1650 }
1651
1652 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
1653 {
1654   struct GadgetInfo *gi = gadget_list_first_entry;
1655
1656   while (gi)
1657   {
1658     if (gi->mapped &&
1659         mx >= gi->x && mx < gi->x + gi->width &&
1660         my >= gi->y && my < gi->y + gi->height)
1661         break;
1662
1663     gi = gi->next;
1664   }
1665
1666   return gi;
1667 }
1668
1669 static void default_callback_info(void *ptr)
1670 {
1671   if (game_status == LEVELED)
1672     HandleEditorGadgetInfoText(ptr);
1673 }
1674
1675 static void default_callback_action(void *ptr)
1676 {
1677   return;
1678 }
1679
1680 struct GadgetInfo *CreateGadget(int first_tag, ...)
1681 {
1682   struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
1683   int tag = first_tag;
1684   va_list ap;
1685
1686   va_start(ap, first_tag);
1687
1688   /* always start with reliable default values */
1689   memset(new_gadget, 0, sizeof(struct GadgetInfo));     /* zero all fields */
1690   new_gadget->id = getNewGadgetID();
1691   new_gadget->callback_info = default_callback_info;
1692   new_gadget->callback_action = default_callback_action;
1693
1694   while (tag != GDI_END)
1695   {
1696     switch(tag)
1697     {
1698       case GDI_CUSTOM_ID:
1699         new_gadget->custom_id = va_arg(ap, int);
1700         break;
1701
1702       case GDI_INFO_TEXT:
1703         {
1704           int max_textsize = MAX_INFO_TEXTSIZE;
1705
1706           strncpy(new_gadget->info_text, va_arg(ap, char *), max_textsize);
1707           new_gadget->info_text[max_textsize] = '\0';
1708         }
1709         break;
1710
1711       case GDI_X:
1712         new_gadget->x = va_arg(ap, int);
1713         break;
1714
1715       case GDI_Y:
1716         new_gadget->y = va_arg(ap, int);
1717         break;
1718
1719       case GDI_WIDTH:
1720         new_gadget->width = va_arg(ap, int);
1721         break;
1722
1723       case GDI_HEIGHT:
1724         new_gadget->height = va_arg(ap, int);
1725         break;
1726
1727       case GDI_TYPE:
1728         new_gadget->type = va_arg(ap, unsigned long);
1729         break;
1730
1731       case GDI_STATE:
1732         new_gadget->state = va_arg(ap, unsigned long);
1733         break;
1734
1735       case GDI_CHECKED:
1736         new_gadget->checked = va_arg(ap, boolean);
1737         break;
1738
1739       case GDI_RADIO_NR:
1740         new_gadget->radio_nr = va_arg(ap, unsigned long);
1741         break;
1742
1743       case GDI_NUMBER_VALUE:
1744         new_gadget->text.number_value = va_arg(ap, long);
1745         sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1746         new_gadget->text.cursor_position = strlen(new_gadget->text.value);
1747         break;
1748
1749       case GDI_NUMBER_MIN:
1750         new_gadget->text.number_min = va_arg(ap, long);
1751         if (new_gadget->text.number_value < new_gadget->text.number_min)
1752         {
1753           new_gadget->text.number_value = new_gadget->text.number_min;
1754           sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1755         }
1756         break;
1757
1758       case GDI_NUMBER_MAX:
1759         new_gadget->text.number_max = va_arg(ap, long);
1760         if (new_gadget->text.number_value > new_gadget->text.number_max)
1761         {
1762           new_gadget->text.number_value = new_gadget->text.number_max;
1763           sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1764         }
1765         break;
1766
1767       case GDI_TEXT_VALUE:
1768         {
1769           int max_textsize = MAX_GADGET_TEXTSIZE;
1770
1771           if (new_gadget->text.size)
1772             max_textsize = MIN(new_gadget->text.size, MAX_GADGET_TEXTSIZE - 1);
1773
1774           strncpy(new_gadget->text.value, va_arg(ap, char *), max_textsize);
1775           new_gadget->text.value[max_textsize] = '\0';
1776           new_gadget->text.cursor_position = strlen(new_gadget->text.value);
1777         }
1778         break;
1779
1780       case GDI_TEXT_SIZE:
1781         {
1782           int tag_value = va_arg(ap, int);
1783           int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
1784
1785           new_gadget->text.size = max_textsize;
1786           new_gadget->text.value[max_textsize] = '\0';
1787
1788           if (new_gadget->width == 0 && new_gadget->height == 0)
1789           {
1790             new_gadget->width = (new_gadget->text.size + 1) * FONT2_XSIZE + 6;
1791             new_gadget->height = ED_WIN_COUNT_YSIZE;
1792           }
1793         }
1794         break;
1795
1796       case GDI_DESIGN_UNPRESSED:
1797         new_gadget->design[GD_BUTTON_UNPRESSED].pixmap = va_arg(ap, Pixmap);
1798         new_gadget->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1799         new_gadget->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1800         break;
1801
1802       case GDI_DESIGN_PRESSED:
1803         new_gadget->design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1804         new_gadget->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1805         new_gadget->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1806         break;
1807
1808       case GDI_ALT_DESIGN_UNPRESSED:
1809         new_gadget->alt_design[GD_BUTTON_UNPRESSED].pixmap= va_arg(ap, Pixmap);
1810         new_gadget->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1811         new_gadget->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1812         break;
1813
1814       case GDI_ALT_DESIGN_PRESSED:
1815         new_gadget->alt_design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1816         new_gadget->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1817         new_gadget->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1818         break;
1819
1820       case GDI_DESIGN_BORDER:
1821         new_gadget->design_border = va_arg(ap, int);
1822         break;
1823
1824       case GDI_DECORATION_DESIGN:
1825         new_gadget->deco.design.pixmap = va_arg(ap, Pixmap);
1826         new_gadget->deco.design.x = va_arg(ap, int);
1827         new_gadget->deco.design.y = va_arg(ap, int);
1828         break;
1829
1830       case GDI_DECORATION_POSITION:
1831         new_gadget->deco.x = va_arg(ap, int);
1832         new_gadget->deco.y = va_arg(ap, int);
1833         break;
1834
1835       case GDI_DECORATION_SIZE:
1836         new_gadget->deco.width = va_arg(ap, int);
1837         new_gadget->deco.height = va_arg(ap, int);
1838         break;
1839
1840       case GDI_DECORATION_SHIFTING:
1841         new_gadget->deco.xshift = va_arg(ap, int);
1842         new_gadget->deco.yshift = va_arg(ap, int);
1843         break;
1844
1845       case GDI_EVENT_MASK:
1846         new_gadget->event_mask = va_arg(ap, unsigned long);
1847         break;
1848
1849       case GDI_AREA_SIZE:
1850         new_gadget->drawing.area_xsize = va_arg(ap, int);
1851         new_gadget->drawing.area_ysize = va_arg(ap, int);
1852
1853         /* determine dependent values for drawing area gadget, if needed */
1854         if (new_gadget->width == 0 &&
1855             new_gadget->height == 0 &&
1856             new_gadget->drawing.item_xsize !=0 &&
1857             new_gadget->drawing.item_ysize !=0)
1858         {
1859           new_gadget->width =
1860             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1861           new_gadget->height =
1862             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1863         }
1864         else if (new_gadget->drawing.item_xsize == 0 &&
1865                  new_gadget->drawing.item_ysize == 0 &&
1866                  new_gadget->width != 0 &&
1867                  new_gadget->height != 0)
1868         {
1869           new_gadget->drawing.item_xsize =
1870             new_gadget->width / new_gadget->drawing.area_xsize;
1871           new_gadget->drawing.item_ysize =
1872             new_gadget->height / new_gadget->drawing.area_ysize;
1873         }
1874         break;
1875
1876       case GDI_ITEM_SIZE:
1877         new_gadget->drawing.item_xsize = va_arg(ap, int);
1878         new_gadget->drawing.item_ysize = va_arg(ap, int);
1879
1880         /* determine dependent values for drawing area gadget, if needed */
1881         if (new_gadget->width == 0 &&
1882             new_gadget->height == 0 &&
1883             new_gadget->drawing.area_xsize !=0 &&
1884             new_gadget->drawing.area_ysize !=0)
1885         {
1886           new_gadget->width =
1887             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1888           new_gadget->height =
1889             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1890         }
1891         else if (new_gadget->drawing.area_xsize == 0 &&
1892                  new_gadget->drawing.area_ysize == 0 &&
1893                  new_gadget->width != 0 &&
1894                  new_gadget->height != 0)
1895         {
1896           new_gadget->drawing.area_xsize =
1897             new_gadget->width / new_gadget->drawing.item_xsize;
1898           new_gadget->drawing.area_ysize =
1899             new_gadget->height / new_gadget->drawing.item_ysize;
1900         }
1901         break;
1902
1903       case GDI_SCROLLBAR_ITEMS_MAX:
1904         new_gadget->scrollbar.items_max = va_arg(ap, int);
1905         break;
1906
1907       case GDI_SCROLLBAR_ITEMS_VISIBLE:
1908         new_gadget->scrollbar.items_visible = va_arg(ap, int);
1909         break;
1910
1911       case GDI_SCROLLBAR_ITEM_POSITION:
1912         new_gadget->scrollbar.item_position = va_arg(ap, int);
1913         break;
1914
1915       case GDI_CALLBACK_INFO:
1916         new_gadget->callback_info = va_arg(ap, gadget_function);
1917         break;
1918
1919       case GDI_CALLBACK_ACTION:
1920         new_gadget->callback_action = va_arg(ap, gadget_function);
1921         break;
1922
1923       default:
1924         Error(ERR_EXIT, "CreateGadget(): unknown tag %d", tag);
1925     }
1926
1927     tag = va_arg(ap, int);      /* read next tag */
1928   }
1929
1930   va_end(ap);
1931
1932   /* check if gadget complete */
1933   if (new_gadget->type != GD_TYPE_DRAWING_AREA &&
1934       (!new_gadget->design[GD_BUTTON_UNPRESSED].pixmap ||
1935        !new_gadget->design[GD_BUTTON_PRESSED].pixmap))
1936     Error(ERR_EXIT, "gadget incomplete (missing Pixmap)");
1937
1938   if (new_gadget->type & GD_TYPE_SCROLLBAR)
1939   {
1940     struct GadgetScrollbar *gs = &new_gadget->scrollbar;
1941
1942     if (new_gadget->width == 0 || new_gadget->height == 0 ||
1943         gs->items_max == 0 || gs->items_visible == 0)
1944       Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
1945
1946     /* calculate internal scrollbar values */
1947     gs->size_max = (new_gadget->type == GD_TYPE_SCROLLBAR_VERTICAL ?
1948                     new_gadget->height : new_gadget->width);
1949     gs->size = gs->size_max * gs->items_visible / gs->items_max;
1950     gs->position = gs->size_max * gs->item_position / gs->items_max;
1951     gs->position_max = gs->size_max - gs->size;
1952   }
1953
1954   /* insert new gadget into global gadget list */
1955   if (gadget_list_last_entry)
1956   {
1957     gadget_list_last_entry->next = new_gadget;
1958     gadget_list_last_entry = gadget_list_last_entry->next;
1959   }
1960   else
1961     gadget_list_first_entry = gadget_list_last_entry = new_gadget;
1962
1963   return new_gadget;
1964 }
1965
1966 void FreeGadget(struct GadgetInfo *gi)
1967 {
1968   struct GadgetInfo *gi_previous = gadget_list_first_entry;
1969
1970   while (gi_previous && gi_previous->next != gi)
1971     gi_previous = gi_previous->next;
1972
1973   if (gi == gadget_list_first_entry)
1974     gadget_list_first_entry = gi->next;
1975
1976   if (gi == gadget_list_last_entry)
1977     gadget_list_last_entry = gi_previous;
1978
1979   gi_previous->next = gi->next;
1980   free(gi);
1981 }
1982
1983 /* values for DrawGadget() */
1984 #define DG_UNPRESSED    0
1985 #define DG_PRESSED      1
1986 #define DG_BUFFERED     0
1987 #define DG_DIRECT       1
1988
1989 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
1990 {
1991   if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
1992     return;
1993
1994   gi->text.number_value = atoi(gi->text.value);
1995
1996   if (gi->text.number_value < gi->text.number_min)
1997     gi->text.number_value = gi->text.number_min;
1998   if (gi->text.number_value > gi->text.number_max)
1999     gi->text.number_value = gi->text.number_max;
2000
2001   sprintf(gi->text.value, "%d", gi->text.number_value);
2002
2003   if (gi->text.cursor_position < 0)
2004     gi->text.cursor_position = 0;
2005   else if (gi->text.cursor_position > strlen(gi->text.value))
2006     gi->text.cursor_position = strlen(gi->text.value);
2007 }
2008
2009 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
2010 {
2011   int state = (pressed ? 1 : 0);
2012   struct GadgetDesign *gd = (gi->checked ?
2013                              &gi->alt_design[state] :
2014                              &gi->design[state]);
2015
2016   switch (gi->type)
2017   {
2018     case GD_TYPE_NORMAL_BUTTON:
2019     case GD_TYPE_CHECK_BUTTON:
2020     case GD_TYPE_RADIO_BUTTON:
2021       XCopyArea(display, gd->pixmap, drawto, gc,
2022                 gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
2023       if (gi->deco.design.pixmap)
2024         XCopyArea(display, gi->deco.design.pixmap, drawto, gc,
2025                   gi->deco.design.x, gi->deco.design.y,
2026                   gi->deco.width, gi->deco.height,
2027                   gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
2028                   gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
2029       break;
2030
2031     case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
2032     case GD_TYPE_TEXTINPUT_NUMERIC:
2033       {
2034         int i;
2035         char cursor_letter;
2036         char cursor_string[3];
2037         char text[MAX_GADGET_TEXTSIZE + 1];
2038         int font_color = FC_YELLOW;
2039         int border = gi->design_border;
2040         strcpy(text, gi->text.value);
2041         strcat(text, " ");
2042
2043         /* left part of gadget */
2044         XCopyArea(display, gd->pixmap, drawto, gc,
2045                   gd->x, gd->y, border, gi->height, gi->x, gi->y);
2046
2047         /* middle part of gadget */
2048         for (i=0; i<=gi->text.size; i++)
2049           XCopyArea(display, gd->pixmap, drawto, gc,
2050                     gd->x + border, gd->y, FONT2_XSIZE, gi->height,
2051                     gi->x + border + i * FONT2_XSIZE, gi->y);
2052
2053         /* right part of gadget */
2054         XCopyArea(display, gd->pixmap, drawto, gc,
2055                   gd->x + ED_WIN_COUNT_XSIZE - border, gd->y,
2056                   border, gi->height, gi->x + gi->width - border, gi->y);
2057
2058         /* gadget text value */
2059         DrawText(gi->x + border, gi->y + border, text, FS_SMALL, font_color);
2060
2061         cursor_letter = gi->text.value[gi->text.cursor_position];
2062         cursor_string[0] = '~';
2063         cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
2064         cursor_string[2] = '\0';
2065
2066         /* draw cursor, if active */
2067         if (pressed)
2068           DrawText(gi->x + border + gi->text.cursor_position * FONT2_XSIZE,
2069                    gi->y + border, cursor_string, FS_SMALL, font_color);
2070       }
2071       break;
2072
2073     case GD_TYPE_SCROLLBAR_VERTICAL:
2074       {
2075         int i;
2076         int xpos = gi->x;
2077         int ypos = gi->y + gi->scrollbar.position;
2078         int design_full = gi->width;
2079         int design_body = design_full - 2 * gi->design_border;
2080         int size_full = gi->scrollbar.size;
2081         int size_body = size_full - 2 * gi->design_border;
2082         int num_steps = size_body / design_body;
2083         int step_size_remain = size_body - num_steps * design_body;
2084
2085         /* clear scrollbar area */
2086         XFillRectangle(display, backbuffer, gc,
2087                        gi->x, gi->y, gi->width, gi->height);
2088
2089         /* upper part of gadget */
2090         XCopyArea(display, gd->pixmap, drawto, gc,
2091                   gd->x, gd->y,
2092                   gi->width, gi->design_border,
2093                   xpos, ypos);
2094
2095         /* middle part of gadget */
2096         for (i=0; i<num_steps; i++)
2097           XCopyArea(display, gd->pixmap, drawto, gc,
2098                     gd->x, gd->y + gi->design_border,
2099                     gi->width, design_body,
2100                     xpos, ypos + gi->design_border + i * design_body);
2101
2102         /* remaining middle part of gadget */
2103         if (step_size_remain > 0)
2104           XCopyArea(display, gd->pixmap, drawto, gc,
2105                     gd->x,  gd->y + gi->design_border,
2106                     gi->width, step_size_remain,
2107                     xpos, ypos + gi->design_border + num_steps * design_body);
2108
2109         /* lower part of gadget */
2110         XCopyArea(display, gd->pixmap, drawto, gc,
2111                   gd->x, gd->y + design_full - gi->design_border,
2112                   gi->width, gi->design_border,
2113                   xpos, ypos + size_full - gi->design_border);
2114       }
2115       break;
2116
2117     case GD_TYPE_SCROLLBAR_HORIZONTAL:
2118       {
2119         int i;
2120         int xpos = gi->x + gi->scrollbar.position;
2121         int ypos = gi->y;
2122         int design_full = gi->height;
2123         int design_body = design_full - 2 * gi->design_border;
2124         int size_full = gi->scrollbar.size;
2125         int size_body = size_full - 2 * gi->design_border;
2126         int num_steps = size_body / design_body;
2127         int step_size_remain = size_body - num_steps * design_body;
2128
2129         /* clear scrollbar area */
2130         XFillRectangle(display, backbuffer, gc,
2131                        gi->x, gi->y, gi->width, gi->height);
2132
2133         /* left part of gadget */
2134         XCopyArea(display, gd->pixmap, drawto, gc,
2135                   gd->x, gd->y,
2136                   gi->design_border, gi->height,
2137                   xpos, ypos);
2138
2139         /* middle part of gadget */
2140         for (i=0; i<num_steps; i++)
2141           XCopyArea(display, gd->pixmap, drawto, gc,
2142                     gd->x + gi->design_border, gd->y,
2143                     design_body, gi->height,
2144                     xpos + gi->design_border + i * design_body, ypos);
2145
2146         /* remaining middle part of gadget */
2147         if (step_size_remain > 0)
2148           XCopyArea(display, gd->pixmap, drawto, gc,
2149                     gd->x + gi->design_border, gd->y,
2150                     step_size_remain, gi->height,
2151                     xpos + gi->design_border + num_steps * design_body, ypos);
2152
2153         /* right part of gadget */
2154         XCopyArea(display, gd->pixmap, drawto, gc,
2155                   gd->x + design_full - gi->design_border, gd->y,
2156                   gi->design_border, gi->height,
2157                   xpos + size_full - gi->design_border, ypos);
2158       }
2159       break;
2160
2161     default:
2162       return;
2163   }
2164
2165   if (direct)
2166     XCopyArea(display, drawto, window, gc,
2167               gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
2168   else
2169     redraw_mask |= REDRAW_ALL;
2170 }
2171
2172 void ClickOnGadget(struct GadgetInfo *gi)
2173 {
2174   /* simulate releasing mouse button over last gadget, if still pressed */
2175   if (button_status)
2176     HandleGadgets(-1, -1, 0);
2177
2178   /* simulate pressing mouse button over specified gadget */
2179   HandleGadgets(gi->x, gi->y, 1);
2180
2181   /* simulate releasing mouse button over specified gadget */
2182   HandleGadgets(gi->x, gi->y, 0);
2183 }
2184
2185 void AdjustScrollbar(struct GadgetInfo *gi, int items_max, int item_pos)
2186 {
2187   struct GadgetScrollbar *gs = &gi->scrollbar;
2188
2189   gs->items_max = items_max;
2190   gs->item_position = item_pos;
2191
2192   gs->size = gs->size_max * gs->items_visible / gs->items_max;
2193   gs->position = gs->size_max * gs->item_position / gs->items_max;
2194   gs->position_max = gs->size_max - gs->size;
2195
2196   /* finetuning for maximal right/bottom position */
2197   if (gs->item_position == gs->items_max - gs->items_visible)
2198     gs->position = gs->position_max;
2199
2200   if (gi->mapped)
2201     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2202 }
2203
2204 void ModifyTextInputTextValue(struct GadgetInfo *gi, char *new_text)
2205 {
2206   struct GadgetTextInput *text = &gi->text;
2207   int max_textsize = MAX_GADGET_TEXTSIZE;
2208
2209   if (text->size)
2210     max_textsize = MIN(text->size, MAX_GADGET_TEXTSIZE - 1);
2211
2212   strncpy(text->value, new_text, max_textsize);
2213   text->value[max_textsize] = '\0';
2214   text->cursor_position = strlen(text->value);
2215
2216   if (gi->mapped)
2217     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2218 }
2219
2220 void ModifyTextInputNumberValue(struct GadgetInfo *gi, int new_value)
2221 {
2222   struct GadgetTextInput *text = &gi->text;
2223
2224   text->number_value = (new_value < text->number_min ? text->number_min :
2225                         new_value > text->number_max ? text->number_max :
2226                         new_value);
2227
2228   sprintf(text->value, "%d", text->number_value);
2229
2230   if (gi->mapped)
2231     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2232 }
2233
2234 /* global pointer to gadget actually in use (when mouse button pressed) */
2235 static struct GadgetInfo *last_gi = NULL;
2236
2237 void MapGadget(struct GadgetInfo *gi)
2238 {
2239   if (gi == NULL || gi->mapped)
2240     return;
2241
2242   gi->mapped = TRUE;
2243
2244   DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
2245 }
2246
2247 void UnmapGadget(struct GadgetInfo *gi)
2248 {
2249   if (gi == NULL || !gi->mapped)
2250     return;
2251
2252   gi->mapped = FALSE;
2253
2254   if (gi == last_gi)
2255     last_gi = NULL;
2256 }
2257
2258 void HandleGadgets(int mx, int my, int button)
2259 {
2260   static struct GadgetInfo *last_info_gi = NULL;
2261   static unsigned long pressed_delay = 0;
2262   static int last_button = 0;
2263   static int last_mx = 0, last_my = 0;
2264   int scrollbar_mouse_pos;
2265   struct GadgetInfo *new_gi, *gi;
2266   boolean press_event;
2267   boolean release_event;
2268   boolean mouse_moving;
2269   boolean gadget_pressed;
2270   boolean gadget_pressed_repeated;
2271   boolean gadget_moving;
2272   boolean gadget_moving_inside;
2273   boolean gadget_moving_off_borders;
2274   boolean gadget_released;
2275   boolean gadget_released_inside;
2276   boolean gadget_released_off_borders;
2277   boolean changed_position = FALSE;
2278
2279   /* check if there are any gadgets defined */
2280   if (gadget_list_first_entry == NULL)
2281     return;
2282
2283   /* check which gadget is under the mouse pointer */
2284   new_gi = getGadgetInfoFromMousePosition(mx, my);
2285
2286   /* check if button state has changed since last invocation */
2287   press_event = (button != 0 && last_button == 0);
2288   release_event = (button == 0 && last_button != 0);
2289   last_button = button;
2290
2291   /* check if mouse has been moved since last invocation */
2292   mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
2293   last_mx = mx;
2294   last_my = my;
2295
2296   /* special treatment for text and number input gadgets */
2297   if (last_gi && last_gi->type & GD_TYPE_TEXTINPUT && last_gi->mapped &&
2298       button != 0 && !motion_status)
2299   {
2300     struct GadgetInfo *gi = last_gi;
2301
2302     if (new_gi == last_gi)
2303     {
2304       /* if mouse button pressed inside activated text gadget, set cursor */
2305       gi->text.cursor_position = (mx - gi->x) / FONT2_XSIZE;
2306
2307       if (gi->text.cursor_position < 0)
2308         gi->text.cursor_position = 0;
2309       else if (gi->text.cursor_position > strlen(gi->text.value))
2310         gi->text.cursor_position = strlen(gi->text.value);
2311
2312       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2313     }
2314     else
2315     {
2316       /* if mouse button pressed outside text input gadget, deactivate it */
2317       CheckRangeOfNumericInputGadget(gi);
2318       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2319
2320       if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
2321         gi->callback_action(gi);
2322
2323       last_gi = NULL;
2324     }
2325   }
2326
2327   gadget_pressed =
2328     (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
2329   gadget_pressed_repeated =
2330     (button != 0 && last_gi != NULL && new_gi == last_gi);
2331
2332   gadget_released =             (release_event && last_gi != NULL);
2333   gadget_released_inside =      (gadget_released && new_gi == last_gi);
2334   gadget_released_off_borders = (gadget_released && new_gi != last_gi);
2335
2336   gadget_moving =             (button != 0 && last_gi != NULL && mouse_moving);
2337   gadget_moving_inside =      (gadget_moving && new_gi == last_gi);
2338   gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
2339
2340   /* if new gadget pressed, store this gadget  */
2341   if (gadget_pressed)
2342     last_gi = new_gi;
2343
2344   /* 'gi' is actually handled gadget */
2345   gi = last_gi;
2346
2347   /* if gadget is scrollbar, choose mouse position value */
2348   if (gi && gi->type & GD_TYPE_SCROLLBAR)
2349     scrollbar_mouse_pos =
2350       (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
2351
2352   /* if mouse button released, no gadget needs to be handled anymore */
2353   if (button == 0 && last_gi && !(last_gi->type & GD_TYPE_TEXTINPUT))
2354     last_gi = NULL;
2355
2356   /* modify event position values even if no gadget is pressed */
2357   if (button == 0 && !release_event)
2358     gi = new_gi;
2359
2360   if (gi)
2361   {
2362     int last_x = gi->event.x;
2363     int last_y = gi->event.y;
2364
2365     gi->event.x = mx - gi->x;
2366     gi->event.y = my - gi->y;
2367
2368     if (gi->type == GD_TYPE_DRAWING_AREA)
2369     {
2370       gi->event.x /= gi->drawing.item_xsize;
2371       gi->event.y /= gi->drawing.item_ysize;
2372
2373       if (last_x != gi->event.x || last_y != gi->event.y)
2374         changed_position = TRUE;
2375     }
2376   }
2377
2378   /* handle gadget popup info text */
2379   if (last_info_gi != new_gi ||
2380       (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
2381   {
2382     last_info_gi = new_gi;
2383
2384     if (new_gi != NULL && (button == 0 || new_gi == last_gi))
2385     {
2386       new_gi->event.type = 0;
2387       new_gi->callback_info(new_gi);
2388     }
2389     else
2390       default_callback_info(NULL);
2391   }
2392
2393   if (gadget_pressed)
2394   {
2395     if (gi->type == GD_TYPE_CHECK_BUTTON)
2396     {
2397       gi->checked = !gi->checked;
2398     }
2399     else if (gi->type == GD_TYPE_RADIO_BUTTON)
2400     {
2401       struct GadgetInfo *rgi = gadget_list_first_entry;
2402
2403       while (rgi)
2404       {
2405         if (rgi->mapped &&
2406             rgi->type == GD_TYPE_RADIO_BUTTON &&
2407             rgi->radio_nr == gi->radio_nr &&
2408             rgi != gi)
2409         {
2410           rgi->checked = FALSE;
2411           DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
2412         }
2413
2414         rgi = rgi->next;
2415       }
2416
2417       gi->checked = TRUE;
2418     }
2419     else if (gi->type & GD_TYPE_SCROLLBAR)
2420     {
2421       int mpos, gpos;
2422
2423       if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
2424       {
2425         mpos = mx;
2426         gpos = gi->x;
2427       }
2428       else
2429       {
2430         mpos = my;
2431         gpos = gi->y;
2432       }
2433
2434       if (mpos >= gpos + gi->scrollbar.position &&
2435           mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
2436       {
2437         /* drag scrollbar */
2438         gi->scrollbar.drag_position =
2439           scrollbar_mouse_pos - gi->scrollbar.position;
2440       }
2441       else
2442       {
2443         /* click scrollbar one scrollbar length up/left or down/right */
2444
2445         struct GadgetScrollbar *gs = &gi->scrollbar;
2446         int old_item_position = gs->item_position;
2447
2448         changed_position = FALSE;
2449
2450         gs->item_position +=
2451           gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
2452
2453         if (gs->item_position < 0)
2454           gs->item_position = 0;
2455         if (gs->item_position > gs->items_max - gs->items_visible)
2456           gs->item_position = gs->items_max - gs->items_visible;
2457
2458         if (old_item_position != gs->item_position)
2459         {
2460           gi->event.item_position = gs->item_position;
2461           changed_position = TRUE;
2462         }
2463
2464         AdjustScrollbar(gi, gs->items_max, gs->item_position);
2465
2466         gi->state = GD_BUTTON_UNPRESSED;
2467         gi->event.type = GD_EVENT_MOVING;
2468         gi->event.off_borders = FALSE;
2469
2470         if (gi->event_mask & GD_EVENT_MOVING && changed_position)
2471           gi->callback_action(gi);
2472
2473         /* don't handle this scrollbar anymore while mouse button pressed */
2474         last_gi = NULL;
2475
2476         return;
2477       }
2478     }
2479
2480     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2481
2482     gi->state = GD_BUTTON_PRESSED;
2483     gi->event.type = GD_EVENT_PRESSED;
2484     gi->event.button = button;
2485     gi->event.off_borders = FALSE;
2486
2487     /* initialize delay counter */
2488     DelayReached(&pressed_delay, 0);
2489
2490     if (gi->event_mask & GD_EVENT_PRESSED)
2491       gi->callback_action(gi);
2492   }
2493
2494   if (gadget_pressed_repeated)
2495   {
2496     if (gi->event_mask & GD_EVENT_REPEATED &&
2497         DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
2498       gi->callback_action(gi);
2499   }
2500
2501   if (gadget_moving)
2502   {
2503     if (gi->type & GD_TYPE_BUTTON)
2504     {
2505       if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
2506         DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2507       else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
2508         DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2509     }
2510
2511     if (gi->type & GD_TYPE_SCROLLBAR)
2512     {
2513       struct GadgetScrollbar *gs = &gi->scrollbar;
2514       int old_item_position = gs->item_position;
2515
2516       gs->position = scrollbar_mouse_pos - gs->drag_position;
2517
2518       if (gs->position < 0)
2519         gs->position = 0;
2520       if (gs->position > gs->position_max)
2521         gs->position = gs->position_max;
2522
2523       gs->item_position = gs->items_max * gs->position / gs->size_max;
2524
2525       if (old_item_position != gs->item_position)
2526       {
2527         gi->event.item_position = gs->item_position;
2528         changed_position = TRUE;
2529       }
2530
2531       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2532     }
2533
2534     gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
2535                  GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
2536     gi->event.type = GD_EVENT_MOVING;
2537     gi->event.off_borders = gadget_moving_off_borders;
2538
2539     if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
2540         (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
2541       gi->callback_action(gi);
2542   }
2543
2544   if (gadget_released_inside)
2545   {
2546     if (!(gi->type & GD_TYPE_TEXTINPUT))
2547       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2548
2549     gi->state = GD_BUTTON_UNPRESSED;
2550     gi->event.type = GD_EVENT_RELEASED;
2551
2552     if (gi->event_mask & GD_EVENT_RELEASED)
2553       gi->callback_action(gi);
2554   }
2555
2556   if (gadget_released_off_borders)
2557   {
2558     if (gi->type & GD_TYPE_SCROLLBAR)
2559       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2560
2561     gi->event.type = GD_EVENT_RELEASED;
2562
2563     if (gi->event_mask & GD_EVENT_RELEASED &&
2564         gi->event_mask & GD_EVENT_OFF_BORDERS)
2565       gi->callback_action(gi);
2566   }
2567 }
2568
2569 void HandleGadgetsKeyInput(KeySym key)
2570 {
2571   struct GadgetInfo *gi = last_gi;
2572   char text[MAX_GADGET_TEXTSIZE];
2573   int text_length;
2574   int cursor_pos;
2575   char letter;
2576   boolean legal_letter;
2577
2578   if (gi == NULL || !(gi->type & GD_TYPE_TEXTINPUT) || !gi->mapped)
2579     return;
2580
2581   text_length = strlen(gi->text.value);
2582   cursor_pos = gi->text.cursor_position;
2583   letter = getCharFromKeySym(key);
2584   legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
2585                   letter >= '0' && letter <= '9' :
2586                   letter != 0);
2587
2588   if (legal_letter && text_length < gi->text.size)
2589   {
2590     strcpy(text, gi->text.value);
2591     strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
2592     gi->text.value[cursor_pos] = letter;
2593     gi->text.cursor_position++;
2594     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2595   }
2596   else if (key == XK_Left && cursor_pos > 0)
2597   {
2598     gi->text.cursor_position--;
2599     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2600   }
2601   else if (key == XK_Right && cursor_pos < text_length)
2602   {
2603     gi->text.cursor_position++;
2604     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2605   }
2606   else if (key == XK_BackSpace && cursor_pos > 0)
2607   {
2608     strcpy(text, gi->text.value);
2609     strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
2610     gi->text.cursor_position--;
2611     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2612   }
2613   else if (key == XK_Delete && cursor_pos < text_length)
2614   {
2615     strcpy(text, gi->text.value);
2616     strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
2617     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2618   }
2619   else if (key == XK_Return)
2620   {
2621     CheckRangeOfNumericInputGadget(gi);
2622     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2623
2624     if (gi->event_mask & GD_EVENT_TEXT_RETURN)
2625       gi->callback_action(gi);
2626
2627     last_gi = NULL;
2628   }
2629 }