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
29 static struct GadgetInfo *gadget_list_first_entry = NULL;
30 static struct GadgetInfo *gadget_list_last_entry = NULL;
31 static int next_free_gadget_id = 1;
32 static boolean gadget_id_wrapped = FALSE;
34 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
36 struct GadgetInfo *gi = gadget_list_first_entry;
38 while (gi && gi->id != id)
44 static int getNewGadgetID()
46 int id = next_free_gadget_id++;
48 if (next_free_gadget_id <= 0) /* counter overrun */
50 gadget_id_wrapped = TRUE; /* now we must check each ID */
51 next_free_gadget_id = 0;
54 if (gadget_id_wrapped)
56 next_free_gadget_id++;
57 while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
58 next_free_gadget_id++;
61 if (next_free_gadget_id <= 0) /* cannot get new gadget id */
62 Error(ERR_EXIT, "too much gadgets -- this should not happen");
68 void DUMP_GADGET_MAP_STATE()
70 struct GadgetInfo *gi = gadget_list_first_entry;
74 printf("-XXX-1-> '%s': %s\n",
75 gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
82 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
84 struct GadgetInfo *gi;
86 /* open selectboxes may overlap other active gadgets, so check them first */
87 for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
89 if (gi->mapped && gi->active &&
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)
96 /* check all other gadgets */
97 for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
99 if (gi->mapped && gi->active &&
100 mx >= gi->x && mx < gi->x + gi->width &&
101 my >= gi->y && my < gi->y + gi->height)
108 static void default_callback_info(void *ptr)
113 static void default_callback_action(void *ptr)
118 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
120 int state = (pressed ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
121 struct GadgetDesign *gd = (!gi->active ? &gi->alt_design[state] :
122 gi->checked ? &gi->alt_design[state] :
124 boolean redraw_selectbox = FALSE;
128 case GD_TYPE_NORMAL_BUTTON:
129 case GD_TYPE_CHECK_BUTTON:
130 case GD_TYPE_RADIO_BUTTON:
131 BlitBitmapOnBackground(gd->bitmap, drawto,
132 gd->x, gd->y, gi->width, gi->height,
134 if (gi->deco.design.bitmap)
135 BlitBitmap(gi->deco.design.bitmap, drawto,
136 gi->deco.design.x, gi->deco.design.y,
137 gi->deco.width, gi->deco.height,
138 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
139 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
142 case GD_TYPE_TEXT_BUTTON:
145 int font_nr = (gi->active ? gi->font_active : gi->font);
146 int font_width = getFontWidth(font_nr);
147 int border_x = gi->border.xsize;
148 int border_y = gi->border.ysize;
149 int text_size = strlen(gi->textbutton.value);
150 int text_start = (gi->width - text_size * font_width) / 2;
152 /* left part of gadget */
153 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
154 border_x, gi->height, gi->x, gi->y);
156 /* middle part of gadget */
157 for (i=0; i < gi->textbutton.size; i++)
158 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
159 font_width, gi->height,
160 gi->x + border_x + i * font_width, gi->y);
162 /* right part of gadget */
163 BlitBitmapOnBackground(gd->bitmap, drawto,
164 gd->x + gi->border.width - border_x, gd->y,
165 border_x, gi->height,
166 gi->x + gi->width - border_x, gi->y);
168 /* gadget text value */
170 gi->x + text_start + (pressed ? gi->deco.xshift : 0),
171 gi->y + border_y + (pressed ? gi->deco.yshift : 0),
172 gi->textbutton.value, font_nr, BLIT_MASKED);
176 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
177 case GD_TYPE_TEXTINPUT_NUMERIC:
181 char cursor_string[2];
182 char text[MAX_GADGET_TEXTSIZE + 1];
183 int font_nr = (pressed ? gi->font_active : gi->font);
184 int font_width = getFontWidth(font_nr);
185 int border_x = gi->border.xsize;
186 int border_y = gi->border.ysize;
188 /* left part of gadget */
189 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
190 border_x, gi->height, gi->x, gi->y);
192 /* middle part of gadget */
193 for (i=0; i < gi->text.size + 1; i++)
194 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
195 font_width, gi->height,
196 gi->x + border_x + i * font_width, gi->y);
198 /* right part of gadget */
199 BlitBitmapOnBackground(gd->bitmap, drawto,
200 gd->x + gi->border.width - border_x, gd->y,
201 border_x, gi->height,
202 gi->x + gi->width - border_x, gi->y);
205 strcpy(text, gi->text.value);
208 /* gadget text value */
210 gi->x + border_x, gi->y + border_y, text,
211 font_nr, BLIT_MASKED);
213 cursor_letter = gi->text.value[gi->text.cursor_position];
214 cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
215 cursor_string[1] = '\0';
217 /* draw cursor, if active */
220 gi->x + border_x + gi->text.cursor_position * font_width,
221 gi->y + border_y, cursor_string,
222 font_nr, BLIT_INVERSE);
226 case GD_TYPE_SELECTBOX:
229 char text[MAX_GADGET_TEXTSIZE + 1];
230 int font_nr = (pressed ? gi->font_active : gi->font);
231 int font_width = getFontWidth(font_nr);
232 int font_height = getFontHeight(font_nr);
233 int border_x = gi->border.xsize;
234 int border_y = gi->border.ysize;
235 int button = gi->border.xsize_selectbutton;
236 int width_inner = gi->border.width - button - 2 * border_x;
237 int box_width = gi->selectbox.width;
238 int box_height = gi->selectbox.height;
240 /* left part of gadget */
241 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
242 border_x, gi->height, gi->x, gi->y);
244 /* middle part of gadget */
245 for (i=0; i < gi->selectbox.size; i++)
246 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
247 font_width, gi->height,
248 gi->x + border_x + i * font_width, gi->y);
250 /* button part of gadget */
251 BlitBitmapOnBackground(gd->bitmap, drawto,
252 gd->x + border_x + width_inner, gd->y,
254 gi->x + gi->width - border_x - button, gi->y);
256 /* right part of gadget */
257 BlitBitmapOnBackground(gd->bitmap, drawto,
258 gd->x + gi->border.width - border_x, gd->y,
259 border_x, gi->height,
260 gi->x + gi->width - border_x, gi->y);
263 strncpy(text, gi->selectbox.options[gi->selectbox.index].text,
265 text[gi->selectbox.size] = '\0';
267 /* gadget text value */
268 DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text,
269 font_nr, BLIT_MASKED);
273 if (!gi->selectbox.open)
275 gi->selectbox.open = TRUE;
276 gi->selectbox.stay_open = FALSE;
277 gi->selectbox.current_index = gi->selectbox.index;
279 /* save background under selectbox */
280 BlitBitmap(drawto, gfx.field_save_buffer,
281 gi->selectbox.x, gi->selectbox.y,
282 gi->selectbox.width, gi->selectbox.height,
283 gi->selectbox.x, gi->selectbox.y);
286 /* draw open selectbox */
288 /* top left part of gadget border */
289 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
291 gi->selectbox.x, gi->selectbox.y);
293 /* top middle part of gadget border */
294 for (i=0; i < gi->selectbox.size; i++)
295 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
296 font_width, border_y,
297 gi->selectbox.x + border_x + i * font_width,
300 /* top button part of gadget border */
301 BlitBitmapOnBackground(gd->bitmap, drawto,
302 gd->x + border_x + width_inner, gd->y,
304 gi->selectbox.x + box_width -border_x -button,
307 /* top right part of gadget border */
308 BlitBitmapOnBackground(gd->bitmap, drawto,
309 gd->x + gi->border.width - border_x, gd->y,
311 gi->selectbox.x + box_width - border_x,
314 /* left and right part of gadget border for each row */
315 for (i=0; i < gi->selectbox.num_values; i++)
317 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y,
318 border_x, font_height,
320 gi->selectbox.y + border_y + i*font_height);
321 BlitBitmapOnBackground(gd->bitmap, drawto,
322 gd->x + gi->border.width - border_x,
324 border_x, font_height,
325 gi->selectbox.x + box_width - border_x,
326 gi->selectbox.y + border_y + i*font_height);
329 /* bottom left part of gadget border */
330 BlitBitmapOnBackground(gd->bitmap, drawto,
331 gd->x, gd->y + gi->height - border_y,
334 gi->selectbox.y + box_height - border_y);
336 /* bottom middle part of gadget border */
337 for (i=0; i < gi->selectbox.size; i++)
338 BlitBitmapOnBackground(gd->bitmap, drawto,
340 gd->y + gi->height - border_y,
341 font_width, border_y,
342 gi->selectbox.x + border_x + i * font_width,
343 gi->selectbox.y + box_height - border_y);
345 /* bottom button part of gadget border */
346 BlitBitmapOnBackground(gd->bitmap, drawto,
347 gd->x + border_x + width_inner,
348 gd->y + gi->height - border_y,
350 gi->selectbox.x + box_width -border_x -button,
351 gi->selectbox.y + box_height - border_y);
353 /* bottom right part of gadget border */
354 BlitBitmapOnBackground(gd->bitmap, drawto,
355 gd->x + gi->border.width - border_x,
356 gd->y + gi->height - border_y,
358 gi->selectbox.x + box_width - border_x,
359 gi->selectbox.y + box_height - border_y);
361 ClearRectangleOnBackground(drawto,
362 gi->selectbox.x + border_x,
363 gi->selectbox.y + border_y,
364 gi->selectbox.width - 2 * border_x,
365 gi->selectbox.height - 2 * border_y);
367 /* selectbox text values */
368 for (i=0; i < gi->selectbox.num_values; i++)
372 if (i == gi->selectbox.current_index)
374 FillRectangle(drawto,
375 gi->selectbox.x + border_x,
376 gi->selectbox.y + border_y + i * font_height,
377 gi->selectbox.width - 2 * border_x, font_height,
378 gi->selectbox.inverse_color);
380 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
381 text[1 + gi->selectbox.size] = '\0';
383 mask_mode = BLIT_INVERSE;
387 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
388 text[gi->selectbox.size] = '\0';
390 mask_mode = BLIT_MASKED;
394 gi->selectbox.x + border_x,
395 gi->selectbox.y + border_y + i * font_height, text,
399 redraw_selectbox = TRUE;
401 else if (gi->selectbox.open)
403 gi->selectbox.open = FALSE;
405 /* redraw closed selectbox */
406 DrawGadget(gi, FALSE, FALSE);
408 /* restore background under selectbox */
409 BlitBitmap(gfx.field_save_buffer, drawto,
410 gi->selectbox.x, gi->selectbox.y,
411 gi->selectbox.width, gi->selectbox.height,
412 gi->selectbox.x, gi->selectbox.y);
414 redraw_selectbox = TRUE;
419 case GD_TYPE_SCROLLBAR_VERTICAL:
423 int ypos = gi->y + gi->scrollbar.position;
424 int design_full = gi->width;
425 int design_body = design_full - 2 * gi->border.ysize;
426 int size_full = gi->scrollbar.size;
427 int size_body = size_full - 2 * gi->border.ysize;
428 int num_steps = size_body / design_body;
429 int step_size_remain = size_body - num_steps * design_body;
431 /* clear scrollbar area */
432 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
433 gi->width, gi->height);
435 /* upper part of gadget */
436 BlitBitmapOnBackground(gd->bitmap, drawto,
438 gi->width, gi->border.ysize,
441 /* middle part of gadget */
442 for (i=0; i<num_steps; i++)
443 BlitBitmapOnBackground(gd->bitmap, drawto,
444 gd->x, gd->y + gi->border.ysize,
445 gi->width, design_body,
447 ypos + gi->border.ysize + i * design_body);
449 /* remaining middle part of gadget */
450 if (step_size_remain > 0)
451 BlitBitmapOnBackground(gd->bitmap, drawto,
452 gd->x, gd->y + gi->border.ysize,
453 gi->width, step_size_remain,
455 ypos + gi->border.ysize
456 + num_steps * design_body);
458 /* lower part of gadget */
459 BlitBitmapOnBackground(gd->bitmap, drawto,
460 gd->x, gd->y + design_full - gi->border.ysize,
461 gi->width, gi->border.ysize,
462 xpos, ypos + size_full - gi->border.ysize);
466 case GD_TYPE_SCROLLBAR_HORIZONTAL:
469 int xpos = gi->x + gi->scrollbar.position;
471 int design_full = gi->height;
472 int design_body = design_full - 2 * gi->border.xsize;
473 int size_full = gi->scrollbar.size;
474 int size_body = size_full - 2 * gi->border.xsize;
475 int num_steps = size_body / design_body;
476 int step_size_remain = size_body - num_steps * design_body;
478 /* clear scrollbar area */
479 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
480 gi->width, gi->height);
482 /* left part of gadget */
483 BlitBitmapOnBackground(gd->bitmap, drawto,
485 gi->border.xsize, gi->height,
488 /* middle part of gadget */
489 for (i=0; i<num_steps; i++)
490 BlitBitmapOnBackground(gd->bitmap, drawto,
491 gd->x + gi->border.xsize, gd->y,
492 design_body, gi->height,
493 xpos + gi->border.xsize + i * design_body,
496 /* remaining middle part of gadget */
497 if (step_size_remain > 0)
498 BlitBitmapOnBackground(gd->bitmap, drawto,
499 gd->x + gi->border.xsize, gd->y,
500 step_size_remain, gi->height,
501 xpos + gi->border.xsize
502 + num_steps * design_body,
505 /* right part of gadget */
506 BlitBitmapOnBackground(gd->bitmap, drawto,
507 gd->x + design_full - gi->border.xsize, gd->y,
508 gi->border.xsize, gi->height,
509 xpos + size_full - gi->border.xsize, ypos);
519 BlitBitmap(drawto, window,
520 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
522 if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
523 BlitBitmap(drawto, window,
524 gi->selectbox.x, gi->selectbox.y,
525 gi->selectbox.width, gi->selectbox.height,
526 gi->selectbox.x, gi->selectbox.y);
529 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
530 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
531 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
534 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
538 while (tag != GDI_END)
543 gi->custom_id = va_arg(ap, int);
546 case GDI_CUSTOM_TYPE_ID:
547 gi->custom_type_id = va_arg(ap, int);
552 int max_textsize = MAX_INFO_TEXTSIZE - 1;
553 char *text = va_arg(ap, char *);
556 strncpy(gi->info_text, text, max_textsize);
560 gi->info_text[max_textsize] = '\0';
565 gi->x = va_arg(ap, int);
569 gi->y = va_arg(ap, int);
573 gi->width = va_arg(ap, int);
577 gi->height = va_arg(ap, int);
581 gi->type = va_arg(ap, unsigned long);
585 gi->state = va_arg(ap, unsigned long);
589 /* take care here: "boolean" is typedef'ed as "unsigned char",
590 which gets promoted to "int" */
591 gi->active = (boolean)va_arg(ap, int);
594 case GDI_DIRECT_DRAW:
595 /* take care here: "boolean" is typedef'ed as "unsigned char",
596 which gets promoted to "int" */
597 gi->direct_draw = (boolean)va_arg(ap, int);
601 /* take care here: "boolean" is typedef'ed as "unsigned char",
602 which gets promoted to "int" */
603 gi->checked = (boolean)va_arg(ap, int);
607 gi->radio_nr = va_arg(ap, unsigned long);
610 case GDI_NUMBER_VALUE:
611 gi->text.number_value = va_arg(ap, long);
612 sprintf(gi->text.value, "%d", gi->text.number_value);
613 gi->text.cursor_position = strlen(gi->text.value);
617 gi->text.number_min = va_arg(ap, long);
618 if (gi->text.number_value < gi->text.number_min)
620 gi->text.number_value = gi->text.number_min;
621 sprintf(gi->text.value, "%d", gi->text.number_value);
626 gi->text.number_max = va_arg(ap, long);
627 if (gi->text.number_value > gi->text.number_max)
629 gi->text.number_value = gi->text.number_max;
630 sprintf(gi->text.value, "%d", gi->text.number_value);
636 int max_textsize = MAX_GADGET_TEXTSIZE;
639 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
641 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
642 gi->text.value[max_textsize] = '\0';
643 gi->text.cursor_position = strlen(gi->text.value);
645 /* same tag also used for textbutton definition */
646 strcpy(gi->textbutton.value, gi->text.value);
652 int tag_value = va_arg(ap, int);
653 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
655 gi->text.size = max_textsize;
656 gi->text.value[max_textsize] = '\0';
658 /* same tag also used for textbutton and selectbox definition */
659 strcpy(gi->textbutton.value, gi->text.value);
660 gi->textbutton.size = gi->text.size;
661 gi->selectbox.size = gi->text.size;
666 gi->font = va_arg(ap, int);
667 if (gi->font_active == 0)
668 gi->font_active = gi->font;
671 case GDI_TEXT_FONT_ACTIVE:
672 gi->font_active = va_arg(ap, int);
675 case GDI_SELECTBOX_OPTIONS:
676 gi->selectbox.options = va_arg(ap, struct ValueTextInfo *);
679 case GDI_SELECTBOX_INDEX:
680 gi->selectbox.index = va_arg(ap, int);
683 case GDI_DESIGN_UNPRESSED:
684 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
685 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
686 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
689 case GDI_DESIGN_PRESSED:
690 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
691 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
692 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
695 case GDI_ALT_DESIGN_UNPRESSED:
696 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
697 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
698 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
701 case GDI_ALT_DESIGN_PRESSED:
702 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
703 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
704 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
707 case GDI_BORDER_SIZE:
708 gi->border.xsize = va_arg(ap, int);
709 gi->border.ysize = va_arg(ap, int);
712 case GDI_BORDER_SIZE_SELECTBUTTON:
713 gi->border.xsize_selectbutton = va_arg(ap, int);
716 case GDI_DESIGN_WIDTH:
717 gi->border.width = va_arg(ap, int);
720 case GDI_DECORATION_DESIGN:
721 gi->deco.design.bitmap = va_arg(ap, Bitmap *);
722 gi->deco.design.x = va_arg(ap, int);
723 gi->deco.design.y = va_arg(ap, int);
726 case GDI_DECORATION_POSITION:
727 gi->deco.x = va_arg(ap, int);
728 gi->deco.y = va_arg(ap, int);
731 case GDI_DECORATION_SIZE:
732 gi->deco.width = va_arg(ap, int);
733 gi->deco.height = va_arg(ap, int);
736 case GDI_DECORATION_SHIFTING:
737 gi->deco.xshift = va_arg(ap, int);
738 gi->deco.yshift = va_arg(ap, int);
742 gi->event_mask = va_arg(ap, unsigned long);
746 gi->drawing.area_xsize = va_arg(ap, int);
747 gi->drawing.area_ysize = va_arg(ap, int);
749 /* determine dependent values for drawing area gadget, if needed */
750 if (gi->width == 0 && gi->height == 0 &&
751 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
753 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
754 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
756 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
757 gi->width != 0 && gi->height != 0)
759 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
760 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
765 gi->drawing.item_xsize = va_arg(ap, int);
766 gi->drawing.item_ysize = va_arg(ap, int);
768 /* determine dependent values for drawing area gadget, if needed */
769 if (gi->width == 0 && gi->height == 0 &&
770 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
772 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
773 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
775 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
776 gi->width != 0 && gi->height != 0)
778 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
779 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
783 case GDI_SCROLLBAR_ITEMS_MAX:
784 gi->scrollbar.items_max = va_arg(ap, int);
787 case GDI_SCROLLBAR_ITEMS_VISIBLE:
788 gi->scrollbar.items_visible = va_arg(ap, int);
791 case GDI_SCROLLBAR_ITEM_POSITION:
792 gi->scrollbar.item_position = va_arg(ap, int);
795 case GDI_CALLBACK_INFO:
796 gi->callback_info = va_arg(ap, gadget_function);
799 case GDI_CALLBACK_ACTION:
800 gi->callback_action = va_arg(ap, gadget_function);
804 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
807 tag = va_arg(ap, int); /* read next tag */
810 /* check if gadget is complete */
811 if (gi->type != GD_TYPE_DRAWING_AREA &&
812 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
813 !gi->design[GD_BUTTON_PRESSED].bitmap))
814 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
816 /* adjust gadget values in relation to other gadget values */
818 if (gi->type & GD_TYPE_TEXTINPUT)
820 int font_nr = gi->font_active;
821 int font_width = getFontWidth(font_nr);
822 int font_height = getFontHeight(font_nr);
823 int border_xsize = gi->border.xsize;
824 int border_ysize = gi->border.ysize;
826 gi->width = 2 * border_xsize + (gi->text.size + 1) * font_width;
827 gi->height = 2 * border_ysize + font_height;
830 if (gi->type & GD_TYPE_SELECTBOX)
832 int font_nr = gi->font_active;
833 int font_width = getFontWidth(font_nr);
834 int font_height = getFontHeight(font_nr);
835 int border_xsize = gi->border.xsize;
836 int border_ysize = gi->border.ysize;
837 int button_size = gi->border.xsize_selectbutton;
838 int bottom_screen_border = gfx.sy + gfx.sysize - font_height;
842 gi->width = 2 * border_xsize + gi->text.size * font_width + button_size;
843 gi->height = 2 * border_ysize + font_height;
845 if (gi->selectbox.options == NULL)
846 Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)");
848 gi->selectbox.num_values = 0;
849 while (gi->selectbox.options[gi->selectbox.num_values].text != NULL)
850 gi->selectbox.num_values++;
852 /* calculate values for open selectbox */
853 gi->selectbox.width = gi->width;
854 gi->selectbox.height =
855 2 * border_ysize + gi->selectbox.num_values * font_height;
857 gi->selectbox.x = gi->x;
858 gi->selectbox.y = gi->y + gi->height;
859 if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border)
860 gi->selectbox.y = gi->y - gi->selectbox.height;
861 if (gi->selectbox.y < 0)
862 gi->selectbox.y = bottom_screen_border - gi->selectbox.height;
864 getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y);
865 src_x += font_width / 2;
866 src_y += font_height / 2;
867 gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y);
869 /* always start with closed selectbox */
870 gi->selectbox.open = FALSE;
873 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
875 struct GadgetTextInput *text = &gi->text;
876 int value = text->number_value;
878 text->number_value = (value < text->number_min ? text->number_min :
879 value > text->number_max ? text->number_max :
882 sprintf(text->value, "%d", text->number_value);
885 if (gi->type & GD_TYPE_TEXT_BUTTON)
887 int font_nr = gi->font_active;
888 int font_width = getFontWidth(font_nr);
889 int font_height = getFontHeight(font_nr);
890 int border_xsize = gi->border.xsize;
891 int border_ysize = gi->border.ysize;
893 gi->width = 2 * border_xsize + gi->textbutton.size * font_width;
894 gi->height = 2 * border_ysize + font_height;
897 if (gi->type & GD_TYPE_SCROLLBAR)
899 struct GadgetScrollbar *gs = &gi->scrollbar;
901 if (gi->width == 0 || gi->height == 0 ||
902 gs->items_max == 0 || gs->items_visible == 0)
903 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
905 /* calculate internal scrollbar values */
906 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
907 gi->height : gi->width);
908 gs->size = gs->size_max * gs->items_visible / gs->items_max;
909 gs->position = gs->size_max * gs->item_position / gs->items_max;
910 gs->position_max = gs->size_max - gs->size;
911 gs->correction = gs->size_max / gs->items_max / 2;
913 /* finetuning for maximal right/bottom position */
914 if (gs->item_position == gs->items_max - gs->items_visible)
915 gs->position = gs->position_max;
919 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
923 va_start(ap, first_tag);
924 HandleGadgetTags(gi, first_tag, ap);
930 void RedrawGadget(struct GadgetInfo *gi)
933 DrawGadget(gi, gi->state, gi->direct_draw);
936 struct GadgetInfo *CreateGadget(int first_tag, ...)
938 struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
941 /* always start with reliable default values */
942 new_gadget->id = getNewGadgetID();
943 new_gadget->callback_info = default_callback_info;
944 new_gadget->callback_action = default_callback_action;
945 new_gadget->active = TRUE;
946 new_gadget->direct_draw = TRUE;
948 new_gadget->next = NULL;
950 va_start(ap, first_tag);
951 HandleGadgetTags(new_gadget, first_tag, ap);
954 /* insert new gadget into global gadget list */
955 if (gadget_list_last_entry)
957 gadget_list_last_entry->next = new_gadget;
958 gadget_list_last_entry = gadget_list_last_entry->next;
961 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
966 void FreeGadget(struct GadgetInfo *gi)
968 struct GadgetInfo *gi_previous = gadget_list_first_entry;
970 while (gi_previous != NULL && gi_previous->next != gi)
971 gi_previous = gi_previous->next;
973 if (gi == gadget_list_first_entry)
974 gadget_list_first_entry = gi->next;
976 if (gi == gadget_list_last_entry)
977 gadget_list_last_entry = gi_previous;
979 if (gi_previous != NULL)
980 gi_previous->next = gi->next;
985 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
987 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
990 gi->text.number_value = atoi(gi->text.value);
992 if (gi->text.number_value < gi->text.number_min)
993 gi->text.number_value = gi->text.number_min;
994 if (gi->text.number_value > gi->text.number_max)
995 gi->text.number_value = gi->text.number_max;
997 sprintf(gi->text.value, "%d", gi->text.number_value);
999 if (gi->text.cursor_position < 0)
1000 gi->text.cursor_position = 0;
1001 else if (gi->text.cursor_position > strlen(gi->text.value))
1002 gi->text.cursor_position = strlen(gi->text.value);
1005 /* global pointer to gadget actually in use (when mouse button pressed) */
1006 static struct GadgetInfo *last_gi = NULL;
1008 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
1010 if (gi == NULL || gi->mapped)
1016 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
1019 void MapGadget(struct GadgetInfo *gi)
1021 MapGadgetExt(gi, TRUE);
1024 void UnmapGadget(struct GadgetInfo *gi)
1026 if (gi == NULL || !gi->mapped)
1035 #define MAX_NUM_GADGETS 1024
1036 #define MULTIMAP_UNMAP (1 << 0)
1037 #define MULTIMAP_REMAP (1 << 1)
1038 #define MULTIMAP_REDRAW (1 << 2)
1039 #define MULTIMAP_PLAYFIELD (1 << 3)
1040 #define MULTIMAP_DOOR_1 (1 << 4)
1041 #define MULTIMAP_DOOR_2 (1 << 5)
1042 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
1046 static void MultiMapGadgets(int mode)
1048 struct GadgetInfo *gi = gadget_list_first_entry;
1049 static boolean map_state[MAX_NUM_GADGETS];
1054 if ((mode & MULTIMAP_PLAYFIELD &&
1055 gi->x < gfx.sx + gfx.sxsize) ||
1056 (mode & MULTIMAP_DOOR_1 &&
1057 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
1058 (mode & MULTIMAP_DOOR_2 &&
1059 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
1060 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
1062 if (mode & MULTIMAP_UNMAP)
1064 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
1069 if (map_state[map_count++ % MAX_NUM_GADGETS])
1070 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
1078 void UnmapAllGadgets()
1080 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
1083 void RemapAllGadgets()
1085 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
1088 boolean anyTextInputGadgetActive()
1090 return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
1093 boolean anySelectboxGadgetActive()
1095 return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
1098 boolean anyTextGadgetActive()
1100 return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
1103 void ClickOnGadget(struct GadgetInfo *gi, int button)
1105 /* simulate releasing mouse button over last gadget, if still pressed */
1107 HandleGadgets(-1, -1, 0);
1109 /* simulate pressing mouse button over specified gadget */
1110 HandleGadgets(gi->x, gi->y, button);
1112 /* simulate releasing mouse button over specified gadget */
1113 HandleGadgets(gi->x, gi->y, 0);
1116 void HandleGadgets(int mx, int my, int button)
1118 static struct GadgetInfo *last_info_gi = NULL;
1119 static unsigned long pressed_delay = 0;
1120 static int last_button = 0;
1121 static int last_mx = 0, last_my = 0;
1122 int scrollbar_mouse_pos = 0;
1123 struct GadgetInfo *new_gi, *gi;
1124 boolean press_event;
1125 boolean release_event;
1126 boolean mouse_moving;
1127 boolean gadget_pressed;
1128 boolean gadget_pressed_repeated;
1129 boolean gadget_moving;
1130 boolean gadget_moving_inside;
1131 boolean gadget_moving_off_borders;
1132 boolean gadget_released;
1133 boolean gadget_released_inside;
1134 boolean gadget_released_inside_select_line;
1135 boolean gadget_released_inside_select_area;
1136 boolean gadget_released_off_borders;
1137 boolean changed_position = FALSE;
1139 /* check if there are any gadgets defined */
1140 if (gadget_list_first_entry == NULL)
1143 /* simulated release of mouse button over last gadget */
1144 if (mx == -1 && my == -1 && button == 0)
1150 /* check which gadget is under the mouse pointer */
1151 new_gi = getGadgetInfoFromMousePosition(mx, my);
1153 /* check if button state has changed since last invocation */
1154 press_event = (button != 0 && last_button == 0);
1155 release_event = (button == 0 && last_button != 0);
1156 last_button = button;
1158 /* check if mouse has been moved since last invocation */
1159 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
1163 /* special treatment for text and number input gadgets */
1164 if (anyTextInputGadgetActive() && button != 0 && !motion_status)
1166 struct GadgetInfo *gi = last_gi;
1168 if (new_gi == last_gi)
1170 int old_cursor_position = gi->text.cursor_position;
1172 /* if mouse button pressed inside activated text gadget, set cursor */
1173 gi->text.cursor_position =
1174 (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
1176 if (gi->text.cursor_position < 0)
1177 gi->text.cursor_position = 0;
1178 else if (gi->text.cursor_position > strlen(gi->text.value))
1179 gi->text.cursor_position = strlen(gi->text.value);
1181 if (gi->text.cursor_position != old_cursor_position)
1182 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1186 /* if mouse button pressed outside text input gadget, deactivate it */
1187 CheckRangeOfNumericInputGadget(gi);
1188 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1190 gi->event.type = GD_EVENT_TEXT_LEAVING;
1192 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1193 gi->callback_action(gi);
1199 /* special treatment for selectbox gadgets */
1200 if (anySelectboxGadgetActive() && button != 0 && !motion_status)
1202 struct GadgetInfo *gi = last_gi;
1204 if (new_gi == last_gi)
1206 int old_index = gi->selectbox.current_index;
1208 /* if mouse button pressed inside activated selectbox, select value */
1209 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1210 gi->selectbox.current_index =
1211 (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
1213 if (gi->selectbox.current_index < 0)
1214 gi->selectbox.current_index = 0;
1215 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1216 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1218 if (gi->selectbox.current_index != old_index)
1219 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1223 /* if mouse button pressed outside selectbox gadget, deactivate it */
1224 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1226 gi->event.type = GD_EVENT_TEXT_LEAVING;
1228 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1229 gi->callback_action(gi);
1236 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
1237 gadget_pressed_repeated =
1238 (button != 0 && last_gi != NULL && new_gi == last_gi);
1240 gadget_released = (release_event && last_gi != NULL);
1241 gadget_released_inside = (gadget_released && new_gi == last_gi);
1242 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
1244 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
1245 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
1246 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
1248 /* when handling selectbox, set additional state values */
1249 if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
1251 struct GadgetInfo *gi = last_gi;
1253 gadget_released_inside_select_line =
1254 (mx >= gi->x && mx < gi->x + gi->width &&
1255 my >= gi->y && my < gi->y + gi->height);
1256 gadget_released_inside_select_area =
1257 (mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
1258 my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height);
1262 gadget_released_inside_select_line = FALSE;
1263 gadget_released_inside_select_area = FALSE;
1266 /* if new gadget pressed, store this gadget */
1270 /* 'gi' is actually handled gadget */
1273 /* if gadget is scrollbar, choose mouse position value */
1274 if (gi && gi->type & GD_TYPE_SCROLLBAR)
1275 scrollbar_mouse_pos =
1276 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
1278 /* if mouse button released, no gadget needs to be handled anymore */
1279 if (gadget_released)
1281 if ((last_gi->type & GD_TYPE_SELECTBOX) &&
1282 (gadget_released_inside_select_line ||
1283 gadget_released_off_borders)) /* selectbox stays open */
1284 gi->selectbox.stay_open = TRUE;
1285 else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1289 /* modify event position values even if no gadget is pressed */
1290 if (button == 0 && !release_event)
1295 int last_x = gi->event.x;
1296 int last_y = gi->event.y;
1298 gi->event.x = mx - gi->x;
1299 gi->event.y = my - gi->y;
1301 if (gi->type == GD_TYPE_DRAWING_AREA)
1303 gi->event.x /= gi->drawing.item_xsize;
1304 gi->event.y /= gi->drawing.item_ysize;
1306 if (last_x != gi->event.x || last_y != gi->event.y)
1307 changed_position = TRUE;
1309 else if (gi->type & GD_TYPE_SELECTBOX)
1311 int old_index = gi->selectbox.current_index;
1313 /* if mouse moving inside activated selectbox, select value */
1314 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1315 gi->selectbox.current_index =
1316 (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
1318 if (gi->selectbox.current_index < 0)
1319 gi->selectbox.current_index = 0;
1320 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1321 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1323 if (gi->selectbox.current_index != old_index)
1324 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1328 /* handle gadget popup info text */
1329 if (last_info_gi != new_gi ||
1330 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
1332 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
1334 new_gi->event.type = GD_EVENT_INFO_ENTERING;
1335 new_gi->callback_info(new_gi);
1337 else if (last_info_gi != NULL)
1339 last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
1340 last_info_gi->callback_info(last_info_gi);
1343 default_callback_info(NULL);
1345 printf("It seems that we are leaving gadget [%s]!\n",
1346 (last_info_gi != NULL &&
1347 last_info_gi->info_text != NULL ?
1348 last_info_gi->info_text : ""));
1352 last_info_gi = new_gi;
1357 if (gi->type == GD_TYPE_CHECK_BUTTON)
1359 gi->checked = !gi->checked;
1361 else if (gi->type == GD_TYPE_RADIO_BUTTON)
1363 struct GadgetInfo *rgi = gadget_list_first_entry;
1368 rgi->type == GD_TYPE_RADIO_BUTTON &&
1369 rgi->radio_nr == gi->radio_nr &&
1372 rgi->checked = FALSE;
1373 DrawGadget(rgi, DG_UNPRESSED, rgi->direct_draw);
1381 else if (gi->type & GD_TYPE_SCROLLBAR)
1385 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1396 if (mpos >= gpos + gi->scrollbar.position &&
1397 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1399 /* drag scrollbar */
1400 gi->scrollbar.drag_position =
1401 scrollbar_mouse_pos - gi->scrollbar.position;
1405 /* click scrollbar one scrollbar length up/left or down/right */
1407 struct GadgetScrollbar *gs = &gi->scrollbar;
1408 int old_item_position = gs->item_position;
1410 changed_position = FALSE;
1412 gs->item_position +=
1413 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
1415 if (gs->item_position < 0)
1416 gs->item_position = 0;
1417 if (gs->item_position > gs->items_max - gs->items_visible)
1418 gs->item_position = gs->items_max - gs->items_visible;
1420 if (old_item_position != gs->item_position)
1422 gi->event.item_position = gs->item_position;
1423 changed_position = TRUE;
1426 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
1429 gi->state = GD_BUTTON_UNPRESSED;
1430 gi->event.type = GD_EVENT_MOVING;
1431 gi->event.off_borders = FALSE;
1433 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
1434 gi->callback_action(gi);
1436 /* don't handle this scrollbar anymore while mouse button pressed */
1443 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1445 gi->state = GD_BUTTON_PRESSED;
1446 gi->event.type = GD_EVENT_PRESSED;
1447 gi->event.button = button;
1448 gi->event.off_borders = FALSE;
1450 /* initialize delay counter */
1451 DelayReached(&pressed_delay, 0);
1453 if (gi->event_mask & GD_EVENT_PRESSED)
1454 gi->callback_action(gi);
1457 if (gadget_pressed_repeated)
1459 gi->event.type = GD_EVENT_PRESSED;
1461 if (gi->event_mask & GD_EVENT_REPEATED &&
1462 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1463 gi->callback_action(gi);
1468 if (gi->type & GD_TYPE_BUTTON)
1470 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
1471 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1472 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
1473 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1475 else if (gi->type & GD_TYPE_SELECTBOX)
1477 int old_index = gi->selectbox.current_index;
1479 /* if mouse moving inside activated selectbox, select value */
1480 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1481 gi->selectbox.current_index =
1482 (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
1484 if (gi->selectbox.current_index < 0)
1485 gi->selectbox.current_index = 0;
1486 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1487 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1489 if (gi->selectbox.current_index != old_index)
1490 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1492 else if (gi->type & GD_TYPE_SCROLLBAR)
1494 struct GadgetScrollbar *gs = &gi->scrollbar;
1495 int old_item_position = gs->item_position;
1497 gs->position = scrollbar_mouse_pos - gs->drag_position;
1499 if (gs->position < 0)
1501 if (gs->position > gs->position_max)
1502 gs->position = gs->position_max;
1505 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1507 if (gs->item_position < 0)
1508 gs->item_position = 0;
1509 if (gs->item_position > gs->items_max - 1)
1510 gs->item_position = gs->items_max - 1;
1512 if (old_item_position != gs->item_position)
1514 gi->event.item_position = gs->item_position;
1515 changed_position = TRUE;
1518 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1521 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1522 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1523 gi->event.type = GD_EVENT_MOVING;
1524 gi->event.off_borders = gadget_moving_off_borders;
1526 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1527 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1528 gi->callback_action(gi);
1531 if (gadget_released_inside)
1533 boolean deactivate_gadget = TRUE;
1535 if (gi->type & GD_TYPE_SELECTBOX)
1537 if (gadget_released_inside_select_line ||
1538 gadget_released_off_borders) /* selectbox stays open */
1539 deactivate_gadget = FALSE;
1541 gi->selectbox.index = gi->selectbox.current_index;
1544 if (deactivate_gadget &&
1545 !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1546 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1548 gi->state = GD_BUTTON_UNPRESSED;
1549 gi->event.type = GD_EVENT_RELEASED;
1551 if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
1552 gi->callback_action(gi);
1555 if (gadget_released_off_borders)
1557 if (gi->type & GD_TYPE_SCROLLBAR)
1558 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1560 gi->event.type = GD_EVENT_RELEASED;
1562 if (gi->event_mask & GD_EVENT_RELEASED &&
1563 gi->event_mask & GD_EVENT_OFF_BORDERS)
1564 gi->callback_action(gi);
1567 /* handle gadgets unmapped/mapped between pressing and releasing */
1568 if (release_event && !gadget_released && new_gi)
1569 new_gi->state = GD_BUTTON_UNPRESSED;
1572 void HandleGadgetsKeyInput(Key key)
1574 struct GadgetInfo *gi = last_gi;
1576 if (gi == NULL || !gi->mapped ||
1577 !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
1580 if (key == KSYM_Return) /* valid for both text input and selectbox */
1582 if (gi->type & GD_TYPE_TEXTINPUT)
1583 CheckRangeOfNumericInputGadget(gi);
1584 else if (gi->type & GD_TYPE_SELECTBOX)
1585 gi->selectbox.index = gi->selectbox.current_index;
1587 DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
1589 gi->event.type = GD_EVENT_TEXT_RETURN;
1591 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1592 gi->callback_action(gi);
1596 else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */
1598 char text[MAX_GADGET_TEXTSIZE];
1599 int text_length = strlen(gi->text.value);
1600 int cursor_pos = gi->text.cursor_position;
1601 char letter = getCharFromKey(key);
1602 boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1603 letter >= '0' && letter <= '9' :
1606 if (legal_letter && text_length < gi->text.size)
1608 strcpy(text, gi->text.value);
1609 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1610 gi->text.value[cursor_pos] = letter;
1611 gi->text.cursor_position++;
1613 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1615 else if (key == KSYM_Left && cursor_pos > 0)
1617 gi->text.cursor_position--;
1618 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1620 else if (key == KSYM_Right && cursor_pos < text_length)
1622 gi->text.cursor_position++;
1623 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1625 else if (key == KSYM_BackSpace && cursor_pos > 0)
1627 strcpy(text, gi->text.value);
1628 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1629 gi->text.cursor_position--;
1630 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1632 else if (key == KSYM_Delete && cursor_pos < text_length)
1634 strcpy(text, gi->text.value);
1635 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1636 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1639 else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
1641 int index = gi->selectbox.current_index;
1642 int num_values = gi->selectbox.num_values;
1644 if (key == KSYM_Up && index > 0)
1646 gi->selectbox.current_index--;
1647 DrawGadget(gi, DG_PRESSED, gi->direct_draw);
1649 else if (key == KSYM_Down && index < num_values - 1)
1651 gi->selectbox.current_index++;
1652 DrawGadget(gi, DG_PRESSED, gi->direct_draw);