1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
22 /* values for DrawGadget() */
23 #define DG_UNPRESSED 0
28 static struct GadgetInfo *gadget_list_first_entry = NULL;
29 static struct GadgetInfo *gadget_list_last_entry = NULL;
30 static int next_free_gadget_id = 1;
31 static boolean gadget_id_wrapped = FALSE;
33 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
35 struct GadgetInfo *gi = gadget_list_first_entry;
37 while (gi && gi->id != id)
43 static int getNewGadgetID()
45 int id = next_free_gadget_id++;
47 if (next_free_gadget_id <= 0) /* counter overrun */
49 gadget_id_wrapped = TRUE; /* now we must check each ID */
50 next_free_gadget_id = 0;
53 if (gadget_id_wrapped)
55 next_free_gadget_id++;
56 while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
57 next_free_gadget_id++;
60 if (next_free_gadget_id <= 0) /* cannot get new gadget id */
61 Error(ERR_EXIT, "too much gadgets -- this should not happen");
67 void DUMP_GADGET_MAP_STATE()
69 struct GadgetInfo *gi = gadget_list_first_entry;
73 printf("-XXX-1-> '%s': %s\n",
74 gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
81 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
83 struct GadgetInfo *gi = gadget_list_first_entry;
88 ((mx >= gi->x && mx < gi->x + gi->width &&
89 my >= gi->y && my < gi->y + gi->height) ||
90 (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
91 mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
92 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height)))
101 static void default_callback_info(void *ptr)
106 static void default_callback_action(void *ptr)
111 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
113 int state = (pressed ? 1 : 0);
114 struct GadgetDesign *gd = (gi->checked ?
115 &gi->alt_design[state] :
117 boolean redraw_selectbox = FALSE;
121 case GD_TYPE_NORMAL_BUTTON:
122 case GD_TYPE_CHECK_BUTTON:
123 case GD_TYPE_RADIO_BUTTON:
124 BlitBitmapOnBackground(gd->bitmap, drawto,
125 gd->x, gd->y, gi->width, gi->height,
127 if (gi->deco.design.bitmap)
128 BlitBitmap(gi->deco.design.bitmap, drawto,
129 gi->deco.design.x, gi->deco.design.y,
130 gi->deco.width, gi->deco.height,
131 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
132 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
135 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
136 case GD_TYPE_TEXTINPUT_NUMERIC:
140 char cursor_string[3];
141 char text[MAX_GADGET_TEXTSIZE + 1];
142 int font_type = gi->text.font_type;
143 int font_width = getFontWidth(font_type);
144 int border = gi->border.size;
146 /* left part of gadget */
147 BlitBitmapOnBackground(gd->bitmap, drawto,
148 gd->x, gd->y, border, gi->height, gi->x, gi->y);
150 /* middle part of gadget */
151 for (i=0; i < gi->text.size + 1; i++)
152 BlitBitmapOnBackground(gd->bitmap, drawto,
153 gd->x + border, gd->y, font_width, gi->height,
154 gi->x + border + i * font_width, gi->y);
156 /* right part of gadget */
157 BlitBitmapOnBackground(gd->bitmap, drawto,
158 gd->x + gi->border.width - border, gd->y,border,
159 gi->height, gi->x + gi->width - border, gi->y);
162 strcpy(text, gi->text.value);
165 /* gadget text value */
167 gi->x + border, gi->y + border, text,
168 font_type, BLIT_MASKED);
170 cursor_letter = gi->text.value[gi->text.cursor_position];
171 cursor_string[0] = '~';
172 cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
173 cursor_string[2] = '\0';
175 /* draw cursor, if active */
178 gi->x + border + gi->text.cursor_position * font_width,
179 gi->y + border, cursor_string,
180 font_type, BLIT_MASKED);
184 case GD_TYPE_SELECTBOX:
187 char text[MAX_GADGET_TEXTSIZE + 1];
188 int font_type = gi->selectbox.font_type;
189 int font_width = getFontWidth(font_type);
190 int font_height = getFontHeight(font_type);
191 int border = gi->border.size;
192 int button = gi->border.size_selectbutton;
193 int width_inner = gi->border.width - button - 2 * border;
194 int box_width = gi->selectbox.width;
195 int box_height = gi->selectbox.height;
197 /* left part of gadget */
198 BlitBitmapOnBackground(gd->bitmap, drawto,
199 gd->x, gd->y, border, gi->height, gi->x, gi->y);
201 /* middle part of gadget */
202 for (i=0; i < gi->selectbox.size; i++)
203 BlitBitmapOnBackground(gd->bitmap, drawto,
204 gd->x + border, gd->y, font_width, gi->height,
205 gi->x + border + i * font_width, gi->y);
207 /* button part of gadget */
208 BlitBitmapOnBackground(gd->bitmap, drawto,
209 gd->x + border + width_inner, gd->y,
211 gi->x + gi->width - border - button, gi->y);
213 /* right part of gadget */
214 BlitBitmapOnBackground(gd->bitmap, drawto,
215 gd->x + gi->border.width - border, gd->y,border,
216 gi->height, gi->x + gi->width - border, gi->y);
219 strncpy(text, gi->selectbox.values[gi->selectbox.index],
221 text[gi->selectbox.size] = '\0';
223 /* gadget text value */
224 DrawTextExt(drawto, gi->x + border, gi->y + border, text,
225 font_type, BLIT_MASKED);
229 if (!gi->selectbox.open)
231 gi->selectbox.open = TRUE;
232 gi->selectbox.stay_open = FALSE;
233 gi->selectbox.current_index = gi->selectbox.index;
235 /* save background under selectbox */
236 BlitBitmap(drawto, gfx.field_save_buffer,
237 gi->selectbox.x, gi->selectbox.y,
238 gi->selectbox.width, gi->selectbox.height,
239 gi->selectbox.x, gi->selectbox.y);
242 /* draw open selectbox */
244 /* top left part of gadget border */
245 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
247 gi->selectbox.x, gi->selectbox.y);
249 /* top middle part of gadget border */
250 for (i=0; i < gi->selectbox.size; i++)
251 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border, gd->y,
253 gi->selectbox.x + border + i * font_width,
256 /* top button part of gadget border */
257 BlitBitmapOnBackground(gd->bitmap, drawto,
258 gd->x + border + width_inner, gd->y,
260 gi->selectbox.x + box_width - border - button,
263 /* top right part of gadget border */
264 BlitBitmapOnBackground(gd->bitmap, drawto,
265 gd->x + gi->border.width - border, gd->y,
267 gi->selectbox.x + box_width - border,
270 /* left and right part of gadget border for each row */
271 for (i=0; i < gi->selectbox.num_values; i++)
273 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border,
276 gi->selectbox.y + border + i * font_height);
277 BlitBitmapOnBackground(gd->bitmap, drawto,
278 gd->x + gi->border.width - border,
281 gi->selectbox.x + box_width - border,
282 gi->selectbox.y + border + i * font_height);
285 /* bottom left part of gadget border */
286 BlitBitmapOnBackground(gd->bitmap, drawto,
287 gd->x, gd->y + gi->height - border,
290 gi->selectbox.y + box_height - border);
292 /* bottom middle part of gadget border */
293 for (i=0; i < gi->selectbox.size; i++)
294 BlitBitmapOnBackground(gd->bitmap, drawto,
295 gd->x + border, gd->y + gi->height - border,
297 gi->selectbox.x + border + i * font_width,
298 gi->selectbox.y + box_height - border);
300 /* bottom button part of gadget border */
301 BlitBitmapOnBackground(gd->bitmap, drawto,
302 gd->x + border + width_inner,
303 gd->y + gi->height - border,
305 gi->selectbox.x + box_width - border - button,
306 gi->selectbox.y + box_height - border);
308 /* bottom right part of gadget border */
309 BlitBitmapOnBackground(gd->bitmap, drawto,
310 gd->x + gi->border.width - border,
311 gd->y + gi->height - border,
313 gi->selectbox.x + box_width - border,
314 gi->selectbox.y + box_height - border);
316 ClearRectangleOnBackground(drawto,
317 gi->selectbox.x + border,
318 gi->selectbox.y + border,
319 gi->selectbox.width - 2 * border,
320 gi->selectbox.height - 2 * border);
322 /* selectbox text values */
323 for (i=0; i < gi->selectbox.num_values; i++)
325 if (i == gi->selectbox.current_index)
327 FillRectangle(drawto,
328 gi->selectbox.x + border,
329 gi->selectbox.y + border + i * font_height,
330 gi->selectbox.width - 2 * border, font_height,
331 gi->selectbox.reverse_color);
334 strncpy(&text[1], gi->selectbox.values[i], gi->selectbox.size);
335 text[1 + gi->selectbox.size] = '\0';
339 strncpy(text, gi->selectbox.values[i], gi->selectbox.size);
340 text[gi->selectbox.size] = '\0';
344 gi->selectbox.x + border,
345 gi->selectbox.y + border + i * font_height, text,
346 font_type, BLIT_MASKED);
349 redraw_selectbox = TRUE;
351 else if (gi->selectbox.open)
353 gi->selectbox.open = FALSE;
355 /* redraw closed selectbox */
356 DrawGadget(gi, FALSE, FALSE);
358 /* restore background under selectbox */
359 BlitBitmap(gfx.field_save_buffer, drawto,
360 gi->selectbox.x, gi->selectbox.y,
361 gi->selectbox.width, gi->selectbox.height,
362 gi->selectbox.x, gi->selectbox.y);
364 redraw_selectbox = TRUE;
369 case GD_TYPE_SCROLLBAR_VERTICAL:
373 int ypos = gi->y + gi->scrollbar.position;
374 int design_full = gi->width;
375 int design_body = design_full - 2 * gi->border.size;
376 int size_full = gi->scrollbar.size;
377 int size_body = size_full - 2 * gi->border.size;
378 int num_steps = size_body / design_body;
379 int step_size_remain = size_body - num_steps * design_body;
381 /* clear scrollbar area */
382 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
383 gi->width, gi->height);
385 /* upper part of gadget */
386 BlitBitmapOnBackground(gd->bitmap, drawto,
388 gi->width, gi->border.size,
391 /* middle part of gadget */
392 for (i=0; i<num_steps; i++)
393 BlitBitmapOnBackground(gd->bitmap, drawto,
394 gd->x, gd->y + gi->border.size,
395 gi->width, design_body,
397 ypos + gi->border.size + i * design_body);
399 /* remaining middle part of gadget */
400 if (step_size_remain > 0)
401 BlitBitmapOnBackground(gd->bitmap, drawto,
402 gd->x, gd->y + gi->border.size,
403 gi->width, step_size_remain,
405 ypos + gi->border.size
406 + num_steps * design_body);
408 /* lower part of gadget */
409 BlitBitmapOnBackground(gd->bitmap, drawto,
410 gd->x, gd->y + design_full - gi->border.size,
411 gi->width, gi->border.size,
412 xpos, ypos + size_full - gi->border.size);
416 case GD_TYPE_SCROLLBAR_HORIZONTAL:
419 int xpos = gi->x + gi->scrollbar.position;
421 int design_full = gi->height;
422 int design_body = design_full - 2 * gi->border.size;
423 int size_full = gi->scrollbar.size;
424 int size_body = size_full - 2 * gi->border.size;
425 int num_steps = size_body / design_body;
426 int step_size_remain = size_body - num_steps * design_body;
428 /* clear scrollbar area */
429 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
430 gi->width, gi->height);
432 /* left part of gadget */
433 BlitBitmapOnBackground(gd->bitmap, drawto,
435 gi->border.size, gi->height,
438 /* middle part of gadget */
439 for (i=0; i<num_steps; i++)
440 BlitBitmapOnBackground(gd->bitmap, drawto,
441 gd->x + gi->border.size, gd->y,
442 design_body, gi->height,
443 xpos + gi->border.size + i * design_body,
446 /* remaining middle part of gadget */
447 if (step_size_remain > 0)
448 BlitBitmapOnBackground(gd->bitmap, drawto,
449 gd->x + gi->border.size, gd->y,
450 step_size_remain, gi->height,
451 xpos + gi->border.size
452 + num_steps * design_body,
455 /* right part of gadget */
456 BlitBitmapOnBackground(gd->bitmap, drawto,
457 gd->x + design_full - gi->border.size, gd->y,
458 gi->border.size, gi->height,
459 xpos + size_full - gi->border.size, ypos);
469 BlitBitmap(drawto, window,
470 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
472 if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
473 BlitBitmap(drawto, window,
474 gi->selectbox.x, gi->selectbox.y,
475 gi->selectbox.width, gi->selectbox.height,
476 gi->selectbox.x, gi->selectbox.y);
479 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
480 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
481 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
484 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
488 while (tag != GDI_END)
493 gi->custom_id = va_arg(ap, int);
496 case GDI_CUSTOM_TYPE_ID:
497 gi->custom_type_id = va_arg(ap, int);
502 int max_textsize = MAX_INFO_TEXTSIZE - 1;
503 char *text = va_arg(ap, char *);
506 strncpy(gi->info_text, text, max_textsize);
510 gi->info_text[max_textsize] = '\0';
515 gi->x = va_arg(ap, int);
519 gi->y = va_arg(ap, int);
523 gi->width = va_arg(ap, int);
527 gi->height = va_arg(ap, int);
531 gi->type = va_arg(ap, unsigned long);
535 gi->state = va_arg(ap, unsigned long);
539 /* take care here: "boolean" is typedef'ed as "unsigned char",
540 which gets promoted to "int" */
541 gi->checked = (boolean)va_arg(ap, int);
545 gi->radio_nr = va_arg(ap, unsigned long);
548 case GDI_NUMBER_VALUE:
549 gi->text.number_value = va_arg(ap, long);
550 sprintf(gi->text.value, "%d", gi->text.number_value);
551 gi->text.cursor_position = strlen(gi->text.value);
555 gi->text.number_min = va_arg(ap, long);
556 if (gi->text.number_value < gi->text.number_min)
558 gi->text.number_value = gi->text.number_min;
559 sprintf(gi->text.value, "%d", gi->text.number_value);
564 gi->text.number_max = va_arg(ap, long);
565 if (gi->text.number_value > gi->text.number_max)
567 gi->text.number_value = gi->text.number_max;
568 sprintf(gi->text.value, "%d", gi->text.number_value);
574 int max_textsize = MAX_GADGET_TEXTSIZE;
577 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
579 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
580 gi->text.value[max_textsize] = '\0';
581 gi->text.cursor_position = strlen(gi->text.value);
587 int tag_value = va_arg(ap, int);
588 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
590 gi->text.size = max_textsize;
591 gi->text.value[max_textsize] = '\0';
593 /* same tag also used for selectbox definition */
594 gi->selectbox.size = gi->text.size;
599 gi->text.font_type = va_arg(ap, int);
601 /* same tag also used for selectbox definition */
602 gi->selectbox.font_type = gi->text.font_type;
605 case GDI_SELECTBOX_VALUES:
606 gi->selectbox.values = va_arg(ap, const char **);
609 case GDI_SELECTBOX_INDEX:
610 gi->selectbox.index = va_arg(ap, int);
613 case GDI_DESIGN_UNPRESSED:
614 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
615 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
616 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
619 case GDI_DESIGN_PRESSED:
620 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
621 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
622 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
625 case GDI_ALT_DESIGN_UNPRESSED:
626 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
627 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
628 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
631 case GDI_ALT_DESIGN_PRESSED:
632 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
633 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
634 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
637 case GDI_BORDER_SIZE:
638 gi->border.size = va_arg(ap, int);
641 case GDI_BORDER_SIZE_SELECTBUTTON:
642 gi->border.size_selectbutton = va_arg(ap, int);
645 case GDI_TEXTINPUT_DESIGN_WIDTH:
646 gi->border.width = va_arg(ap, int);
649 case GDI_DECORATION_DESIGN:
650 gi->deco.design.bitmap = va_arg(ap, Bitmap *);
651 gi->deco.design.x = va_arg(ap, int);
652 gi->deco.design.y = va_arg(ap, int);
655 case GDI_DECORATION_POSITION:
656 gi->deco.x = va_arg(ap, int);
657 gi->deco.y = va_arg(ap, int);
660 case GDI_DECORATION_SIZE:
661 gi->deco.width = va_arg(ap, int);
662 gi->deco.height = va_arg(ap, int);
665 case GDI_DECORATION_SHIFTING:
666 gi->deco.xshift = va_arg(ap, int);
667 gi->deco.yshift = va_arg(ap, int);
671 gi->event_mask = va_arg(ap, unsigned long);
675 gi->drawing.area_xsize = va_arg(ap, int);
676 gi->drawing.area_ysize = va_arg(ap, int);
678 /* determine dependent values for drawing area gadget, if needed */
679 if (gi->width == 0 && gi->height == 0 &&
680 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
682 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
683 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
685 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
686 gi->width != 0 && gi->height != 0)
688 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
689 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
694 gi->drawing.item_xsize = va_arg(ap, int);
695 gi->drawing.item_ysize = va_arg(ap, int);
697 /* determine dependent values for drawing area gadget, if needed */
698 if (gi->width == 0 && gi->height == 0 &&
699 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
701 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
702 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
704 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
705 gi->width != 0 && gi->height != 0)
707 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
708 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
712 case GDI_SCROLLBAR_ITEMS_MAX:
713 gi->scrollbar.items_max = va_arg(ap, int);
716 case GDI_SCROLLBAR_ITEMS_VISIBLE:
717 gi->scrollbar.items_visible = va_arg(ap, int);
720 case GDI_SCROLLBAR_ITEM_POSITION:
721 gi->scrollbar.item_position = va_arg(ap, int);
724 case GDI_CALLBACK_INFO:
725 gi->callback_info = va_arg(ap, gadget_function);
728 case GDI_CALLBACK_ACTION:
729 gi->callback_action = va_arg(ap, gadget_function);
733 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
736 tag = va_arg(ap, int); /* read next tag */
739 /* check if gadget is complete */
740 if (gi->type != GD_TYPE_DRAWING_AREA &&
741 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
742 !gi->design[GD_BUTTON_PRESSED].bitmap))
743 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
745 /* adjust gadget values in relation to other gadget values */
747 if (gi->type & GD_TYPE_TEXTINPUT)
749 int font_width = getFontWidth(gi->text.font_type);
750 int font_height = getFontHeight(gi->text.font_type);
751 int border_size = gi->border.size;
753 gi->width = 2 * border_size + (gi->text.size + 1) * font_width;
754 gi->height = 2 * border_size + font_height;
757 if (gi->type & GD_TYPE_SELECTBOX)
759 int font_nr = gi->selectbox.font_type;
760 int font_bitmap_id = gfx.select_font_function(font_nr);
761 struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
762 int font_width = getFontWidth(gi->selectbox.font_type);
763 int font_height = getFontHeight(gi->selectbox.font_type);
764 int border_size = gi->border.size;
765 int button_size = gi->border.size_selectbutton;
768 gi->width = 2 * border_size + gi->text.size * font_width + button_size;
769 gi->height = 2 * border_size + font_height;
771 if (gi->selectbox.values == NULL)
772 Error(ERR_EXIT, "selectbox gadget incomplete (missing values array)");
774 gi->selectbox.num_values = 0;
775 while (gi->selectbox.values[gi->selectbox.num_values] != NULL)
776 gi->selectbox.num_values++;
778 /* calculate values for open selectbox */
779 gi->selectbox.width = gi->width;
780 gi->selectbox.height =
781 2 * border_size + gi->selectbox.num_values * font_height;
783 gi->selectbox.x = gi->x;
784 gi->selectbox.y = gi->y + gi->height;
785 if (gi->selectbox.y + gi->selectbox.height > gfx.real_sy + gfx.full_sysize)
786 gi->selectbox.y = gi->y - gi->selectbox.height;
787 if (gi->selectbox.y < 0)
788 gi->selectbox.y = gfx.real_sy + gfx.full_sysize - gi->selectbox.height;
790 if (!getFontChar(font_nr, '|', &src_x, &src_y))
791 Error(ERR_EXIT, "selectbox gadget incomplete (cannot get cursor)");
793 src_x += font_width / 2;
794 src_y += font_height / 2;
795 gi->selectbox.reverse_color = GetPixel(font->bitmap, src_x, src_y);
797 /* always start with closed selectbox */
798 gi->selectbox.open = FALSE;
801 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
803 struct GadgetTextInput *text = &gi->text;
804 int value = text->number_value;
806 text->number_value = (value < text->number_min ? text->number_min :
807 value > text->number_max ? text->number_max :
810 sprintf(text->value, "%d", text->number_value);
813 if (gi->type & GD_TYPE_SCROLLBAR)
815 struct GadgetScrollbar *gs = &gi->scrollbar;
817 if (gi->width == 0 || gi->height == 0 ||
818 gs->items_max == 0 || gs->items_visible == 0)
819 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
821 /* calculate internal scrollbar values */
822 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
823 gi->height : gi->width);
824 gs->size = gs->size_max * gs->items_visible / gs->items_max;
825 gs->position = gs->size_max * gs->item_position / gs->items_max;
826 gs->position_max = gs->size_max - gs->size;
827 gs->correction = gs->size_max / gs->items_max / 2;
829 /* finetuning for maximal right/bottom position */
830 if (gs->item_position == gs->items_max - gs->items_visible)
831 gs->position = gs->position_max;
835 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
839 va_start(ap, first_tag);
840 HandleGadgetTags(gi, first_tag, ap);
846 void RedrawGadget(struct GadgetInfo *gi)
849 DrawGadget(gi, gi->state, DG_DIRECT);
852 struct GadgetInfo *CreateGadget(int first_tag, ...)
854 struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
857 /* always start with reliable default values */
858 new_gadget->id = getNewGadgetID();
859 new_gadget->callback_info = default_callback_info;
860 new_gadget->callback_action = default_callback_action;
861 new_gadget->next = NULL;
863 va_start(ap, first_tag);
864 HandleGadgetTags(new_gadget, first_tag, ap);
867 /* insert new gadget into global gadget list */
868 if (gadget_list_last_entry)
870 gadget_list_last_entry->next = new_gadget;
871 gadget_list_last_entry = gadget_list_last_entry->next;
874 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
879 void FreeGadget(struct GadgetInfo *gi)
881 struct GadgetInfo *gi_previous = gadget_list_first_entry;
883 while (gi_previous != NULL && gi_previous->next != gi)
884 gi_previous = gi_previous->next;
886 if (gi == gadget_list_first_entry)
887 gadget_list_first_entry = gi->next;
889 if (gi == gadget_list_last_entry)
890 gadget_list_last_entry = gi_previous;
892 if (gi_previous != NULL)
893 gi_previous->next = gi->next;
898 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
900 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
903 gi->text.number_value = atoi(gi->text.value);
905 if (gi->text.number_value < gi->text.number_min)
906 gi->text.number_value = gi->text.number_min;
907 if (gi->text.number_value > gi->text.number_max)
908 gi->text.number_value = gi->text.number_max;
910 sprintf(gi->text.value, "%d", gi->text.number_value);
912 if (gi->text.cursor_position < 0)
913 gi->text.cursor_position = 0;
914 else if (gi->text.cursor_position > strlen(gi->text.value))
915 gi->text.cursor_position = strlen(gi->text.value);
918 /* global pointer to gadget actually in use (when mouse button pressed) */
919 static struct GadgetInfo *last_gi = NULL;
921 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
923 if (gi == NULL || gi->mapped)
929 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
932 void MapGadget(struct GadgetInfo *gi)
934 MapGadgetExt(gi, TRUE);
937 void UnmapGadget(struct GadgetInfo *gi)
939 if (gi == NULL || !gi->mapped)
948 #define MAX_NUM_GADGETS 1024
949 #define MULTIMAP_UNMAP (1 << 0)
950 #define MULTIMAP_REMAP (1 << 1)
951 #define MULTIMAP_REDRAW (1 << 2)
952 #define MULTIMAP_PLAYFIELD (1 << 3)
953 #define MULTIMAP_DOOR_1 (1 << 4)
954 #define MULTIMAP_DOOR_2 (1 << 5)
955 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
959 static void MultiMapGadgets(int mode)
961 struct GadgetInfo *gi = gadget_list_first_entry;
962 static boolean map_state[MAX_NUM_GADGETS];
967 if ((mode & MULTIMAP_PLAYFIELD &&
968 gi->x < gfx.sx + gfx.sxsize) ||
969 (mode & MULTIMAP_DOOR_1 &&
970 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
971 (mode & MULTIMAP_DOOR_2 &&
972 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
973 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
975 if (mode & MULTIMAP_UNMAP)
977 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
982 if (map_state[map_count++ % MAX_NUM_GADGETS])
983 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
991 void UnmapAllGadgets()
993 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
996 void RemapAllGadgets()
998 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
1001 boolean anyTextInputGadgetActive()
1003 return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
1006 boolean anySelectboxGadgetActive()
1008 return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
1011 boolean anyTextGadgetActive()
1013 return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
1016 void ClickOnGadget(struct GadgetInfo *gi, int button)
1018 /* simulate releasing mouse button over last gadget, if still pressed */
1020 HandleGadgets(-1, -1, 0);
1022 /* simulate pressing mouse button over specified gadget */
1023 HandleGadgets(gi->x, gi->y, button);
1025 /* simulate releasing mouse button over specified gadget */
1026 HandleGadgets(gi->x, gi->y, 0);
1029 void HandleGadgets(int mx, int my, int button)
1031 static struct GadgetInfo *last_info_gi = NULL;
1032 static unsigned long pressed_delay = 0;
1033 static int last_button = 0;
1034 static int last_mx = 0, last_my = 0;
1035 int scrollbar_mouse_pos = 0;
1036 struct GadgetInfo *new_gi, *gi;
1037 boolean press_event;
1038 boolean release_event;
1039 boolean mouse_moving;
1040 boolean gadget_pressed;
1041 boolean gadget_pressed_repeated;
1042 boolean gadget_moving;
1043 boolean gadget_moving_inside;
1044 boolean gadget_moving_off_borders;
1045 boolean gadget_released;
1046 boolean gadget_released_inside;
1047 boolean gadget_released_inside_select_line;
1048 boolean gadget_released_inside_select_area;
1049 boolean gadget_released_off_borders;
1050 boolean changed_position = FALSE;
1052 /* check if there are any gadgets defined */
1053 if (gadget_list_first_entry == NULL)
1056 /* check which gadget is under the mouse pointer */
1057 new_gi = getGadgetInfoFromMousePosition(mx, my);
1059 /* check if button state has changed since last invocation */
1060 press_event = (button != 0 && last_button == 0);
1061 release_event = (button == 0 && last_button != 0);
1062 last_button = button;
1064 /* check if mouse has been moved since last invocation */
1065 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
1069 /* special treatment for text and number input gadgets */
1070 if (anyTextInputGadgetActive() && button != 0 && !motion_status)
1072 struct GadgetInfo *gi = last_gi;
1074 if (new_gi == last_gi)
1076 int old_cursor_position = gi->text.cursor_position;
1078 /* if mouse button pressed inside activated text gadget, set cursor */
1079 gi->text.cursor_position =
1080 (mx - gi->x - gi->border.size) / getFontWidth(gi->text.font_type);
1082 if (gi->text.cursor_position < 0)
1083 gi->text.cursor_position = 0;
1084 else if (gi->text.cursor_position > strlen(gi->text.value))
1085 gi->text.cursor_position = strlen(gi->text.value);
1087 if (gi->text.cursor_position != old_cursor_position)
1088 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1092 /* if mouse button pressed outside text input gadget, deactivate it */
1093 CheckRangeOfNumericInputGadget(gi);
1094 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1096 gi->event.type = GD_EVENT_TEXT_LEAVING;
1098 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1099 gi->callback_action(gi);
1105 /* special treatment for selectbox gadgets */
1106 if (anySelectboxGadgetActive() && button != 0 && !motion_status)
1108 struct GadgetInfo *gi = last_gi;
1110 if (new_gi == last_gi)
1112 int old_index = gi->selectbox.current_index;
1114 /* if mouse button pressed inside activated selectbox, select value */
1115 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1116 gi->selectbox.current_index =
1117 (my - gi->selectbox.y - gi->border.size) /
1118 getFontWidth(gi->selectbox.font_type);
1120 if (gi->selectbox.current_index < 0)
1121 gi->selectbox.current_index = 0;
1122 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1123 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1125 if (gi->selectbox.current_index != old_index)
1126 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1130 /* if mouse button pressed outside selectbox gadget, deactivate it */
1131 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1133 gi->event.type = GD_EVENT_TEXT_LEAVING;
1135 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1136 gi->callback_action(gi);
1143 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
1144 gadget_pressed_repeated =
1145 (button != 0 && last_gi != NULL && new_gi == last_gi);
1147 gadget_released = (release_event && last_gi != NULL);
1148 gadget_released_inside = (gadget_released && new_gi == last_gi);
1149 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
1151 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
1152 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
1153 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
1155 /* when handling selectbox, set additional state values */
1156 if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
1158 struct GadgetInfo *gi = last_gi;
1160 gadget_released_inside_select_line =
1161 (mx >= gi->x && mx < gi->x + gi->width &&
1162 my >= gi->y && my < gi->y + gi->height);
1163 gadget_released_inside_select_area =
1164 (mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
1165 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height);
1169 gadget_released_inside_select_line = FALSE;
1170 gadget_released_inside_select_area = FALSE;
1173 /* if new gadget pressed, store this gadget */
1177 /* 'gi' is actually handled gadget */
1180 /* if gadget is scrollbar, choose mouse position value */
1181 if (gi && gi->type & GD_TYPE_SCROLLBAR)
1182 scrollbar_mouse_pos =
1183 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
1185 /* if mouse button released, no gadget needs to be handled anymore */
1186 if (gadget_released)
1188 if ((last_gi->type & GD_TYPE_SELECTBOX) &&
1189 (gadget_released_inside_select_line ||
1190 gadget_released_off_borders)) /* selectbox stays open */
1191 gi->selectbox.stay_open = TRUE;
1192 else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1196 /* modify event position values even if no gadget is pressed */
1197 if (button == 0 && !release_event)
1202 int last_x = gi->event.x;
1203 int last_y = gi->event.y;
1205 gi->event.x = mx - gi->x;
1206 gi->event.y = my - gi->y;
1208 if (gi->type == GD_TYPE_DRAWING_AREA)
1210 gi->event.x /= gi->drawing.item_xsize;
1211 gi->event.y /= gi->drawing.item_ysize;
1213 if (last_x != gi->event.x || last_y != gi->event.y)
1214 changed_position = TRUE;
1216 else if (gi->type & GD_TYPE_SELECTBOX)
1218 int old_index = gi->selectbox.current_index;
1220 /* if mouse moving inside activated selectbox, select value */
1221 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1222 gi->selectbox.current_index =
1223 (my - gi->selectbox.y - gi->border.size) /
1224 getFontWidth(gi->selectbox.font_type);
1226 if (gi->selectbox.current_index < 0)
1227 gi->selectbox.current_index = 0;
1228 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1229 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1231 if (gi->selectbox.current_index != old_index)
1232 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1236 /* handle gadget popup info text */
1237 if (last_info_gi != new_gi ||
1238 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
1240 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
1242 new_gi->event.type = GD_EVENT_INFO_ENTERING;
1243 new_gi->callback_info(new_gi);
1245 else if (last_info_gi != NULL)
1247 last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
1248 last_info_gi->callback_info(last_info_gi);
1251 default_callback_info(NULL);
1253 printf("It seems that we are leaving gadget [%s]!\n",
1254 (last_info_gi != NULL &&
1255 last_info_gi->info_text != NULL ?
1256 last_info_gi->info_text : ""));
1260 last_info_gi = new_gi;
1265 if (gi->type == GD_TYPE_CHECK_BUTTON)
1267 gi->checked = !gi->checked;
1269 else if (gi->type == GD_TYPE_RADIO_BUTTON)
1271 struct GadgetInfo *rgi = gadget_list_first_entry;
1276 rgi->type == GD_TYPE_RADIO_BUTTON &&
1277 rgi->radio_nr == gi->radio_nr &&
1280 rgi->checked = FALSE;
1281 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
1289 else if (gi->type & GD_TYPE_SCROLLBAR)
1293 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1304 if (mpos >= gpos + gi->scrollbar.position &&
1305 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1307 /* drag scrollbar */
1308 gi->scrollbar.drag_position =
1309 scrollbar_mouse_pos - gi->scrollbar.position;
1313 /* click scrollbar one scrollbar length up/left or down/right */
1315 struct GadgetScrollbar *gs = &gi->scrollbar;
1316 int old_item_position = gs->item_position;
1318 changed_position = FALSE;
1320 gs->item_position +=
1321 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
1323 if (gs->item_position < 0)
1324 gs->item_position = 0;
1325 if (gs->item_position > gs->items_max - gs->items_visible)
1326 gs->item_position = gs->items_max - gs->items_visible;
1328 if (old_item_position != gs->item_position)
1330 gi->event.item_position = gs->item_position;
1331 changed_position = TRUE;
1334 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
1337 gi->state = GD_BUTTON_UNPRESSED;
1338 gi->event.type = GD_EVENT_MOVING;
1339 gi->event.off_borders = FALSE;
1341 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
1342 gi->callback_action(gi);
1344 /* don't handle this scrollbar anymore while mouse button pressed */
1351 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1353 gi->state = GD_BUTTON_PRESSED;
1354 gi->event.type = GD_EVENT_PRESSED;
1355 gi->event.button = button;
1356 gi->event.off_borders = FALSE;
1358 /* initialize delay counter */
1359 DelayReached(&pressed_delay, 0);
1361 if (gi->event_mask & GD_EVENT_PRESSED)
1362 gi->callback_action(gi);
1365 if (gadget_pressed_repeated)
1367 gi->event.type = GD_EVENT_PRESSED;
1369 if (gi->event_mask & GD_EVENT_REPEATED &&
1370 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1371 gi->callback_action(gi);
1376 if (gi->type & GD_TYPE_BUTTON)
1378 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
1379 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1380 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
1381 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1383 else if (gi->type & GD_TYPE_SELECTBOX)
1385 int old_index = gi->selectbox.current_index;
1387 /* if mouse moving inside activated selectbox, select value */
1388 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1389 gi->selectbox.current_index =
1390 (my - gi->selectbox.y - gi->border.size) /
1391 getFontWidth(gi->selectbox.font_type);
1393 if (gi->selectbox.current_index < 0)
1394 gi->selectbox.current_index = 0;
1395 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1396 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1398 if (gi->selectbox.current_index != old_index)
1399 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1401 else if (gi->type & GD_TYPE_SCROLLBAR)
1403 struct GadgetScrollbar *gs = &gi->scrollbar;
1404 int old_item_position = gs->item_position;
1406 gs->position = scrollbar_mouse_pos - gs->drag_position;
1408 if (gs->position < 0)
1410 if (gs->position > gs->position_max)
1411 gs->position = gs->position_max;
1414 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1416 if (gs->item_position < 0)
1417 gs->item_position = 0;
1418 if (gs->item_position > gs->items_max - 1)
1419 gs->item_position = gs->items_max - 1;
1421 if (old_item_position != gs->item_position)
1423 gi->event.item_position = gs->item_position;
1424 changed_position = TRUE;
1427 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1430 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1431 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1432 gi->event.type = GD_EVENT_MOVING;
1433 gi->event.off_borders = gadget_moving_off_borders;
1435 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1436 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1437 gi->callback_action(gi);
1440 if (gadget_released_inside)
1442 boolean deactivate_gadget = TRUE;
1444 if (gi->type & GD_TYPE_SELECTBOX)
1446 if (gadget_released_inside_select_line ||
1447 gadget_released_off_borders) /* selectbox stays open */
1448 deactivate_gadget = FALSE;
1450 gi->selectbox.index = gi->selectbox.current_index;
1453 if (deactivate_gadget &&
1454 !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1455 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1457 gi->state = GD_BUTTON_UNPRESSED;
1458 gi->event.type = GD_EVENT_RELEASED;
1460 if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
1461 gi->callback_action(gi);
1464 if (gadget_released_off_borders)
1466 if (gi->type & GD_TYPE_SCROLLBAR)
1467 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1469 gi->event.type = GD_EVENT_RELEASED;
1471 if (gi->event_mask & GD_EVENT_RELEASED &&
1472 gi->event_mask & GD_EVENT_OFF_BORDERS)
1473 gi->callback_action(gi);
1477 void HandleGadgetsKeyInput(Key key)
1479 struct GadgetInfo *gi = last_gi;
1481 if (gi == NULL || !gi->mapped ||
1482 !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
1485 if (key == KSYM_Return) /* valid for both text input and selectbox */
1487 if (gi->type & GD_TYPE_TEXTINPUT)
1488 CheckRangeOfNumericInputGadget(gi);
1489 else if (gi->type & GD_TYPE_SELECTBOX)
1490 gi->selectbox.index = gi->selectbox.current_index;
1492 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1494 gi->event.type = GD_EVENT_TEXT_RETURN;
1496 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1497 gi->callback_action(gi);
1501 else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */
1503 char text[MAX_GADGET_TEXTSIZE];
1504 int text_length = strlen(gi->text.value);
1505 int cursor_pos = gi->text.cursor_position;
1506 char letter = getCharFromKey(key);
1507 boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1508 letter >= '0' && letter <= '9' :
1511 if (legal_letter && text_length < gi->text.size)
1513 strcpy(text, gi->text.value);
1514 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1515 gi->text.value[cursor_pos] = letter;
1516 gi->text.cursor_position++;
1518 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1520 else if (key == KSYM_Left && cursor_pos > 0)
1522 gi->text.cursor_position--;
1523 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1525 else if (key == KSYM_Right && cursor_pos < text_length)
1527 gi->text.cursor_position++;
1528 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1530 else if (key == KSYM_BackSpace && cursor_pos > 0)
1532 strcpy(text, gi->text.value);
1533 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1534 gi->text.cursor_position--;
1535 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1537 else if (key == KSYM_Delete && cursor_pos < text_length)
1539 strcpy(text, gi->text.value);
1540 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1541 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1544 else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
1546 int index = gi->selectbox.current_index;
1547 int num_values = gi->selectbox.num_values;
1549 if (key == KSYM_Up && index > 0)
1551 gi->selectbox.current_index--;
1552 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1554 else if (key == KSYM_Down && index < num_values - 1)
1556 gi->selectbox.current_index++;
1557 DrawGadget(gi, DG_PRESSED, DG_DIRECT);