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