c9c1348000018e6853f28f3aba2acdde8c26b76e
[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_PAUSE_XPOS  (GAME_CONTROL_XPOS + 1 * GAME_BUTTON_XSIZE)
136 #define GAME_BUTTON_PLAY_XPOS   (GAME_CONTROL_XPOS + 2 * GAME_BUTTON_XSIZE)
137 #define GAME_BUTTON_ANY_YPOS    (GAME_CONTROL_YPOS)
138
139 #define ON_GAME_BUTTON(x,y)     ((x)>=(DX+GAME_CONTROL_XPOS) && \
140                                  (x)< (DX+GAME_CONTROL_XPOS +           \
141                                        GAME_CONTROL_XSIZE) &&           \
142                                  (y)>=(DY+GAME_CONTROL_YPOS) && \
143                                  (y)< (DY+GAME_CONTROL_YPOS +           \
144                                        GAME_CONTROL_YSIZE))
145 #define GAME_BUTTON(x)          (((x)-(DX+GAME_CONTROL_XPOS))/GAME_BUTTON_XSIZE)
146
147 /* some positions in the asking window */
148 #define OK_BUTTON_XPOS          2
149 #define OK_BUTTON_YPOS          250
150 #define OK_BUTTON_GFX_YPOS      0
151 #define OK_BUTTON_XSIZE         46
152 #define OK_BUTTON_YSIZE         28
153 #define NO_BUTTON_XPOS          52
154 #define NO_BUTTON_YPOS          OK_BUTTON_YPOS
155 #define NO_BUTTON_XSIZE         OK_BUTTON_XSIZE
156 #define NO_BUTTON_YSIZE         OK_BUTTON_YSIZE
157 #define CONFIRM_BUTTON_XPOS     2
158 #define CONFIRM_BUTTON_GFX_YPOS 30
159 #define CONFIRM_BUTTON_YPOS     OK_BUTTON_YPOS
160 #define CONFIRM_BUTTON_XSIZE    96
161 #define CONFIRM_BUTTON_YSIZE    OK_BUTTON_YSIZE
162
163 #define ON_YESNO_BUTTON(x,y)    (((x)>=(DX+OK_BUTTON_XPOS) &&           \
164                                   (x)< (DX+OK_BUTTON_XPOS +             \
165                                         OK_BUTTON_XSIZE) &&             \
166                                   (y)>=(DY+OK_BUTTON_YPOS) &&           \
167                                   (y)< (DY+OK_BUTTON_YPOS +             \
168                                         OK_BUTTON_YSIZE)) ||            \
169                                  ((x)>=(DX+NO_BUTTON_XPOS) &&           \
170                                   (x)< (DX+NO_BUTTON_XPOS +             \
171                                         NO_BUTTON_XSIZE) &&             \
172                                   (y)>=(DY+NO_BUTTON_YPOS) &&           \
173                                   (y)< (DY+NO_BUTTON_YPOS +             \
174                                         NO_BUTTON_YSIZE)))
175 #define ON_CONFIRM_BUTTON(x,y)  (((x)>=(DX+CONFIRM_BUTTON_XPOS) &&      \
176                                   (x)< (DX+CONFIRM_BUTTON_XPOS +        \
177                                         CONFIRM_BUTTON_XSIZE) &&        \
178                                   (y)>=(DY+CONFIRM_BUTTON_YPOS) &&      \
179                                   (y)< (DY+CONFIRM_BUTTON_YPOS +        \
180                                         CONFIRM_BUTTON_YSIZE)))
181 #define YESNO_BUTTON(x)         (((x)-(DX+OK_BUTTON_XPOS))/OK_BUTTON_XSIZE)
182
183 /* some positions in the choose player window */
184 #define PLAYER_BUTTON_XSIZE     30
185 #define PLAYER_BUTTON_YSIZE     30
186 #define PLAYER_BUTTON_GFX_XPOS  5
187 #define PLAYER_BUTTON_GFX_YPOS  (215-30)
188 #define PLAYER_CONTROL_XPOS     (5 + PLAYER_BUTTON_XSIZE/2)
189 #define PLAYER_CONTROL_YPOS     (215 - PLAYER_BUTTON_YSIZE/2)
190 #define PLAYER_CONTROL_XSIZE    (2*PLAYER_BUTTON_XSIZE)
191 #define PLAYER_CONTROL_YSIZE    (2*PLAYER_BUTTON_YSIZE)
192 #define PLAYER_BUTTON_1_XPOS    (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE)
193 #define PLAYER_BUTTON_2_XPOS    (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE)
194 #define PLAYER_BUTTON_3_XPOS    (PLAYER_CONTROL_XPOS + 0 * PLAYER_BUTTON_XSIZE)
195 #define PLAYER_BUTTON_4_XPOS    (PLAYER_CONTROL_XPOS + 1 * PLAYER_BUTTON_XSIZE)
196 #define PLAYER_BUTTON_1_YPOS    (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE)
197 #define PLAYER_BUTTON_2_YPOS    (PLAYER_CONTROL_YPOS + 0 * PLAYER_BUTTON_YSIZE)
198 #define PLAYER_BUTTON_3_YPOS    (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE)
199 #define PLAYER_BUTTON_4_YPOS    (PLAYER_CONTROL_YPOS + 1 * PLAYER_BUTTON_YSIZE)
200
201 #define ON_PLAYER_BUTTON(x,y)   ((x)>=(DX+PLAYER_CONTROL_XPOS) &&       \
202                                  (x)< (DX+PLAYER_CONTROL_XPOS +         \
203                                        PLAYER_CONTROL_XSIZE) &&         \
204                                  (y)>=(DY+PLAYER_CONTROL_YPOS) &&       \
205                                  (y)< (DY+PLAYER_CONTROL_YPOS +         \
206                                        PLAYER_CONTROL_YSIZE))
207 #define PLAYER_BUTTON(x,y)      ((((x)-(DX+PLAYER_CONTROL_XPOS)) /      \
208                                   PLAYER_BUTTON_XSIZE) + 2 *            \
209                                  (((y)-(DY+PLAYER_CONTROL_YPOS)) /      \
210                                   PLAYER_BUTTON_YSIZE))
211
212
213 /* some definitions for the editor control window */
214
215 #define ON_EDIT_BUTTON(x,y)     (((x)>=(VX+ED_BUTTON_CTRL_XPOS) &&      \
216                                   (x)< (VX+ED_BUTTON_CTRL_XPOS +        \
217                                         ED_BUTTON_CTRL_XSIZE) &&        \
218                                   (y)>=(VY+ED_BUTTON_CTRL_YPOS) &&      \
219                                   (y)< (VY+ED_BUTTON_CTRL_YPOS +        \
220                                         ED_BUTTON_CTRL_YSIZE +          \
221                                         ED_BUTTON_FILL_YSIZE)) ||       \
222                                  ((x)>=(VX+ED_BUTTON_LEFT_XPOS) &&      \
223                                   (x)< (VX+ED_BUTTON_LEFT_XPOS +        \
224                                         ED_BUTTON_LEFT_XSIZE +          \
225                                         ED_BUTTON_UP_XSIZE +            \
226                                         ED_BUTTON_RIGHT_XSIZE) &&       \
227                                   (y)>=(VY+ED_BUTTON_LEFT_YPOS) &&      \
228                                   (y)< (VY+ED_BUTTON_LEFT_YPOS +        \
229                                         ED_BUTTON_LEFT_YSIZE)) ||       \
230                                  ((x)>=(VX+ED_BUTTON_UP_XPOS) &&        \
231                                   (x)< (VX+ED_BUTTON_UP_XPOS +          \
232                                         ED_BUTTON_UP_XSIZE) &&          \
233                                   (y)>=(VY+ED_BUTTON_UP_YPOS) &&        \
234                                   (y)< (VY+ED_BUTTON_UP_YPOS +          \
235                                         ED_BUTTON_UP_YSIZE +            \
236                                         ED_BUTTON_DOWN_YSIZE)))
237
238 #define ON_CTRL_BUTTON(x,y)     ((x)>=(VX+ED_BUTTON_EDIT_XPOS) &&       \
239                                  (x)< (VX+ED_BUTTON_EDIT_XPOS +         \
240                                        ED_BUTTON_EDIT_XSIZE) &&         \
241                                  (y)>=(VY+ED_BUTTON_EDIT_YPOS) &&       \
242                                  (y)< (VY+ED_BUTTON_EDIT_YPOS +         \
243                                        ED_BUTTON_EDIT_YSIZE +           \
244                                        ED_BUTTON_CLEAR_YSIZE +          \
245                                        ED_BUTTON_UNDO_YSIZE +           \
246                                        ED_BUTTON_EXIT_YSIZE))
247
248 #define ON_ELEM_BUTTON(x,y)     (((x)>=(DX+ED_BUTTON_EUP_XPOS) &&       \
249                                   (x)< (DX+ED_BUTTON_EUP_XPOS +         \
250                                         ED_BUTTON_EUP_XSIZE) &&         \
251                                   (y)>=(DY+ED_BUTTON_EUP_YPOS) &&       \
252                                   (y)< (DY+ED_BUTTON_EUP_YPOS +         \
253                                         ED_BUTTON_EUP_YSIZE)) ||        \
254                                  ((x)>=(DX+ED_BUTTON_EDOWN_XPOS) &&     \
255                                   (x)< (DX+ED_BUTTON_EDOWN_XPOS +       \
256                                         ED_BUTTON_EDOWN_XSIZE) &&       \
257                                   (y)>=(DY+ED_BUTTON_EDOWN_YPOS) &&     \
258                                   (y)< (DY+ED_BUTTON_EDOWN_YPOS +       \
259                                         ED_BUTTON_EDOWN_YSIZE)) ||      \
260                                  ((x)>=(DX+ED_BUTTON_ELEM_XPOS) &&      \
261                                   (x)< (DX+ED_BUTTON_ELEM_XPOS +        \
262                                         MAX_ELEM_X*ED_BUTTON_ELEM_XSIZE) && \
263                                   (y)>=(DY+ED_BUTTON_ELEM_YPOS) &&      \
264                                   (y)< (DY+ED_BUTTON_ELEM_YPOS +        \
265                                         MAX_ELEM_Y*ED_BUTTON_ELEM_YSIZE)))
266
267 #define ON_COUNT_BUTTON(x,y)    (((((x)>=ED_COUNT_GADGET_XPOS &&        \
268                                     (x)<(ED_COUNT_GADGET_XPOS +         \
269                                          ED_BUTTON_MINUS_XSIZE)) ||     \
270                                    ((x)>=(ED_COUNT_GADGET_XPOS +        \
271                                           (ED_BUTTON_PLUS_XPOS -        \
272                                            ED_BUTTON_MINUS_XPOS)) &&    \
273                                     (x)<(ED_COUNT_GADGET_XPOS +         \
274                                          (ED_BUTTON_PLUS_XPOS -         \
275                                           ED_BUTTON_MINUS_XPOS) +       \
276                                          ED_BUTTON_PLUS_XSIZE))) &&     \
277                                   ((y)>=ED_COUNT_GADGET_YPOS &&         \
278                                    (y)<(ED_COUNT_GADGET_YPOS +          \
279                                         16*ED_COUNT_GADGET_YSIZE)) &&   \
280                                   (((y)-ED_COUNT_GADGET_YPOS) %         \
281                                    ED_COUNT_GADGET_YSIZE) <             \
282                                   ED_BUTTON_MINUS_YSIZE) ||             \
283                                  ((((x)>=ED_SIZE_GADGET_XPOS &&         \
284                                     (x)<(ED_SIZE_GADGET_XPOS +          \
285                                          ED_BUTTON_MINUS_XSIZE)) ||     \
286                                    ((x)>=(ED_SIZE_GADGET_XPOS +         \
287                                           (ED_BUTTON_PLUS_XPOS -        \
288                                            ED_BUTTON_MINUS_XPOS)) &&    \
289                                     (x)<(ED_SIZE_GADGET_XPOS +          \
290                                          (ED_BUTTON_PLUS_XPOS -         \
291                                           ED_BUTTON_MINUS_XPOS) +       \
292                                          ED_BUTTON_PLUS_XSIZE))) &&     \
293                                   ((y)>=ED_SIZE_GADGET_YPOS &&          \
294                                    (y)<(ED_SIZE_GADGET_YPOS +           \
295                                         2*ED_SIZE_GADGET_YSIZE)) &&     \
296                                   (((y)-ED_SIZE_GADGET_YPOS) %          \
297                                    ED_SIZE_GADGET_YSIZE) <              \
298                                   ED_BUTTON_MINUS_YSIZE))
299
300 #define EDIT_BUTTON(x,y)        (((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
301                                          ED_BUTTON_CTRL_YSIZE)) ? 0 :   \
302                                  ((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
303                                          ED_BUTTON_CTRL_YSIZE +         \
304                                          ED_BUTTON_FILL_YSIZE)) ? 1 :   \
305                                  ((x) < (VX + ED_BUTTON_LEFT_XPOS +     \
306                                          ED_BUTTON_LEFT_XSIZE) ? 2 :    \
307                                   (x) > (VX + ED_BUTTON_LEFT_XPOS +     \
308                                          ED_BUTTON_LEFT_XSIZE +         \
309                                          ED_BUTTON_UP_XSIZE) ? 5 :      \
310                                   3+(((y)-(VY + ED_BUTTON_CTRL_YPOS +   \
311                                            ED_BUTTON_CTRL_YSIZE +       \
312                                            ED_BUTTON_FILL_YSIZE)) /     \
313                                      ED_BUTTON_UP_YSIZE)))
314
315 #define CTRL_BUTTON(x,y)        (((y) < (VY + ED_BUTTON_EDIT_YPOS +     \
316                                          ED_BUTTON_EDIT_YSIZE)) ? 0 :   \
317                                  1+(((y)-(VY + ED_BUTTON_EDIT_YPOS +    \
318                                          ED_BUTTON_EDIT_YSIZE)) /       \
319                                     ED_BUTTON_CLEAR_YSIZE))
320
321 #define ELEM_BUTTON(x,y)        (((y) < (DY + ED_BUTTON_EUP_YPOS +      \
322                                          ED_BUTTON_EUP_YSIZE)) ? 0 :    \
323                                  ((y) > (DY + ED_BUTTON_EDOWN_YPOS)) ? 1 : \
324                                  2+(((y) - (DY + ED_BUTTON_ELEM_YPOS)) /   \
325                                  ED_BUTTON_ELEM_YSIZE)*MAX_ELEM_X +     \
326                                  ((x) - (DX + ED_BUTTON_ELEM_XPOS)) /   \
327                                  ED_BUTTON_ELEM_XSIZE)
328
329 #define COUNT_BUTTON(x,y)       ((x) < ED_SIZE_GADGET_XPOS ?            \
330                                  ((((y) - ED_COUNT_GADGET_YPOS) /       \
331                                    ED_COUNT_GADGET_YSIZE)*2 +           \
332                                   ((x) < (ED_COUNT_GADGET_XPOS +        \
333                                           ED_BUTTON_MINUS_XSIZE) ? 0 : 1)) : \
334                                  32+((((y) - ED_SIZE_GADGET_YPOS) /     \
335                                       ED_SIZE_GADGET_YSIZE)*2 +         \
336                                      ((x) < (ED_SIZE_GADGET_XPOS +      \
337                                              ED_BUTTON_MINUS_XSIZE) ? 0 : 1)))
338
339 /****************************************************************/
340 /********** drawing buttons and corresponding displays **********/
341 /****************************************************************/
342
343 void DrawVideoDisplay(unsigned long state, unsigned long value)
344 {
345   int i;
346   int part_label = 0, part_symbol = 1;
347   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
348   static char *monatsname[12] =
349   {
350     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
351     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
352   };
353   static int video_pos[10][2][4] =
354   {
355     {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
356        VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE },
357      { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
358        VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }},
359
360     {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
361        VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE },
362      { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
363        VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }},
364
365     {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
366        VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE },
367      { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
368        VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }},
369
370     {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
371        VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE },
372      { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
373        VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }},
374
375     {{ 0,0,
376        0,0 },
377      { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
378        VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }},
379
380     {{ VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS,
381        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
382      { 0,0,
383        0,0 }},
384
385     {{ VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS,
386        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
387      { 0,0,
388        0,0 }},
389
390     {{ VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS,
391        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
392      { 0,0,
393        0,0 }},
394
395     {{ VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS,
396        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
397      { 0,0,
398        0,0 }},
399
400     {{ VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS,
401        VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE },
402      { 0,0,
403        0,0 }}
404   };
405
406   if (state & VIDEO_STATE_PBEND_OFF)
407   {
408     int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
409
410     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
411               cx + VIDEO_REC_LABEL_XPOS,
412               cy + VIDEO_REC_LABEL_YPOS,
413               VIDEO_PBEND_LABEL_XSIZE,
414               VIDEO_PBEND_LABEL_YSIZE,
415               VX + VIDEO_REC_LABEL_XPOS,
416               VY + VIDEO_REC_LABEL_YPOS);
417   }
418
419   for(i=0;i<20;i++)
420   {
421     if (state & (1<<i))
422     {
423       int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
424
425       if (i%2)                  /* i ungerade => STATE_ON / PRESS_OFF */
426         cx = DOOR_GFX_PAGEX4;
427       else
428         cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
429
430       if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
431         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
432                   cx + video_pos[pos][part_label][xpos],
433                   cy + video_pos[pos][part_label][ypos],
434                   video_pos[pos][part_label][xsize],
435                   video_pos[pos][part_label][ysize],
436                   VX + video_pos[pos][part_label][xpos],
437                   VY + video_pos[pos][part_label][ypos]);
438       if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
439         XCopyArea(display,pix[PIX_DOOR],drawto,gc,
440                   cx + video_pos[pos][part_symbol][xpos],
441                   cy + video_pos[pos][part_symbol][ypos],
442                   video_pos[pos][part_symbol][xsize],
443                   video_pos[pos][part_symbol][ysize],
444                   VX + video_pos[pos][part_symbol][xpos],
445                   VY + video_pos[pos][part_symbol][ypos]);
446     }
447   }
448
449   if (state & VIDEO_STATE_FFWD_ON)
450   {
451     int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
452
453     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
454               cx + VIDEO_PLAY_SYMBOL_XPOS,
455               cy + VIDEO_PLAY_SYMBOL_YPOS,
456               VIDEO_PLAY_SYMBOL_XSIZE - 2,
457               VIDEO_PLAY_SYMBOL_YSIZE,
458               VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
459               VY + VIDEO_PLAY_SYMBOL_YPOS);
460   }
461
462   if (state & VIDEO_STATE_PBEND_ON)
463   {
464     int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
465
466     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
467               cx + VIDEO_PBEND_LABEL_XPOS,
468               cy + VIDEO_PBEND_LABEL_YPOS,
469               VIDEO_PBEND_LABEL_XSIZE,
470               VIDEO_PBEND_LABEL_YSIZE,
471               VX + VIDEO_REC_LABEL_XPOS,
472               VY + VIDEO_REC_LABEL_YPOS);
473   }
474
475   if (state & VIDEO_STATE_DATE_ON)
476   {
477     int tag = value % 100;
478     int monat = (value/100) % 100;
479     int jahr = (value/10000);
480
481     DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
482              int2str(tag,2),FS_SMALL,FC_SPECIAL1);
483     DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
484              monatsname[monat],FS_SMALL,FC_SPECIAL1);
485     DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
486              int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
487   }
488
489   if (state & VIDEO_STATE_TIME_ON)
490   {
491     int min = value / 60;
492     int sec = value % 60;
493
494     DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
495              int2str(min,2),FS_SMALL,FC_SPECIAL1);
496     DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
497              int2str(sec,2),FS_SMALL,FC_SPECIAL1);
498   }
499
500   if (state & VIDEO_STATE_DATE)
501     redraw_mask |= REDRAW_VIDEO_1;
502   if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
503     redraw_mask |= REDRAW_VIDEO_2;
504   if (state & VIDEO_PRESS)
505     redraw_mask |= REDRAW_VIDEO_3;
506 }
507
508 void DrawCompleteVideoDisplay()
509 {
510   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
511             DOOR_GFX_PAGEX3,DOOR_GFX_PAGEY2, VXSIZE,VYSIZE, VX,VY);
512   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
513             DOOR_GFX_PAGEX4+VIDEO_CONTROL_XPOS,
514             DOOR_GFX_PAGEY2+VIDEO_CONTROL_YPOS,
515             VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
516             VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
517
518   DrawVideoDisplay(VIDEO_ALL_OFF,0);
519   if (tape.date && tape.length)
520   {
521     DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
522     DrawVideoDisplay(VIDEO_STATE_TIME_ON,tape.length_seconds);
523   }
524
525   XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
526             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
527 }
528
529 void DrawSoundDisplay(unsigned long state)
530 {
531   int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
532
533   pos = (state & BUTTON_SOUND_MUSIC ? SOUND_BUTTON_MUSIC_XPOS :
534          state & BUTTON_SOUND_LOOPS ? SOUND_BUTTON_LOOPS_XPOS :
535          SOUND_BUTTON_SIMPLE_XPOS);
536
537   if (state & BUTTON_ON)
538     cy -= SOUND_BUTTON_YSIZE;
539
540   if (state & BUTTON_PRESSED)
541     cx = DOOR_GFX_PAGEX3;
542
543   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
544             cx + pos,cy + SOUND_BUTTON_ANY_YPOS,
545             SOUND_BUTTON_XSIZE,SOUND_BUTTON_YSIZE,
546             DX + pos,DY + SOUND_BUTTON_ANY_YPOS);
547
548   redraw_mask |= REDRAW_DOOR_1;
549 }
550
551 void DrawGameButton(unsigned long state)
552 {
553   int pos, cx = DOOR_GFX_PAGEX4, cy = -GAME_BUTTON_YSIZE;
554
555   pos = (state & BUTTON_GAME_STOP ? GAME_BUTTON_STOP_XPOS :
556          state & BUTTON_GAME_PAUSE ? GAME_BUTTON_PAUSE_XPOS :
557          GAME_BUTTON_PLAY_XPOS);
558
559   if (state & BUTTON_PRESSED)
560     cx = DOOR_GFX_PAGEX3;
561
562   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
563             cx + pos,cy + GAME_BUTTON_ANY_YPOS,
564             GAME_BUTTON_XSIZE,GAME_BUTTON_YSIZE,
565             DX + pos,DY + GAME_BUTTON_ANY_YPOS);
566
567   redraw_mask |= REDRAW_DOOR_1;
568 }
569
570 void DrawYesNoButton(unsigned long state, int mode)
571 {
572   Drawable dest_drawto;
573   int dest_xoffset, dest_yoffset;
574   int xpos, cx = DOOR_GFX_PAGEX4;
575
576   if (mode == DB_INIT)
577   {
578     dest_drawto = pix[PIX_DB_DOOR];
579     dest_xoffset = DOOR_GFX_PAGEX1;
580     dest_yoffset = 0;
581   }
582   else
583   {
584     dest_drawto = drawto;
585     dest_xoffset = DX;
586     dest_yoffset = DY;
587   }
588
589   xpos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS);
590
591   if (state & BUTTON_PRESSED)
592     cx = DOOR_GFX_PAGEX3;
593
594   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
595             cx + xpos, OK_BUTTON_GFX_YPOS,
596             OK_BUTTON_XSIZE, OK_BUTTON_YSIZE,
597             dest_xoffset + xpos, dest_yoffset + OK_BUTTON_YPOS);
598
599   redraw_mask |= REDRAW_DOOR_1;
600 }
601
602 void DrawConfirmButton(unsigned long state, int mode)
603 {
604   Drawable dest_drawto;
605   int dest_xoffset, dest_yoffset;
606   int cx = DOOR_GFX_PAGEX4;
607
608   if (mode == DB_INIT)
609   {
610     dest_drawto = pix[PIX_DB_DOOR];
611     dest_xoffset = DOOR_GFX_PAGEX1;
612     dest_yoffset = 0;
613   }
614   else
615   {
616     dest_drawto = drawto;
617     dest_xoffset = DX;
618     dest_yoffset = DY;
619   }
620
621   if (state & BUTTON_PRESSED)
622     cx = DOOR_GFX_PAGEX3;
623
624   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
625             cx + CONFIRM_BUTTON_XPOS, CONFIRM_BUTTON_GFX_YPOS,
626             CONFIRM_BUTTON_XSIZE, CONFIRM_BUTTON_YSIZE,
627             dest_xoffset + CONFIRM_BUTTON_XPOS,
628             dest_yoffset + CONFIRM_BUTTON_YPOS);
629
630   redraw_mask |= REDRAW_DOOR_1;
631 }
632
633 void DrawPlayerButton(unsigned long state, int mode)
634 {
635   Drawable dest_drawto;
636   int dest_xoffset, dest_yoffset;
637   int graphic = GFX_SPIELER1;   /* default */
638   int graphic_offset = (PLAYER_BUTTON_XSIZE - TILEX/2)/2;
639   int xpos, ypos;
640   int cx = DOOR_GFX_PAGEX4, cy = 0;
641
642   if (mode == DB_INIT)
643   {
644     dest_drawto = pix[PIX_DB_DOOR];
645     dest_xoffset = DOOR_GFX_PAGEX1;
646     dest_yoffset = 0;
647   }
648   else
649   {
650     dest_drawto = drawto;
651     dest_xoffset = DX;
652     dest_yoffset = DY;
653   }
654
655   if (state & BUTTON_PLAYER_1)
656     graphic = GFX_SPIELER1;
657   else if (state & BUTTON_PLAYER_2)
658     graphic = GFX_SPIELER2;
659   else if (state & BUTTON_PLAYER_3)
660     graphic = GFX_SPIELER3;
661   else if (state & BUTTON_PLAYER_4)
662     graphic = GFX_SPIELER4;
663
664   xpos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_3 ?
665           PLAYER_BUTTON_1_XPOS : PLAYER_BUTTON_2_XPOS);
666   ypos = (state & BUTTON_PLAYER_1 || state & BUTTON_PLAYER_2 ?
667           PLAYER_BUTTON_1_YPOS : PLAYER_BUTTON_3_YPOS);
668
669   if (state & BUTTON_PRESSED)
670   {
671     cx = DOOR_GFX_PAGEX3;
672     graphic_offset += 1;
673   }
674
675   XCopyArea(display, pix[PIX_DOOR], dest_drawto, gc,
676             cx + PLAYER_BUTTON_GFX_XPOS, cy + PLAYER_BUTTON_GFX_YPOS,
677             PLAYER_BUTTON_XSIZE, PLAYER_BUTTON_YSIZE,
678             dest_xoffset + xpos, dest_yoffset + ypos);
679   DrawMiniGraphicExt(dest_drawto,gc,
680                      dest_xoffset + xpos + graphic_offset,
681                      dest_yoffset + ypos + graphic_offset,
682                      graphic);
683
684   redraw_mask |= REDRAW_DOOR_1;
685 }
686
687 /* several buttons in the level editor */
688
689 void DrawEditButton(unsigned long state)
690 {
691   int i;
692   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
693   int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY2;
694   static int edit_pos[6][4] =
695   {
696    {ED_BUTTON_CTRL_XPOS,ED_BUTTON_CTRL_YPOS,
697     ED_BUTTON_CTRL_XSIZE,ED_BUTTON_CTRL_YSIZE},
698
699    {ED_BUTTON_FILL_XPOS,ED_BUTTON_FILL_YPOS,
700     ED_BUTTON_FILL_XSIZE,ED_BUTTON_FILL_YSIZE},
701
702    {ED_BUTTON_LEFT_XPOS,ED_BUTTON_LEFT_YPOS,
703     ED_BUTTON_LEFT_XSIZE,ED_BUTTON_LEFT_YSIZE},
704
705    {ED_BUTTON_UP_XPOS,ED_BUTTON_UP_YPOS,
706     ED_BUTTON_UP_XSIZE,ED_BUTTON_UP_YSIZE},
707
708    {ED_BUTTON_DOWN_XPOS,ED_BUTTON_DOWN_YPOS,
709     ED_BUTTON_DOWN_XSIZE,ED_BUTTON_DOWN_YSIZE},
710
711    {ED_BUTTON_RIGHT_XPOS,ED_BUTTON_RIGHT_YPOS,
712     ED_BUTTON_RIGHT_XSIZE,ED_BUTTON_RIGHT_YSIZE}
713   };
714
715   if (state & ED_BUTTON_PRESSED)
716     cx = DOOR_GFX_PAGEX5;
717
718   for(i=0;i<6;i++)
719   {
720     if (state & (1<<i))
721       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
722                 cx + edit_pos[i][xpos],
723                 cy + edit_pos[i][ypos],
724                 edit_pos[i][xsize],
725                 edit_pos[i][ysize],
726                 VX + edit_pos[i][xpos],
727                 VY + edit_pos[i][ypos]);
728   }
729
730   redraw_mask |= REDRAW_DOOR_2;
731 }
732
733 void DrawCtrlButton(unsigned long state)
734 {
735   int i;
736   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
737   int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY1+80;
738   static int edit_pos[4][4] =
739   {
740    {ED_BUTTON_EDIT_XPOS,ED_BUTTON_EDIT_YPOS,
741     ED_BUTTON_EDIT_XSIZE,ED_BUTTON_EDIT_YSIZE},
742
743    {ED_BUTTON_CLEAR_XPOS,ED_BUTTON_CLEAR_YPOS,
744     ED_BUTTON_CLEAR_XSIZE,ED_BUTTON_CLEAR_YSIZE},
745
746    {ED_BUTTON_UNDO_XPOS,ED_BUTTON_UNDO_YPOS,
747     ED_BUTTON_UNDO_XSIZE,ED_BUTTON_UNDO_YSIZE},
748
749    {ED_BUTTON_EXIT_XPOS,ED_BUTTON_EXIT_YPOS,
750     ED_BUTTON_EXIT_XSIZE,ED_BUTTON_EXIT_YSIZE}
751   };
752
753   if (state & ED_BUTTON_PRESSED)
754     cx = DOOR_GFX_PAGEX3;
755
756   for(i=0;i<4;i++)
757   {
758     if (state & (1<<(i+6)))
759       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
760                 cx + edit_pos[i][xpos],
761                 cy + edit_pos[i][ypos],
762                 edit_pos[i][xsize],
763                 edit_pos[i][ysize],
764                 VX + edit_pos[i][xpos],
765                 VY + edit_pos[i][ypos]);
766   }
767
768   redraw_mask |= REDRAW_DOOR_2;
769 }
770
771 void DrawElemButton(int button_nr, int button_state)
772 {
773   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
774   int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
775   int from_x, from_y, to_x,to_y, size_x, size_y;
776   static int edit_pos[3][4] =
777   {
778    {ED_BUTTON_EUP_XPOS,ED_BUTTON_EUP_YPOS,
779     ED_BUTTON_EUP_XSIZE,ED_BUTTON_EUP_YSIZE},
780
781    {ED_BUTTON_EDOWN_XPOS,ED_BUTTON_EDOWN_YPOS,
782     ED_BUTTON_EDOWN_XSIZE,ED_BUTTON_EDOWN_YSIZE},
783
784    {ED_BUTTON_ELEM_XPOS,ED_BUTTON_ELEM_YPOS,
785     ED_BUTTON_ELEM_XSIZE,ED_BUTTON_ELEM_YSIZE}
786   };
787
788   if (button_nr<ED_BUTTON_ELEM)
789   {
790     int pos = button_nr;
791
792     from_x = cx + edit_pos[pos][xpos];
793     from_y = cy + edit_pos[pos][ypos];
794     size_x = edit_pos[pos][xsize];
795     size_y = edit_pos[pos][ysize];
796     to_x   = DX + edit_pos[pos][xpos];
797     to_y   = DY + edit_pos[pos][ypos];
798
799     if (button_state & ED_BUTTON_PRESSED)
800     {
801       if (button_nr==ED_BUTTON_EUP)
802         from_y = cy + ED_BUTTON_EUP_Y2POS;
803       else
804         from_y = cy + ED_BUTTON_EDOWN_Y2POS;
805     }
806
807     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
808               from_x,from_y, size_x,size_y, to_x,to_y);
809   }
810   else
811   {
812     int pos = ED_BUTTON_ELEM;
813     int elem_pos = button_nr-ED_BUTTON_ELEM;
814     int x = elem_pos % MAX_ELEM_X;
815     int y = elem_pos / MAX_ELEM_X;
816     int graphic;
817     int shift = 0;
818
819     if (elem_pos+element_shift < elements_in_list)
820       graphic = el2gfx(editor_element[elem_pos+element_shift]);
821     else
822       graphic = GFX_LEERRAUM;
823
824     from_x = cx + edit_pos[pos][xpos];
825     from_y = cy + edit_pos[pos][ypos];
826     size_x = edit_pos[pos][xsize];
827     size_y = edit_pos[pos][ysize];
828     to_x   = DX + edit_pos[pos][xpos] + x * ED_BUTTON_ELEM_XSIZE;
829     to_y   = DY + edit_pos[pos][ypos] + y * ED_BUTTON_ELEM_YSIZE;
830
831     if (button_state & ED_BUTTON_PRESSED)
832     {
833       from_y = ED_BUTTON_ELEM_Y2POS;
834       shift = 1;
835     }
836
837     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
838               from_x,from_y, size_x,size_y, to_x,to_y);
839
840     DrawMiniGraphicExt(drawto,gc,
841                        DX+ED_BUTTON_ELEM_XPOS+3+shift + 
842                        (elem_pos % MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
843                        DY+ED_BUTTON_ELEM_YPOS+3+shift +
844                        (elem_pos / MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
845                        graphic);
846   }
847
848   redraw_mask |= REDRAW_DOOR_1;
849 }
850
851 void DrawCountButton(int button_nr, int button_state)
852 {
853   int from_x, from_y, to_x,to_y, size_x, size_y;
854
855   from_x =
856     DOOR_GFX_PAGEX4+(button_nr%2 ? ED_BUTTON_PLUS_XPOS : ED_BUTTON_MINUS_XPOS);
857   from_y = DOOR_GFX_PAGEY1 + ED_BUTTON_MINUS_YPOS;
858   size_x = ED_BUTTON_MINUS_XSIZE;
859   size_y = ED_BUTTON_MINUS_YSIZE;
860   to_x = (button_nr<32 ? ED_COUNT_GADGET_XPOS : ED_SIZE_GADGET_XPOS);
861   if (button_nr % 2)
862     to_x += (ED_BUTTON_PLUS_XPOS - ED_BUTTON_MINUS_XPOS);
863   to_y = (button_nr<32 ? ED_COUNT_GADGET_YPOS : ED_SIZE_GADGET_YPOS) +
864     ((button_nr<32 ? button_nr : button_nr-32)/2)*ED_COUNT_GADGET_YSIZE;
865
866   if (button_state & ED_BUTTON_PRESSED)
867     from_x -= DXSIZE;
868
869   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
870             from_x,from_y, size_x,size_y, to_x,to_y);
871   XCopyArea(display,pix[PIX_DOOR],window,gc,
872             from_x,from_y, size_x,size_y, to_x,to_y);
873 }
874
875 /**********************************************************************/
876 /********** checking buttons (and redrawing them, if needed) **********/
877 /**********************************************************************/
878
879 int CheckVideoButtons(int mx, int my, int button)
880 {
881   int return_code = 0;
882   static int choice = -1;
883   static boolean pressed = FALSE;
884   static int video_button[5] =
885   {
886     VIDEO_PRESS_EJECT_ON,
887     VIDEO_PRESS_STOP_ON,
888     VIDEO_PRESS_PAUSE_ON,
889     VIDEO_PRESS_REC_ON,
890     VIDEO_PRESS_PLAY_ON
891   };
892
893   if (button)
894   {
895     if (!motion_status)         /* Maustaste neu gedrückt */
896     {
897       if (ON_VIDEO_BUTTON(mx,my))
898       {
899         choice = VIDEO_BUTTON(mx);
900         pressed = TRUE;
901         DrawVideoDisplay(video_button[choice],0);
902       }
903     }
904     else                        /* Mausbewegung bei gedrückter Maustaste */
905     {
906       if ((!ON_VIDEO_BUTTON(mx,my) || VIDEO_BUTTON(mx)!=choice) &&
907           choice>=0 && pressed)
908       {
909         pressed = FALSE;
910         DrawVideoDisplay(video_button[choice]<<1,0);
911       }
912       else if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && !pressed)
913       {
914         pressed = TRUE;
915         DrawVideoDisplay(video_button[choice],0);
916       }
917     }
918   }
919   else                          /* Maustaste wieder losgelassen */
920   {
921     if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && pressed)
922     {
923       DrawVideoDisplay(video_button[choice]<<1,0);
924       return_code = choice+1;
925       choice = -1;
926       pressed = FALSE;
927     }
928     else
929     {
930       choice = -1;
931       pressed = FALSE;
932     }
933   }
934
935   BackToFront();
936   return(return_code);
937 }
938
939 int CheckSoundButtons(int mx, int my, int button)
940 {
941   int return_code = 0;
942   static int choice = -1;
943   static boolean pressed = FALSE;
944   int sound_state[3];
945
946   sound_state[0] = BUTTON_SOUND_MUSIC  | (BUTTON_ON * setup.sound_music);
947   sound_state[1] = BUTTON_SOUND_LOOPS  | (BUTTON_ON * setup.sound_loops);
948   sound_state[2] = BUTTON_SOUND_SIMPLE | (BUTTON_ON * setup.sound_simple);
949
950   if (button)
951   {
952     if (!motion_status)         /* Maustaste neu gedrückt */
953     {
954       if (ON_SOUND_BUTTON(mx,my))
955       {
956         choice = SOUND_BUTTON(mx);
957         pressed = TRUE;
958         DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
959       }
960     }
961     else                        /* Mausbewegung bei gedrückter Maustaste */
962     {
963       if ((!ON_SOUND_BUTTON(mx,my) || SOUND_BUTTON(mx)!=choice) &&
964           choice>=0 && pressed)
965       {
966         pressed = FALSE;
967         DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
968       }
969       else if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && !pressed)
970       {
971         pressed = TRUE;
972         DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
973       }
974     }
975   }
976   else                          /* Maustaste wieder losgelassen */
977   {
978     if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && pressed)
979     {
980       DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
981       return_code = 1<<choice;
982       choice = -1;
983       pressed = FALSE;
984     }
985     else
986     {
987       choice = -1;
988       pressed = FALSE;
989     }
990   }
991
992   BackToFront();
993   return(return_code);
994 }
995
996 int CheckGameButtons(int mx, int my, int button)
997 {
998   int return_code = 0;
999   static int choice = -1;
1000   static boolean pressed = FALSE;
1001   int game_state[3] =
1002   {
1003     BUTTON_GAME_STOP,
1004     BUTTON_GAME_PAUSE,
1005     BUTTON_GAME_PLAY
1006   };
1007
1008   if (button)
1009   {
1010     if (!motion_status)         /* Maustaste neu gedrückt */
1011     {
1012       if (ON_GAME_BUTTON(mx,my))
1013       {
1014         choice = GAME_BUTTON(mx);
1015         pressed = TRUE;
1016         DrawGameButton(game_state[choice] | BUTTON_PRESSED);
1017       }
1018     }
1019     else                        /* Mausbewegung bei gedrückter Maustaste */
1020     {
1021       if ((!ON_GAME_BUTTON(mx,my) || GAME_BUTTON(mx)!=choice) &&
1022           choice>=0 && pressed)
1023       {
1024         pressed = FALSE;
1025         DrawGameButton(game_state[choice] | BUTTON_RELEASED);
1026       }
1027       else if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && !pressed)
1028       {
1029         pressed = TRUE;
1030         DrawGameButton(game_state[choice] | BUTTON_PRESSED);
1031       }
1032     }
1033   }
1034   else                          /* Maustaste wieder losgelassen */
1035   {
1036     if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && pressed)
1037     {
1038       DrawGameButton(game_state[choice] | BUTTON_RELEASED);
1039       return_code = 1<<choice;
1040       choice = -1;
1041       pressed = FALSE;
1042     }
1043     else
1044     {
1045       choice = -1;
1046       pressed = FALSE;
1047     }
1048   }
1049
1050   BackToFront();
1051   return(return_code);
1052 }
1053
1054 int CheckYesNoButtons(int mx, int my, int button)
1055 {
1056   int return_code = 0;
1057   static int choice = -1;
1058   static boolean pressed = FALSE;
1059   static int yesno_button[5] =
1060   {
1061     BUTTON_OK,
1062     BUTTON_NO
1063   };
1064
1065   if (button)
1066   {
1067     if (!motion_status)         /* Maustaste neu gedrückt */
1068     {
1069       if (ON_YESNO_BUTTON(mx,my))
1070       {
1071         choice = YESNO_BUTTON(mx);
1072         pressed = TRUE;
1073         DrawYesNoButton(yesno_button[choice] | BUTTON_PRESSED, DB_NORMAL);
1074       }
1075     }
1076     else                        /* Mausbewegung bei gedrückter Maustaste */
1077     {
1078       if ((!ON_YESNO_BUTTON(mx,my) || YESNO_BUTTON(mx)!=choice) &&
1079           choice>=0 && pressed)
1080       {
1081         pressed = FALSE;
1082         DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL);
1083       }
1084       else if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && !pressed)
1085       {
1086         pressed = TRUE;
1087         DrawYesNoButton(yesno_button[choice] | BUTTON_PRESSED, DB_NORMAL);
1088       }
1089     }
1090   }
1091   else                          /* Maustaste wieder losgelassen */
1092   {
1093     if (ON_YESNO_BUTTON(mx,my) && YESNO_BUTTON(mx)==choice && pressed)
1094     {
1095       DrawYesNoButton(yesno_button[choice] | BUTTON_RELEASED, DB_NORMAL);
1096       return_code = choice+1;
1097       choice = -1;
1098       pressed = FALSE;
1099     }
1100     else
1101     {
1102       choice = -1;
1103       pressed = FALSE;
1104     }
1105   }
1106
1107   BackToFront();
1108   return(return_code);
1109 }
1110
1111 int CheckConfirmButton(int mx, int my, int button)
1112 {
1113   int return_code = 0;
1114   static int choice = -1;
1115   static boolean pressed = FALSE;
1116
1117   if (button)
1118   {
1119     if (!motion_status)         /* Maustaste neu gedrückt */
1120     {
1121       if (ON_CONFIRM_BUTTON(mx,my))
1122       {
1123         choice = 0;
1124         pressed = TRUE;
1125         DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL);
1126       }
1127     }
1128     else                        /* Mausbewegung bei gedrückter Maustaste */
1129     {
1130       if (!ON_CONFIRM_BUTTON(mx,my) && choice>=0 && pressed)
1131       {
1132         pressed = FALSE;
1133         DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL);
1134       }
1135       else if (ON_CONFIRM_BUTTON(mx,my) && !pressed)
1136       {
1137         pressed = TRUE;
1138         DrawConfirmButton(BUTTON_PRESSED, DB_NORMAL);
1139       }
1140     }
1141   }
1142   else                          /* Maustaste wieder losgelassen */
1143   {
1144     if (ON_CONFIRM_BUTTON(mx,my) && pressed)
1145     {
1146       DrawConfirmButton(BUTTON_RELEASED, DB_NORMAL);
1147       return_code = BUTTON_CONFIRM;
1148       choice = -1;
1149       pressed = FALSE;
1150     }
1151     else
1152     {
1153       choice = -1;
1154       pressed = FALSE;
1155     }
1156   }
1157
1158   BackToFront();
1159   return(return_code);
1160 }
1161
1162 int CheckPlayerButtons(int mx, int my, int button)
1163 {
1164   int return_code = 0;
1165   static int choice = -1;
1166   static boolean pressed = FALSE;
1167   int player_state[4] =
1168   {
1169     BUTTON_PLAYER_1,
1170     BUTTON_PLAYER_2,
1171     BUTTON_PLAYER_3,
1172     BUTTON_PLAYER_4
1173   };
1174
1175   if (button)
1176   {
1177     if (!motion_status)         /* Maustaste neu gedrückt */
1178     {
1179       if (ON_PLAYER_BUTTON(mx,my))
1180       {
1181         choice = PLAYER_BUTTON(mx,my);
1182         pressed = TRUE;
1183         DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL);
1184       }
1185     }
1186     else                        /* Mausbewegung bei gedrückter Maustaste */
1187     {
1188       if ((!ON_PLAYER_BUTTON(mx,my) || PLAYER_BUTTON(mx,my)!=choice) &&
1189           choice>=0 && pressed)
1190       {
1191         pressed = FALSE;
1192         DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL);
1193       }
1194       else if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && !pressed)
1195       {
1196         pressed = TRUE;
1197         DrawPlayerButton(player_state[choice] | BUTTON_PRESSED, DB_NORMAL);
1198       }
1199     }
1200   }
1201   else                          /* Maustaste wieder losgelassen */
1202   {
1203     if (ON_PLAYER_BUTTON(mx,my) && PLAYER_BUTTON(mx,my)==choice && pressed)
1204     {
1205       DrawPlayerButton(player_state[choice] | BUTTON_RELEASED, DB_NORMAL);
1206       return_code = player_state[choice];
1207       choice = -1;
1208       pressed = FALSE;
1209     }
1210     else
1211     {
1212       choice = -1;
1213       pressed = FALSE;
1214     }
1215   }
1216
1217   BackToFront();
1218   return(return_code);
1219 }
1220
1221 /* several buttons in the level editor */
1222
1223 int CheckEditButtons(int mx, int my, int button)
1224 {
1225   int return_code = 0;
1226   static int choice = -1;
1227   static boolean pressed = FALSE;
1228   static int edit_button[6] =
1229   {
1230     ED_BUTTON_CTRL,
1231     ED_BUTTON_FILL,
1232     ED_BUTTON_LEFT,
1233     ED_BUTTON_UP,
1234     ED_BUTTON_DOWN,
1235     ED_BUTTON_RIGHT
1236   };
1237
1238   if (button)
1239   {
1240     if (!motion_status)         /* Maustaste neu gedrückt */
1241     {
1242       if (ON_EDIT_BUTTON(mx,my))
1243       {
1244         choice = EDIT_BUTTON(mx,my);
1245         pressed = TRUE;
1246         DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
1247         if (edit_button[choice]!=ED_BUTTON_CTRL &&
1248             edit_button[choice]!=ED_BUTTON_FILL)
1249           return_code = 1<<choice;
1250       }
1251     }
1252     else                        /* Mausbewegung bei gedrückter Maustaste */
1253     {
1254       if ((!ON_EDIT_BUTTON(mx,my) || EDIT_BUTTON(mx,my)!=choice) &&
1255           choice>=0 && pressed)
1256       {
1257         pressed = FALSE;
1258         DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
1259       }
1260       else if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice)
1261       {
1262         if (!pressed)
1263           DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
1264         pressed = TRUE;
1265         if (edit_button[choice]!=ED_BUTTON_CTRL &&
1266             edit_button[choice]!=ED_BUTTON_FILL)
1267           return_code = 1<<choice;
1268       }
1269     }
1270   }
1271   else                          /* Maustaste wieder losgelassen */
1272   {
1273     if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice && pressed)
1274     {
1275       DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
1276       if (edit_button[choice]==ED_BUTTON_CTRL ||
1277           edit_button[choice]==ED_BUTTON_FILL)
1278         return_code = 1<<choice;
1279       choice = -1;
1280       pressed = FALSE;
1281     }
1282     else
1283     {
1284       choice = -1;
1285       pressed = FALSE;
1286     }
1287   }
1288
1289   BackToFront();
1290   return(return_code);
1291 }
1292
1293 int CheckCtrlButtons(int mx, int my, int button)
1294 {
1295   int return_code = 0;
1296   static int choice = -1;
1297   static boolean pressed = FALSE;
1298   static int ctrl_button[4] =
1299   {
1300     ED_BUTTON_EDIT,
1301     ED_BUTTON_CLEAR,
1302     ED_BUTTON_UNDO,
1303     ED_BUTTON_EXIT
1304   };
1305
1306   if (button)
1307   {
1308     if (!motion_status)         /* Maustaste neu gedrückt */
1309     {
1310       if (ON_CTRL_BUTTON(mx,my))
1311       {
1312         choice = CTRL_BUTTON(mx,my);
1313         pressed = TRUE;
1314         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
1315       }
1316     }
1317     else                        /* Mausbewegung bei gedrückter Maustaste */
1318     {
1319       if ((!ON_CTRL_BUTTON(mx,my) || CTRL_BUTTON(mx,my)!=choice) &&
1320           choice>=0 && pressed)
1321       {
1322         pressed = FALSE;
1323         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
1324       }
1325       else if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && !pressed)
1326       {
1327         pressed = TRUE;
1328         DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
1329       }
1330     }
1331   }
1332   else                          /* Maustaste wieder losgelassen */
1333   {
1334     if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && pressed)
1335     {
1336       DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
1337       return_code = 1<<(choice+6);
1338       choice = -1;
1339       pressed = FALSE;
1340     }
1341     else
1342     {
1343       choice = -1;
1344       pressed = FALSE;
1345     }
1346   }
1347
1348   BackToFront();
1349   return(return_code);
1350 }
1351
1352 int CheckElemButtons(int mx, int my, int button)
1353 {
1354   int return_code = -1;
1355   static int choice = -1;
1356   static boolean pressed = FALSE;
1357
1358   if (button)
1359   {
1360     if (!motion_status)         /* Maustaste neu gedrückt */
1361     {
1362       if (ON_ELEM_BUTTON(mx,my))
1363       {
1364         choice = ELEM_BUTTON(mx,my);
1365         pressed = TRUE;
1366         DrawElemButton(choice,ED_BUTTON_PRESSED);
1367         if (choice==ED_BUTTON_EUP ||
1368             choice==ED_BUTTON_EDOWN)
1369           return_code = choice;
1370       }
1371     }
1372     else                        /* Mausbewegung bei gedrückter Maustaste */
1373     {
1374       if ((!ON_ELEM_BUTTON(mx,my) || ELEM_BUTTON(mx,my)!=choice) &&
1375           choice>=0 && pressed)
1376       {
1377         pressed = FALSE;
1378         DrawElemButton(choice,ED_BUTTON_RELEASED);
1379       }
1380       else if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice)
1381       {
1382         if (!pressed)
1383           DrawElemButton(choice,ED_BUTTON_PRESSED);
1384         pressed = TRUE;
1385         if (choice==ED_BUTTON_EUP ||
1386             choice==ED_BUTTON_EDOWN)
1387           return_code = choice;
1388       }
1389     }
1390   }
1391   else                          /* Maustaste wieder losgelassen */
1392   {
1393     if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice && pressed)
1394     {
1395       DrawElemButton(choice,ED_BUTTON_RELEASED);
1396       if (choice!=ED_BUTTON_EUP &&
1397           choice!=ED_BUTTON_EDOWN)
1398         return_code = choice;
1399       choice = -1;
1400       pressed = FALSE;
1401     }
1402     else
1403     {
1404       choice = -1;
1405       pressed = FALSE;
1406     }
1407   }
1408
1409   BackToFront();
1410   return(return_code);
1411 }
1412
1413 int CheckCountButtons(int mx, int my, int button)
1414 {
1415   int return_code = -1;
1416   static int choice = -1;
1417   static boolean pressed = FALSE;
1418
1419   if (button)
1420   {
1421     if (!motion_status)         /* Maustaste neu gedrückt */
1422     {
1423       if (ON_COUNT_BUTTON(mx,my))
1424       {
1425         choice = COUNT_BUTTON(mx,my);
1426         pressed = TRUE;
1427         DrawCountButton(choice,ED_BUTTON_PRESSED);
1428         return_code = choice;
1429       }
1430     }
1431     else                        /* Mausbewegung bei gedrückter Maustaste */
1432     {
1433       if ((!ON_COUNT_BUTTON(mx,my) || COUNT_BUTTON(mx,my)!=choice) &&
1434           choice>=0 && pressed)
1435       {
1436         pressed = FALSE;
1437         DrawCountButton(choice,ED_BUTTON_RELEASED);
1438       }
1439       else if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice)
1440       {
1441         if (!pressed)
1442           DrawCountButton(choice,ED_BUTTON_PRESSED);
1443         pressed = TRUE;
1444         return_code = choice;
1445       }
1446     }
1447   }
1448   else                          /* Maustaste wieder losgelassen */
1449   {
1450     if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice && pressed)
1451     {
1452       DrawCountButton(choice,ED_BUTTON_RELEASED);
1453       choice = -1;
1454       pressed = FALSE;
1455     }
1456     else
1457     {
1458       choice = -1;
1459       pressed = FALSE;
1460     }
1461   }
1462
1463   BackToFront();
1464   return(return_code);
1465 }
1466
1467
1468 /* NEW GADGET STUFF -------------------------------------------------------- */
1469
1470
1471 static struct GadgetInfo *gadget_list_first_entry = NULL;
1472 static struct GadgetInfo *gadget_list_last_entry = NULL;
1473 static int next_free_gadget_id = 1;
1474 static boolean gadget_id_wrapped = FALSE;
1475
1476 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
1477 {
1478   struct GadgetInfo *gi = gadget_list_first_entry;
1479
1480   while (gi && gi->id != id)
1481     gi = gi->next;
1482
1483   return gi;
1484 }
1485
1486 static int getNewGadgetID()
1487 {
1488   int id = next_free_gadget_id++;
1489
1490   if (next_free_gadget_id <= 0)         /* counter overrun */
1491   {
1492     gadget_id_wrapped = TRUE;           /* now we must check each ID */
1493     next_free_gadget_id = 0;
1494   }
1495
1496   if (gadget_id_wrapped)
1497   {
1498     next_free_gadget_id++;
1499     while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
1500       next_free_gadget_id++;
1501   }
1502
1503   if (next_free_gadget_id <= 0)         /* cannot get new gadget id */
1504     Error(ERR_EXIT, "too much gadgets -- this should not happen");
1505
1506   return id;
1507 }
1508
1509 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
1510 {
1511   struct GadgetInfo *gi = gadget_list_first_entry;
1512
1513   while (gi)
1514   {
1515     if (gi->mapped &&
1516         mx >= gi->x && mx < gi->x + gi->width &&
1517         my >= gi->y && my < gi->y + gi->height)
1518       break;
1519
1520     gi = gi->next;
1521   }
1522
1523   return gi;
1524 }
1525
1526 static void default_callback_function(void *ptr)
1527 {
1528   return;
1529 }
1530
1531 struct GadgetInfo *CreateGadget(int first_tag, ...)
1532 {
1533   struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
1534   int tag = first_tag;
1535   va_list ap;
1536
1537   va_start(ap, first_tag);
1538
1539   /* always start with reliable default values */
1540   memset(new_gadget, 0, sizeof(struct GadgetInfo));     /* zero all fields */
1541   new_gadget->id = getNewGadgetID();                    /* new gadget id */
1542   new_gadget->callback = default_callback_function;     /* dummy function */
1543
1544   while (tag != GDI_END)
1545   {
1546     switch(tag)
1547     {
1548       case GDI_CUSTOM_ID:
1549         new_gadget->custom_id = va_arg(ap, int);
1550         break;
1551
1552       case GDI_X:
1553         new_gadget->x = va_arg(ap, int);
1554         break;
1555
1556       case GDI_Y:
1557         new_gadget->y = va_arg(ap, int);
1558         break;
1559
1560       case GDI_WIDTH:
1561         new_gadget->width = va_arg(ap, int);
1562         break;
1563
1564       case GDI_HEIGHT:
1565         new_gadget->height = va_arg(ap, int);
1566         break;
1567
1568       case GDI_TYPE:
1569         new_gadget->type = va_arg(ap, unsigned long);
1570         break;
1571
1572       case GDI_STATE:
1573         new_gadget->state = va_arg(ap, unsigned long);
1574         break;
1575
1576       case GDI_ALT_STATE:
1577         new_gadget->state = va_arg(ap, boolean);
1578         break;
1579
1580       case GDI_NUMBER_VALUE:
1581         new_gadget->number_value = va_arg(ap, long);
1582         break;
1583
1584       case GDI_TEXT_VALUE:
1585         strcpy(new_gadget->text_value, va_arg(ap, char *));
1586         break;
1587
1588       case GDI_DESIGN_UNPRESSED:
1589         new_gadget->design[GD_BUTTON_UNPRESSED].pixmap = va_arg(ap, Pixmap);
1590         new_gadget->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1591         new_gadget->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1592         break;
1593
1594       case GDI_DESIGN_PRESSED:
1595         new_gadget->design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1596         new_gadget->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1597         new_gadget->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1598         break;
1599
1600       case GDI_ALT_DESIGN_UNPRESSED:
1601         new_gadget->alt_design[GD_BUTTON_UNPRESSED].pixmap= va_arg(ap, Pixmap);
1602         new_gadget->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1603         new_gadget->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1604         break;
1605
1606       case GDI_ALT_DESIGN_PRESSED:
1607         new_gadget->alt_design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1608         new_gadget->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1609         new_gadget->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1610         break;
1611
1612       case GDI_EVENT_MASK:
1613         new_gadget->event_mask = va_arg(ap, unsigned long);
1614         break;
1615
1616       case GDI_AREA_SIZE:
1617         new_gadget->drawing.area_xsize = va_arg(ap, int);
1618         new_gadget->drawing.area_ysize = va_arg(ap, int);
1619
1620         /* determine dependent values for drawing area gadget, if needed */
1621         if (new_gadget->width == 0 &&
1622             new_gadget->height == 0 &&
1623             new_gadget->drawing.item_xsize !=0 &&
1624             new_gadget->drawing.item_ysize !=0)
1625         {
1626           new_gadget->width =
1627             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1628           new_gadget->height =
1629             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1630         }
1631         else if (new_gadget->drawing.item_xsize == 0 &&
1632                  new_gadget->drawing.item_ysize == 0 &&
1633                  new_gadget->width != 0 &&
1634                  new_gadget->height != 0)
1635         {
1636           new_gadget->drawing.item_xsize =
1637             new_gadget->width / new_gadget->drawing.area_xsize;
1638           new_gadget->drawing.item_ysize =
1639             new_gadget->height / new_gadget->drawing.area_ysize;
1640         }
1641         break;
1642
1643       case GDI_ITEM_SIZE:
1644         new_gadget->drawing.item_xsize = va_arg(ap, int);
1645         new_gadget->drawing.item_ysize = va_arg(ap, int);
1646
1647         /* determine dependent values for drawing area gadget, if needed */
1648         if (new_gadget->width == 0 &&
1649             new_gadget->height == 0 &&
1650             new_gadget->drawing.area_xsize !=0 &&
1651             new_gadget->drawing.area_ysize !=0)
1652         {
1653           new_gadget->width =
1654             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1655           new_gadget->height =
1656             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1657         }
1658         else if (new_gadget->drawing.area_xsize == 0 &&
1659                  new_gadget->drawing.area_ysize == 0 &&
1660                  new_gadget->width != 0 &&
1661                  new_gadget->height != 0)
1662         {
1663           new_gadget->drawing.area_xsize =
1664             new_gadget->width / new_gadget->drawing.item_xsize;
1665           new_gadget->drawing.area_ysize =
1666             new_gadget->height / new_gadget->drawing.item_ysize;
1667         }
1668         break;
1669
1670       case GDI_CALLBACK:
1671         new_gadget->callback = va_arg(ap, gadget_callback_function);
1672         break;
1673
1674       default:
1675         Error(ERR_EXIT, "CreateGadget(): unknown tag %d", tag);
1676     }
1677
1678     tag = va_arg(ap, int);      /* read next tag */
1679   }
1680
1681   va_end(ap);
1682
1683   /* check if gadget complete */
1684   if (new_gadget->type != GD_TYPE_DRAWING_AREA &&
1685       (!new_gadget->design[GD_BUTTON_UNPRESSED].pixmap ||
1686        !new_gadget->design[GD_BUTTON_PRESSED].pixmap))
1687     Error(ERR_EXIT, "gadget incomplete (missing Pixmap)");
1688
1689   /* insert new gadget into gloabl gadget list */
1690
1691   if (gadget_list_last_entry)
1692   {
1693     gadget_list_last_entry->next = new_gadget;
1694     gadget_list_last_entry = gadget_list_last_entry->next;
1695   }
1696   else
1697   {
1698     gadget_list_first_entry = gadget_list_last_entry = new_gadget;
1699   }
1700
1701   return new_gadget;
1702 }
1703
1704 void FreeGadget(struct GadgetInfo *gi)
1705 {
1706   struct GadgetInfo *gi_previous = gadget_list_first_entry;
1707
1708   while (gi_previous && gi_previous->next != gi)
1709     gi_previous = gi_previous->next;
1710
1711   if (gi == gadget_list_first_entry)
1712     gadget_list_first_entry = gi->next;
1713
1714   if (gi == gadget_list_last_entry)
1715     gadget_list_last_entry = gi_previous;
1716
1717   gi_previous->next = gi->next;
1718   free(gi);
1719 }
1720
1721 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
1722 {
1723   int state = (pressed ? 1 : 0);
1724   struct GadgetDesign *gd = (gi->alt_state ?
1725                              &gi->alt_design[state] :
1726                              &gi->design[state]);
1727
1728   if (gi->type != GD_TYPE_NORMAL_BUTTON)
1729     return;
1730
1731   XCopyArea(display, gd->pixmap, drawto, gc,
1732             gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
1733
1734   if (direct)
1735     XCopyArea(display, gd->pixmap, window, gc,
1736               gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
1737   else
1738     redraw_mask |= REDRAW_ALL;
1739 }
1740
1741 void MapGadget(struct GadgetInfo *gi)
1742 {
1743   if (gi == NULL)
1744     return;
1745
1746   gi->mapped = TRUE;
1747
1748   DrawGadget(gi, (gi->state == GD_BUTTON_PRESSED), FALSE);
1749 }
1750
1751 void UnmapGadget(struct GadgetInfo *gi)
1752 {
1753   if (gi == NULL)
1754     return;
1755
1756   gi->mapped = FALSE;
1757 }
1758
1759 void HandleGadgets(int mx, int my, int button)
1760 {
1761   static struct GadgetInfo *gi = NULL;
1762   static unsigned long pressed_delay = 0;
1763
1764 #if 0
1765   static boolean pressed = FALSE;
1766 #endif
1767
1768   struct GadgetInfo *new_gi;
1769   boolean gadget_pressed;
1770   boolean gadget_pressed_repeated;
1771   boolean gadget_moving_inside;
1772   boolean gadget_moving_outside;
1773   boolean gadget_released;
1774
1775   if (gadget_list_first_entry == NULL)
1776     return;
1777
1778   new_gi = getGadgetInfoFromMousePosition(mx,my);
1779
1780   gadget_pressed =
1781     (button != 0 && gi == NULL && new_gi != NULL);
1782   gadget_pressed_repeated =
1783     (button != 0 && gi != NULL && new_gi == gi);
1784   gadget_moving_inside =
1785     (button != 0 && gi != NULL && new_gi == gi && motion_status);
1786   gadget_moving_outside =
1787     (button != 0 && gi != NULL && new_gi != gi && motion_status);
1788   gadget_released =
1789     (button == 0 && gi != NULL && new_gi == gi);
1790
1791   if (gadget_pressed)
1792     gi = new_gi;
1793
1794   if (gi)
1795   {
1796     gi->event.x = mx - gi->x;
1797     gi->event.y = my - gi->y;
1798
1799     if (gi->type == GD_TYPE_DRAWING_AREA)
1800     {
1801       gi->event.x /= gi->drawing.item_xsize;
1802       gi->event.y /= gi->drawing.item_ysize;
1803     }
1804   }
1805
1806   if (gadget_pressed)
1807   {
1808     DrawGadget(gi, TRUE, TRUE);
1809
1810     gi->state = GD_BUTTON_PRESSED;
1811     gi->event.type = GD_EVENT_PRESSED;
1812     gi->event.button = button;
1813
1814     /* initialize delay counter */
1815     pressed_delay = 0;
1816     DelayReached(&pressed_delay, GADGET_FRAME_DELAY);
1817
1818     if (gi->event_mask & GD_EVENT_PRESSED)
1819       gi->callback(gi);
1820   }
1821
1822   if (gadget_pressed_repeated)
1823   {
1824     if (gi->event_mask & GD_EVENT_REPEATED &&
1825         DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1826       gi->callback(gi);
1827   }
1828
1829   if (gadget_moving_inside)
1830   {
1831     if (gi->state == GD_BUTTON_UNPRESSED)
1832       DrawGadget(gi, TRUE, TRUE);
1833
1834     gi->state = GD_BUTTON_PRESSED;
1835     gi->event.type = GD_EVENT_MOVING;
1836
1837     if (gi->event_mask & GD_EVENT_MOVING)
1838       gi->callback(gi);
1839   }
1840
1841   if (gadget_moving_outside)
1842   {
1843     if (gi->state == GD_BUTTON_PRESSED)
1844       DrawGadget(gi, FALSE, TRUE);
1845
1846     gi->state = GD_BUTTON_UNPRESSED;
1847     gi->event.type = GD_EVENT_MOVING;
1848
1849     if (gi->event_mask & GD_EVENT_MOVING)
1850       gi->callback(gi);
1851   }
1852
1853   if (gadget_released)
1854   {
1855     DrawGadget(gi, FALSE, TRUE);
1856
1857     gi->state = GD_BUTTON_UNPRESSED;
1858     gi->event.type = GD_EVENT_RELEASED;
1859
1860     if (gi->event_mask & GD_EVENT_RELEASED)
1861       gi->callback(gi);
1862   }
1863
1864   if (button == 0)
1865     gi = NULL;
1866
1867
1868
1869 #if 0
1870   if (button)
1871   {
1872     if (!motion_status)         /* mouse button just pressed */
1873     {
1874       if (new_gi != NULL)
1875       {
1876         gi = new_gi;
1877         gi->state = GD_BUTTON_PRESSED;
1878         gi->event.type = GD_EVENT_PRESSED;
1879         gi->event.button = button;
1880         DrawGadget(gi, TRUE, TRUE);
1881
1882         /* initialize delay counter */
1883         pressed_delay = 0;
1884         DelayReached(&pressed_delay, GADGET_FRAME_DELAY);
1885
1886
1887         printf("new gadget pressed\n");
1888
1889
1890         if (gi->event_mask & GD_EVENT_PRESSED)
1891           gi->callback(gi);
1892
1893         pressed = TRUE;
1894       }
1895     }
1896     else                        /* mouse movement with pressed mouse button */
1897     {
1898       if (new_gi != gi && gi != NULL)
1899       {
1900         if (pressed)
1901           DrawGadget(gi, FALSE, TRUE);
1902         gi->state = GD_BUTTON_UNPRESSED;
1903         gi->event.type = GD_EVENT_MOVING;
1904
1905
1906         printf("outside gadget\n");
1907
1908
1909
1910
1911         if (gi->event_mask & GD_EVENT_MOVING)
1912           gi->callback(gi);
1913
1914         pressed = FALSE;
1915       }
1916       else if (new_gi == gi && gi != NULL)
1917       {
1918         if (!pressed)
1919           DrawGadget(gi, TRUE, TRUE);
1920         gi->state = GD_BUTTON_PRESSED;
1921         gi->event.type = GD_EVENT_MOVING;
1922
1923
1924         printf("inside gadget\n");
1925
1926
1927
1928
1929         if (gi->event_mask & GD_EVENT_MOVING)
1930           gi->callback(gi);
1931
1932         pressed = TRUE;
1933       }
1934     }
1935
1936     if (gi != NULL &&
1937         gi->event_mask & GD_EVENT_PRESSED_REPEATED &&
1938         gi->state == GD_BUTTON_PRESSED &&
1939         DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1940     {
1941         printf("gadget pressed (repeated)\n");
1942
1943
1944         gi->callback(gi);
1945     }
1946   }
1947   else                          /* mouse button just released */
1948   {
1949     if (new_gi == gi && gi != NULL && pressed)
1950     {
1951       gi->state = GD_BUTTON_UNPRESSED;
1952       gi->event.type = GD_EVENT_RELEASED;
1953       DrawGadget(gi, FALSE, TRUE);
1954
1955
1956       printf("gadget released\n");
1957
1958
1959
1960       if (gi->event_mask & GD_EVENT_RELEASED)
1961         gi->callback(gi);
1962     }
1963
1964     gi = NULL;
1965     pressed = FALSE;
1966   }
1967 #endif
1968
1969
1970
1971 }