1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
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");
66 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
68 struct GadgetInfo *gi = gadget_list_first_entry;
73 mx >= gi->x && mx < gi->x + gi->width &&
74 my >= gi->y && my < gi->y + gi->height)
83 static void default_callback_info(void *ptr)
86 if (game_status == LEVELED)
87 HandleEditorGadgetInfoText(ptr);
93 static void default_callback_action(void *ptr)
98 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
100 int state = (pressed ? 1 : 0);
101 struct GadgetDesign *gd = (gi->checked ?
102 &gi->alt_design[state] :
107 case GD_TYPE_NORMAL_BUTTON:
108 case GD_TYPE_CHECK_BUTTON:
109 case GD_TYPE_RADIO_BUTTON:
110 BlitBitmap(gd->bitmap, drawto,
111 gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
112 if (gi->deco.design.bitmap)
113 BlitBitmap(gi->deco.design.bitmap, drawto,
114 gi->deco.design.x, gi->deco.design.y,
115 gi->deco.width, gi->deco.height,
116 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
117 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
120 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
121 case GD_TYPE_TEXTINPUT_NUMERIC:
125 char cursor_string[3];
126 char text[MAX_GADGET_TEXTSIZE + 1];
127 int font_type = gi->text.font_type;
128 int font_width = getFontWidth(FS_SMALL, font_type);
129 int border = gi->border.size;
130 strcpy(text, gi->text.value);
133 /* left part of gadget */
134 BlitBitmap(gd->bitmap, drawto,
135 gd->x, gd->y, border, gi->height, gi->x, gi->y);
137 /* middle part of gadget */
138 for (i=0; i<=gi->text.size; i++)
139 BlitBitmap(gd->bitmap, drawto,
140 gd->x + border, gd->y, font_width, gi->height,
141 gi->x + border + i * font_width, gi->y);
143 /* right part of gadget */
144 BlitBitmap(gd->bitmap, drawto,
145 gd->x + gi->border.width - border, gd->y,
146 border, gi->height, gi->x + gi->width - border, gi->y);
148 /* gadget text value */
149 DrawText(gi->x + border, gi->y + border, text, FS_SMALL, font_type);
151 cursor_letter = gi->text.value[gi->text.cursor_position];
152 cursor_string[0] = '~';
153 cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
154 cursor_string[2] = '\0';
156 /* draw cursor, if active */
158 DrawText(gi->x + border + gi->text.cursor_position * font_width,
159 gi->y + border, cursor_string, FS_SMALL, font_type);
163 case GD_TYPE_SCROLLBAR_VERTICAL:
167 int ypos = gi->y + gi->scrollbar.position;
168 int design_full = gi->width;
169 int design_body = design_full - 2 * gi->border.size;
170 int size_full = gi->scrollbar.size;
171 int size_body = size_full - 2 * gi->border.size;
172 int num_steps = size_body / design_body;
173 int step_size_remain = size_body - num_steps * design_body;
175 /* clear scrollbar area */
176 ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
178 /* upper part of gadget */
179 BlitBitmap(gd->bitmap, drawto,
181 gi->width, gi->border.size,
184 /* middle part of gadget */
185 for (i=0; i<num_steps; i++)
186 BlitBitmap(gd->bitmap, drawto,
187 gd->x, gd->y + gi->border.size,
188 gi->width, design_body,
189 xpos, ypos + gi->border.size + i * design_body);
191 /* remaining middle part of gadget */
192 if (step_size_remain > 0)
193 BlitBitmap(gd->bitmap, drawto,
194 gd->x, gd->y + gi->border.size,
195 gi->width, step_size_remain,
196 xpos, ypos + gi->border.size + num_steps * design_body);
198 /* lower part of gadget */
199 BlitBitmap(gd->bitmap, drawto,
200 gd->x, gd->y + design_full - gi->border.size,
201 gi->width, gi->border.size,
202 xpos, ypos + size_full - gi->border.size);
206 case GD_TYPE_SCROLLBAR_HORIZONTAL:
209 int xpos = gi->x + gi->scrollbar.position;
211 int design_full = gi->height;
212 int design_body = design_full - 2 * gi->border.size;
213 int size_full = gi->scrollbar.size;
214 int size_body = size_full - 2 * gi->border.size;
215 int num_steps = size_body / design_body;
216 int step_size_remain = size_body - num_steps * design_body;
218 /* clear scrollbar area */
219 ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
221 /* left part of gadget */
222 BlitBitmap(gd->bitmap, drawto,
224 gi->border.size, gi->height,
227 /* middle part of gadget */
228 for (i=0; i<num_steps; i++)
229 BlitBitmap(gd->bitmap, drawto,
230 gd->x + gi->border.size, gd->y,
231 design_body, gi->height,
232 xpos + gi->border.size + i * design_body, ypos);
234 /* remaining middle part of gadget */
235 if (step_size_remain > 0)
236 BlitBitmap(gd->bitmap, drawto,
237 gd->x + gi->border.size, gd->y,
238 step_size_remain, gi->height,
239 xpos + gi->border.size + num_steps * design_body, ypos);
241 /* right part of gadget */
242 BlitBitmap(gd->bitmap, drawto,
243 gd->x + design_full - gi->border.size, gd->y,
244 gi->border.size, gi->height,
245 xpos + size_full - gi->border.size, ypos);
254 BlitBitmap(drawto, window,
255 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
257 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
258 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
259 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
262 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
266 while (tag != GDI_END)
271 gi->custom_id = va_arg(ap, int);
274 case GDI_CUSTOM_TYPE_ID:
275 gi->custom_type_id = va_arg(ap, int);
280 int max_textsize = MAX_INFO_TEXTSIZE - 1;
282 strncpy(gi->info_text, va_arg(ap, char *), max_textsize);
283 gi->info_text[max_textsize] = '\0';
288 gi->x = va_arg(ap, int);
292 gi->y = va_arg(ap, int);
296 gi->width = va_arg(ap, int);
300 gi->height = va_arg(ap, int);
304 gi->type = va_arg(ap, unsigned long);
308 gi->state = va_arg(ap, unsigned long);
312 gi->checked = va_arg(ap, boolean);
316 gi->radio_nr = va_arg(ap, unsigned long);
319 case GDI_NUMBER_VALUE:
320 gi->text.number_value = va_arg(ap, long);
321 sprintf(gi->text.value, "%d", gi->text.number_value);
322 gi->text.cursor_position = strlen(gi->text.value);
326 gi->text.number_min = va_arg(ap, long);
327 if (gi->text.number_value < gi->text.number_min)
329 gi->text.number_value = gi->text.number_min;
330 sprintf(gi->text.value, "%d", gi->text.number_value);
335 gi->text.number_max = va_arg(ap, long);
336 if (gi->text.number_value > gi->text.number_max)
338 gi->text.number_value = gi->text.number_max;
339 sprintf(gi->text.value, "%d", gi->text.number_value);
345 int max_textsize = MAX_GADGET_TEXTSIZE;
348 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
350 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
351 gi->text.value[max_textsize] = '\0';
352 gi->text.cursor_position = strlen(gi->text.value);
358 int tag_value = va_arg(ap, int);
359 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
361 gi->text.size = max_textsize;
362 gi->text.value[max_textsize] = '\0';
367 gi->text.font_type = va_arg(ap, int);
370 case GDI_DESIGN_UNPRESSED:
371 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap);
372 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
373 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
376 case GDI_DESIGN_PRESSED:
377 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap);
378 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
379 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
382 case GDI_ALT_DESIGN_UNPRESSED:
383 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap);
384 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
385 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
388 case GDI_ALT_DESIGN_PRESSED:
389 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap);
390 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
391 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
394 case GDI_BORDER_SIZE:
395 gi->border.size = va_arg(ap, int);
398 case GDI_TEXTINPUT_DESIGN_WIDTH:
399 gi->border.width = va_arg(ap, int);
402 case GDI_DECORATION_DESIGN:
403 gi->deco.design.bitmap = va_arg(ap, Bitmap);
404 gi->deco.design.x = va_arg(ap, int);
405 gi->deco.design.y = va_arg(ap, int);
408 case GDI_DECORATION_POSITION:
409 gi->deco.x = va_arg(ap, int);
410 gi->deco.y = va_arg(ap, int);
413 case GDI_DECORATION_SIZE:
414 gi->deco.width = va_arg(ap, int);
415 gi->deco.height = va_arg(ap, int);
418 case GDI_DECORATION_SHIFTING:
419 gi->deco.xshift = va_arg(ap, int);
420 gi->deco.yshift = va_arg(ap, int);
424 gi->event_mask = va_arg(ap, unsigned long);
428 gi->drawing.area_xsize = va_arg(ap, int);
429 gi->drawing.area_ysize = va_arg(ap, int);
431 /* determine dependent values for drawing area gadget, if needed */
432 if (gi->width == 0 && gi->height == 0 &&
433 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
435 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
436 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
438 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
439 gi->width != 0 && gi->height != 0)
441 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
442 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
447 gi->drawing.item_xsize = va_arg(ap, int);
448 gi->drawing.item_ysize = va_arg(ap, int);
450 /* determine dependent values for drawing area gadget, if needed */
451 if (gi->width == 0 && gi->height == 0 &&
452 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
454 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
455 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
457 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
458 gi->width != 0 && gi->height != 0)
460 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
461 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
465 case GDI_SCROLLBAR_ITEMS_MAX:
466 gi->scrollbar.items_max = va_arg(ap, int);
469 case GDI_SCROLLBAR_ITEMS_VISIBLE:
470 gi->scrollbar.items_visible = va_arg(ap, int);
473 case GDI_SCROLLBAR_ITEM_POSITION:
474 gi->scrollbar.item_position = va_arg(ap, int);
477 case GDI_CALLBACK_INFO:
478 gi->callback_info = va_arg(ap, gadget_function);
481 case GDI_CALLBACK_ACTION:
482 gi->callback_action = va_arg(ap, gadget_function);
486 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
489 tag = va_arg(ap, int); /* read next tag */
492 /* check if gadget complete */
493 if (gi->type != GD_TYPE_DRAWING_AREA &&
494 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
495 !gi->design[GD_BUTTON_PRESSED].bitmap))
496 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
498 /* adjust gadget values in relation to other gadget values */
500 if (gi->type & GD_TYPE_TEXTINPUT)
502 int font_width = getFontWidth(FS_SMALL, gi->text.font_type);
503 int font_height = getFontHeight(FS_SMALL, gi->text.font_type);
505 gi->width = 2 * gi->border.size + (gi->text.size + 1) * font_width;
506 gi->height = 2 * gi->border.size + font_height;
509 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
511 struct GadgetTextInput *text = &gi->text;
512 int value = text->number_value;
514 text->number_value = (value < text->number_min ? text->number_min :
515 value > text->number_max ? text->number_max :
518 sprintf(text->value, "%d", text->number_value);
521 if (gi->type & GD_TYPE_SCROLLBAR)
523 struct GadgetScrollbar *gs = &gi->scrollbar;
525 if (gi->width == 0 || gi->height == 0 ||
526 gs->items_max == 0 || gs->items_visible == 0)
527 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
529 /* calculate internal scrollbar values */
530 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
531 gi->height : gi->width);
532 gs->size = gs->size_max * gs->items_visible / gs->items_max;
533 gs->position = gs->size_max * gs->item_position / gs->items_max;
534 gs->position_max = gs->size_max - gs->size;
535 gs->correction = gs->size_max / gs->items_max / 2;
537 /* finetuning for maximal right/bottom position */
538 if (gs->item_position == gs->items_max - gs->items_visible)
539 gs->position = gs->position_max;
543 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
547 va_start(ap, first_tag);
548 HandleGadgetTags(gi, first_tag, ap);
554 void RedrawGadget(struct GadgetInfo *gi)
557 DrawGadget(gi, gi->state, DG_DIRECT);
560 struct GadgetInfo *CreateGadget(int first_tag, ...)
562 struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
565 /* always start with reliable default values */
566 memset(new_gadget, 0, sizeof(struct GadgetInfo)); /* zero all fields */
567 new_gadget->id = getNewGadgetID();
568 new_gadget->callback_info = default_callback_info;
569 new_gadget->callback_action = default_callback_action;
571 va_start(ap, first_tag);
572 HandleGadgetTags(new_gadget, first_tag, ap);
575 /* insert new gadget into global gadget list */
576 if (gadget_list_last_entry)
578 gadget_list_last_entry->next = new_gadget;
579 gadget_list_last_entry = gadget_list_last_entry->next;
582 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
587 void FreeGadget(struct GadgetInfo *gi)
589 struct GadgetInfo *gi_previous = gadget_list_first_entry;
591 while (gi_previous && gi_previous->next != gi)
592 gi_previous = gi_previous->next;
594 if (gi == gadget_list_first_entry)
595 gadget_list_first_entry = gi->next;
597 if (gi == gadget_list_last_entry)
598 gadget_list_last_entry = gi_previous;
600 gi_previous->next = gi->next;
604 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
606 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
609 gi->text.number_value = atoi(gi->text.value);
611 if (gi->text.number_value < gi->text.number_min)
612 gi->text.number_value = gi->text.number_min;
613 if (gi->text.number_value > gi->text.number_max)
614 gi->text.number_value = gi->text.number_max;
616 sprintf(gi->text.value, "%d", gi->text.number_value);
618 if (gi->text.cursor_position < 0)
619 gi->text.cursor_position = 0;
620 else if (gi->text.cursor_position > strlen(gi->text.value))
621 gi->text.cursor_position = strlen(gi->text.value);
624 /* global pointer to gadget actually in use (when mouse button pressed) */
625 static struct GadgetInfo *last_gi = NULL;
627 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
629 if (gi == NULL || gi->mapped)
635 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
638 void MapGadget(struct GadgetInfo *gi)
640 MapGadgetExt(gi, TRUE);
643 void UnmapGadget(struct GadgetInfo *gi)
645 if (gi == NULL || !gi->mapped)
654 #define MAX_NUM_GADGETS 1024
655 #define MULTIMAP_UNMAP (1 << 0)
656 #define MULTIMAP_REMAP (1 << 1)
657 #define MULTIMAP_REDRAW (1 << 2)
658 #define MULTIMAP_PLAYFIELD (1 << 3)
659 #define MULTIMAP_DOOR_1 (1 << 4)
660 #define MULTIMAP_DOOR_2 (1 << 5)
661 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
665 static void MultiMapGadgets(int mode)
667 struct GadgetInfo *gi = gadget_list_first_entry;
668 static boolean map_state[MAX_NUM_GADGETS];
673 if ((mode & MULTIMAP_PLAYFIELD &&
674 gi->x < gfx.sx + gfx.sxsize) ||
675 (mode & MULTIMAP_DOOR_1 &&
676 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
677 (mode & MULTIMAP_DOOR_2 &&
678 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
679 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
681 if (mode & MULTIMAP_UNMAP)
683 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
688 if (map_state[map_count++ % MAX_NUM_GADGETS])
689 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
697 void UnmapAllGadgets()
699 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
702 void RemapAllGadgets()
704 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
707 boolean anyTextGadgetActive()
709 return (last_gi && last_gi->type & GD_TYPE_TEXTINPUT && last_gi->mapped);
712 void ClickOnGadget(struct GadgetInfo *gi, int button)
714 /* simulate releasing mouse button over last gadget, if still pressed */
716 HandleGadgets(-1, -1, 0);
718 /* simulate pressing mouse button over specified gadget */
719 HandleGadgets(gi->x, gi->y, button);
721 /* simulate releasing mouse button over specified gadget */
722 HandleGadgets(gi->x, gi->y, 0);
725 void HandleGadgets(int mx, int my, int button)
727 static struct GadgetInfo *last_info_gi = NULL;
728 static unsigned long pressed_delay = 0;
729 static int last_button = 0;
730 static int last_mx = 0, last_my = 0;
731 int scrollbar_mouse_pos = 0;
732 struct GadgetInfo *new_gi, *gi;
734 boolean release_event;
735 boolean mouse_moving;
736 boolean gadget_pressed;
737 boolean gadget_pressed_repeated;
738 boolean gadget_moving;
739 boolean gadget_moving_inside;
740 boolean gadget_moving_off_borders;
741 boolean gadget_released;
742 boolean gadget_released_inside;
743 boolean gadget_released_off_borders;
744 boolean changed_position = FALSE;
746 /* check if there are any gadgets defined */
747 if (gadget_list_first_entry == NULL)
750 /* check which gadget is under the mouse pointer */
751 new_gi = getGadgetInfoFromMousePosition(mx, my);
753 /* check if button state has changed since last invocation */
754 press_event = (button != 0 && last_button == 0);
755 release_event = (button == 0 && last_button != 0);
756 last_button = button;
758 /* check if mouse has been moved since last invocation */
759 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
763 /* special treatment for text and number input gadgets */
764 if (anyTextGadgetActive() && button != 0 && !motion_status)
766 struct GadgetInfo *gi = last_gi;
768 if (new_gi == last_gi)
770 /* if mouse button pressed inside activated text gadget, set cursor */
771 gi->text.cursor_position =
772 (mx - gi->x - gi->border.size) /
773 getFontWidth(FS_SMALL, gi->text.font_type);
775 if (gi->text.cursor_position < 0)
776 gi->text.cursor_position = 0;
777 else if (gi->text.cursor_position > strlen(gi->text.value))
778 gi->text.cursor_position = strlen(gi->text.value);
780 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
784 /* if mouse button pressed outside text input gadget, deactivate it */
785 CheckRangeOfNumericInputGadget(gi);
786 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
788 gi->event.type = GD_EVENT_TEXT_LEAVING;
790 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
791 gi->callback_action(gi);
798 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
799 gadget_pressed_repeated =
800 (button != 0 && last_gi != NULL && new_gi == last_gi);
802 gadget_released = (release_event && last_gi != NULL);
803 gadget_released_inside = (gadget_released && new_gi == last_gi);
804 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
806 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
807 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
808 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
810 /* if new gadget pressed, store this gadget */
814 /* 'gi' is actually handled gadget */
817 /* if gadget is scrollbar, choose mouse position value */
818 if (gi && gi->type & GD_TYPE_SCROLLBAR)
819 scrollbar_mouse_pos =
820 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
822 /* if mouse button released, no gadget needs to be handled anymore */
823 if (button == 0 && last_gi && !(last_gi->type & GD_TYPE_TEXTINPUT))
826 /* modify event position values even if no gadget is pressed */
827 if (button == 0 && !release_event)
832 int last_x = gi->event.x;
833 int last_y = gi->event.y;
835 gi->event.x = mx - gi->x;
836 gi->event.y = my - gi->y;
838 if (gi->type == GD_TYPE_DRAWING_AREA)
840 gi->event.x /= gi->drawing.item_xsize;
841 gi->event.y /= gi->drawing.item_ysize;
843 if (last_x != gi->event.x || last_y != gi->event.y)
844 changed_position = TRUE;
848 /* handle gadget popup info text */
849 if (last_info_gi != new_gi ||
850 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
852 last_info_gi = new_gi;
854 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
856 new_gi->event.type = 0;
857 new_gi->callback_info(new_gi);
860 default_callback_info(NULL);
865 if (gi->type == GD_TYPE_CHECK_BUTTON)
867 gi->checked = !gi->checked;
869 else if (gi->type == GD_TYPE_RADIO_BUTTON)
871 struct GadgetInfo *rgi = gadget_list_first_entry;
876 rgi->type == GD_TYPE_RADIO_BUTTON &&
877 rgi->radio_nr == gi->radio_nr &&
880 rgi->checked = FALSE;
881 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
889 else if (gi->type & GD_TYPE_SCROLLBAR)
893 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
904 if (mpos >= gpos + gi->scrollbar.position &&
905 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
908 gi->scrollbar.drag_position =
909 scrollbar_mouse_pos - gi->scrollbar.position;
913 /* click scrollbar one scrollbar length up/left or down/right */
915 struct GadgetScrollbar *gs = &gi->scrollbar;
916 int old_item_position = gs->item_position;
918 changed_position = FALSE;
921 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
923 if (gs->item_position < 0)
924 gs->item_position = 0;
925 if (gs->item_position > gs->items_max - gs->items_visible)
926 gs->item_position = gs->items_max - gs->items_visible;
928 if (old_item_position != gs->item_position)
930 gi->event.item_position = gs->item_position;
931 changed_position = TRUE;
934 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
937 gi->state = GD_BUTTON_UNPRESSED;
938 gi->event.type = GD_EVENT_MOVING;
939 gi->event.off_borders = FALSE;
941 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
942 gi->callback_action(gi);
944 /* don't handle this scrollbar anymore while mouse button pressed */
951 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
953 gi->state = GD_BUTTON_PRESSED;
954 gi->event.type = GD_EVENT_PRESSED;
955 gi->event.button = button;
956 gi->event.off_borders = FALSE;
958 /* initialize delay counter */
959 DelayReached(&pressed_delay, 0);
961 if (gi->event_mask & GD_EVENT_PRESSED)
962 gi->callback_action(gi);
965 if (gadget_pressed_repeated)
967 gi->event.type = GD_EVENT_PRESSED;
969 if (gi->event_mask & GD_EVENT_REPEATED &&
970 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
971 gi->callback_action(gi);
976 if (gi->type & GD_TYPE_BUTTON)
978 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
979 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
980 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
981 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
984 if (gi->type & GD_TYPE_SCROLLBAR)
986 struct GadgetScrollbar *gs = &gi->scrollbar;
987 int old_item_position = gs->item_position;
989 gs->position = scrollbar_mouse_pos - gs->drag_position;
991 if (gs->position < 0)
993 if (gs->position > gs->position_max)
994 gs->position = gs->position_max;
997 gs->items_max * (gs->position + gs->correction) / gs->size_max;
999 if (gs->item_position < 0)
1000 gs->item_position = 0;
1001 if (gs->item_position > gs->items_max - 1)
1002 gs->item_position = gs->items_max - 1;
1004 if (old_item_position != gs->item_position)
1006 gi->event.item_position = gs->item_position;
1007 changed_position = TRUE;
1010 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1013 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1014 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1015 gi->event.type = GD_EVENT_MOVING;
1016 gi->event.off_borders = gadget_moving_off_borders;
1018 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1019 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1020 gi->callback_action(gi);
1023 if (gadget_released_inside)
1025 if (!(gi->type & GD_TYPE_TEXTINPUT))
1026 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1028 gi->state = GD_BUTTON_UNPRESSED;
1029 gi->event.type = GD_EVENT_RELEASED;
1031 if (gi->event_mask & GD_EVENT_RELEASED)
1032 gi->callback_action(gi);
1035 if (gadget_released_off_borders)
1037 if (gi->type & GD_TYPE_SCROLLBAR)
1038 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1040 gi->event.type = GD_EVENT_RELEASED;
1042 if (gi->event_mask & GD_EVENT_RELEASED &&
1043 gi->event_mask & GD_EVENT_OFF_BORDERS)
1044 gi->callback_action(gi);
1048 void HandleGadgetsKeyInput(Key key)
1050 struct GadgetInfo *gi = last_gi;
1051 char text[MAX_GADGET_TEXTSIZE];
1055 boolean legal_letter;
1057 if (gi == NULL || !(gi->type & GD_TYPE_TEXTINPUT) || !gi->mapped)
1060 text_length = strlen(gi->text.value);
1061 cursor_pos = gi->text.cursor_position;
1062 letter = getCharFromKey(key);
1063 legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1064 letter >= '0' && letter <= '9' :
1067 if (legal_letter && text_length < gi->text.size)
1069 strcpy(text, gi->text.value);
1070 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1071 gi->text.value[cursor_pos] = letter;
1072 gi->text.cursor_position++;
1073 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1075 else if (key == KSYM_Left && cursor_pos > 0)
1077 gi->text.cursor_position--;
1078 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1080 else if (key == KSYM_Right && cursor_pos < text_length)
1082 gi->text.cursor_position++;
1083 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1085 else if (key == KSYM_BackSpace && cursor_pos > 0)
1087 strcpy(text, gi->text.value);
1088 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1089 gi->text.cursor_position--;
1090 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1092 else if (key == KSYM_Delete && cursor_pos < text_length)
1094 strcpy(text, gi->text.value);
1095 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1096 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1098 else if (key == KSYM_Return)
1100 CheckRangeOfNumericInputGadget(gi);
1101 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1103 gi->event.type = GD_EVENT_TEXT_RETURN;
1105 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1106 gi->callback_action(gi);