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;
87 if (gi->mapped && gi->active &&
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 ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
114 struct GadgetDesign *gd = (!gi->active ? &gi->alt_design[state] :
115 gi->checked ? &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_TEXT_BUTTON:
138 int font_nr = (gi->active ? gi->font_active : gi->font);
139 int font_width = getFontWidth(font_nr);
140 int border_x = gi->border.xsize;
141 int border_y = gi->border.ysize;
142 int text_size = strlen(gi->textbutton.value);
143 int text_start = (gi->width - text_size * font_width) / 2;
145 /* left part of gadget */
146 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
147 border_x, gi->height, gi->x, gi->y);
149 /* middle part of gadget */
150 for (i=0; i < gi->textbutton.size; i++)
151 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
152 font_width, gi->height,
153 gi->x + border_x + i * font_width, gi->y);
155 /* right part of gadget */
156 BlitBitmapOnBackground(gd->bitmap, drawto,
157 gd->x + gi->border.width - border_x, gd->y,
158 border_x, gi->height,
159 gi->x + gi->width - border_x, gi->y);
161 /* gadget text value */
163 gi->x + text_start + (pressed ? gi->deco.xshift : 0),
164 gi->y + border_y + (pressed ? gi->deco.yshift : 0),
165 gi->textbutton.value, font_nr, BLIT_MASKED);
169 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
170 case GD_TYPE_TEXTINPUT_NUMERIC:
174 char cursor_string[2];
175 char text[MAX_GADGET_TEXTSIZE + 1];
176 int font_nr = (pressed ? gi->font_active : gi->font);
177 int font_width = getFontWidth(font_nr);
178 int border_x = gi->border.xsize;
179 int border_y = gi->border.ysize;
181 /* left part of gadget */
182 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
183 border_x, gi->height, gi->x, gi->y);
185 /* middle part of gadget */
186 for (i=0; i < gi->text.size + 1; i++)
187 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
188 font_width, gi->height,
189 gi->x + border_x + i * font_width, gi->y);
191 /* right part of gadget */
192 BlitBitmapOnBackground(gd->bitmap, drawto,
193 gd->x + gi->border.width - border_x, gd->y,
194 border_x, gi->height,
195 gi->x + gi->width - border_x, gi->y);
198 strcpy(text, gi->text.value);
201 /* gadget text value */
203 gi->x + border_x, gi->y + border_y, text,
204 font_nr, BLIT_MASKED);
206 cursor_letter = gi->text.value[gi->text.cursor_position];
207 cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
208 cursor_string[1] = '\0';
210 /* draw cursor, if active */
213 gi->x + border_x + gi->text.cursor_position * font_width,
214 gi->y + border_y, cursor_string,
215 font_nr, BLIT_INVERSE);
219 case GD_TYPE_SELECTBOX:
222 char text[MAX_GADGET_TEXTSIZE + 1];
223 int font_nr = (pressed ? gi->font_active : gi->font);
224 int font_width = getFontWidth(font_nr);
225 int font_height = getFontHeight(font_nr);
226 int border_x = gi->border.xsize;
227 int border_y = gi->border.ysize;
228 int button = gi->border.xsize_selectbutton;
229 int width_inner = gi->border.width - button - 2 * border_x;
230 int box_width = gi->selectbox.width;
231 int box_height = gi->selectbox.height;
233 /* left part of gadget */
234 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
235 border_x, gi->height, gi->x, gi->y);
237 /* middle part of gadget */
238 for (i=0; i < gi->selectbox.size; i++)
239 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
240 font_width, gi->height,
241 gi->x + border_x + i * font_width, gi->y);
243 /* button part of gadget */
244 BlitBitmapOnBackground(gd->bitmap, drawto,
245 gd->x + border_x + width_inner, gd->y,
247 gi->x + gi->width - border_x - button, gi->y);
249 /* right part of gadget */
250 BlitBitmapOnBackground(gd->bitmap, drawto,
251 gd->x + gi->border.width - border_x, gd->y,
252 border_x, gi->height,
253 gi->x + gi->width - border_x, gi->y);
256 strncpy(text, gi->selectbox.options[gi->selectbox.index].text,
258 text[gi->selectbox.size] = '\0';
260 /* gadget text value */
261 DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text,
262 font_nr, BLIT_MASKED);
266 if (!gi->selectbox.open)
268 gi->selectbox.open = TRUE;
269 gi->selectbox.stay_open = FALSE;
270 gi->selectbox.current_index = gi->selectbox.index;
272 /* save background under selectbox */
273 BlitBitmap(drawto, gfx.field_save_buffer,
274 gi->selectbox.x, gi->selectbox.y,
275 gi->selectbox.width, gi->selectbox.height,
276 gi->selectbox.x, gi->selectbox.y);
279 /* draw open selectbox */
281 /* top left part of gadget border */
282 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
284 gi->selectbox.x, gi->selectbox.y);
286 /* top middle part of gadget border */
287 for (i=0; i < gi->selectbox.size; i++)
288 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
289 font_width, border_y,
290 gi->selectbox.x + border_x + i * font_width,
293 /* top button part of gadget border */
294 BlitBitmapOnBackground(gd->bitmap, drawto,
295 gd->x + border_x + width_inner, gd->y,
297 gi->selectbox.x + box_width -border_x -button,
300 /* top right part of gadget border */
301 BlitBitmapOnBackground(gd->bitmap, drawto,
302 gd->x + gi->border.width - border_x, gd->y,
304 gi->selectbox.x + box_width - border_x,
307 /* left and right part of gadget border for each row */
308 for (i=0; i < gi->selectbox.num_values; i++)
310 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y,
311 border_x, font_height,
313 gi->selectbox.y + border_y + i*font_height);
314 BlitBitmapOnBackground(gd->bitmap, drawto,
315 gd->x + gi->border.width - border_x,
317 border_x, font_height,
318 gi->selectbox.x + box_width - border_x,
319 gi->selectbox.y + border_y + i*font_height);
322 /* bottom left part of gadget border */
323 BlitBitmapOnBackground(gd->bitmap, drawto,
324 gd->x, gd->y + gi->height - border_y,
327 gi->selectbox.y + box_height - border_y);
329 /* bottom middle part of gadget border */
330 for (i=0; i < gi->selectbox.size; i++)
331 BlitBitmapOnBackground(gd->bitmap, drawto,
333 gd->y + gi->height - border_y,
334 font_width, border_y,
335 gi->selectbox.x + border_x + i * font_width,
336 gi->selectbox.y + box_height - border_y);
338 /* bottom button part of gadget border */
339 BlitBitmapOnBackground(gd->bitmap, drawto,
340 gd->x + border_x + width_inner,
341 gd->y + gi->height - border_y,
343 gi->selectbox.x + box_width -border_x -button,
344 gi->selectbox.y + box_height - border_y);
346 /* bottom right part of gadget border */
347 BlitBitmapOnBackground(gd->bitmap, drawto,
348 gd->x + gi->border.width - border_x,
349 gd->y + gi->height - border_y,
351 gi->selectbox.x + box_width - border_x,
352 gi->selectbox.y + box_height - border_y);
354 ClearRectangleOnBackground(drawto,
355 gi->selectbox.x + border_x,
356 gi->selectbox.y + border_y,
357 gi->selectbox.width - 2 * border_x,
358 gi->selectbox.height - 2 * border_y);
360 /* selectbox text values */
361 for (i=0; i < gi->selectbox.num_values; i++)
365 if (i == gi->selectbox.current_index)
367 FillRectangle(drawto,
368 gi->selectbox.x + border_x,
369 gi->selectbox.y + border_y + i * font_height,
370 gi->selectbox.width - 2 * border_x, font_height,
371 gi->selectbox.inverse_color);
373 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
374 text[1 + gi->selectbox.size] = '\0';
376 mask_mode = BLIT_INVERSE;
380 strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
381 text[gi->selectbox.size] = '\0';
383 mask_mode = BLIT_MASKED;
387 gi->selectbox.x + border_x,
388 gi->selectbox.y + border_y + i * font_height, text,
392 redraw_selectbox = TRUE;
394 else if (gi->selectbox.open)
396 gi->selectbox.open = FALSE;
398 /* redraw closed selectbox */
399 DrawGadget(gi, FALSE, FALSE);
401 /* restore background under selectbox */
402 BlitBitmap(gfx.field_save_buffer, drawto,
403 gi->selectbox.x, gi->selectbox.y,
404 gi->selectbox.width, gi->selectbox.height,
405 gi->selectbox.x, gi->selectbox.y);
407 redraw_selectbox = TRUE;
412 case GD_TYPE_SCROLLBAR_VERTICAL:
416 int ypos = gi->y + gi->scrollbar.position;
417 int design_full = gi->width;
418 int design_body = design_full - 2 * gi->border.ysize;
419 int size_full = gi->scrollbar.size;
420 int size_body = size_full - 2 * gi->border.ysize;
421 int num_steps = size_body / design_body;
422 int step_size_remain = size_body - num_steps * design_body;
424 /* clear scrollbar area */
425 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
426 gi->width, gi->height);
428 /* upper part of gadget */
429 BlitBitmapOnBackground(gd->bitmap, drawto,
431 gi->width, gi->border.ysize,
434 /* middle part of gadget */
435 for (i=0; i<num_steps; i++)
436 BlitBitmapOnBackground(gd->bitmap, drawto,
437 gd->x, gd->y + gi->border.ysize,
438 gi->width, design_body,
440 ypos + gi->border.ysize + i * design_body);
442 /* remaining middle part of gadget */
443 if (step_size_remain > 0)
444 BlitBitmapOnBackground(gd->bitmap, drawto,
445 gd->x, gd->y + gi->border.ysize,
446 gi->width, step_size_remain,
448 ypos + gi->border.ysize
449 + num_steps * design_body);
451 /* lower part of gadget */
452 BlitBitmapOnBackground(gd->bitmap, drawto,
453 gd->x, gd->y + design_full - gi->border.ysize,
454 gi->width, gi->border.ysize,
455 xpos, ypos + size_full - gi->border.ysize);
459 case GD_TYPE_SCROLLBAR_HORIZONTAL:
462 int xpos = gi->x + gi->scrollbar.position;
464 int design_full = gi->height;
465 int design_body = design_full - 2 * gi->border.xsize;
466 int size_full = gi->scrollbar.size;
467 int size_body = size_full - 2 * gi->border.xsize;
468 int num_steps = size_body / design_body;
469 int step_size_remain = size_body - num_steps * design_body;
471 /* clear scrollbar area */
472 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
473 gi->width, gi->height);
475 /* left part of gadget */
476 BlitBitmapOnBackground(gd->bitmap, drawto,
478 gi->border.xsize, gi->height,
481 /* middle part of gadget */
482 for (i=0; i<num_steps; i++)
483 BlitBitmapOnBackground(gd->bitmap, drawto,
484 gd->x + gi->border.xsize, gd->y,
485 design_body, gi->height,
486 xpos + gi->border.xsize + i * design_body,
489 /* remaining middle part of gadget */
490 if (step_size_remain > 0)
491 BlitBitmapOnBackground(gd->bitmap, drawto,
492 gd->x + gi->border.xsize, gd->y,
493 step_size_remain, gi->height,
494 xpos + gi->border.xsize
495 + num_steps * design_body,
498 /* right part of gadget */
499 BlitBitmapOnBackground(gd->bitmap, drawto,
500 gd->x + design_full - gi->border.xsize, gd->y,
501 gi->border.xsize, gi->height,
502 xpos + size_full - gi->border.xsize, ypos);
512 BlitBitmap(drawto, window,
513 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
515 if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
516 BlitBitmap(drawto, window,
517 gi->selectbox.x, gi->selectbox.y,
518 gi->selectbox.width, gi->selectbox.height,
519 gi->selectbox.x, gi->selectbox.y);
522 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
523 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
524 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
527 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
531 while (tag != GDI_END)
536 gi->custom_id = va_arg(ap, int);
539 case GDI_CUSTOM_TYPE_ID:
540 gi->custom_type_id = va_arg(ap, int);
545 int max_textsize = MAX_INFO_TEXTSIZE - 1;
546 char *text = va_arg(ap, char *);
549 strncpy(gi->info_text, text, max_textsize);
553 gi->info_text[max_textsize] = '\0';
558 gi->x = va_arg(ap, int);
562 gi->y = va_arg(ap, int);
566 gi->width = va_arg(ap, int);
570 gi->height = va_arg(ap, int);
574 gi->type = va_arg(ap, unsigned long);
578 gi->state = va_arg(ap, unsigned long);
582 /* take care here: "boolean" is typedef'ed as "unsigned char",
583 which gets promoted to "int" */
584 gi->active = (boolean)va_arg(ap, int);
588 /* take care here: "boolean" is typedef'ed as "unsigned char",
589 which gets promoted to "int" */
590 gi->checked = (boolean)va_arg(ap, int);
594 gi->radio_nr = va_arg(ap, unsigned long);
597 case GDI_NUMBER_VALUE:
598 gi->text.number_value = va_arg(ap, long);
599 sprintf(gi->text.value, "%d", gi->text.number_value);
600 gi->text.cursor_position = strlen(gi->text.value);
604 gi->text.number_min = va_arg(ap, long);
605 if (gi->text.number_value < gi->text.number_min)
607 gi->text.number_value = gi->text.number_min;
608 sprintf(gi->text.value, "%d", gi->text.number_value);
613 gi->text.number_max = va_arg(ap, long);
614 if (gi->text.number_value > gi->text.number_max)
616 gi->text.number_value = gi->text.number_max;
617 sprintf(gi->text.value, "%d", gi->text.number_value);
623 int max_textsize = MAX_GADGET_TEXTSIZE;
626 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
628 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
629 gi->text.value[max_textsize] = '\0';
630 gi->text.cursor_position = strlen(gi->text.value);
632 /* same tag also used for textbutton definition */
633 strcpy(gi->textbutton.value, gi->text.value);
639 int tag_value = va_arg(ap, int);
640 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
642 gi->text.size = max_textsize;
643 gi->text.value[max_textsize] = '\0';
645 /* same tag also used for textbutton and selectbox definition */
646 strcpy(gi->textbutton.value, gi->text.value);
647 gi->textbutton.size = gi->text.size;
648 gi->selectbox.size = gi->text.size;
653 gi->font = va_arg(ap, int);
654 if (gi->font_active == 0)
655 gi->font_active = gi->font;
658 case GDI_TEXT_FONT_ACTIVE:
659 gi->font_active = va_arg(ap, int);
662 case GDI_SELECTBOX_OPTIONS:
663 gi->selectbox.options = va_arg(ap, struct ValueTextInfo *);
666 case GDI_SELECTBOX_INDEX:
667 gi->selectbox.index = va_arg(ap, int);
670 case GDI_DESIGN_UNPRESSED:
671 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
672 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
673 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
676 case GDI_DESIGN_PRESSED:
677 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
678 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
679 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
682 case GDI_ALT_DESIGN_UNPRESSED:
683 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
684 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
685 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
688 case GDI_ALT_DESIGN_PRESSED:
689 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
690 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
691 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
694 case GDI_BORDER_SIZE:
695 gi->border.xsize = va_arg(ap, int);
696 gi->border.ysize = va_arg(ap, int);
699 case GDI_BORDER_SIZE_SELECTBUTTON:
700 gi->border.xsize_selectbutton = va_arg(ap, int);
703 case GDI_DESIGN_WIDTH:
704 gi->border.width = va_arg(ap, int);
707 case GDI_DECORATION_DESIGN:
708 gi->deco.design.bitmap = va_arg(ap, Bitmap *);
709 gi->deco.design.x = va_arg(ap, int);
710 gi->deco.design.y = va_arg(ap, int);
713 case GDI_DECORATION_POSITION:
714 gi->deco.x = va_arg(ap, int);
715 gi->deco.y = va_arg(ap, int);
718 case GDI_DECORATION_SIZE:
719 gi->deco.width = va_arg(ap, int);
720 gi->deco.height = va_arg(ap, int);
723 case GDI_DECORATION_SHIFTING:
724 gi->deco.xshift = va_arg(ap, int);
725 gi->deco.yshift = va_arg(ap, int);
729 gi->event_mask = va_arg(ap, unsigned long);
733 gi->drawing.area_xsize = va_arg(ap, int);
734 gi->drawing.area_ysize = va_arg(ap, int);
736 /* determine dependent values for drawing area gadget, if needed */
737 if (gi->width == 0 && gi->height == 0 &&
738 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
740 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
741 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
743 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
744 gi->width != 0 && gi->height != 0)
746 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
747 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
752 gi->drawing.item_xsize = va_arg(ap, int);
753 gi->drawing.item_ysize = va_arg(ap, int);
755 /* determine dependent values for drawing area gadget, if needed */
756 if (gi->width == 0 && gi->height == 0 &&
757 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
759 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
760 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
762 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
763 gi->width != 0 && gi->height != 0)
765 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
766 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
770 case GDI_SCROLLBAR_ITEMS_MAX:
771 gi->scrollbar.items_max = va_arg(ap, int);
774 case GDI_SCROLLBAR_ITEMS_VISIBLE:
775 gi->scrollbar.items_visible = va_arg(ap, int);
778 case GDI_SCROLLBAR_ITEM_POSITION:
779 gi->scrollbar.item_position = va_arg(ap, int);
782 case GDI_CALLBACK_INFO:
783 gi->callback_info = va_arg(ap, gadget_function);
786 case GDI_CALLBACK_ACTION:
787 gi->callback_action = va_arg(ap, gadget_function);
791 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
794 tag = va_arg(ap, int); /* read next tag */
797 /* check if gadget is complete */
798 if (gi->type != GD_TYPE_DRAWING_AREA &&
799 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
800 !gi->design[GD_BUTTON_PRESSED].bitmap))
801 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
803 /* adjust gadget values in relation to other gadget values */
805 if (gi->type & GD_TYPE_TEXTINPUT)
807 int font_nr = gi->font_active;
808 int font_width = getFontWidth(font_nr);
809 int font_height = getFontHeight(font_nr);
810 int border_xsize = gi->border.xsize;
811 int border_ysize = gi->border.ysize;
813 gi->width = 2 * border_xsize + (gi->text.size + 1) * font_width;
814 gi->height = 2 * border_ysize + font_height;
817 if (gi->type & GD_TYPE_SELECTBOX)
819 int font_nr = gi->font_active;
820 int font_width = getFontWidth(font_nr);
821 int font_height = getFontHeight(font_nr);
822 int border_xsize = gi->border.xsize;
823 int border_ysize = gi->border.ysize;
824 int button_size = gi->border.xsize_selectbutton;
828 gi->width = 2 * border_xsize + gi->text.size * font_width + button_size;
829 gi->height = 2 * border_ysize + font_height;
831 if (gi->selectbox.options == NULL)
832 Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)");
834 gi->selectbox.num_values = 0;
835 while (gi->selectbox.options[gi->selectbox.num_values].text != NULL)
836 gi->selectbox.num_values++;
838 /* calculate values for open selectbox */
839 gi->selectbox.width = gi->width;
840 gi->selectbox.height =
841 2 * border_ysize + gi->selectbox.num_values * font_height;
843 gi->selectbox.x = gi->x;
844 gi->selectbox.y = gi->y + gi->height;
845 if (gi->selectbox.y + gi->selectbox.height > gfx.real_sy + gfx.full_sysize)
846 gi->selectbox.y = gi->y - gi->selectbox.height;
847 if (gi->selectbox.y < 0)
848 gi->selectbox.y = gfx.real_sy + gfx.full_sysize - gi->selectbox.height;
850 getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y);
851 src_x += font_width / 2;
852 src_y += font_height / 2;
853 gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y);
855 /* always start with closed selectbox */
856 gi->selectbox.open = FALSE;
859 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
861 struct GadgetTextInput *text = &gi->text;
862 int value = text->number_value;
864 text->number_value = (value < text->number_min ? text->number_min :
865 value > text->number_max ? text->number_max :
868 sprintf(text->value, "%d", text->number_value);
871 if (gi->type & GD_TYPE_TEXT_BUTTON)
873 int font_nr = gi->font_active;
874 int font_width = getFontWidth(font_nr);
875 int font_height = getFontHeight(font_nr);
876 int border_xsize = gi->border.xsize;
877 int border_ysize = gi->border.ysize;
879 gi->width = 2 * border_xsize + gi->textbutton.size * font_width;
880 gi->height = 2 * border_ysize + font_height;
883 if (gi->type & GD_TYPE_SCROLLBAR)
885 struct GadgetScrollbar *gs = &gi->scrollbar;
887 if (gi->width == 0 || gi->height == 0 ||
888 gs->items_max == 0 || gs->items_visible == 0)
889 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
891 /* calculate internal scrollbar values */
892 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
893 gi->height : gi->width);
894 gs->size = gs->size_max * gs->items_visible / gs->items_max;
895 gs->position = gs->size_max * gs->item_position / gs->items_max;
896 gs->position_max = gs->size_max - gs->size;
897 gs->correction = gs->size_max / gs->items_max / 2;
899 /* finetuning for maximal right/bottom position */
900 if (gs->item_position == gs->items_max - gs->items_visible)
901 gs->position = gs->position_max;
905 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
909 va_start(ap, first_tag);
910 HandleGadgetTags(gi, first_tag, ap);
916 void RedrawGadget(struct GadgetInfo *gi)
919 DrawGadget(gi, gi->state, DG_DIRECT);
922 struct GadgetInfo *CreateGadget(int first_tag, ...)
924 struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
927 /* always start with reliable default values */
928 new_gadget->id = getNewGadgetID();
929 new_gadget->callback_info = default_callback_info;
930 new_gadget->callback_action = default_callback_action;
931 new_gadget->active = TRUE;
932 new_gadget->next = NULL;
934 va_start(ap, first_tag);
935 HandleGadgetTags(new_gadget, first_tag, ap);
938 /* insert new gadget into global gadget list */
939 if (gadget_list_last_entry)
941 gadget_list_last_entry->next = new_gadget;
942 gadget_list_last_entry = gadget_list_last_entry->next;
945 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
950 void FreeGadget(struct GadgetInfo *gi)
952 struct GadgetInfo *gi_previous = gadget_list_first_entry;
954 while (gi_previous != NULL && gi_previous->next != gi)
955 gi_previous = gi_previous->next;
957 if (gi == gadget_list_first_entry)
958 gadget_list_first_entry = gi->next;
960 if (gi == gadget_list_last_entry)
961 gadget_list_last_entry = gi_previous;
963 if (gi_previous != NULL)
964 gi_previous->next = gi->next;
969 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
971 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
974 gi->text.number_value = atoi(gi->text.value);
976 if (gi->text.number_value < gi->text.number_min)
977 gi->text.number_value = gi->text.number_min;
978 if (gi->text.number_value > gi->text.number_max)
979 gi->text.number_value = gi->text.number_max;
981 sprintf(gi->text.value, "%d", gi->text.number_value);
983 if (gi->text.cursor_position < 0)
984 gi->text.cursor_position = 0;
985 else if (gi->text.cursor_position > strlen(gi->text.value))
986 gi->text.cursor_position = strlen(gi->text.value);
989 /* global pointer to gadget actually in use (when mouse button pressed) */
990 static struct GadgetInfo *last_gi = NULL;
992 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
994 if (gi == NULL || gi->mapped)
1000 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
1003 void MapGadget(struct GadgetInfo *gi)
1005 MapGadgetExt(gi, TRUE);
1008 void UnmapGadget(struct GadgetInfo *gi)
1010 if (gi == NULL || !gi->mapped)
1019 #define MAX_NUM_GADGETS 1024
1020 #define MULTIMAP_UNMAP (1 << 0)
1021 #define MULTIMAP_REMAP (1 << 1)
1022 #define MULTIMAP_REDRAW (1 << 2)
1023 #define MULTIMAP_PLAYFIELD (1 << 3)
1024 #define MULTIMAP_DOOR_1 (1 << 4)
1025 #define MULTIMAP_DOOR_2 (1 << 5)
1026 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
1030 static void MultiMapGadgets(int mode)
1032 struct GadgetInfo *gi = gadget_list_first_entry;
1033 static boolean map_state[MAX_NUM_GADGETS];
1038 if ((mode & MULTIMAP_PLAYFIELD &&
1039 gi->x < gfx.sx + gfx.sxsize) ||
1040 (mode & MULTIMAP_DOOR_1 &&
1041 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
1042 (mode & MULTIMAP_DOOR_2 &&
1043 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
1044 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
1046 if (mode & MULTIMAP_UNMAP)
1048 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
1053 if (map_state[map_count++ % MAX_NUM_GADGETS])
1054 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
1062 void UnmapAllGadgets()
1064 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
1067 void RemapAllGadgets()
1069 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
1072 boolean anyTextInputGadgetActive()
1074 return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
1077 boolean anySelectboxGadgetActive()
1079 return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
1082 boolean anyTextGadgetActive()
1084 return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
1087 void ClickOnGadget(struct GadgetInfo *gi, int button)
1089 /* simulate releasing mouse button over last gadget, if still pressed */
1091 HandleGadgets(-1, -1, 0);
1093 /* simulate pressing mouse button over specified gadget */
1094 HandleGadgets(gi->x, gi->y, button);
1096 /* simulate releasing mouse button over specified gadget */
1097 HandleGadgets(gi->x, gi->y, 0);
1100 void HandleGadgets(int mx, int my, int button)
1102 static struct GadgetInfo *last_info_gi = NULL;
1103 static unsigned long pressed_delay = 0;
1104 static int last_button = 0;
1105 static int last_mx = 0, last_my = 0;
1106 int scrollbar_mouse_pos = 0;
1107 struct GadgetInfo *new_gi, *gi;
1108 boolean press_event;
1109 boolean release_event;
1110 boolean mouse_moving;
1111 boolean gadget_pressed;
1112 boolean gadget_pressed_repeated;
1113 boolean gadget_moving;
1114 boolean gadget_moving_inside;
1115 boolean gadget_moving_off_borders;
1116 boolean gadget_released;
1117 boolean gadget_released_inside;
1118 boolean gadget_released_inside_select_line;
1119 boolean gadget_released_inside_select_area;
1120 boolean gadget_released_off_borders;
1121 boolean changed_position = FALSE;
1123 /* check if there are any gadgets defined */
1124 if (gadget_list_first_entry == NULL)
1127 /* check which gadget is under the mouse pointer */
1128 new_gi = getGadgetInfoFromMousePosition(mx, my);
1130 /* check if button state has changed since last invocation */
1131 press_event = (button != 0 && last_button == 0);
1132 release_event = (button == 0 && last_button != 0);
1133 last_button = button;
1135 /* check if mouse has been moved since last invocation */
1136 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
1140 /* special treatment for text and number input gadgets */
1141 if (anyTextInputGadgetActive() && button != 0 && !motion_status)
1143 struct GadgetInfo *gi = last_gi;
1145 if (new_gi == last_gi)
1147 int old_cursor_position = gi->text.cursor_position;
1149 /* if mouse button pressed inside activated text gadget, set cursor */
1150 gi->text.cursor_position =
1151 (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
1153 if (gi->text.cursor_position < 0)
1154 gi->text.cursor_position = 0;
1155 else if (gi->text.cursor_position > strlen(gi->text.value))
1156 gi->text.cursor_position = strlen(gi->text.value);
1158 if (gi->text.cursor_position != old_cursor_position)
1159 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1163 /* if mouse button pressed outside text input gadget, deactivate it */
1164 CheckRangeOfNumericInputGadget(gi);
1165 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1167 gi->event.type = GD_EVENT_TEXT_LEAVING;
1169 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1170 gi->callback_action(gi);
1176 /* special treatment for selectbox gadgets */
1177 if (anySelectboxGadgetActive() && button != 0 && !motion_status)
1179 struct GadgetInfo *gi = last_gi;
1181 if (new_gi == last_gi)
1183 int old_index = gi->selectbox.current_index;
1185 /* if mouse button pressed inside activated selectbox, select value */
1186 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1187 gi->selectbox.current_index =
1188 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1190 if (gi->selectbox.current_index < 0)
1191 gi->selectbox.current_index = 0;
1192 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1193 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1195 if (gi->selectbox.current_index != old_index)
1196 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1200 /* if mouse button pressed outside selectbox gadget, deactivate it */
1201 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1203 gi->event.type = GD_EVENT_TEXT_LEAVING;
1205 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1206 gi->callback_action(gi);
1213 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
1214 gadget_pressed_repeated =
1215 (button != 0 && last_gi != NULL && new_gi == last_gi);
1217 gadget_released = (release_event && last_gi != NULL);
1218 gadget_released_inside = (gadget_released && new_gi == last_gi);
1219 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
1221 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
1222 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
1223 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
1225 /* when handling selectbox, set additional state values */
1226 if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
1228 struct GadgetInfo *gi = last_gi;
1230 gadget_released_inside_select_line =
1231 (mx >= gi->x && mx < gi->x + gi->width &&
1232 my >= gi->y && my < gi->y + gi->height);
1233 gadget_released_inside_select_area =
1234 (mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
1235 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height);
1239 gadget_released_inside_select_line = FALSE;
1240 gadget_released_inside_select_area = FALSE;
1243 /* if new gadget pressed, store this gadget */
1247 /* 'gi' is actually handled gadget */
1250 /* if gadget is scrollbar, choose mouse position value */
1251 if (gi && gi->type & GD_TYPE_SCROLLBAR)
1252 scrollbar_mouse_pos =
1253 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
1255 /* if mouse button released, no gadget needs to be handled anymore */
1256 if (gadget_released)
1258 if ((last_gi->type & GD_TYPE_SELECTBOX) &&
1259 (gadget_released_inside_select_line ||
1260 gadget_released_off_borders)) /* selectbox stays open */
1261 gi->selectbox.stay_open = TRUE;
1262 else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1266 /* modify event position values even if no gadget is pressed */
1267 if (button == 0 && !release_event)
1272 int last_x = gi->event.x;
1273 int last_y = gi->event.y;
1275 gi->event.x = mx - gi->x;
1276 gi->event.y = my - gi->y;
1278 if (gi->type == GD_TYPE_DRAWING_AREA)
1280 gi->event.x /= gi->drawing.item_xsize;
1281 gi->event.y /= gi->drawing.item_ysize;
1283 if (last_x != gi->event.x || last_y != gi->event.y)
1284 changed_position = TRUE;
1286 else if (gi->type & GD_TYPE_SELECTBOX)
1288 int old_index = gi->selectbox.current_index;
1290 /* if mouse moving inside activated selectbox, select value */
1291 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1292 gi->selectbox.current_index =
1293 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1295 if (gi->selectbox.current_index < 0)
1296 gi->selectbox.current_index = 0;
1297 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1298 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1300 if (gi->selectbox.current_index != old_index)
1301 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1305 /* handle gadget popup info text */
1306 if (last_info_gi != new_gi ||
1307 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
1309 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
1311 new_gi->event.type = GD_EVENT_INFO_ENTERING;
1312 new_gi->callback_info(new_gi);
1314 else if (last_info_gi != NULL)
1316 last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
1317 last_info_gi->callback_info(last_info_gi);
1320 default_callback_info(NULL);
1322 printf("It seems that we are leaving gadget [%s]!\n",
1323 (last_info_gi != NULL &&
1324 last_info_gi->info_text != NULL ?
1325 last_info_gi->info_text : ""));
1329 last_info_gi = new_gi;
1334 if (gi->type == GD_TYPE_CHECK_BUTTON)
1336 gi->checked = !gi->checked;
1338 else if (gi->type == GD_TYPE_RADIO_BUTTON)
1340 struct GadgetInfo *rgi = gadget_list_first_entry;
1345 rgi->type == GD_TYPE_RADIO_BUTTON &&
1346 rgi->radio_nr == gi->radio_nr &&
1349 rgi->checked = FALSE;
1350 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
1358 else if (gi->type & GD_TYPE_SCROLLBAR)
1362 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1373 if (mpos >= gpos + gi->scrollbar.position &&
1374 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1376 /* drag scrollbar */
1377 gi->scrollbar.drag_position =
1378 scrollbar_mouse_pos - gi->scrollbar.position;
1382 /* click scrollbar one scrollbar length up/left or down/right */
1384 struct GadgetScrollbar *gs = &gi->scrollbar;
1385 int old_item_position = gs->item_position;
1387 changed_position = FALSE;
1389 gs->item_position +=
1390 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
1392 if (gs->item_position < 0)
1393 gs->item_position = 0;
1394 if (gs->item_position > gs->items_max - gs->items_visible)
1395 gs->item_position = gs->items_max - gs->items_visible;
1397 if (old_item_position != gs->item_position)
1399 gi->event.item_position = gs->item_position;
1400 changed_position = TRUE;
1403 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
1406 gi->state = GD_BUTTON_UNPRESSED;
1407 gi->event.type = GD_EVENT_MOVING;
1408 gi->event.off_borders = FALSE;
1410 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
1411 gi->callback_action(gi);
1413 /* don't handle this scrollbar anymore while mouse button pressed */
1420 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1422 gi->state = GD_BUTTON_PRESSED;
1423 gi->event.type = GD_EVENT_PRESSED;
1424 gi->event.button = button;
1425 gi->event.off_borders = FALSE;
1427 /* initialize delay counter */
1428 DelayReached(&pressed_delay, 0);
1430 if (gi->event_mask & GD_EVENT_PRESSED)
1431 gi->callback_action(gi);
1434 if (gadget_pressed_repeated)
1436 gi->event.type = GD_EVENT_PRESSED;
1438 if (gi->event_mask & GD_EVENT_REPEATED &&
1439 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1440 gi->callback_action(gi);
1445 if (gi->type & GD_TYPE_BUTTON)
1447 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
1448 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1449 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
1450 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1452 else if (gi->type & GD_TYPE_SELECTBOX)
1454 int old_index = gi->selectbox.current_index;
1456 /* if mouse moving inside activated selectbox, select value */
1457 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1458 gi->selectbox.current_index =
1459 (my - gi->selectbox.y - gi->border.xsize) / getFontWidth(gi->font);
1461 if (gi->selectbox.current_index < 0)
1462 gi->selectbox.current_index = 0;
1463 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1464 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1466 if (gi->selectbox.current_index != old_index)
1467 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1469 else if (gi->type & GD_TYPE_SCROLLBAR)
1471 struct GadgetScrollbar *gs = &gi->scrollbar;
1472 int old_item_position = gs->item_position;
1474 gs->position = scrollbar_mouse_pos - gs->drag_position;
1476 if (gs->position < 0)
1478 if (gs->position > gs->position_max)
1479 gs->position = gs->position_max;
1482 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1484 if (gs->item_position < 0)
1485 gs->item_position = 0;
1486 if (gs->item_position > gs->items_max - 1)
1487 gs->item_position = gs->items_max - 1;
1489 if (old_item_position != gs->item_position)
1491 gi->event.item_position = gs->item_position;
1492 changed_position = TRUE;
1495 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1498 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1499 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1500 gi->event.type = GD_EVENT_MOVING;
1501 gi->event.off_borders = gadget_moving_off_borders;
1503 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1504 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1505 gi->callback_action(gi);
1508 if (gadget_released_inside)
1510 boolean deactivate_gadget = TRUE;
1512 if (gi->type & GD_TYPE_SELECTBOX)
1514 if (gadget_released_inside_select_line ||
1515 gadget_released_off_borders) /* selectbox stays open */
1516 deactivate_gadget = FALSE;
1518 gi->selectbox.index = gi->selectbox.current_index;
1521 if (deactivate_gadget &&
1522 !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1523 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1525 gi->state = GD_BUTTON_UNPRESSED;
1526 gi->event.type = GD_EVENT_RELEASED;
1528 if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
1529 gi->callback_action(gi);
1532 if (gadget_released_off_borders)
1534 if (gi->type & GD_TYPE_SCROLLBAR)
1535 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1537 gi->event.type = GD_EVENT_RELEASED;
1539 if (gi->event_mask & GD_EVENT_RELEASED &&
1540 gi->event_mask & GD_EVENT_OFF_BORDERS)
1541 gi->callback_action(gi);
1545 void HandleGadgetsKeyInput(Key key)
1547 struct GadgetInfo *gi = last_gi;
1549 if (gi == NULL || !gi->mapped ||
1550 !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
1553 if (key == KSYM_Return) /* valid for both text input and selectbox */
1555 if (gi->type & GD_TYPE_TEXTINPUT)
1556 CheckRangeOfNumericInputGadget(gi);
1557 else if (gi->type & GD_TYPE_SELECTBOX)
1558 gi->selectbox.index = gi->selectbox.current_index;
1560 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1562 gi->event.type = GD_EVENT_TEXT_RETURN;
1564 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1565 gi->callback_action(gi);
1569 else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */
1571 char text[MAX_GADGET_TEXTSIZE];
1572 int text_length = strlen(gi->text.value);
1573 int cursor_pos = gi->text.cursor_position;
1574 char letter = getCharFromKey(key);
1575 boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1576 letter >= '0' && letter <= '9' :
1579 if (legal_letter && text_length < gi->text.size)
1581 strcpy(text, gi->text.value);
1582 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1583 gi->text.value[cursor_pos] = letter;
1584 gi->text.cursor_position++;
1586 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1588 else if (key == KSYM_Left && cursor_pos > 0)
1590 gi->text.cursor_position--;
1591 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1593 else if (key == KSYM_Right && cursor_pos < text_length)
1595 gi->text.cursor_position++;
1596 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1598 else if (key == KSYM_BackSpace && cursor_pos > 0)
1600 strcpy(text, gi->text.value);
1601 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1602 gi->text.cursor_position--;
1603 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1605 else if (key == KSYM_Delete && cursor_pos < text_length)
1607 strcpy(text, gi->text.value);
1608 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1609 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1612 else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
1614 int index = gi->selectbox.current_index;
1615 int num_values = gi->selectbox.num_values;
1617 if (key == KSYM_Up && index > 0)
1619 gi->selectbox.current_index--;
1620 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1622 else if (key == KSYM_Down && index < num_values - 1)
1624 gi->selectbox.current_index++;
1625 DrawGadget(gi, DG_PRESSED, DG_DIRECT);