1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
22 /* values for DrawGadget() */
23 #define DG_UNPRESSED 0
28 static struct GadgetInfo *gadget_list_first_entry = NULL;
29 static struct GadgetInfo *gadget_list_last_entry = NULL;
30 static int next_free_gadget_id = 1;
31 static boolean gadget_id_wrapped = FALSE;
33 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
35 struct GadgetInfo *gi = gadget_list_first_entry;
37 while (gi && gi->id != id)
43 static int getNewGadgetID()
45 int id = next_free_gadget_id++;
47 if (next_free_gadget_id <= 0) /* counter overrun */
49 gadget_id_wrapped = TRUE; /* now we must check each ID */
50 next_free_gadget_id = 0;
53 if (gadget_id_wrapped)
55 next_free_gadget_id++;
56 while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
57 next_free_gadget_id++;
60 if (next_free_gadget_id <= 0) /* cannot get new gadget id */
61 Error(ERR_EXIT, "too much gadgets -- this should not happen");
67 void DUMP_GADGET_MAP_STATE()
69 struct GadgetInfo *gi = gadget_list_first_entry;
73 printf("-XXX-1-> '%s': %s\n",
74 gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
81 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
83 struct GadgetInfo *gi = gadget_list_first_entry;
88 ((mx >= gi->x && mx < gi->x + gi->width &&
89 my >= gi->y && my < gi->y + gi->height) ||
90 (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
91 mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
92 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height)))
101 static void default_callback_info(void *ptr)
106 static void default_callback_action(void *ptr)
111 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
113 int state = (pressed ? 1 : 0);
114 struct GadgetDesign *gd = (gi->checked ?
115 &gi->alt_design[state] :
117 boolean redraw_selectbox = FALSE;
121 case GD_TYPE_NORMAL_BUTTON:
122 case GD_TYPE_CHECK_BUTTON:
123 case GD_TYPE_RADIO_BUTTON:
124 BlitBitmapOnBackground(gd->bitmap, drawto,
125 gd->x, gd->y, gi->width, gi->height,
127 if (gi->deco.design.bitmap)
128 BlitBitmap(gi->deco.design.bitmap, drawto,
129 gi->deco.design.x, gi->deco.design.y,
130 gi->deco.width, gi->deco.height,
131 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
132 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
135 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
136 case GD_TYPE_TEXTINPUT_NUMERIC:
140 char cursor_string[3];
141 char text[MAX_GADGET_TEXTSIZE + 1];
142 int font_type = gi->text.font_type;
143 int font_width = getFontWidth(font_type);
144 int border = gi->border.size;
146 /* left part of gadget */
147 BlitBitmapOnBackground(gd->bitmap, drawto,
148 gd->x, gd->y, border, gi->height, gi->x, gi->y);
150 /* middle part of gadget */
151 for (i=0; i < gi->text.size + 1; i++)
152 BlitBitmapOnBackground(gd->bitmap, drawto,
153 gd->x + border, gd->y, font_width, gi->height,
154 gi->x + border + i * font_width, gi->y);
156 /* right part of gadget */
157 BlitBitmapOnBackground(gd->bitmap, drawto,
158 gd->x + gi->border.width - border, gd->y,border,
159 gi->height, gi->x + gi->width - border, gi->y);
162 strcpy(text, gi->text.value);
165 /* gadget text value */
167 gi->x + border, gi->y + border, text,
168 font_type, BLIT_MASKED);
170 cursor_letter = gi->text.value[gi->text.cursor_position];
171 cursor_string[0] = '~';
172 cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
173 cursor_string[2] = '\0';
175 SetInverseTextColor(gi->text.inverse_color);
177 /* draw cursor, if active */
180 gi->x + border + gi->text.cursor_position * font_width,
181 gi->y + border, cursor_string,
182 font_type, BLIT_MASKED);
186 case GD_TYPE_SELECTBOX:
189 char text[MAX_GADGET_TEXTSIZE + 1];
190 int font_type = gi->selectbox.font_type;
191 int font_width = getFontWidth(font_type);
192 int font_height = getFontHeight(font_type);
193 int border = gi->border.size;
194 int button = gi->border.size_selectbutton;
195 int width_inner = gi->border.width - button - 2 * border;
196 int box_width = gi->selectbox.width;
197 int box_height = gi->selectbox.height;
199 /* left part of gadget */
200 BlitBitmapOnBackground(gd->bitmap, drawto,
201 gd->x, gd->y, border, gi->height, gi->x, gi->y);
203 /* middle part of gadget */
204 for (i=0; i < gi->selectbox.size; i++)
205 BlitBitmapOnBackground(gd->bitmap, drawto,
206 gd->x + border, gd->y, font_width, gi->height,
207 gi->x + border + i * font_width, gi->y);
209 /* button part of gadget */
210 BlitBitmapOnBackground(gd->bitmap, drawto,
211 gd->x + border + width_inner, gd->y,
213 gi->x + gi->width - border - button, gi->y);
215 /* right part of gadget */
216 BlitBitmapOnBackground(gd->bitmap, drawto,
217 gd->x + gi->border.width - border, gd->y,border,
218 gi->height, gi->x + gi->width - border, gi->y);
221 strncpy(text, gi->selectbox.values[gi->selectbox.index],
223 text[gi->selectbox.size] = '\0';
225 /* gadget text value */
226 DrawTextExt(drawto, gi->x + border, gi->y + border, text,
227 font_type, BLIT_MASKED);
231 if (!gi->selectbox.open)
233 gi->selectbox.open = TRUE;
234 gi->selectbox.stay_open = FALSE;
235 gi->selectbox.current_index = gi->selectbox.index;
237 /* save background under selectbox */
238 BlitBitmap(drawto, gfx.field_save_buffer,
239 gi->selectbox.x, gi->selectbox.y,
240 gi->selectbox.width, gi->selectbox.height,
241 gi->selectbox.x, gi->selectbox.y);
244 /* draw open selectbox */
246 /* top left part of gadget border */
247 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
249 gi->selectbox.x, gi->selectbox.y);
251 /* top middle part of gadget border */
252 for (i=0; i < gi->selectbox.size; i++)
253 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border, gd->y,
255 gi->selectbox.x + border + i * font_width,
258 /* top button part of gadget border */
259 BlitBitmapOnBackground(gd->bitmap, drawto,
260 gd->x + border + width_inner, gd->y,
262 gi->selectbox.x + box_width - border - button,
265 /* top right part of gadget border */
266 BlitBitmapOnBackground(gd->bitmap, drawto,
267 gd->x + gi->border.width - border, gd->y,
269 gi->selectbox.x + box_width - border,
272 /* left and right part of gadget border for each row */
273 for (i=0; i < gi->selectbox.num_values; i++)
275 BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border,
278 gi->selectbox.y + border + i * font_height);
279 BlitBitmapOnBackground(gd->bitmap, drawto,
280 gd->x + gi->border.width - border,
283 gi->selectbox.x + box_width - border,
284 gi->selectbox.y + border + i * font_height);
287 /* bottom left part of gadget border */
288 BlitBitmapOnBackground(gd->bitmap, drawto,
289 gd->x, gd->y + gi->height - border,
292 gi->selectbox.y + box_height - border);
294 /* bottom middle part of gadget border */
295 for (i=0; i < gi->selectbox.size; i++)
296 BlitBitmapOnBackground(gd->bitmap, drawto,
297 gd->x + border, gd->y + gi->height - border,
299 gi->selectbox.x + border + i * font_width,
300 gi->selectbox.y + box_height - border);
302 /* bottom button part of gadget border */
303 BlitBitmapOnBackground(gd->bitmap, drawto,
304 gd->x + border + width_inner,
305 gd->y + gi->height - border,
307 gi->selectbox.x + box_width - border - button,
308 gi->selectbox.y + box_height - border);
310 /* bottom right part of gadget border */
311 BlitBitmapOnBackground(gd->bitmap, drawto,
312 gd->x + gi->border.width - border,
313 gd->y + gi->height - border,
315 gi->selectbox.x + box_width - border,
316 gi->selectbox.y + box_height - border);
318 ClearRectangleOnBackground(drawto,
319 gi->selectbox.x + border,
320 gi->selectbox.y + border,
321 gi->selectbox.width - 2 * border,
322 gi->selectbox.height - 2 * border);
324 /* selectbox text values */
325 for (i=0; i < gi->selectbox.num_values; i++)
327 if (i == gi->selectbox.current_index)
329 FillRectangle(drawto,
330 gi->selectbox.x + border,
331 gi->selectbox.y + border + i * font_height,
332 gi->selectbox.width - 2 * border, font_height,
333 gi->selectbox.inverse_color);
336 strncpy(&text[1], gi->selectbox.values[i], gi->selectbox.size);
337 text[1 + gi->selectbox.size] = '\0';
339 SetInverseTextColor(gi->selectbox.inverse_color);
343 strncpy(text, gi->selectbox.values[i], gi->selectbox.size);
344 text[gi->selectbox.size] = '\0';
348 gi->selectbox.x + border,
349 gi->selectbox.y + border + i * font_height, text,
350 font_type, BLIT_MASKED);
353 redraw_selectbox = TRUE;
355 else if (gi->selectbox.open)
357 gi->selectbox.open = FALSE;
359 /* redraw closed selectbox */
360 DrawGadget(gi, FALSE, FALSE);
362 /* restore background under selectbox */
363 BlitBitmap(gfx.field_save_buffer, drawto,
364 gi->selectbox.x, gi->selectbox.y,
365 gi->selectbox.width, gi->selectbox.height,
366 gi->selectbox.x, gi->selectbox.y);
368 redraw_selectbox = TRUE;
373 case GD_TYPE_SCROLLBAR_VERTICAL:
377 int ypos = gi->y + gi->scrollbar.position;
378 int design_full = gi->width;
379 int design_body = design_full - 2 * gi->border.size;
380 int size_full = gi->scrollbar.size;
381 int size_body = size_full - 2 * gi->border.size;
382 int num_steps = size_body / design_body;
383 int step_size_remain = size_body - num_steps * design_body;
385 /* clear scrollbar area */
386 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
387 gi->width, gi->height);
389 /* upper part of gadget */
390 BlitBitmapOnBackground(gd->bitmap, drawto,
392 gi->width, gi->border.size,
395 /* middle part of gadget */
396 for (i=0; i<num_steps; i++)
397 BlitBitmapOnBackground(gd->bitmap, drawto,
398 gd->x, gd->y + gi->border.size,
399 gi->width, design_body,
401 ypos + gi->border.size + i * design_body);
403 /* remaining middle part of gadget */
404 if (step_size_remain > 0)
405 BlitBitmapOnBackground(gd->bitmap, drawto,
406 gd->x, gd->y + gi->border.size,
407 gi->width, step_size_remain,
409 ypos + gi->border.size
410 + num_steps * design_body);
412 /* lower part of gadget */
413 BlitBitmapOnBackground(gd->bitmap, drawto,
414 gd->x, gd->y + design_full - gi->border.size,
415 gi->width, gi->border.size,
416 xpos, ypos + size_full - gi->border.size);
420 case GD_TYPE_SCROLLBAR_HORIZONTAL:
423 int xpos = gi->x + gi->scrollbar.position;
425 int design_full = gi->height;
426 int design_body = design_full - 2 * gi->border.size;
427 int size_full = gi->scrollbar.size;
428 int size_body = size_full - 2 * gi->border.size;
429 int num_steps = size_body / design_body;
430 int step_size_remain = size_body - num_steps * design_body;
432 /* clear scrollbar area */
433 ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
434 gi->width, gi->height);
436 /* left part of gadget */
437 BlitBitmapOnBackground(gd->bitmap, drawto,
439 gi->border.size, gi->height,
442 /* middle part of gadget */
443 for (i=0; i<num_steps; i++)
444 BlitBitmapOnBackground(gd->bitmap, drawto,
445 gd->x + gi->border.size, gd->y,
446 design_body, gi->height,
447 xpos + gi->border.size + i * design_body,
450 /* remaining middle part of gadget */
451 if (step_size_remain > 0)
452 BlitBitmapOnBackground(gd->bitmap, drawto,
453 gd->x + gi->border.size, gd->y,
454 step_size_remain, gi->height,
455 xpos + gi->border.size
456 + num_steps * design_body,
459 /* right part of gadget */
460 BlitBitmapOnBackground(gd->bitmap, drawto,
461 gd->x + design_full - gi->border.size, gd->y,
462 gi->border.size, gi->height,
463 xpos + size_full - gi->border.size, ypos);
473 BlitBitmap(drawto, window,
474 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
476 if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
477 BlitBitmap(drawto, window,
478 gi->selectbox.x, gi->selectbox.y,
479 gi->selectbox.width, gi->selectbox.height,
480 gi->selectbox.x, gi->selectbox.y);
483 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
484 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
485 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
488 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
492 while (tag != GDI_END)
497 gi->custom_id = va_arg(ap, int);
500 case GDI_CUSTOM_TYPE_ID:
501 gi->custom_type_id = va_arg(ap, int);
506 int max_textsize = MAX_INFO_TEXTSIZE - 1;
507 char *text = va_arg(ap, char *);
510 strncpy(gi->info_text, text, max_textsize);
514 gi->info_text[max_textsize] = '\0';
519 gi->x = va_arg(ap, int);
523 gi->y = va_arg(ap, int);
527 gi->width = va_arg(ap, int);
531 gi->height = va_arg(ap, int);
535 gi->type = va_arg(ap, unsigned long);
539 gi->state = va_arg(ap, unsigned long);
543 /* take care here: "boolean" is typedef'ed as "unsigned char",
544 which gets promoted to "int" */
545 gi->checked = (boolean)va_arg(ap, int);
549 gi->radio_nr = va_arg(ap, unsigned long);
552 case GDI_NUMBER_VALUE:
553 gi->text.number_value = va_arg(ap, long);
554 sprintf(gi->text.value, "%d", gi->text.number_value);
555 gi->text.cursor_position = strlen(gi->text.value);
559 gi->text.number_min = va_arg(ap, long);
560 if (gi->text.number_value < gi->text.number_min)
562 gi->text.number_value = gi->text.number_min;
563 sprintf(gi->text.value, "%d", gi->text.number_value);
568 gi->text.number_max = va_arg(ap, long);
569 if (gi->text.number_value > gi->text.number_max)
571 gi->text.number_value = gi->text.number_max;
572 sprintf(gi->text.value, "%d", gi->text.number_value);
578 int max_textsize = MAX_GADGET_TEXTSIZE;
581 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
583 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
584 gi->text.value[max_textsize] = '\0';
585 gi->text.cursor_position = strlen(gi->text.value);
591 int tag_value = va_arg(ap, int);
592 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
594 gi->text.size = max_textsize;
595 gi->text.value[max_textsize] = '\0';
597 /* same tag also used for selectbox definition */
598 gi->selectbox.size = gi->text.size;
603 gi->text.font_type = va_arg(ap, int);
605 /* same tag also used for selectbox definition */
606 gi->selectbox.font_type = gi->text.font_type;
609 case GDI_SELECTBOX_VALUES:
610 gi->selectbox.values = va_arg(ap, const char **);
613 case GDI_SELECTBOX_INDEX:
614 gi->selectbox.index = va_arg(ap, int);
617 case GDI_DESIGN_UNPRESSED:
618 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
619 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
620 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
623 case GDI_DESIGN_PRESSED:
624 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
625 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
626 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
629 case GDI_ALT_DESIGN_UNPRESSED:
630 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
631 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
632 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
635 case GDI_ALT_DESIGN_PRESSED:
636 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap *);
637 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
638 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
641 case GDI_BORDER_SIZE:
642 gi->border.size = va_arg(ap, int);
645 case GDI_BORDER_SIZE_SELECTBUTTON:
646 gi->border.size_selectbutton = va_arg(ap, int);
649 case GDI_TEXTINPUT_DESIGN_WIDTH:
650 gi->border.width = va_arg(ap, int);
653 case GDI_DECORATION_DESIGN:
654 gi->deco.design.bitmap = va_arg(ap, Bitmap *);
655 gi->deco.design.x = va_arg(ap, int);
656 gi->deco.design.y = va_arg(ap, int);
659 case GDI_DECORATION_POSITION:
660 gi->deco.x = va_arg(ap, int);
661 gi->deco.y = va_arg(ap, int);
664 case GDI_DECORATION_SIZE:
665 gi->deco.width = va_arg(ap, int);
666 gi->deco.height = va_arg(ap, int);
669 case GDI_DECORATION_SHIFTING:
670 gi->deco.xshift = va_arg(ap, int);
671 gi->deco.yshift = va_arg(ap, int);
675 gi->event_mask = va_arg(ap, unsigned long);
679 gi->drawing.area_xsize = va_arg(ap, int);
680 gi->drawing.area_ysize = va_arg(ap, int);
682 /* determine dependent values for drawing area gadget, if needed */
683 if (gi->width == 0 && gi->height == 0 &&
684 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
686 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
687 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
689 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
690 gi->width != 0 && gi->height != 0)
692 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
693 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
698 gi->drawing.item_xsize = va_arg(ap, int);
699 gi->drawing.item_ysize = va_arg(ap, int);
701 /* determine dependent values for drawing area gadget, if needed */
702 if (gi->width == 0 && gi->height == 0 &&
703 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
705 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
706 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
708 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
709 gi->width != 0 && gi->height != 0)
711 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
712 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
716 case GDI_SCROLLBAR_ITEMS_MAX:
717 gi->scrollbar.items_max = va_arg(ap, int);
720 case GDI_SCROLLBAR_ITEMS_VISIBLE:
721 gi->scrollbar.items_visible = va_arg(ap, int);
724 case GDI_SCROLLBAR_ITEM_POSITION:
725 gi->scrollbar.item_position = va_arg(ap, int);
728 case GDI_CALLBACK_INFO:
729 gi->callback_info = va_arg(ap, gadget_function);
732 case GDI_CALLBACK_ACTION:
733 gi->callback_action = va_arg(ap, gadget_function);
737 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
740 tag = va_arg(ap, int); /* read next tag */
743 /* check if gadget is complete */
744 if (gi->type != GD_TYPE_DRAWING_AREA &&
745 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
746 !gi->design[GD_BUTTON_PRESSED].bitmap))
747 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
749 /* adjust gadget values in relation to other gadget values */
751 if (gi->type & GD_TYPE_TEXTINPUT)
753 int font_nr = gi->text.font_type;
754 int font_bitmap_id = gfx.select_font_function(font_nr);
755 struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
756 int font_width = getFontWidth(font_nr);
757 int font_height = getFontHeight(font_nr);
758 int border_size = gi->border.size;
761 gi->width = 2 * border_size + (gi->text.size + 1) * font_width;
762 gi->height = 2 * border_size + font_height;
764 if (!getFontChar(font_nr, '|', &src_x, &src_y))
765 Error(ERR_EXIT, "text input gadget incomplete (cannot get cursor)");
767 src_x += font_width / 2;
768 src_y += font_height / 2;
769 gi->text.inverse_color = GetPixel(font->bitmap, src_x, src_y);
772 if (gi->type & GD_TYPE_SELECTBOX)
774 int font_nr = gi->selectbox.font_type;
775 int font_bitmap_id = gfx.select_font_function(font_nr);
776 struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
777 int font_width = getFontWidth(font_nr);
778 int font_height = getFontHeight(font_nr);
779 int border_size = gi->border.size;
780 int button_size = gi->border.size_selectbutton;
783 gi->width = 2 * border_size + gi->text.size * font_width + button_size;
784 gi->height = 2 * border_size + font_height;
786 if (gi->selectbox.values == NULL)
787 Error(ERR_EXIT, "selectbox gadget incomplete (missing values array)");
789 gi->selectbox.num_values = 0;
790 while (gi->selectbox.values[gi->selectbox.num_values] != NULL)
791 gi->selectbox.num_values++;
793 /* calculate values for open selectbox */
794 gi->selectbox.width = gi->width;
795 gi->selectbox.height =
796 2 * border_size + gi->selectbox.num_values * font_height;
798 gi->selectbox.x = gi->x;
799 gi->selectbox.y = gi->y + gi->height;
800 if (gi->selectbox.y + gi->selectbox.height > gfx.real_sy + gfx.full_sysize)
801 gi->selectbox.y = gi->y - gi->selectbox.height;
802 if (gi->selectbox.y < 0)
803 gi->selectbox.y = gfx.real_sy + gfx.full_sysize - gi->selectbox.height;
805 if (!getFontChar(font_nr, '|', &src_x, &src_y))
806 Error(ERR_EXIT, "selectbox gadget incomplete (cannot get cursor)");
808 src_x += font_width / 2;
809 src_y += font_height / 2;
810 gi->selectbox.inverse_color = GetPixel(font->bitmap, src_x, src_y);
812 /* always start with closed selectbox */
813 gi->selectbox.open = FALSE;
816 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
818 struct GadgetTextInput *text = &gi->text;
819 int value = text->number_value;
821 text->number_value = (value < text->number_min ? text->number_min :
822 value > text->number_max ? text->number_max :
825 sprintf(text->value, "%d", text->number_value);
828 if (gi->type & GD_TYPE_SCROLLBAR)
830 struct GadgetScrollbar *gs = &gi->scrollbar;
832 if (gi->width == 0 || gi->height == 0 ||
833 gs->items_max == 0 || gs->items_visible == 0)
834 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
836 /* calculate internal scrollbar values */
837 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
838 gi->height : gi->width);
839 gs->size = gs->size_max * gs->items_visible / gs->items_max;
840 gs->position = gs->size_max * gs->item_position / gs->items_max;
841 gs->position_max = gs->size_max - gs->size;
842 gs->correction = gs->size_max / gs->items_max / 2;
844 /* finetuning for maximal right/bottom position */
845 if (gs->item_position == gs->items_max - gs->items_visible)
846 gs->position = gs->position_max;
850 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
854 va_start(ap, first_tag);
855 HandleGadgetTags(gi, first_tag, ap);
861 void RedrawGadget(struct GadgetInfo *gi)
864 DrawGadget(gi, gi->state, DG_DIRECT);
867 struct GadgetInfo *CreateGadget(int first_tag, ...)
869 struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
872 /* always start with reliable default values */
873 new_gadget->id = getNewGadgetID();
874 new_gadget->callback_info = default_callback_info;
875 new_gadget->callback_action = default_callback_action;
876 new_gadget->next = NULL;
878 va_start(ap, first_tag);
879 HandleGadgetTags(new_gadget, first_tag, ap);
882 /* insert new gadget into global gadget list */
883 if (gadget_list_last_entry)
885 gadget_list_last_entry->next = new_gadget;
886 gadget_list_last_entry = gadget_list_last_entry->next;
889 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
894 void FreeGadget(struct GadgetInfo *gi)
896 struct GadgetInfo *gi_previous = gadget_list_first_entry;
898 while (gi_previous != NULL && gi_previous->next != gi)
899 gi_previous = gi_previous->next;
901 if (gi == gadget_list_first_entry)
902 gadget_list_first_entry = gi->next;
904 if (gi == gadget_list_last_entry)
905 gadget_list_last_entry = gi_previous;
907 if (gi_previous != NULL)
908 gi_previous->next = gi->next;
913 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
915 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
918 gi->text.number_value = atoi(gi->text.value);
920 if (gi->text.number_value < gi->text.number_min)
921 gi->text.number_value = gi->text.number_min;
922 if (gi->text.number_value > gi->text.number_max)
923 gi->text.number_value = gi->text.number_max;
925 sprintf(gi->text.value, "%d", gi->text.number_value);
927 if (gi->text.cursor_position < 0)
928 gi->text.cursor_position = 0;
929 else if (gi->text.cursor_position > strlen(gi->text.value))
930 gi->text.cursor_position = strlen(gi->text.value);
933 /* global pointer to gadget actually in use (when mouse button pressed) */
934 static struct GadgetInfo *last_gi = NULL;
936 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
938 if (gi == NULL || gi->mapped)
944 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
947 void MapGadget(struct GadgetInfo *gi)
949 MapGadgetExt(gi, TRUE);
952 void UnmapGadget(struct GadgetInfo *gi)
954 if (gi == NULL || !gi->mapped)
963 #define MAX_NUM_GADGETS 1024
964 #define MULTIMAP_UNMAP (1 << 0)
965 #define MULTIMAP_REMAP (1 << 1)
966 #define MULTIMAP_REDRAW (1 << 2)
967 #define MULTIMAP_PLAYFIELD (1 << 3)
968 #define MULTIMAP_DOOR_1 (1 << 4)
969 #define MULTIMAP_DOOR_2 (1 << 5)
970 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
974 static void MultiMapGadgets(int mode)
976 struct GadgetInfo *gi = gadget_list_first_entry;
977 static boolean map_state[MAX_NUM_GADGETS];
982 if ((mode & MULTIMAP_PLAYFIELD &&
983 gi->x < gfx.sx + gfx.sxsize) ||
984 (mode & MULTIMAP_DOOR_1 &&
985 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
986 (mode & MULTIMAP_DOOR_2 &&
987 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
988 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
990 if (mode & MULTIMAP_UNMAP)
992 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
997 if (map_state[map_count++ % MAX_NUM_GADGETS])
998 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
1006 void UnmapAllGadgets()
1008 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
1011 void RemapAllGadgets()
1013 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
1016 boolean anyTextInputGadgetActive()
1018 return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
1021 boolean anySelectboxGadgetActive()
1023 return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
1026 boolean anyTextGadgetActive()
1028 return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
1031 void ClickOnGadget(struct GadgetInfo *gi, int button)
1033 /* simulate releasing mouse button over last gadget, if still pressed */
1035 HandleGadgets(-1, -1, 0);
1037 /* simulate pressing mouse button over specified gadget */
1038 HandleGadgets(gi->x, gi->y, button);
1040 /* simulate releasing mouse button over specified gadget */
1041 HandleGadgets(gi->x, gi->y, 0);
1044 void HandleGadgets(int mx, int my, int button)
1046 static struct GadgetInfo *last_info_gi = NULL;
1047 static unsigned long pressed_delay = 0;
1048 static int last_button = 0;
1049 static int last_mx = 0, last_my = 0;
1050 int scrollbar_mouse_pos = 0;
1051 struct GadgetInfo *new_gi, *gi;
1052 boolean press_event;
1053 boolean release_event;
1054 boolean mouse_moving;
1055 boolean gadget_pressed;
1056 boolean gadget_pressed_repeated;
1057 boolean gadget_moving;
1058 boolean gadget_moving_inside;
1059 boolean gadget_moving_off_borders;
1060 boolean gadget_released;
1061 boolean gadget_released_inside;
1062 boolean gadget_released_inside_select_line;
1063 boolean gadget_released_inside_select_area;
1064 boolean gadget_released_off_borders;
1065 boolean changed_position = FALSE;
1067 /* check if there are any gadgets defined */
1068 if (gadget_list_first_entry == NULL)
1071 /* check which gadget is under the mouse pointer */
1072 new_gi = getGadgetInfoFromMousePosition(mx, my);
1074 /* check if button state has changed since last invocation */
1075 press_event = (button != 0 && last_button == 0);
1076 release_event = (button == 0 && last_button != 0);
1077 last_button = button;
1079 /* check if mouse has been moved since last invocation */
1080 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
1084 /* special treatment for text and number input gadgets */
1085 if (anyTextInputGadgetActive() && button != 0 && !motion_status)
1087 struct GadgetInfo *gi = last_gi;
1089 if (new_gi == last_gi)
1091 int old_cursor_position = gi->text.cursor_position;
1093 /* if mouse button pressed inside activated text gadget, set cursor */
1094 gi->text.cursor_position =
1095 (mx - gi->x - gi->border.size) / getFontWidth(gi->text.font_type);
1097 if (gi->text.cursor_position < 0)
1098 gi->text.cursor_position = 0;
1099 else if (gi->text.cursor_position > strlen(gi->text.value))
1100 gi->text.cursor_position = strlen(gi->text.value);
1102 if (gi->text.cursor_position != old_cursor_position)
1103 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1107 /* if mouse button pressed outside text input gadget, deactivate it */
1108 CheckRangeOfNumericInputGadget(gi);
1109 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1111 gi->event.type = GD_EVENT_TEXT_LEAVING;
1113 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1114 gi->callback_action(gi);
1120 /* special treatment for selectbox gadgets */
1121 if (anySelectboxGadgetActive() && button != 0 && !motion_status)
1123 struct GadgetInfo *gi = last_gi;
1125 if (new_gi == last_gi)
1127 int old_index = gi->selectbox.current_index;
1129 /* if mouse button pressed inside activated selectbox, select value */
1130 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1131 gi->selectbox.current_index =
1132 (my - gi->selectbox.y - gi->border.size) /
1133 getFontWidth(gi->selectbox.font_type);
1135 if (gi->selectbox.current_index < 0)
1136 gi->selectbox.current_index = 0;
1137 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1138 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1140 if (gi->selectbox.current_index != old_index)
1141 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1145 /* if mouse button pressed outside selectbox gadget, deactivate it */
1146 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1148 gi->event.type = GD_EVENT_TEXT_LEAVING;
1150 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
1151 gi->callback_action(gi);
1158 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
1159 gadget_pressed_repeated =
1160 (button != 0 && last_gi != NULL && new_gi == last_gi);
1162 gadget_released = (release_event && last_gi != NULL);
1163 gadget_released_inside = (gadget_released && new_gi == last_gi);
1164 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
1166 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
1167 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
1168 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
1170 /* when handling selectbox, set additional state values */
1171 if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
1173 struct GadgetInfo *gi = last_gi;
1175 gadget_released_inside_select_line =
1176 (mx >= gi->x && mx < gi->x + gi->width &&
1177 my >= gi->y && my < gi->y + gi->height);
1178 gadget_released_inside_select_area =
1179 (mx >= gi->selectbox.x && mx < gi->selectbox.x+gi->selectbox.width &&
1180 my >= gi->selectbox.y && my < gi->selectbox.y+gi->selectbox.height);
1184 gadget_released_inside_select_line = FALSE;
1185 gadget_released_inside_select_area = FALSE;
1188 /* if new gadget pressed, store this gadget */
1192 /* 'gi' is actually handled gadget */
1195 /* if gadget is scrollbar, choose mouse position value */
1196 if (gi && gi->type & GD_TYPE_SCROLLBAR)
1197 scrollbar_mouse_pos =
1198 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
1200 /* if mouse button released, no gadget needs to be handled anymore */
1201 if (gadget_released)
1203 if ((last_gi->type & GD_TYPE_SELECTBOX) &&
1204 (gadget_released_inside_select_line ||
1205 gadget_released_off_borders)) /* selectbox stays open */
1206 gi->selectbox.stay_open = TRUE;
1207 else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1211 /* modify event position values even if no gadget is pressed */
1212 if (button == 0 && !release_event)
1217 int last_x = gi->event.x;
1218 int last_y = gi->event.y;
1220 gi->event.x = mx - gi->x;
1221 gi->event.y = my - gi->y;
1223 if (gi->type == GD_TYPE_DRAWING_AREA)
1225 gi->event.x /= gi->drawing.item_xsize;
1226 gi->event.y /= gi->drawing.item_ysize;
1228 if (last_x != gi->event.x || last_y != gi->event.y)
1229 changed_position = TRUE;
1231 else if (gi->type & GD_TYPE_SELECTBOX)
1233 int old_index = gi->selectbox.current_index;
1235 /* if mouse moving inside activated selectbox, select value */
1236 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1237 gi->selectbox.current_index =
1238 (my - gi->selectbox.y - gi->border.size) /
1239 getFontWidth(gi->selectbox.font_type);
1241 if (gi->selectbox.current_index < 0)
1242 gi->selectbox.current_index = 0;
1243 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1244 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1246 if (gi->selectbox.current_index != old_index)
1247 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1251 /* handle gadget popup info text */
1252 if (last_info_gi != new_gi ||
1253 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
1255 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
1257 new_gi->event.type = GD_EVENT_INFO_ENTERING;
1258 new_gi->callback_info(new_gi);
1260 else if (last_info_gi != NULL)
1262 last_info_gi->event.type = GD_EVENT_INFO_LEAVING;
1263 last_info_gi->callback_info(last_info_gi);
1266 default_callback_info(NULL);
1268 printf("It seems that we are leaving gadget [%s]!\n",
1269 (last_info_gi != NULL &&
1270 last_info_gi->info_text != NULL ?
1271 last_info_gi->info_text : ""));
1275 last_info_gi = new_gi;
1280 if (gi->type == GD_TYPE_CHECK_BUTTON)
1282 gi->checked = !gi->checked;
1284 else if (gi->type == GD_TYPE_RADIO_BUTTON)
1286 struct GadgetInfo *rgi = gadget_list_first_entry;
1291 rgi->type == GD_TYPE_RADIO_BUTTON &&
1292 rgi->radio_nr == gi->radio_nr &&
1295 rgi->checked = FALSE;
1296 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
1304 else if (gi->type & GD_TYPE_SCROLLBAR)
1308 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1319 if (mpos >= gpos + gi->scrollbar.position &&
1320 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
1322 /* drag scrollbar */
1323 gi->scrollbar.drag_position =
1324 scrollbar_mouse_pos - gi->scrollbar.position;
1328 /* click scrollbar one scrollbar length up/left or down/right */
1330 struct GadgetScrollbar *gs = &gi->scrollbar;
1331 int old_item_position = gs->item_position;
1333 changed_position = FALSE;
1335 gs->item_position +=
1336 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
1338 if (gs->item_position < 0)
1339 gs->item_position = 0;
1340 if (gs->item_position > gs->items_max - gs->items_visible)
1341 gs->item_position = gs->items_max - gs->items_visible;
1343 if (old_item_position != gs->item_position)
1345 gi->event.item_position = gs->item_position;
1346 changed_position = TRUE;
1349 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
1352 gi->state = GD_BUTTON_UNPRESSED;
1353 gi->event.type = GD_EVENT_MOVING;
1354 gi->event.off_borders = FALSE;
1356 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
1357 gi->callback_action(gi);
1359 /* don't handle this scrollbar anymore while mouse button pressed */
1366 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1368 gi->state = GD_BUTTON_PRESSED;
1369 gi->event.type = GD_EVENT_PRESSED;
1370 gi->event.button = button;
1371 gi->event.off_borders = FALSE;
1373 /* initialize delay counter */
1374 DelayReached(&pressed_delay, 0);
1376 if (gi->event_mask & GD_EVENT_PRESSED)
1377 gi->callback_action(gi);
1380 if (gadget_pressed_repeated)
1382 gi->event.type = GD_EVENT_PRESSED;
1384 if (gi->event_mask & GD_EVENT_REPEATED &&
1385 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
1386 gi->callback_action(gi);
1391 if (gi->type & GD_TYPE_BUTTON)
1393 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
1394 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1395 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
1396 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1398 else if (gi->type & GD_TYPE_SELECTBOX)
1400 int old_index = gi->selectbox.current_index;
1402 /* if mouse moving inside activated selectbox, select value */
1403 if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
1404 gi->selectbox.current_index =
1405 (my - gi->selectbox.y - gi->border.size) /
1406 getFontWidth(gi->selectbox.font_type);
1408 if (gi->selectbox.current_index < 0)
1409 gi->selectbox.current_index = 0;
1410 else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
1411 gi->selectbox.current_index = gi->selectbox.num_values - 1;
1413 if (gi->selectbox.current_index != old_index)
1414 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1416 else if (gi->type & GD_TYPE_SCROLLBAR)
1418 struct GadgetScrollbar *gs = &gi->scrollbar;
1419 int old_item_position = gs->item_position;
1421 gs->position = scrollbar_mouse_pos - gs->drag_position;
1423 if (gs->position < 0)
1425 if (gs->position > gs->position_max)
1426 gs->position = gs->position_max;
1429 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1431 if (gs->item_position < 0)
1432 gs->item_position = 0;
1433 if (gs->item_position > gs->items_max - 1)
1434 gs->item_position = gs->items_max - 1;
1436 if (old_item_position != gs->item_position)
1438 gi->event.item_position = gs->item_position;
1439 changed_position = TRUE;
1442 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1445 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1446 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1447 gi->event.type = GD_EVENT_MOVING;
1448 gi->event.off_borders = gadget_moving_off_borders;
1450 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1451 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1452 gi->callback_action(gi);
1455 if (gadget_released_inside)
1457 boolean deactivate_gadget = TRUE;
1459 if (gi->type & GD_TYPE_SELECTBOX)
1461 if (gadget_released_inside_select_line ||
1462 gadget_released_off_borders) /* selectbox stays open */
1463 deactivate_gadget = FALSE;
1465 gi->selectbox.index = gi->selectbox.current_index;
1468 if (deactivate_gadget &&
1469 !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
1470 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1472 gi->state = GD_BUTTON_UNPRESSED;
1473 gi->event.type = GD_EVENT_RELEASED;
1475 if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
1476 gi->callback_action(gi);
1479 if (gadget_released_off_borders)
1481 if (gi->type & GD_TYPE_SCROLLBAR)
1482 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1484 gi->event.type = GD_EVENT_RELEASED;
1486 if (gi->event_mask & GD_EVENT_RELEASED &&
1487 gi->event_mask & GD_EVENT_OFF_BORDERS)
1488 gi->callback_action(gi);
1492 void HandleGadgetsKeyInput(Key key)
1494 struct GadgetInfo *gi = last_gi;
1496 if (gi == NULL || !gi->mapped ||
1497 !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
1500 if (key == KSYM_Return) /* valid for both text input and selectbox */
1502 if (gi->type & GD_TYPE_TEXTINPUT)
1503 CheckRangeOfNumericInputGadget(gi);
1504 else if (gi->type & GD_TYPE_SELECTBOX)
1505 gi->selectbox.index = gi->selectbox.current_index;
1507 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1509 gi->event.type = GD_EVENT_TEXT_RETURN;
1511 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1512 gi->callback_action(gi);
1516 else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */
1518 char text[MAX_GADGET_TEXTSIZE];
1519 int text_length = strlen(gi->text.value);
1520 int cursor_pos = gi->text.cursor_position;
1521 char letter = getCharFromKey(key);
1522 boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1523 letter >= '0' && letter <= '9' :
1526 if (legal_letter && text_length < gi->text.size)
1528 strcpy(text, gi->text.value);
1529 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1530 gi->text.value[cursor_pos] = letter;
1531 gi->text.cursor_position++;
1533 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1535 else if (key == KSYM_Left && cursor_pos > 0)
1537 gi->text.cursor_position--;
1538 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1540 else if (key == KSYM_Right && cursor_pos < text_length)
1542 gi->text.cursor_position++;
1543 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1545 else if (key == KSYM_BackSpace && cursor_pos > 0)
1547 strcpy(text, gi->text.value);
1548 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1549 gi->text.cursor_position--;
1550 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1552 else if (key == KSYM_Delete && cursor_pos < text_length)
1554 strcpy(text, gi->text.value);
1555 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1556 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1559 else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
1561 int index = gi->selectbox.current_index;
1562 int num_values = gi->selectbox.num_values;
1564 if (key == KSYM_Up && index > 0)
1566 gi->selectbox.current_index--;
1567 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1569 else if (key == KSYM_Down && index < num_values - 1)
1571 gi->selectbox.current_index++;
1572 DrawGadget(gi, DG_PRESSED, DG_DIRECT);