228072e03f0c1c04a2ae02896151a8bf6b917e7b
[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     {
1519
1520 #if 0
1521       if (gi->type & GD_TYPE_SCROLLBAR)
1522       {
1523         int mpos, gpos;
1524
1525         if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1526         {
1527           mpos = mx;
1528           gpos = gi->x;
1529         }
1530         else
1531         {
1532           mpos = my;
1533           gpos = gi->y;
1534         }
1535
1536         if (mpos >= gpos + gi->scrollbar.position &&
1537             mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1538           break;
1539       }
1540       else
1541 #endif
1542
1543         break;
1544     }
1545
1546     gi = gi->next;
1547   }
1548
1549   return gi;
1550 }
1551
1552 static void default_callback_info(void *ptr)
1553 {
1554   if (game_status == LEVELED)
1555     HandleEditorGadgetInfoText(ptr);
1556 }
1557
1558 static void default_callback_action(void *ptr)
1559 {
1560   return;
1561 }
1562
1563 struct GadgetInfo *CreateGadget(int first_tag, ...)
1564 {
1565   struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
1566   int tag = first_tag;
1567   va_list ap;
1568
1569   va_start(ap, first_tag);
1570
1571   /* always start with reliable default values */
1572   memset(new_gadget, 0, sizeof(struct GadgetInfo));     /* zero all fields */
1573   new_gadget->id = getNewGadgetID();
1574   new_gadget->callback_info = default_callback_info;
1575   new_gadget->callback_action = default_callback_action;
1576
1577   while (tag != GDI_END)
1578   {
1579     switch(tag)
1580     {
1581       case GDI_CUSTOM_ID:
1582         new_gadget->custom_id = va_arg(ap, int);
1583         break;
1584
1585       case GDI_DESCRIPTION_TEXT:
1586         new_gadget->description_text = va_arg(ap, char *);
1587         break;
1588
1589       case GDI_X:
1590         new_gadget->x = va_arg(ap, int);
1591         break;
1592
1593       case GDI_Y:
1594         new_gadget->y = va_arg(ap, int);
1595         break;
1596
1597       case GDI_WIDTH:
1598         new_gadget->width = va_arg(ap, int);
1599         break;
1600
1601       case GDI_HEIGHT:
1602         new_gadget->height = va_arg(ap, int);
1603         break;
1604
1605       case GDI_TYPE:
1606         new_gadget->type = va_arg(ap, unsigned long);
1607         break;
1608
1609       case GDI_STATE:
1610         new_gadget->state = va_arg(ap, unsigned long);
1611         break;
1612
1613       case GDI_RADIO_NR:
1614         new_gadget->radio_nr = va_arg(ap, unsigned long);
1615         break;
1616
1617       case GDI_RADIO_PRESSED:
1618         new_gadget->radio_pressed = va_arg(ap, boolean);
1619         break;
1620
1621       case GDI_NUMBER_VALUE:
1622         new_gadget->text.number_value = va_arg(ap, long);
1623         sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1624         new_gadget->text.cursor_position = strlen(new_gadget->text.value);
1625         break;
1626
1627       case GDI_NUMBER_MIN:
1628         new_gadget->text.number_min = va_arg(ap, long);
1629         if (new_gadget->text.number_value < new_gadget->text.number_min)
1630         {
1631           new_gadget->text.number_value = new_gadget->text.number_min;
1632           sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1633         }
1634         break;
1635
1636       case GDI_NUMBER_MAX:
1637         new_gadget->text.number_max = va_arg(ap, long);
1638         if (new_gadget->text.number_value > new_gadget->text.number_max)
1639         {
1640           new_gadget->text.number_value = new_gadget->text.number_max;
1641           sprintf(new_gadget->text.value, "%d", new_gadget->text.number_value);
1642         }
1643         break;
1644
1645       case GDI_TEXT_VALUE:
1646         {
1647           int max_textsize = MAX_GADGET_TEXTSIZE;
1648
1649           if (new_gadget->text.size)
1650             max_textsize = MIN(new_gadget->text.size, MAX_GADGET_TEXTSIZE - 1);
1651
1652           strncpy(new_gadget->text.value, va_arg(ap, char *), max_textsize);
1653           new_gadget->text.value[max_textsize] = '\0';
1654           new_gadget->text.cursor_position = strlen(new_gadget->text.value);
1655         }
1656         break;
1657
1658       case GDI_TEXT_SIZE:
1659         {
1660           int tag_value = va_arg(ap, int);
1661           int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
1662
1663           new_gadget->text.size = max_textsize;
1664           new_gadget->text.value[max_textsize] = '\0';
1665
1666           if (new_gadget->width == 0 && new_gadget->height == 0)
1667           {
1668             new_gadget->width = (new_gadget->text.size + 1) * FONT2_XSIZE + 6;
1669             new_gadget->height = ED_WIN_COUNT_YSIZE;
1670           }
1671         }
1672         break;
1673
1674       case GDI_DESIGN_UNPRESSED:
1675         new_gadget->design[GD_BUTTON_UNPRESSED].pixmap = va_arg(ap, Pixmap);
1676         new_gadget->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1677         new_gadget->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1678         break;
1679
1680       case GDI_DESIGN_PRESSED:
1681         new_gadget->design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1682         new_gadget->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1683         new_gadget->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1684         break;
1685
1686       case GDI_ALT_DESIGN_UNPRESSED:
1687         new_gadget->alt_design[GD_BUTTON_UNPRESSED].pixmap= va_arg(ap, Pixmap);
1688         new_gadget->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
1689         new_gadget->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
1690         break;
1691
1692       case GDI_ALT_DESIGN_PRESSED:
1693         new_gadget->alt_design[GD_BUTTON_PRESSED].pixmap = va_arg(ap, Pixmap);
1694         new_gadget->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
1695         new_gadget->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
1696         break;
1697
1698       case GDI_DESIGN_BORDER:
1699         new_gadget->design_border = va_arg(ap, int);
1700         break;
1701
1702       case GDI_EVENT_MASK:
1703         new_gadget->event_mask = va_arg(ap, unsigned long);
1704         break;
1705
1706       case GDI_AREA_SIZE:
1707         new_gadget->drawing.area_xsize = va_arg(ap, int);
1708         new_gadget->drawing.area_ysize = va_arg(ap, int);
1709
1710         /* determine dependent values for drawing area gadget, if needed */
1711         if (new_gadget->width == 0 &&
1712             new_gadget->height == 0 &&
1713             new_gadget->drawing.item_xsize !=0 &&
1714             new_gadget->drawing.item_ysize !=0)
1715         {
1716           new_gadget->width =
1717             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1718           new_gadget->height =
1719             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1720         }
1721         else if (new_gadget->drawing.item_xsize == 0 &&
1722                  new_gadget->drawing.item_ysize == 0 &&
1723                  new_gadget->width != 0 &&
1724                  new_gadget->height != 0)
1725         {
1726           new_gadget->drawing.item_xsize =
1727             new_gadget->width / new_gadget->drawing.area_xsize;
1728           new_gadget->drawing.item_ysize =
1729             new_gadget->height / new_gadget->drawing.area_ysize;
1730         }
1731         break;
1732
1733       case GDI_ITEM_SIZE:
1734         new_gadget->drawing.item_xsize = va_arg(ap, int);
1735         new_gadget->drawing.item_ysize = va_arg(ap, int);
1736
1737         /* determine dependent values for drawing area gadget, if needed */
1738         if (new_gadget->width == 0 &&
1739             new_gadget->height == 0 &&
1740             new_gadget->drawing.area_xsize !=0 &&
1741             new_gadget->drawing.area_ysize !=0)
1742         {
1743           new_gadget->width =
1744             new_gadget->drawing.area_xsize * new_gadget->drawing.item_xsize;
1745           new_gadget->height =
1746             new_gadget->drawing.area_ysize * new_gadget->drawing.item_ysize;
1747         }
1748         else if (new_gadget->drawing.area_xsize == 0 &&
1749                  new_gadget->drawing.area_ysize == 0 &&
1750                  new_gadget->width != 0 &&
1751                  new_gadget->height != 0)
1752         {
1753           new_gadget->drawing.area_xsize =
1754             new_gadget->width / new_gadget->drawing.item_xsize;
1755           new_gadget->drawing.area_ysize =
1756             new_gadget->height / new_gadget->drawing.item_ysize;
1757         }
1758         break;
1759
1760       case GDI_SCROLLBAR_ITEMS_MAX:
1761         new_gadget->scrollbar.items_max = va_arg(ap, int);
1762         break;
1763
1764       case GDI_SCROLLBAR_ITEMS_VISIBLE:
1765         new_gadget->scrollbar.items_visible = va_arg(ap, int);
1766         break;
1767
1768       case GDI_SCROLLBAR_ITEM_POSITION:
1769         new_gadget->scrollbar.item_position = va_arg(ap, int);
1770         break;
1771
1772       case GDI_CALLBACK_INFO:
1773         new_gadget->callback_info = va_arg(ap, gadget_function);
1774         break;
1775
1776       case GDI_CALLBACK_ACTION:
1777         new_gadget->callback_action = va_arg(ap, gadget_function);
1778         break;
1779
1780       default:
1781         Error(ERR_EXIT, "CreateGadget(): unknown tag %d", tag);
1782     }
1783
1784     tag = va_arg(ap, int);      /* read next tag */
1785   }
1786
1787   va_end(ap);
1788
1789   /* check if gadget complete */
1790   if (new_gadget->type != GD_TYPE_DRAWING_AREA &&
1791       (!new_gadget->design[GD_BUTTON_UNPRESSED].pixmap ||
1792        !new_gadget->design[GD_BUTTON_PRESSED].pixmap))
1793     Error(ERR_EXIT, "gadget incomplete (missing Pixmap)");
1794
1795   if (new_gadget->type & GD_TYPE_SCROLLBAR)
1796   {
1797     struct GadgetScrollbar *gs = &new_gadget->scrollbar;
1798
1799     if (new_gadget->width == 0 || new_gadget->height == 0 ||
1800         gs->items_max == 0 || gs->items_visible == 0)
1801       Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
1802
1803     /* calculate internal scrollbar values */
1804     gs->size_max = (new_gadget->type == GD_TYPE_SCROLLBAR_VERTICAL ?
1805                     new_gadget->height : new_gadget->width);
1806     gs->size = gs->size_max * gs->items_visible / gs->items_max;
1807     gs->position = gs->size_max * gs->item_position / gs->items_max;
1808     gs->position_max = gs->size_max - gs->size;
1809   }
1810
1811   /* insert new gadget into global gadget list */
1812   if (gadget_list_last_entry)
1813   {
1814     gadget_list_last_entry->next = new_gadget;
1815     gadget_list_last_entry = gadget_list_last_entry->next;
1816   }
1817   else
1818     gadget_list_first_entry = gadget_list_last_entry = new_gadget;
1819
1820   return new_gadget;
1821 }
1822
1823 void FreeGadget(struct GadgetInfo *gi)
1824 {
1825   struct GadgetInfo *gi_previous = gadget_list_first_entry;
1826
1827   while (gi_previous && gi_previous->next != gi)
1828     gi_previous = gi_previous->next;
1829
1830   if (gi == gadget_list_first_entry)
1831     gadget_list_first_entry = gi->next;
1832
1833   if (gi == gadget_list_last_entry)
1834     gadget_list_last_entry = gi_previous;
1835
1836   gi_previous->next = gi->next;
1837   free(gi);
1838 }
1839
1840 /* values for DrawGadget() */
1841 #define DG_UNPRESSED    0
1842 #define DG_PRESSED      1
1843 #define DG_BUFFERED     0
1844 #define DG_DIRECT       1
1845
1846 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
1847 {
1848   if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
1849     return;
1850
1851   gi->text.number_value = atoi(gi->text.value);
1852
1853   if (gi->text.number_value < gi->text.number_min)
1854     gi->text.number_value = gi->text.number_min;
1855   if (gi->text.number_value > gi->text.number_max)
1856     gi->text.number_value = gi->text.number_max;
1857
1858   sprintf(gi->text.value, "%d", gi->text.number_value);
1859
1860   if (gi->text.cursor_position < 0)
1861     gi->text.cursor_position = 0;
1862   else if (gi->text.cursor_position > strlen(gi->text.value))
1863     gi->text.cursor_position = strlen(gi->text.value);
1864 }
1865
1866 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
1867 {
1868   int state = (pressed ? 1 : 0);
1869   struct GadgetDesign *gd = (gi->radio_pressed ?
1870                              &gi->alt_design[state] :
1871                              &gi->design[state]);
1872
1873   switch (gi->type)
1874   {
1875     case GD_TYPE_NORMAL_BUTTON:
1876     case GD_TYPE_RADIO_BUTTON:
1877       XCopyArea(display, gd->pixmap, drawto, gc,
1878                 gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
1879       break;
1880
1881     case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
1882     case GD_TYPE_TEXTINPUT_NUMERIC:
1883       {
1884         int i;
1885         char cursor_letter;
1886         char cursor_string[3];
1887         char text[MAX_GADGET_TEXTSIZE + 1];
1888         int font_color = FC_YELLOW;
1889         int border = gi->design_border;
1890         strcpy(text, gi->text.value);
1891         strcat(text, " ");
1892
1893         /* left part of gadget */
1894         XCopyArea(display, gd->pixmap, drawto, gc,
1895                   gd->x, gd->y, border, gi->height, gi->x, gi->y);
1896
1897         /* middle part of gadget */
1898         for (i=0; i<=gi->text.size; i++)
1899           XCopyArea(display, gd->pixmap, drawto, gc,
1900                     gd->x + border, gd->y, FONT2_XSIZE, gi->height,
1901                     gi->x + border + i * FONT2_XSIZE, gi->y);
1902
1903         /* right part of gadget */
1904         XCopyArea(display, gd->pixmap, drawto, gc,
1905                   gd->x + ED_WIN_COUNT_XSIZE - border, gd->y,
1906                   border, gi->height, gi->x + gi->width - border, gi->y);
1907
1908         /* gadget text value */
1909         DrawText(gi->x + border, gi->y + border, text, FS_SMALL, font_color);
1910
1911         cursor_letter = gi->text.value[gi->text.cursor_position];
1912         cursor_string[0] = '~';
1913         cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
1914         cursor_string[2] = '\0';
1915
1916         /* draw cursor, if active */
1917         if (pressed)
1918           DrawText(gi->x + border + gi->text.cursor_position * FONT2_XSIZE,
1919                    gi->y + border, cursor_string, FS_SMALL, font_color);
1920       }
1921       break;
1922
1923     case GD_TYPE_SCROLLBAR_VERTICAL:
1924       {
1925         int i;
1926         int xpos = gi->x;
1927         int ypos = gi->y + gi->scrollbar.position;
1928         int design_full = gi->width;
1929         int design_body = design_full - 2 * gi->design_border;
1930         int size_full = gi->scrollbar.size;
1931         int size_body = size_full - 2 * gi->design_border;
1932         int num_steps = size_body / design_body;
1933         int step_size_remain = size_body - num_steps * design_body;
1934
1935         /* clear scrollbar area */
1936         XFillRectangle(display, backbuffer, gc,
1937                        gi->x, gi->y, gi->width, gi->height);
1938
1939         /* upper part of gadget */
1940         XCopyArea(display, gd->pixmap, drawto, gc,
1941                   gd->x, gd->y,
1942                   gi->width, gi->design_border,
1943                   xpos, ypos);
1944
1945         /* middle part of gadget */
1946         for (i=0; i<num_steps; i++)
1947           XCopyArea(display, gd->pixmap, drawto, gc,
1948                     gd->x, gd->y + gi->design_border,
1949                     gi->width, design_body,
1950                     xpos, ypos + gi->design_border + i * design_body);
1951
1952         /* remaining middle part of gadget */
1953         if (step_size_remain > 0)
1954           XCopyArea(display, gd->pixmap, drawto, gc,
1955                     gd->x,  gd->y + gi->design_border,
1956                     gi->width, step_size_remain,
1957                     xpos, ypos + gi->design_border + num_steps * design_body);
1958
1959         /* lower part of gadget */
1960         XCopyArea(display, gd->pixmap, drawto, gc,
1961                   gd->x, gd->y + design_full - gi->design_border,
1962                   gi->width, gi->design_border,
1963                   xpos, ypos + size_full - gi->design_border);
1964       }
1965       break;
1966
1967     case GD_TYPE_SCROLLBAR_HORIZONTAL:
1968       {
1969         int i;
1970         int xpos = gi->x + gi->scrollbar.position;
1971         int ypos = gi->y;
1972         int design_full = gi->height;
1973         int design_body = design_full - 2 * gi->design_border;
1974         int size_full = gi->scrollbar.size;
1975         int size_body = size_full - 2 * gi->design_border;
1976         int num_steps = size_body / design_body;
1977         int step_size_remain = size_body - num_steps * design_body;
1978
1979         /* clear scrollbar area */
1980         XFillRectangle(display, backbuffer, gc,
1981                        gi->x, gi->y, gi->width, gi->height);
1982
1983         /* left part of gadget */
1984         XCopyArea(display, gd->pixmap, drawto, gc,
1985                   gd->x, gd->y,
1986                   gi->design_border, gi->height,
1987                   xpos, ypos);
1988
1989         /* middle part of gadget */
1990         for (i=0; i<num_steps; i++)
1991           XCopyArea(display, gd->pixmap, drawto, gc,
1992                     gd->x + gi->design_border, gd->y,
1993                     design_body, gi->height,
1994                     xpos + gi->design_border + i * design_body, ypos);
1995
1996         /* remaining middle part of gadget */
1997         if (step_size_remain > 0)
1998           XCopyArea(display, gd->pixmap, drawto, gc,
1999                     gd->x + gi->design_border, gd->y,
2000                     step_size_remain, gi->height,
2001                     xpos + gi->design_border + num_steps * design_body, ypos);
2002
2003         /* right part of gadget */
2004         XCopyArea(display, gd->pixmap, drawto, gc,
2005                   gd->x + design_full - gi->design_border, gd->y,
2006                   gi->design_border, gi->height,
2007                   xpos + size_full - gi->design_border, ypos);
2008       }
2009       break;
2010
2011     default:
2012       return;
2013   }
2014
2015   if (direct)
2016     XCopyArea(display, drawto, window, gc,
2017               gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
2018   else
2019     redraw_mask |= REDRAW_ALL;
2020 }
2021
2022 void ClickOnGadget(struct GadgetInfo *gi)
2023 {
2024   /* simulate releasing mouse button over last gadget, if still pressed */
2025   if (button_status)
2026     HandleGadgets(-1, -1, 0);
2027
2028   /* simulate pressing mouse button over specified gadget */
2029   HandleGadgets(gi->x, gi->y, 1);
2030
2031   /* simulate releasing mouse button over specified gadget */
2032   HandleGadgets(gi->x, gi->y, 0);
2033 }
2034
2035 void AdjustScrollbar(struct GadgetInfo *gi, int items_max, int item_pos)
2036 {
2037   struct GadgetScrollbar *gs = &gi->scrollbar;
2038
2039   gs->items_max = items_max;
2040   gs->item_position = item_pos;
2041
2042   gs->size = gs->size_max * gs->items_visible / gs->items_max;
2043   gs->position = gs->size_max * gs->item_position / gs->items_max;
2044   gs->position_max = gs->size_max - gs->size;
2045
2046   /* finetuning for maximal right/bottom position */
2047   if (gs->item_position == gs->items_max - gs->items_visible)
2048     gs->position = gs->position_max;
2049
2050   if (gi->mapped)
2051     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2052 }
2053
2054 void ModifyTextInputTextValue(struct GadgetInfo *gi, char *new_text)
2055 {
2056   struct GadgetTextInput *text = &gi->text;
2057   int max_textsize = MAX_GADGET_TEXTSIZE;
2058
2059   if (text->size)
2060     max_textsize = MIN(text->size, MAX_GADGET_TEXTSIZE - 1);
2061
2062   strncpy(text->value, new_text, max_textsize);
2063   text->value[max_textsize] = '\0';
2064   text->cursor_position = strlen(text->value);
2065
2066   if (gi->mapped)
2067     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2068 }
2069
2070 void ModifyTextInputNumberValue(struct GadgetInfo *gi, int new_value)
2071 {
2072   struct GadgetTextInput *text = &gi->text;
2073
2074   text->number_value = (new_value < text->number_min ? text->number_min :
2075                         new_value > text->number_max ? text->number_max :
2076                         new_value);
2077
2078   sprintf(text->value, "%d", text->number_value);
2079
2080   if (gi->mapped)
2081     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2082 }
2083
2084 /* global pointer to gadget actually in use (when mouse button pressed) */
2085 static struct GadgetInfo *last_gi = NULL;
2086
2087 void MapGadget(struct GadgetInfo *gi)
2088 {
2089   if (gi == NULL || gi->mapped)
2090     return;
2091
2092   gi->mapped = TRUE;
2093
2094   DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
2095 }
2096
2097 void UnmapGadget(struct GadgetInfo *gi)
2098 {
2099   if (gi == NULL || !gi->mapped)
2100     return;
2101
2102   gi->mapped = FALSE;
2103
2104   if (gi == last_gi)
2105     last_gi = NULL;
2106 }
2107
2108 void HandleGadgets(int mx, int my, int button)
2109 {
2110   static struct GadgetInfo *last_info_gi = NULL;
2111   static unsigned long pressed_delay = 0;
2112   static int last_button = 0;
2113   static int last_mx = 0, last_my = 0;
2114   int scrollbar_mouse_pos;
2115   struct GadgetInfo *new_gi, *gi;
2116   boolean press_event;
2117   boolean release_event;
2118   boolean mouse_moving;
2119   boolean gadget_pressed;
2120   boolean gadget_pressed_repeated;
2121   boolean gadget_moving;
2122   boolean gadget_moving_inside;
2123   boolean gadget_moving_off_borders;
2124   boolean gadget_released;
2125   boolean gadget_released_inside;
2126   boolean gadget_released_off_borders;
2127   boolean changed_position = FALSE;
2128
2129   /* check if there are any gadgets defined */
2130   if (gadget_list_first_entry == NULL)
2131     return;
2132
2133   /* check which gadget is under the mouse pointer */
2134   new_gi = getGadgetInfoFromMousePosition(mx, my);
2135
2136   /* check if button state has changed since last invocation */
2137   press_event = (button != 0 && last_button == 0);
2138   release_event = (button == 0 && last_button != 0);
2139   last_button = button;
2140
2141   /* check if mouse has been moved since last invocation */
2142   mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
2143   last_mx = mx;
2144   last_my = my;
2145
2146   /* special treatment for text and number input gadgets */
2147   if (last_gi && last_gi->type & GD_TYPE_TEXTINPUT && last_gi->mapped &&
2148       button != 0 && !motion_status)
2149   {
2150     struct GadgetInfo *gi = last_gi;
2151
2152     if (new_gi == last_gi)
2153     {
2154       /* if mouse button pressed inside activated text gadget, set cursor */
2155       gi->text.cursor_position = (mx - gi->x) / FONT2_XSIZE;
2156
2157       if (gi->text.cursor_position < 0)
2158         gi->text.cursor_position = 0;
2159       else if (gi->text.cursor_position > strlen(gi->text.value))
2160         gi->text.cursor_position = strlen(gi->text.value);
2161
2162       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2163     }
2164     else
2165     {
2166       /* if mouse button pressed outside text input gadget, deactivate it */
2167       CheckRangeOfNumericInputGadget(gi);
2168       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2169
2170       if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
2171         gi->callback_action(gi);
2172
2173       last_gi = NULL;
2174     }
2175   }
2176
2177   gadget_pressed =
2178     (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
2179   gadget_pressed_repeated =
2180     (button != 0 && last_gi != NULL && new_gi == last_gi);
2181
2182   gadget_released =             (button == 0 && last_gi != NULL);
2183   gadget_released_inside =      (gadget_released && new_gi == last_gi);
2184   gadget_released_off_borders = (gadget_released && new_gi != last_gi);
2185
2186   gadget_moving =             (button != 0 && last_gi != NULL && mouse_moving);
2187   gadget_moving_inside =      (gadget_moving && new_gi == last_gi);
2188   gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
2189
2190   /* if new gadget pressed, store this gadget  */
2191   if (gadget_pressed)
2192     last_gi = new_gi;
2193
2194   /* 'gi' is actually handled gadget */
2195   gi = last_gi;
2196
2197   /* if gadget is scrollbar, choose mouse position value */
2198   if (gi && gi->type & GD_TYPE_SCROLLBAR)
2199     scrollbar_mouse_pos =
2200       (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
2201
2202   /* if mouse button released, no gadget needs to be handled anymore */
2203   if (button == 0 && last_gi && !(last_gi->type & GD_TYPE_TEXTINPUT))
2204     last_gi = NULL;
2205
2206   /* modify event position values even if no gadget is pressed */
2207   if (button == 0 && !release_event)
2208     gi = new_gi;
2209
2210   if (gi)
2211   {
2212     int last_x = gi->event.x;
2213     int last_y = gi->event.y;
2214
2215     gi->event.x = mx - gi->x;
2216     gi->event.y = my - gi->y;
2217
2218     if (gi->type == GD_TYPE_DRAWING_AREA)
2219     {
2220       gi->event.x /= gi->drawing.item_xsize;
2221       gi->event.y /= gi->drawing.item_ysize;
2222
2223       if (last_x != gi->event.x || last_y != gi->event.y)
2224         changed_position = TRUE;
2225     }
2226   }
2227
2228   /* handle gadget popup info text */
2229   if (last_info_gi != new_gi ||
2230       (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
2231   {
2232     last_info_gi = new_gi;
2233
2234     if (new_gi != NULL && (button == 0 || new_gi == last_gi))
2235     {
2236       new_gi->event.type = 0;
2237       new_gi->callback_info(new_gi);
2238     }
2239     else
2240       default_callback_info(NULL);
2241   }
2242
2243   if (gadget_pressed)
2244   {
2245     if (gi->type == GD_TYPE_RADIO_BUTTON)
2246     {
2247       struct GadgetInfo *rgi = gadget_list_first_entry;
2248
2249       while (rgi)
2250       {
2251         if (rgi->mapped &&
2252             rgi->type == GD_TYPE_RADIO_BUTTON &&
2253             rgi->radio_nr == gi->radio_nr &&
2254             rgi != gi)
2255         {
2256           rgi->radio_pressed = FALSE;
2257           DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
2258         }
2259
2260         rgi = rgi->next;
2261       }
2262
2263       gi->radio_pressed = TRUE;
2264     }
2265     else if (gi->type & GD_TYPE_SCROLLBAR)
2266     {
2267       int mpos, gpos;
2268
2269       if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
2270       {
2271         mpos = mx;
2272         gpos = gi->x;
2273       }
2274       else
2275       {
2276         mpos = my;
2277         gpos = gi->y;
2278       }
2279
2280       if (mpos >= gpos + gi->scrollbar.position &&
2281           mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
2282       {
2283         /* drag scrollbar */
2284         gi->scrollbar.drag_position =
2285           scrollbar_mouse_pos - gi->scrollbar.position;
2286       }
2287       else
2288       {
2289         /* click scrollbar one scrollbar length up/left or down/right */
2290
2291         struct GadgetScrollbar *gs = &gi->scrollbar;
2292         int old_item_position = gs->item_position;
2293
2294         changed_position = FALSE;
2295
2296         gs->item_position +=
2297           gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
2298
2299         if (gs->item_position < 0)
2300           gs->item_position = 0;
2301         if (gs->item_position > gs->items_max - gs->items_visible)
2302           gs->item_position = gs->items_max - gs->items_visible;
2303
2304         if (old_item_position != gs->item_position)
2305         {
2306           gi->event.item_position = gs->item_position;
2307           changed_position = TRUE;
2308         }
2309
2310         AdjustScrollbar(gi, gs->items_max, gs->item_position);
2311
2312         gi->state = GD_BUTTON_UNPRESSED;
2313         gi->event.type = GD_EVENT_MOVING;
2314         gi->event.off_borders = FALSE;
2315
2316         if (gi->event_mask & GD_EVENT_MOVING && changed_position)
2317           gi->callback_action(gi);
2318
2319         /* don't handle this scrollbar anymore while mouse button pressed */
2320         last_gi = NULL;
2321
2322         return;
2323       }
2324     }
2325
2326     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2327
2328     gi->state = GD_BUTTON_PRESSED;
2329     gi->event.type = GD_EVENT_PRESSED;
2330     gi->event.button = button;
2331     gi->event.off_borders = FALSE;
2332
2333     /* initialize delay counter */
2334     pressed_delay = 0;
2335     DelayReached(&pressed_delay, GADGET_FRAME_DELAY);
2336
2337     if (gi->event_mask & GD_EVENT_PRESSED)
2338       gi->callback_action(gi);
2339   }
2340
2341   if (gadget_pressed_repeated)
2342   {
2343     if (gi->event_mask & GD_EVENT_REPEATED &&
2344         DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
2345       gi->callback_action(gi);
2346   }
2347
2348   if (gadget_moving)
2349   {
2350     if (gi->type & GD_TYPE_BUTTON)
2351     {
2352       if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
2353         DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2354       else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
2355         DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2356     }
2357
2358     if (gi->type & GD_TYPE_SCROLLBAR)
2359     {
2360       struct GadgetScrollbar *gs = &gi->scrollbar;
2361       int old_item_position = gs->item_position;
2362
2363       gs->position = scrollbar_mouse_pos - gs->drag_position;
2364
2365       if (gs->position < 0)
2366         gs->position = 0;
2367       if (gs->position > gs->position_max)
2368         gs->position = gs->position_max;
2369
2370       gs->item_position = gs->items_max * gs->position / gs->size_max;
2371
2372       if (old_item_position != gs->item_position)
2373       {
2374         gi->event.item_position = gs->item_position;
2375         changed_position = TRUE;
2376       }
2377
2378       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2379     }
2380
2381     gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
2382                  GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
2383     gi->event.type = GD_EVENT_MOVING;
2384     gi->event.off_borders = gadget_moving_off_borders;
2385
2386     if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
2387         (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
2388       gi->callback_action(gi);
2389   }
2390
2391   if (gadget_released_inside)
2392   {
2393     if (!(gi->type & GD_TYPE_TEXTINPUT))
2394       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2395
2396     gi->state = GD_BUTTON_UNPRESSED;
2397     gi->event.type = GD_EVENT_RELEASED;
2398
2399     if (gi->event_mask & GD_EVENT_RELEASED)
2400       gi->callback_action(gi);
2401   }
2402
2403   if (gadget_released_off_borders)
2404   {
2405     if (gi->type & GD_TYPE_SCROLLBAR)
2406       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2407
2408     gi->event.type = GD_EVENT_RELEASED;
2409
2410     if (gi->event_mask & GD_EVENT_RELEASED &&
2411         gi->event_mask & GD_EVENT_OFF_BORDERS)
2412       gi->callback_action(gi);
2413   }
2414 }
2415
2416 void HandleGadgetsKeyInput(KeySym key)
2417 {
2418   struct GadgetInfo *gi = last_gi;
2419   char text[MAX_GADGET_TEXTSIZE];
2420   int text_length;
2421   int cursor_pos;
2422   char letter;
2423   boolean legal_letter;
2424
2425   if (gi == NULL || !(gi->type & GD_TYPE_TEXTINPUT) || !gi->mapped)
2426     return;
2427
2428   text_length = strlen(gi->text.value);
2429   cursor_pos = gi->text.cursor_position;
2430   letter = getCharFromKeySym(key);
2431   legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
2432                   letter >= '0' && letter <= '9' :
2433                   letter != 0);
2434
2435   if (legal_letter && text_length < gi->text.size)
2436   {
2437     strcpy(text, gi->text.value);
2438     strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
2439     gi->text.value[cursor_pos] = letter;
2440     gi->text.cursor_position++;
2441     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2442   }
2443   else if (key == XK_Left && cursor_pos > 0)
2444   {
2445     gi->text.cursor_position--;
2446     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2447   }
2448   else if (key == XK_Right && cursor_pos < text_length)
2449   {
2450     gi->text.cursor_position++;
2451     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2452   }
2453   else if (key == XK_BackSpace && cursor_pos > 0)
2454   {
2455     strcpy(text, gi->text.value);
2456     strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
2457     gi->text.cursor_position--;
2458     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2459   }
2460   else if (key == XK_Delete && cursor_pos < text_length)
2461   {
2462     strcpy(text, gi->text.value);
2463     strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
2464     DrawGadget(gi, DG_PRESSED, DG_DIRECT);
2465   }
2466   else if (key == XK_Return)
2467   {
2468     CheckRangeOfNumericInputGadget(gi);
2469     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
2470
2471     if (gi->event_mask & GD_EVENT_TEXT_RETURN)
2472       gi->callback_action(gi);
2473
2474     last_gi = NULL;
2475   }
2476 }