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;
85 /* open selectboxes may overlap other active gadgets, so check them first */
86 for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
88 if (gi->mapped && gi->active &&
89 gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
90 mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
91 my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
95 /* check all other gadgets */
96 for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
98 if (gi->mapped && gi->active &&
99 mx >= gi->x && mx < gi->x + gi->width &&
100 my >= gi->y && my < gi->y + gi->height)
107 static void default_callback_info(void *ptr)
112 static void default_callback_action(void *ptr)
117 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
119 int state = (pressed ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
120 struct GadgetDesign *gd = (!gi->active ? &gi->alt_design[state] :
121 gi->checked ? &gi->alt_design[state] :
123 boolean redraw_selectbox = FALSE;
127 case GD_TYPE_NORMAL_BUTTON:
128 case GD_TYPE_CHECK_BUTTON:
129 case GD_TYPE_RADIO_BUTTON:
130 BlitBitmapOnBackground(gd->bitmap, drawto,
131 gd->x, gd->y, gi->width, gi->height,
133 if (gi->deco.design.bitmap)
134 BlitBitmap(gi->deco.design.bitmap, drawto,
135 gi->deco.design.x, gi->deco.design.y,
136 gi->deco.width, gi->deco.height,
137 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
138 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
141 case GD_TYPE_TEXT_BUTTON:
144 int font_nr = (gi->active ? gi->font_active : gi->font);
145 int font_width = getFontWidth(font_nr);
146 int border_x = gi->border.xsize;
147 int border_y = gi->border.ysize;
148 int text_size = strlen(gi->textbutton.value);
149 int text_start = (gi->width - text_size * font_width) / 2;
151 /* left part of gadget */
152 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
153 border_x, gi->height, gi->x, gi->y);
155 /* middle part of gadget */
156 for (i=0; i < gi->textbutton.size; i++)
157 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
158 font_width, gi->height,
159 gi->x + border_x + i * font_width, gi->y);
161 /* right part of gadget */
162 BlitBitmapOnBackground(gd->bitmap, drawto,
163 gd->x + gi->border.width - border_x, gd->y,
164 border_x, gi->height,
165 gi->x + gi->width - border_x, gi->y);
167 /* gadget text value */
169 gi->x + text_start + (pressed ? gi->deco.xshift : 0),
170 gi->y + border_y + (pressed ? gi->deco.yshift : 0),
171 gi->textbutton.value, font_nr, BLIT_MASKED);
175 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
176 case GD_TYPE_TEXTINPUT_NUMERIC:
180 char cursor_string[2];
181 char text[MAX_GADGET_TEXTSIZE + 1];
182 int font_nr = (pressed ? gi->font_active : gi->font);
183 int font_width = getFontWidth(font_nr);
184 int border_x = gi->border.xsize;
185 int border_y = gi->border.ysize;
187 /* left part of gadget */
188 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
189 border_x, gi->height, gi->x, gi->y);
191 /* middle part of gadget */
192 for (i=0; i < gi->text.size + 1; i++)
193 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
194 font_width, gi->height,
195 gi->x + border_x + i * font_width, gi->y);
197 /* right part of gadget */
198 BlitBitmapOnBackground(gd->bitmap, drawto,
199 gd->x + gi->border.width - border_x, gd->y,
200 border_x, gi->height,
201 gi->x + gi->width - border_x, gi->y);
204 strcpy(text, gi->text.value);
207 /* gadget text value */
209 gi->x + border_x, gi->y + border_y, text,
210 font_nr, BLIT_MASKED);
212 cursor_letter = gi->text.value[gi->text.cursor_position];
213 cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
214 cursor_string[1] = '\0';
216 /* draw cursor, if active */
219 gi->x + border_x + gi->text.cursor_position * font_width,
220 gi->y + border_y, cursor_string,
221 font_nr, BLIT_INVERSE);
225 case GD_TYPE_SELECTBOX:
228 char text[MAX_GADGET_TEXTSIZE + 1];
229 int font_nr = (pressed ? gi->font_active : gi->font);
230 int font_width = getFontWidth(font_nr);
231 int font_height = getFontHeight(font_nr);
232 int border_x = gi->border.xsize;
233 int border_y = gi->border.ysize;
234 int button = gi->border.xsize_selectbutton;
235 int width_inner = gi->border.width - button - 2 * border_x;
236 int box_width = gi->selectbox.width;
237 int box_height = gi->selectbox.height;
239 /* left part of gadget */
240 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
241 border_x, gi->height, gi->x, gi->y);
243 /* middle part of gadget */
244 for (i=0; i < gi->selectbox.size; i++)
245 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
246 font_width, gi->height,
247 gi->x + border_x + i * font_width, gi->y);
249 /* button part of gadget */
250 BlitBitmapOnBackground(gd->bitmap, drawto,
251 gd->x + border_x + width_inner, gd->y,
253 gi->x + gi->width - border_x - button, gi->y);
255 /* right part of gadget */
256 BlitBitmapOnBackground(gd->bitmap, drawto,
257 gd->x + gi->border.width - border_x, gd->y,
258 border_x, gi->height,
259 gi->x + gi->width - border_x, gi->y);
262 strncpy(text, gi->selectbox.options[gi->selectbox.index].text,
264 text[gi->selectbox.size] = '\0';
266 /* gadget text value */
267 DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text,
268 font_nr, BLIT_MASKED);
272 if (!gi->selectbox.open)
274 gi->selectbox.open = TRUE;
275 gi->selectbox.stay_open = FALSE;
276 gi->selectbox.current_index = gi->selectbox.index;
278 /* save background under selectbox */
279 BlitBitmap(drawto, gfx.field_save_buffer,
280 gi->selectbox.x, gi->selectbox.y,
281 gi->selectbox.width, gi->selectbox.height,
282 gi->selectbox.x, gi->selectbox.y);
285 /* draw open selectbox */
287 /* top left part of gadget border */
288 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
290 gi->selectbox.x, gi->selectbox.y);
292 /* top middle part of gadget border */
293 for (i=0; i < gi->selectbox.size; i++)
294 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
295 font_width, border_y,
296 gi->selectbox.x + border_x + i * font_width,
299 /* top button part of gadget border */
300 BlitBitmapOnBackground(gd->bitmap, drawto,
301 gd->x + border_x + width_inner, gd->y,
303 gi->selectbox.x + box_width -border_x -button,
306 /* top right part of gadget border */
307 BlitBitmapOnBackground(gd->bitmap, drawto,
308 gd->x + gi->border.width - border_x, gd->y,
310 gi->selectbox.x + box_width - border_x,
313 /* left and right part of gadget border for each row */
314 for (i=0; i < gi->selectbox.num_values; i++)
316 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y,
317 border_x, font_height,
319 gi->selectbox.y + border_y + i*font_height);
320 BlitBitmapOnBackground(gd->bitmap, drawto,
321 gd->x + gi->border.width - border_x,
323 border_x, font_height,
324 gi->selectbox.x + box_width - border_x,
325 gi->selectbox.y + border_y + i*font_height);
328 /* bottom left part of gadget border */
329 BlitBitmapOnBackground(gd->bitmap, drawto,
330 gd->x, gd->y + gi->height - border_y,
333 gi->selectbox.y + box_height - border_y);
335 /* bottom middle part of gadget border */
336 for (i=0; i < gi->selectbox.size; i++)
337 BlitBitmapOnBackground(gd->bitmap, drawto,
339 gd->y + gi->height - border_y,
340 font_width, border_y,
341 gi->selectbox.x + border_x + i * font_width,
342 gi->selectbox.y + box_height - border_y);
344 /* bottom button part of gadget border */
345 BlitBitmapOnBackground(gd->bitmap, drawto,
346 gd->x + border_x + width_inner,
347 gd->y + gi->height - border_y,
349 gi->selectbox.x + box_width -border_x -button,
350 gi->selectbox.y + box_height - border_y);
352 /* bottom right part of gadget border */
353 BlitBitmapOnBackground(gd->bitmap, drawto,
354 gd->x + gi->border.width - border_x,
355 gd->y + gi->height - border_y,
357 gi->selectbox.x + box_width - border_x,
358 gi->selectbox.y + box_height - border_y);
360 ClearRectangleOnBackground(drawto,
361 gi->selectbox.x + border_x,
362 gi->selectbox.y + border_y,
363 gi->selectbox.width - 2 * border_x,
364 gi->selectbox.height - 2 * border_y);
366 /* selectbox text values */
367 for (i=0; i < gi->selectbox.num_values; i++)
371 if (i == gi->selectbox.current_index)
373 FillRectangle(drawto,
374 gi->selectbox.x + border_x,
375 gi->selectbox.y + border_y + i * font_height,
376 gi->selectbox.width - 2 * border_x, font_height,
377 gi->selectbox.inverse_color);
379 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
380 text[1 + gi->selectbox.size] = '\0';
382 mask_mode = BLIT_INVERSE;
386 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
387 text[gi->selectbox.size] = '\0';
389 mask_mode = BLIT_MASKED;
393 gi->selectbox.x + border_x,
394 gi->selectbox.y + border_y + i * font_height, text,
398 redraw_selectbox = TRUE;
400 else if (gi->selectbox.open)
402 gi->selectbox.open = FALSE;
404 /* redraw closed selectbox */
405 DrawGadget(gi, FALSE, FALSE);
407 /* restore background under selectbox */
408 BlitBitmap(gfx.field_save_buffer, drawto,
409 gi->selectbox.x, gi->selectbox.y,
410 gi->selectbox.width, gi->selectbox.height,
411 gi->selectbox.x, gi->selectbox.y);
413 redraw_selectbox = TRUE;
418 case GD_TYPE_SCROLLBAR_VERTICAL:
422 int ypos = gi->y + gi->scrollbar.position;
423 int design_full = gi->width;
424 int design_body = design_full - 2 * gi->border.ysize;
425 int size_full = gi->scrollbar.size;
426 int size_body = size_full - 2 * gi->border.ysize;
427 int num_steps = size_body / design_body;
428 int step_size_remain = size_body - num_steps * design_body;
430 /* clear scrollbar area */
431 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
432 gi->width, gi->height);
434 /* upper part of gadget */
435 BlitBitmapOnBackground(gd->bitmap, drawto,
437 gi->width, gi->border.ysize,
440 /* middle part of gadget */
441 for (i=0; i<num_steps; i++)
442 BlitBitmapOnBackground(gd->bitmap, drawto,
443 gd->x, gd->y + gi->border.ysize,
444 gi->width, design_body,
446 ypos + gi->border.ysize + i * design_body);
448 /* remaining middle part of gadget */
449 if (step_size_remain > 0)
450 BlitBitmapOnBackground(gd->bitmap, drawto,
451 gd->x, gd->y + gi->border.ysize,
452 gi->width, step_size_remain,
454 ypos + gi->border.ysize
455 + num_steps * design_body);
457 /* lower part of gadget */
458 BlitBitmapOnBackground(gd->bitmap, drawto,
459 gd->x, gd->y + design_full - gi->border.ysize,
460 gi->width, gi->border.ysize,
461 xpos, ypos + size_full - gi->border.ysize);
465 case GD_TYPE_SCROLLBAR_HORIZONTAL:
468 int xpos = gi->x + gi->scrollbar.position;
470 int design_full = gi->height;
471 int design_body = design_full - 2 * gi->border.xsize;
472 int size_full = gi->scrollbar.size;
473 int size_body = size_full - 2 * gi->border.xsize;
474 int num_steps = size_body / design_body;
475 int step_size_remain = size_body - num_steps * design_body;
477 /* clear scrollbar area */
478 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
479 gi->width, gi->height);
481 /* left part of gadget */
482 BlitBitmapOnBackground(gd->bitmap, drawto,
484 gi->border.xsize, gi->height,
487 /* middle part of gadget */
488 for (i=0; i<num_steps; i++)
489 BlitBitmapOnBackground(gd->bitmap, drawto,
490 gd->x + gi->border.xsize, gd->y,
491 design_body, gi->height,
492 xpos + gi->border.xsize + i * design_body,
495 /* remaining middle part of gadget */
496 if (step_size_remain > 0)
497 BlitBitmapOnBackground(gd->bitmap, drawto,
498 gd->x + gi->border.xsize, gd->y,
499 step_size_remain, gi->height,
500 xpos + gi->border.xsize
501 + num_steps * design_body,
504 /* right part of gadget */
505 BlitBitmapOnBackground(gd->bitmap, drawto,
506 gd->x + design_full - gi->border.xsize, gd->y,
507 gi->border.xsize, gi->height,
508 xpos + size_full - gi->border.xsize, ypos);
518 BlitBitmap(drawto, window,
519 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
521 if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
522 BlitBitmap(drawto, window,
523 gi->selectbox.x, gi->selectbox.y,
524 gi->selectbox.width, gi->selectbox.height,
525 gi->selectbox.x, gi->selectbox.y);
528 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
529 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
530 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
533 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
537 while (tag != GDI_END)
542 gi->custom_id = va_arg(ap, int);
545 case GDI_CUSTOM_TYPE_ID:
546 gi->custom_type_id = va_arg(ap, int);
551 int max_textsize = MAX_INFO_TEXTSIZE - 1;
552 char *text = va_arg(ap, char *);
555 strncpy(gi->info_text, text, max_textsize);
559 gi->info_text[max_textsize] = '\0';
564 gi->x = va_arg(ap, int);
568 gi->y = va_arg(ap, int);
572 gi->width = va_arg(ap, int);
576 gi->height = va_arg(ap, int);
580 gi->type = va_arg(ap, unsigned long);
584 gi->state = va_arg(ap, unsigned long);
588 /* take care here: "boolean" is typedef'ed as "unsigned char",
589 which gets promoted to "int" */
590 gi->active = (boolean)va_arg(ap, int);
594 /* take care here: "boolean" is typedef'ed as "unsigned char",
595 which gets promoted to "int" */
596 gi->checked = (boolean)va_arg(ap, int);
600 gi->radio_nr = va_arg(ap, unsigned long);
603 case GDI_NUMBER_VALUE:
604 gi->text.number_value = va_arg(ap, long);
605 sprintf(gi->text.value, "%d", gi->text.number_value);
606 gi->text.cursor_position = strlen(gi->text.value);
610 gi->text.number_min = va_arg(ap, long);
611 if (gi->text.number_value < gi->text.number_min)
613 gi->text.number_value = gi->text.number_min;
614 sprintf(gi->text.value, "%d", gi->text.number_value);
619 gi->text.number_max = va_arg(ap, long);
620 if (gi->text.number_value > gi->text.number_max)
622 gi->text.number_value = gi->text.number_max;
623 sprintf(gi->text.value, "%d", gi->text.number_value);
629 int max_textsize = MAX_GADGET_TEXTSIZE;
632 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
634 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
635 gi->text.value[max_textsize] = '\0';
636 gi->text.cursor_position = strlen(gi->text.value);
638 /* same tag also used for textbutton definition */
639 strcpy(gi->textbutton.value, gi->text.value);
645 int tag_value = va_arg(ap, int);
646 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
648 gi->text.size = max_textsize;
649 gi->text.value[max_textsize] = '\0';
651 /* same tag also used for textbutton and selectbox definition */
652 strcpy(gi->textbutton.value, gi->text.value);
653 gi->textbutton.size = gi->text.size;
654 gi->selectbox.size = gi->text.size;
659 gi->font = va_arg(ap, int);
660 if (gi->font_active == 0)
661 gi->font_active = gi->font;
664 case GDI_TEXT_FONT_ACTIVE:
665 gi->font_active = va_arg(ap, int);
668 case GDI_SELECTBOX_OPTIONS:
669 gi->selectbox.options = va_arg(ap, struct ValueTextInfo *);
672 case GDI_SELECTBOX_INDEX:
673 gi->selectbox.index = va_arg(ap, int);
676 case GDI_DESIGN_UNPRESSED:
677 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
678 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
679 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
682 case GDI_DESIGN_PRESSED:
683 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
684 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
685 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
688 case GDI_ALT_DESIGN_UNPRESSED:
689 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
690 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
691 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
694 case GDI_ALT_DESIGN_PRESSED:
695 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
696 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
697 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
700 case GDI_BORDER_SIZE:
701 gi->border.xsize = va_arg(ap, int);
702 gi->border.ysize = va_arg(ap, int);
705 case GDI_BORDER_SIZE_SELECTBUTTON:
706 gi->border.xsize_selectbutton = va_arg(ap, int);
709 case GDI_DESIGN_WIDTH:
710 gi->border.width = va_arg(ap, int);
713 case GDI_DECORATION_DESIGN:
714 gi->deco.design.bitmap = va_arg(ap, Bitmap *);
715 gi->deco.design.x = va_arg(ap, int);
716 gi->deco.design.y = va_arg(ap, int);
719 case GDI_DECORATION_POSITION:
720 gi->deco.x = va_arg(ap, int);
721 gi->deco.y = va_arg(ap, int);
724 case GDI_DECORATION_SIZE:
725 gi->deco.width = va_arg(ap, int);
726 gi->deco.height = va_arg(ap, int);
729 case GDI_DECORATION_SHIFTING:
730 gi->deco.xshift = va_arg(ap, int);
731 gi->deco.yshift = va_arg(ap, int);
735 gi->event_mask = va_arg(ap, unsigned long);
739 gi->drawing.area_xsize = va_arg(ap, int);
740 gi->drawing.area_ysize = va_arg(ap, int);
742 /* determine dependent values for drawing area gadget, if needed */
743 if (gi->width == 0 && gi->height == 0 &&
744 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
746 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
747 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
749 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
750 gi->width != 0 && gi->height != 0)
752 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
753 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
758 gi->drawing.item_xsize = va_arg(ap, int);
759 gi->drawing.item_ysize = va_arg(ap, int);
761 /* determine dependent values for drawing area gadget, if needed */
762 if (gi->width == 0 && gi->height == 0 &&
763 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
765 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
766 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
768 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
769 gi->width != 0 && gi->height != 0)
771 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
772 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
776 case GDI_SCROLLBAR_ITEMS_MAX:
777 gi->scrollbar.items_max = va_arg(ap, int);
780 case GDI_SCROLLBAR_ITEMS_VISIBLE:
781 gi->scrollbar.items_visible = va_arg(ap, int);
784 case GDI_SCROLLBAR_ITEM_POSITION:
785 gi->scrollbar.item_position = va_arg(ap, int);
788 case GDI_CALLBACK_INFO:
789 gi->callback_info = va_arg(ap, gadget_function);
792 case GDI_CALLBACK_ACTION:
793 gi->callback_action = va_arg(ap, gadget_function);
797 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
800 tag = va_arg(ap, int); /* read next tag */
803 /* check if gadget is complete */
804 if (gi->type != GD_TYPE_DRAWING_AREA &&
805 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
806 !gi->design[GD_BUTTON_PRESSED].bitmap))
807 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
809 /* adjust gadget values in relation to other gadget values */
811 if (gi->type & GD_TYPE_TEXTINPUT)
813 int font_nr = gi->font_active;
814 int font_width = getFontWidth(font_nr);
815 int font_height = getFontHeight(font_nr);
816 int border_xsize = gi->border.xsize;
817 int border_ysize = gi->border.ysize;
819 gi->width = 2 * border_xsize + (gi->text.size + 1) * font_width;
820 gi->height = 2 * border_ysize + font_height;
823 if (gi->type & GD_TYPE_SELECTBOX)
825 int font_nr = gi->font_active;
826 int font_width = getFontWidth(font_nr);
827 int font_height = getFontHeight(font_nr);
828 int border_xsize = gi->border.xsize;
829 int border_ysize = gi->border.ysize;
830 int button_size = gi->border.xsize_selectbutton;
831 int bottom_screen_border = gfx.sy + gfx.sysize - font_height;
835 gi->width = 2 * border_xsize + gi->text.size * font_width + button_size;
836 gi->height = 2 * border_ysize + font_height;
838 if (gi->selectbox.options == NULL)
839 Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)");
841 gi->selectbox.num_values = 0;
842 while (gi->selectbox.options[gi->selectbox.num_values].text != NULL)
843 gi->selectbox.num_values++;
845 /* calculate values for open selectbox */
846 gi->selectbox.width = gi->width;
847 gi->selectbox.height =
848 2 * border_ysize + gi->selectbox.num_values * font_height;
850 gi->selectbox.x = gi->x;
851 gi->selectbox.y = gi->y + gi->height;
852 if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border)
853 gi->selectbox.y = gi->y - gi->selectbox.height;
854 if (gi->selectbox.y < 0)
855 gi->selectbox.y = bottom_screen_border - gi->selectbox.height;
857 getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y);
858 src_x += font_width / 2;
859 src_y += font_height / 2;
860 gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y);
862 /* always start with closed selectbox */
863 gi->selectbox.open = FALSE;
866 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
868 struct GadgetTextInput *text = &gi->text;
869 int value = text->number_value;
871 text->number_value = (value < text->number_min ? text->number_min :
872 value > text->number_max ? text->number_max :
875 sprintf(text->value, "%d", text->number_value);
878 if (gi->type & GD_TYPE_TEXT_BUTTON)
880 int font_nr = gi->font_active;
881 int font_width = getFontWidth(font_nr);
882 int font_height = getFontHeight(font_nr);
883 int border_xsize = gi->border.xsize;
884 int border_ysize = gi->border.ysize;
886 gi->width = 2 * border_xsize + gi->textbutton.size * font_width;
887 gi->height = 2 * border_ysize + font_height;
890 if (gi->type & GD_TYPE_SCROLLBAR)
892 struct GadgetScrollbar *gs = &gi->scrollbar;
894 if (gi->width == 0 || gi->height == 0 ||
895 gs->items_max == 0 || gs->items_visible == 0)
896 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
898 /* calculate internal scrollbar values */
899 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
900 gi->height : gi->width);
901 gs->size = gs->size_max * gs->items_visible / gs->items_max;
902 gs->position = gs->size_max * gs->item_position / gs->items_max;
903 gs->position_max = gs->size_max - gs->size;
904 gs->correction = gs->size_max / gs->items_max / 2;
906 /* finetuning for maximal right/bottom position */
907 if (gs->item_position == gs->items_max - gs->items_visible)
908 gs->position = gs->position_max;
912 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
916 va_start(ap, first_tag);
917 HandleGadgetTags(gi, first_tag, ap);
923 void RedrawGadget(struct GadgetInfo *gi)
926 DrawGadget(gi, gi->state, DG_DIRECT);
929 struct GadgetInfo *CreateGadget(int first_tag, ...)
931 struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
934 /* always start with reliable default values */
935 new_gadget->id = getNewGadgetID();
936 new_gadget->callback_info = default_callback_info;
937 new_gadget->callback_action = default_callback_action;
938 new_gadget->active = TRUE;
939 new_gadget->next = NULL;
941 va_start(ap, first_tag);
942 HandleGadgetTags(new_gadget, first_tag, ap);
945 /* insert new gadget into global gadget list */
946 if (gadget_list_last_entry)
948 gadget_list_last_entry->next = new_gadget;
949 gadget_list_last_entry = gadget_list_last_entry->next;
952 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
957 void FreeGadget(struct GadgetInfo *gi)
959 struct GadgetInfo *gi_previous = gadget_list_first_entry;
961 while (gi_previous != NULL && gi_previous->next != gi)
962 gi_previous = gi_previous->next;
964 if (gi == gadget_list_first_entry)
965 gadget_list_first_entry = gi->next;
967 if (gi == gadget_list_last_entry)
968 gadget_list_last_entry = gi_previous;
970 if (gi_previous != NULL)
971 gi_previous->next = gi->next;
976 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
978 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
981 gi->text.number_value = atoi(gi->text.value);
983 if (gi->text.number_value < gi->text.number_min)
984 gi->text.number_value = gi->text.number_min;
985 if (gi->text.number_value > gi->text.number_max)
986 gi->text.number_value = gi->text.number_max;
988 sprintf(gi->text.value, "%d", gi->text.number_value);
990 if (gi->text.cursor_position < 0)
991 gi->text.cursor_position = 0;
992 else if (gi->text.cursor_position > strlen(gi->text.value))
993 gi->text.cursor_position = strlen(gi->text.value);
996 /* global pointer to gadget actually in use (when mouse button pressed) */
997 static struct GadgetInfo *last_gi = NULL;
999 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
1001 if (gi == NULL || gi->mapped)
1007 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
1010 void MapGadget(struct GadgetInfo *gi)
1012 MapGadgetExt(gi, TRUE);
1015 void UnmapGadget(struct GadgetInfo *gi)
1017 if (gi == NULL || !gi->mapped)
1026 #define MAX_NUM_GADGETS 1024
1027 #define MULTIMAP_UNMAP (1 << 0)
1028 #define MULTIMAP_REMAP (1 << 1)
1029 #define MULTIMAP_REDRAW (1 << 2)
1030 #define MULTIMAP_PLAYFIELD (1 << 3)
1031 #define MULTIMAP_DOOR_1 (1 << 4)
1032 #define MULTIMAP_DOOR_2 (1 << 5)
1033 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
1037 static void MultiMapGadgets(int mode)
1039 struct GadgetInfo *gi = gadget_list_first_entry;
1040 static boolean map_state[MAX_NUM_GADGETS];
1045 if ((mode & MULTIMAP_PLAYFIELD &&
1046 gi->x < gfx.sx + gfx.sxsize) ||
1047 (mode & MULTIMAP_DOOR_1 &&
1048 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
1049 (mode & MULTIMAP_DOOR_2 &&
1050 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
1051 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
1053 if (mode & MULTIMAP_UNMAP)
1055 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
1060 if (map_state[map_count++ % MAX_NUM_GADGETS])
1061 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
1069 void UnmapAllGadgets()
1071 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
1074 void RemapAllGadgets()
1076 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
1079 boolean anyTextInputGadgetActive()
1081 return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
1084 boolean anySelectboxGadgetActive()
1086 return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
1089 boolean anyTextGadgetActive()
1091 return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
1094 void ClickOnGadget(struct GadgetInfo *gi, int button)
1096 /* simulate releasing mouse button over last gadget, if still pressed */
1098 HandleGadgets(-1, -1, 0);
1100 /* simulate pressing mouse button over specified gadget */
1101 HandleGadgets(gi->x, gi->y, button);
1103 /* simulate releasing mouse button over specified gadget */
1104 HandleGadgets(gi->x, gi->y, 0);
1107 void HandleGadgets(int mx, int my, int button)
1109 static struct GadgetInfo *last_info_gi = NULL;
1110 static unsigned long pressed_delay = 0;
1111 static int last_button = 0;
1112 static int last_mx = 0, last_my = 0;
1113 int scrollbar_mouse_pos = 0;
1114 struct GadgetInfo *new_gi, *gi;
1115 boolean press_event;
1116 boolean release_event;
1117 boolean mouse_moving;
1118 boolean gadget_pressed;
1119 boolean gadget_pressed_repeated;
1120 boolean gadget_moving;
1121 boolean gadget_moving_inside;
1122 boolean gadget_moving_off_borders;
1123 boolean gadget_released;
1124 boolean gadget_released_inside;
1125 boolean gadget_released_inside_select_line;
1126 boolean gadget_released_inside_select_area;
1127 boolean gadget_released_off_borders;
1128 boolean changed_position = FALSE;
1130 /* check if there are any gadgets defined */
1131 if (gadget_list_first_entry == NULL)
1134 /* simulated release of mouse button over last gadget */
1135 if (mx == -1 && my == -1 && button == 0)
1141 /* check which gadget is under the mouse pointer */
1142 new_gi = getGadgetInfoFromMousePosition(mx, my);
1144 /* check if button state has changed since last invocation */
1145 press_event = (button != 0 && last_button == 0);
1146 release_event = (button == 0 && last_button != 0);
1147 last_button = button;
1149 /* check if mouse has been moved since last invocation */
1150 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
1154 /* special treatment for text and number input gadgets */
1155 if (anyTextInputGadgetActive() && button != 0 && !motion_status)
1157 struct GadgetInfo *gi = last_gi;
1159 if (new_gi == last_gi)
1161 int old_cursor_position = gi->text.cursor_position;
1163 /* if mouse button pressed inside activated text gadget, set cursor */
1164 gi->text.cursor_position =
1165 (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
1167 if (gi->text.cursor_position < 0)
1168 gi->text.cursor_position = 0;
1169 else if (gi->text.cursor_position > strlen(gi->text.value))
1170 gi->text.cursor_position = strlen(gi->text.value);
1172 if (gi->text.cursor_position != old_cursor_position)
1173 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1177 /* if mouse button pressed outside text input gadget, deactivate it */
1178 CheckRangeOfNumericInputGadget(gi);
1179 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1181 gi->event.type = GD_EVENT_TEXT_LEAVING;
1183 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1184 gi->callback_action(gi);
1190 /* special treatment for selectbox gadgets */
1191 if (anySelectboxGadgetActive() && button != 0 && !motion_status)
1193 struct GadgetInfo *gi = last_gi;
1195 if (new_gi == last_gi)
1197 int old_index = gi->selectbox.current_index;
1199 /* if mouse button pressed inside activated selectbox, select value */
1200 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1201 gi->selectbox.current_index =
1202 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1204 if (gi->selectbox.current_index < 0)
1205 gi->selectbox.current_index = 0;
1206 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1207 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1209 if (gi->selectbox.current_index != old_index)
1210 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1214 /* if mouse button pressed outside selectbox gadget, deactivate it */
1215 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1217 gi->event.type = GD_EVENT_TEXT_LEAVING;
1219 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1220 gi->callback_action(gi);
1227 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
1228 gadget_pressed_repeated =
1229 (button != 0 && last_gi != NULL && new_gi == last_gi);
1231 gadget_released = (release_event && last_gi != NULL);
1232 gadget_released_inside = (gadget_released && new_gi == last_gi);
1233 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
1235 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
1236 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
1237 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
1239 /* when handling selectbox, set additional state values */
1240 if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
1242 struct GadgetInfo *gi = last_gi;
1244 gadget_released_inside_select_line =
1245 (mx >= gi->x && mx < gi->x + gi->width &&
1246 my >= gi->y && my < gi->y + gi->height);
1247 gadget_released_inside_select_area =
1248 (mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
1249 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height);
1253 gadget_released_inside_select_line = FALSE;
1254 gadget_released_inside_select_area = FALSE;
1257 /* if new gadget pressed, store this gadget */
1261 /* 'gi' is actually handled gadget */
1264 /* if gadget is scrollbar, choose mouse position value */
1265 if (gi && gi->type & GD_TYPE_SCROLLBAR)
1266 scrollbar_mouse_pos =
1267 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
1269 /* if mouse button released, no gadget needs to be handled anymore */
1270 if (gadget_released)
1272 if ((last_gi->type & GD_TYPE_SELECTBOX) &&
1273 (gadget_released_inside_select_line ||
1274 gadget_released_off_borders)) /* selectbox stays open */
1275 gi->selectbox.stay_open = TRUE;
1276 else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1280 /* modify event position values even if no gadget is pressed */
1281 if (button == 0 && !release_event)
1286 int last_x = gi->event.x;
1287 int last_y = gi->event.y;
1289 gi->event.x = mx - gi->x;
1290 gi->event.y = my - gi->y;
1292 if (gi->type == GD_TYPE_DRAWING_AREA)
1294 gi->event.x /= gi->drawing.item_xsize;
1295 gi->event.y /= gi->drawing.item_ysize;
1297 if (last_x != gi->event.x || last_y != gi->event.y)
1298 changed_position = TRUE;
1300 else if (gi->type & GD_TYPE_SELECTBOX)
1302 int old_index = gi->selectbox.current_index;
1304 /* if mouse moving inside activated selectbox, select value */
1305 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1306 gi->selectbox.current_index =
1307 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1309 if (gi->selectbox.current_index < 0)
1310 gi->selectbox.current_index = 0;
1311 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1312 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1314 if (gi->selectbox.current_index != old_index)
1315 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1319 /* handle gadget popup info text */
1320 if (last_info_gi != new_gi ||
1321 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
1323 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
1325 new_gi->event.type = GD_EVENT_INFO_ENTERING;
1326 new_gi->callback_info(new_gi);
1328 else if (last_info_gi != NULL)
1330 last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
1331 last_info_gi->callback_info(last_info_gi);
1334 default_callback_info(NULL);
1336 printf("It seems that we are leaving gadget [%s]!\n",
1337 (last_info_gi != NULL &&
1338 last_info_gi->info_text != NULL ?
1339 last_info_gi->info_text : ""));
1343 last_info_gi = new_gi;
1348 if (gi->type == GD_TYPE_CHECK_BUTTON)
1350 gi->checked = !gi->checked;
1352 else if (gi->type == GD_TYPE_RADIO_BUTTON)
1354 struct GadgetInfo *rgi = gadget_list_first_entry;
1359 rgi->type == GD_TYPE_RADIO_BUTTON &&
1360 rgi->radio_nr == gi->radio_nr &&
1363 rgi->checked = FALSE;
1364 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
1372 else if (gi->type & GD_TYPE_SCROLLBAR)
1376 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1387 if (mpos >= gpos + gi->scrollbar.position &&
1388 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1390 /* drag scrollbar */
1391 gi->scrollbar.drag_position =
1392 scrollbar_mouse_pos - gi->scrollbar.position;
1396 /* click scrollbar one scrollbar length up/left or down/right */
1398 struct GadgetScrollbar *gs = &gi->scrollbar;
1399 int old_item_position = gs->item_position;
1401 changed_position = FALSE;
1403 gs->item_position +=
1404 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
1406 if (gs->item_position < 0)
1407 gs->item_position = 0;
1408 if (gs->item_position > gs->items_max - gs->items_visible)
1409 gs->item_position = gs->items_max - gs->items_visible;
1411 if (old_item_position != gs->item_position)
1413 gi->event.item_position = gs->item_position;
1414 changed_position = TRUE;
1417 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
1420 gi->state = GD_BUTTON_UNPRESSED;
1421 gi->event.type = GD_EVENT_MOVING;
1422 gi->event.off_borders = FALSE;
1424 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
1425 gi->callback_action(gi);
1427 /* don't handle this scrollbar anymore while mouse button pressed */
1434 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1436 gi->state = GD_BUTTON_PRESSED;
1437 gi->event.type = GD_EVENT_PRESSED;
1438 gi->event.button = button;
1439 gi->event.off_borders = FALSE;
1441 /* initialize delay counter */
1442 DelayReached(&pressed_delay, 0);
1444 if (gi->event_mask & GD_EVENT_PRESSED)
1445 gi->callback_action(gi);
1448 if (gadget_pressed_repeated)
1450 gi->event.type = GD_EVENT_PRESSED;
1452 if (gi->event_mask & GD_EVENT_REPEATED &&
1453 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1454 gi->callback_action(gi);
1459 if (gi->type & GD_TYPE_BUTTON)
1461 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
1462 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1463 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
1464 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1466 else if (gi->type & GD_TYPE_SELECTBOX)
1468 int old_index = gi->selectbox.current_index;
1470 /* if mouse moving inside activated selectbox, select value */
1471 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1472 gi->selectbox.current_index =
1473 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1475 if (gi->selectbox.current_index < 0)
1476 gi->selectbox.current_index = 0;
1477 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1478 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1480 if (gi->selectbox.current_index != old_index)
1481 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1483 else if (gi->type & GD_TYPE_SCROLLBAR)
1485 struct GadgetScrollbar *gs = &gi->scrollbar;
1486 int old_item_position = gs->item_position;
1488 gs->position = scrollbar_mouse_pos - gs->drag_position;
1490 if (gs->position < 0)
1492 if (gs->position > gs->position_max)
1493 gs->position = gs->position_max;
1496 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1498 if (gs->item_position < 0)
1499 gs->item_position = 0;
1500 if (gs->item_position > gs->items_max - 1)
1501 gs->item_position = gs->items_max - 1;
1503 if (old_item_position != gs->item_position)
1505 gi->event.item_position = gs->item_position;
1506 changed_position = TRUE;
1509 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1512 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1513 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1514 gi->event.type = GD_EVENT_MOVING;
1515 gi->event.off_borders = gadget_moving_off_borders;
1517 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1518 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1519 gi->callback_action(gi);
1522 if (gadget_released_inside)
1524 boolean deactivate_gadget = TRUE;
1526 if (gi->type & GD_TYPE_SELECTBOX)
1528 if (gadget_released_inside_select_line ||
1529 gadget_released_off_borders) /* selectbox stays open */
1530 deactivate_gadget = FALSE;
1532 gi->selectbox.index = gi->selectbox.current_index;
1535 if (deactivate_gadget &&
1536 !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1537 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1539 gi->state = GD_BUTTON_UNPRESSED;
1540 gi->event.type = GD_EVENT_RELEASED;
1542 if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
1543 gi->callback_action(gi);
1546 if (gadget_released_off_borders)
1548 if (gi->type & GD_TYPE_SCROLLBAR)
1549 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1551 gi->event.type = GD_EVENT_RELEASED;
1553 if (gi->event_mask & GD_EVENT_RELEASED &&
1554 gi->event_mask & GD_EVENT_OFF_BORDERS)
1555 gi->callback_action(gi);
1558 /* handle gadgets unmapped/mapped between pressing and releasing */
1559 if (release_event && !gadget_released && new_gi)
1560 new_gi->state = GD_BUTTON_UNPRESSED;
1563 void HandleGadgetsKeyInput(Key key)
1565 struct GadgetInfo *gi = last_gi;
1567 if (gi == NULL || !gi->mapped ||
1568 !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
1571 if (key == KSYM_Return) /* valid for both text input and selectbox */
1573 if (gi->type & GD_TYPE_TEXTINPUT)
1574 CheckRangeOfNumericInputGadget(gi);
1575 else if (gi->type & GD_TYPE_SELECTBOX)
1576 gi->selectbox.index = gi->selectbox.current_index;
1578 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1580 gi->event.type = GD_EVENT_TEXT_RETURN;
1582 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1583 gi->callback_action(gi);
1587 else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */
1589 char text[MAX_GADGET_TEXTSIZE];
1590 int text_length = strlen(gi->text.value);
1591 int cursor_pos = gi->text.cursor_position;
1592 char letter = getCharFromKey(key);
1593 boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1594 letter >= '0' && letter <= '9' :
1597 if (legal_letter && text_length < gi->text.size)
1599 strcpy(text, gi->text.value);
1600 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1601 gi->text.value[cursor_pos] = letter;
1602 gi->text.cursor_position++;
1604 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1606 else if (key == KSYM_Left && cursor_pos > 0)
1608 gi->text.cursor_position--;
1609 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1611 else if (key == KSYM_Right && cursor_pos < text_length)
1613 gi->text.cursor_position++;
1614 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1616 else if (key == KSYM_BackSpace && cursor_pos > 0)
1618 strcpy(text, gi->text.value);
1619 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1620 gi->text.cursor_position--;
1621 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1623 else if (key == KSYM_Delete && cursor_pos < text_length)
1625 strcpy(text, gi->text.value);
1626 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1627 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1630 else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
1632 int index = gi->selectbox.current_index;
1633 int num_values = gi->selectbox.num_values;
1635 if (key == KSYM_Up && index > 0)
1637 gi->selectbox.current_index--;
1638 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1640 else if (key == KSYM_Down && index < num_values - 1)
1642 gi->selectbox.current_index++;
1643 DrawGadget(gi, DG_PRESSED, DG_DIRECT);