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 ***********************************************************/
25 /* values for DrawGadget() */
26 #define DG_UNPRESSED 0
31 static struct GadgetInfo *gadget_list_first_entry = NULL;
32 static struct GadgetInfo *gadget_list_last_entry = NULL;
33 static int next_free_gadget_id = 1;
34 static boolean gadget_id_wrapped = FALSE;
36 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
38 struct GadgetInfo *gi = gadget_list_first_entry;
40 while (gi && gi->id != id)
46 static int getNewGadgetID()
48 int id = next_free_gadget_id++;
50 if (next_free_gadget_id <= 0) /* counter overrun */
52 gadget_id_wrapped = TRUE; /* now we must check each ID */
53 next_free_gadget_id = 0;
56 if (gadget_id_wrapped)
58 next_free_gadget_id++;
59 while (getGadgetInfoFromGadgetID(next_free_gadget_id) != NULL)
60 next_free_gadget_id++;
63 if (next_free_gadget_id <= 0) /* cannot get new gadget id */
64 Error(ERR_EXIT, "too much gadgets -- this should not happen");
69 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
71 struct GadgetInfo *gi = gadget_list_first_entry;
76 mx >= gi->x && mx < gi->x + gi->width &&
77 my >= gi->y && my < gi->y + gi->height)
86 static void default_callback_info(void *ptr)
89 if (game_status == LEVELED)
90 HandleEditorGadgetInfoText(ptr);
96 static void default_callback_action(void *ptr)
101 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
103 int state = (pressed ? 1 : 0);
104 struct GadgetDesign *gd = (gi->checked ?
105 &gi->alt_design[state] :
110 case GD_TYPE_NORMAL_BUTTON:
111 case GD_TYPE_CHECK_BUTTON:
112 case GD_TYPE_RADIO_BUTTON:
113 BlitBitmap(gd->bitmap, drawto,
114 gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
115 if (gi->deco.design.bitmap)
116 BlitBitmap(gi->deco.design.bitmap, drawto,
117 gi->deco.design.x, gi->deco.design.y,
118 gi->deco.width, gi->deco.height,
119 gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0),
120 gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
123 case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
124 case GD_TYPE_TEXTINPUT_NUMERIC:
128 char cursor_string[3];
129 char text[MAX_GADGET_TEXTSIZE + 1];
130 int font_type = gi->text.font_type;
131 int font_width = getFontWidth(FS_SMALL, font_type);
132 int border = gi->border.size;
133 strcpy(text, gi->text.value);
136 /* left part of gadget */
137 BlitBitmap(gd->bitmap, drawto,
138 gd->x, gd->y, border, gi->height, gi->x, gi->y);
140 /* middle part of gadget */
141 for (i=0; i<=gi->text.size; i++)
142 BlitBitmap(gd->bitmap, drawto,
143 gd->x + border, gd->y, font_width, gi->height,
144 gi->x + border + i * font_width, gi->y);
146 /* right part of gadget */
147 BlitBitmap(gd->bitmap, drawto,
148 gd->x + gi->border.width - border, gd->y,
149 border, gi->height, gi->x + gi->width - border, gi->y);
151 /* gadget text value */
152 DrawText(gi->x + border, gi->y + border, text, FS_SMALL, font_type);
154 cursor_letter = gi->text.value[gi->text.cursor_position];
155 cursor_string[0] = '~';
156 cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
157 cursor_string[2] = '\0';
159 /* draw cursor, if active */
161 DrawText(gi->x + border + gi->text.cursor_position * font_width,
162 gi->y + border, cursor_string, FS_SMALL, font_type);
166 case GD_TYPE_SCROLLBAR_VERTICAL:
170 int ypos = gi->y + gi->scrollbar.position;
171 int design_full = gi->width;
172 int design_body = design_full - 2 * gi->border.size;
173 int size_full = gi->scrollbar.size;
174 int size_body = size_full - 2 * gi->border.size;
175 int num_steps = size_body / design_body;
176 int step_size_remain = size_body - num_steps * design_body;
178 /* clear scrollbar area */
179 ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
181 /* upper part of gadget */
182 BlitBitmap(gd->bitmap, drawto,
184 gi->width, gi->border.size,
187 /* middle part of gadget */
188 for (i=0; i<num_steps; i++)
189 BlitBitmap(gd->bitmap, drawto,
190 gd->x, gd->y + gi->border.size,
191 gi->width, design_body,
192 xpos, ypos + gi->border.size + i * design_body);
194 /* remaining middle part of gadget */
195 if (step_size_remain > 0)
196 BlitBitmap(gd->bitmap, drawto,
197 gd->x, gd->y + gi->border.size,
198 gi->width, step_size_remain,
199 xpos, ypos + gi->border.size + num_steps * design_body);
201 /* lower part of gadget */
202 BlitBitmap(gd->bitmap, drawto,
203 gd->x, gd->y + design_full - gi->border.size,
204 gi->width, gi->border.size,
205 xpos, ypos + size_full - gi->border.size);
209 case GD_TYPE_SCROLLBAR_HORIZONTAL:
212 int xpos = gi->x + gi->scrollbar.position;
214 int design_full = gi->height;
215 int design_body = design_full - 2 * gi->border.size;
216 int size_full = gi->scrollbar.size;
217 int size_body = size_full - 2 * gi->border.size;
218 int num_steps = size_body / design_body;
219 int step_size_remain = size_body - num_steps * design_body;
221 /* clear scrollbar area */
222 ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
224 /* left part of gadget */
225 BlitBitmap(gd->bitmap, drawto,
227 gi->border.size, gi->height,
230 /* middle part of gadget */
231 for (i=0; i<num_steps; i++)
232 BlitBitmap(gd->bitmap, drawto,
233 gd->x + gi->border.size, gd->y,
234 design_body, gi->height,
235 xpos + gi->border.size + i * design_body, ypos);
237 /* remaining middle part of gadget */
238 if (step_size_remain > 0)
239 BlitBitmap(gd->bitmap, drawto,
240 gd->x + gi->border.size, gd->y,
241 step_size_remain, gi->height,
242 xpos + gi->border.size + num_steps * design_body, ypos);
244 /* right part of gadget */
245 BlitBitmap(gd->bitmap, drawto,
246 gd->x + design_full - gi->border.size, gd->y,
247 gi->border.size, gi->height,
248 xpos + size_full - gi->border.size, ypos);
257 BlitBitmap(drawto, window,
258 gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
260 redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
261 gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
262 gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
265 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
269 while (tag != GDI_END)
274 gi->custom_id = va_arg(ap, int);
277 case GDI_CUSTOM_TYPE_ID:
278 gi->custom_type_id = va_arg(ap, int);
283 int max_textsize = MAX_INFO_TEXTSIZE - 1;
285 strncpy(gi->info_text, va_arg(ap, char *), max_textsize);
286 gi->info_text[max_textsize] = '\0';
291 gi->x = va_arg(ap, int);
295 gi->y = va_arg(ap, int);
299 gi->width = va_arg(ap, int);
303 gi->height = va_arg(ap, int);
307 gi->type = va_arg(ap, unsigned long);
311 gi->state = va_arg(ap, unsigned long);
315 gi->checked = va_arg(ap, boolean);
319 gi->radio_nr = va_arg(ap, unsigned long);
322 case GDI_NUMBER_VALUE:
323 gi->text.number_value = va_arg(ap, long);
324 sprintf(gi->text.value, "%d", gi->text.number_value);
325 gi->text.cursor_position = strlen(gi->text.value);
329 gi->text.number_min = va_arg(ap, long);
330 if (gi->text.number_value < gi->text.number_min)
332 gi->text.number_value = gi->text.number_min;
333 sprintf(gi->text.value, "%d", gi->text.number_value);
338 gi->text.number_max = va_arg(ap, long);
339 if (gi->text.number_value > gi->text.number_max)
341 gi->text.number_value = gi->text.number_max;
342 sprintf(gi->text.value, "%d", gi->text.number_value);
348 int max_textsize = MAX_GADGET_TEXTSIZE;
351 max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1);
353 strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
354 gi->text.value[max_textsize] = '\0';
355 gi->text.cursor_position = strlen(gi->text.value);
361 int tag_value = va_arg(ap, int);
362 int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1);
364 gi->text.size = max_textsize;
365 gi->text.value[max_textsize] = '\0';
370 gi->text.font_type = va_arg(ap, int);
373 case GDI_DESIGN_UNPRESSED:
374 gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap);
375 gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
376 gi->design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
379 case GDI_DESIGN_PRESSED:
380 gi->design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap);
381 gi->design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
382 gi->design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
385 case GDI_ALT_DESIGN_UNPRESSED:
386 gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap);
387 gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
388 gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
391 case GDI_ALT_DESIGN_PRESSED:
392 gi->alt_design[GD_BUTTON_PRESSED].bitmap = va_arg(ap, Bitmap);
393 gi->alt_design[GD_BUTTON_PRESSED].x = va_arg(ap, int);
394 gi->alt_design[GD_BUTTON_PRESSED].y = va_arg(ap, int);
397 case GDI_BORDER_SIZE:
398 gi->border.size = va_arg(ap, int);
401 case GDI_TEXTINPUT_DESIGN_WIDTH:
402 gi->border.width = va_arg(ap, int);
405 case GDI_DECORATION_DESIGN:
406 gi->deco.design.bitmap = va_arg(ap, Bitmap);
407 gi->deco.design.x = va_arg(ap, int);
408 gi->deco.design.y = va_arg(ap, int);
411 case GDI_DECORATION_POSITION:
412 gi->deco.x = va_arg(ap, int);
413 gi->deco.y = va_arg(ap, int);
416 case GDI_DECORATION_SIZE:
417 gi->deco.width = va_arg(ap, int);
418 gi->deco.height = va_arg(ap, int);
421 case GDI_DECORATION_SHIFTING:
422 gi->deco.xshift = va_arg(ap, int);
423 gi->deco.yshift = va_arg(ap, int);
427 gi->event_mask = va_arg(ap, unsigned long);
431 gi->drawing.area_xsize = va_arg(ap, int);
432 gi->drawing.area_ysize = va_arg(ap, int);
434 /* determine dependent values for drawing area gadget, if needed */
435 if (gi->width == 0 && gi->height == 0 &&
436 gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0)
438 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
439 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
441 else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 &&
442 gi->width != 0 && gi->height != 0)
444 gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize;
445 gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize;
450 gi->drawing.item_xsize = va_arg(ap, int);
451 gi->drawing.item_ysize = va_arg(ap, int);
453 /* determine dependent values for drawing area gadget, if needed */
454 if (gi->width == 0 && gi->height == 0 &&
455 gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0)
457 gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize;
458 gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize;
460 else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 &&
461 gi->width != 0 && gi->height != 0)
463 gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize;
464 gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize;
468 case GDI_SCROLLBAR_ITEMS_MAX:
469 gi->scrollbar.items_max = va_arg(ap, int);
472 case GDI_SCROLLBAR_ITEMS_VISIBLE:
473 gi->scrollbar.items_visible = va_arg(ap, int);
476 case GDI_SCROLLBAR_ITEM_POSITION:
477 gi->scrollbar.item_position = va_arg(ap, int);
480 case GDI_CALLBACK_INFO:
481 gi->callback_info = va_arg(ap, gadget_function);
484 case GDI_CALLBACK_ACTION:
485 gi->callback_action = va_arg(ap, gadget_function);
489 Error(ERR_EXIT, "HandleGadgetTags(): unknown tag %d", tag);
492 tag = va_arg(ap, int); /* read next tag */
495 /* check if gadget complete */
496 if (gi->type != GD_TYPE_DRAWING_AREA &&
497 (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
498 !gi->design[GD_BUTTON_PRESSED].bitmap))
499 Error(ERR_EXIT, "gadget incomplete (missing Bitmap)");
501 /* adjust gadget values in relation to other gadget values */
503 if (gi->type & GD_TYPE_TEXTINPUT)
505 int font_width = getFontWidth(FS_SMALL, gi->text.font_type);
506 int font_height = getFontHeight(FS_SMALL, gi->text.font_type);
508 gi->width = 2 * gi->border.size + (gi->text.size + 1) * font_width;
509 gi->height = 2 * gi->border.size + font_height;
512 if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
514 struct GadgetTextInput *text = &gi->text;
515 int value = text->number_value;
517 text->number_value = (value < text->number_min ? text->number_min :
518 value > text->number_max ? text->number_max :
521 sprintf(text->value, "%d", text->number_value);
524 if (gi->type & GD_TYPE_SCROLLBAR)
526 struct GadgetScrollbar *gs = &gi->scrollbar;
528 if (gi->width == 0 || gi->height == 0 ||
529 gs->items_max == 0 || gs->items_visible == 0)
530 Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)");
532 /* calculate internal scrollbar values */
533 gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ?
534 gi->height : gi->width);
535 gs->size = gs->size_max * gs->items_visible / gs->items_max;
536 gs->position = gs->size_max * gs->item_position / gs->items_max;
537 gs->position_max = gs->size_max - gs->size;
538 gs->correction = gs->size_max / gs->items_max / 2;
540 /* finetuning for maximal right/bottom position */
541 if (gs->item_position == gs->items_max - gs->items_visible)
542 gs->position = gs->position_max;
546 void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
550 va_start(ap, first_tag);
551 HandleGadgetTags(gi, first_tag, ap);
557 void RedrawGadget(struct GadgetInfo *gi)
560 DrawGadget(gi, gi->state, DG_DIRECT);
563 struct GadgetInfo *CreateGadget(int first_tag, ...)
565 struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
568 /* always start with reliable default values */
569 memset(new_gadget, 0, sizeof(struct GadgetInfo)); /* zero all fields */
570 new_gadget->id = getNewGadgetID();
571 new_gadget->callback_info = default_callback_info;
572 new_gadget->callback_action = default_callback_action;
574 va_start(ap, first_tag);
575 HandleGadgetTags(new_gadget, first_tag, ap);
578 /* insert new gadget into global gadget list */
579 if (gadget_list_last_entry)
581 gadget_list_last_entry->next = new_gadget;
582 gadget_list_last_entry = gadget_list_last_entry->next;
585 gadget_list_first_entry = gadget_list_last_entry = new_gadget;
590 void FreeGadget(struct GadgetInfo *gi)
592 struct GadgetInfo *gi_previous = gadget_list_first_entry;
594 while (gi_previous && gi_previous->next != gi)
595 gi_previous = gi_previous->next;
597 if (gi == gadget_list_first_entry)
598 gadget_list_first_entry = gi->next;
600 if (gi == gadget_list_last_entry)
601 gadget_list_last_entry = gi_previous;
603 gi_previous->next = gi->next;
607 static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi)
609 if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC)
612 gi->text.number_value = atoi(gi->text.value);
614 if (gi->text.number_value < gi->text.number_min)
615 gi->text.number_value = gi->text.number_min;
616 if (gi->text.number_value > gi->text.number_max)
617 gi->text.number_value = gi->text.number_max;
619 sprintf(gi->text.value, "%d", gi->text.number_value);
621 if (gi->text.cursor_position < 0)
622 gi->text.cursor_position = 0;
623 else if (gi->text.cursor_position > strlen(gi->text.value))
624 gi->text.cursor_position = strlen(gi->text.value);
627 /* global pointer to gadget actually in use (when mouse button pressed) */
628 static struct GadgetInfo *last_gi = NULL;
630 static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw)
632 if (gi == NULL || gi->mapped)
638 DrawGadget(gi, DG_UNPRESSED, DG_BUFFERED);
641 void MapGadget(struct GadgetInfo *gi)
643 MapGadgetExt(gi, TRUE);
646 void UnmapGadget(struct GadgetInfo *gi)
648 if (gi == NULL || !gi->mapped)
657 #define MAX_NUM_GADGETS 1024
658 #define MULTIMAP_UNMAP (1 << 0)
659 #define MULTIMAP_REMAP (1 << 1)
660 #define MULTIMAP_REDRAW (1 << 2)
661 #define MULTIMAP_PLAYFIELD (1 << 3)
662 #define MULTIMAP_DOOR_1 (1 << 4)
663 #define MULTIMAP_DOOR_2 (1 << 5)
664 #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \
668 static void MultiMapGadgets(int mode)
670 struct GadgetInfo *gi = gadget_list_first_entry;
671 static boolean map_state[MAX_NUM_GADGETS];
676 if ((mode & MULTIMAP_PLAYFIELD &&
677 gi->x < gfx.sx + gfx.sxsize) ||
678 (mode & MULTIMAP_DOOR_1 &&
679 gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) ||
680 (mode & MULTIMAP_DOOR_2 &&
681 gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) ||
682 (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
684 if (mode & MULTIMAP_UNMAP)
686 map_state[map_count++ % MAX_NUM_GADGETS] = gi->mapped;
691 if (map_state[map_count++ % MAX_NUM_GADGETS])
692 MapGadgetExt(gi, (mode & MULTIMAP_REDRAW));
700 void UnmapAllGadgets()
702 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_UNMAP);
705 void RemapAllGadgets()
707 MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
710 boolean anyTextGadgetActive()
712 return (last_gi && last_gi->type & GD_TYPE_TEXTINPUT && last_gi->mapped);
715 void ClickOnGadget(struct GadgetInfo *gi, int button)
717 /* simulate releasing mouse button over last gadget, if still pressed */
719 HandleGadgets(-1, -1, 0);
721 /* simulate pressing mouse button over specified gadget */
722 HandleGadgets(gi->x, gi->y, button);
724 /* simulate releasing mouse button over specified gadget */
725 HandleGadgets(gi->x, gi->y, 0);
728 void HandleGadgets(int mx, int my, int button)
730 static struct GadgetInfo *last_info_gi = NULL;
731 static unsigned long pressed_delay = 0;
732 static int last_button = 0;
733 static int last_mx = 0, last_my = 0;
734 int scrollbar_mouse_pos = 0;
735 struct GadgetInfo *new_gi, *gi;
737 boolean release_event;
738 boolean mouse_moving;
739 boolean gadget_pressed;
740 boolean gadget_pressed_repeated;
741 boolean gadget_moving;
742 boolean gadget_moving_inside;
743 boolean gadget_moving_off_borders;
744 boolean gadget_released;
745 boolean gadget_released_inside;
746 boolean gadget_released_off_borders;
747 boolean changed_position = FALSE;
749 /* check if there are any gadgets defined */
750 if (gadget_list_first_entry == NULL)
753 /* check which gadget is under the mouse pointer */
754 new_gi = getGadgetInfoFromMousePosition(mx, my);
756 /* check if button state has changed since last invocation */
757 press_event = (button != 0 && last_button == 0);
758 release_event = (button == 0 && last_button != 0);
759 last_button = button;
761 /* check if mouse has been moved since last invocation */
762 mouse_moving = ((mx != last_mx || my != last_my) && motion_status);
766 /* special treatment for text and number input gadgets */
767 if (anyTextGadgetActive() && button != 0 && !motion_status)
769 struct GadgetInfo *gi = last_gi;
771 if (new_gi == last_gi)
773 /* if mouse button pressed inside activated text gadget, set cursor */
774 gi->text.cursor_position =
775 (mx - gi->x - gi->border.size) /
776 getFontWidth(FS_SMALL, gi->text.font_type);
778 if (gi->text.cursor_position < 0)
779 gi->text.cursor_position = 0;
780 else if (gi->text.cursor_position > strlen(gi->text.value))
781 gi->text.cursor_position = strlen(gi->text.value);
783 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
787 /* if mouse button pressed outside text input gadget, deactivate it */
788 CheckRangeOfNumericInputGadget(gi);
789 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
791 gi->event.type = GD_EVENT_TEXT_LEAVING;
793 if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
794 gi->callback_action(gi);
801 (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
802 gadget_pressed_repeated =
803 (button != 0 && last_gi != NULL && new_gi == last_gi);
805 gadget_released = (release_event && last_gi != NULL);
806 gadget_released_inside = (gadget_released && new_gi == last_gi);
807 gadget_released_off_borders = (gadget_released && new_gi != last_gi);
809 gadget_moving = (button != 0 && last_gi != NULL && mouse_moving);
810 gadget_moving_inside = (gadget_moving && new_gi == last_gi);
811 gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
813 /* if new gadget pressed, store this gadget */
817 /* 'gi' is actually handled gadget */
820 /* if gadget is scrollbar, choose mouse position value */
821 if (gi && gi->type & GD_TYPE_SCROLLBAR)
822 scrollbar_mouse_pos =
823 (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
825 /* if mouse button released, no gadget needs to be handled anymore */
826 if (button == 0 && last_gi && !(last_gi->type & GD_TYPE_TEXTINPUT))
829 /* modify event position values even if no gadget is pressed */
830 if (button == 0 && !release_event)
835 int last_x = gi->event.x;
836 int last_y = gi->event.y;
838 gi->event.x = mx - gi->x;
839 gi->event.y = my - gi->y;
841 if (gi->type == GD_TYPE_DRAWING_AREA)
843 gi->event.x /= gi->drawing.item_xsize;
844 gi->event.y /= gi->drawing.item_ysize;
846 if (last_x != gi->event.x || last_y != gi->event.y)
847 changed_position = TRUE;
851 /* handle gadget popup info text */
852 if (last_info_gi != new_gi ||
853 (new_gi && new_gi->type == GD_TYPE_DRAWING_AREA && changed_position))
855 last_info_gi = new_gi;
857 if (new_gi != NULL && (button == 0 || new_gi == last_gi))
859 new_gi->event.type = 0;
860 new_gi->callback_info(new_gi);
863 default_callback_info(NULL);
868 if (gi->type == GD_TYPE_CHECK_BUTTON)
870 gi->checked = !gi->checked;
872 else if (gi->type == GD_TYPE_RADIO_BUTTON)
874 struct GadgetInfo *rgi = gadget_list_first_entry;
879 rgi->type == GD_TYPE_RADIO_BUTTON &&
880 rgi->radio_nr == gi->radio_nr &&
883 rgi->checked = FALSE;
884 DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
892 else if (gi->type & GD_TYPE_SCROLLBAR)
896 if (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL)
907 if (mpos >= gpos + gi->scrollbar.position &&
908 mpos < gpos + gi->scrollbar.position + gi->scrollbar.size)
911 gi->scrollbar.drag_position =
912 scrollbar_mouse_pos - gi->scrollbar.position;
916 /* click scrollbar one scrollbar length up/left or down/right */
918 struct GadgetScrollbar *gs = &gi->scrollbar;
919 int old_item_position = gs->item_position;
921 changed_position = FALSE;
924 gs->items_visible * (mpos < gpos + gi->scrollbar.position ? -1 : +1);
926 if (gs->item_position < 0)
927 gs->item_position = 0;
928 if (gs->item_position > gs->items_max - gs->items_visible)
929 gs->item_position = gs->items_max - gs->items_visible;
931 if (old_item_position != gs->item_position)
933 gi->event.item_position = gs->item_position;
934 changed_position = TRUE;
937 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, gs->item_position,
940 gi->state = GD_BUTTON_UNPRESSED;
941 gi->event.type = GD_EVENT_MOVING;
942 gi->event.off_borders = FALSE;
944 if (gi->event_mask & GD_EVENT_MOVING && changed_position)
945 gi->callback_action(gi);
947 /* don't handle this scrollbar anymore while mouse button pressed */
954 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
956 gi->state = GD_BUTTON_PRESSED;
957 gi->event.type = GD_EVENT_PRESSED;
958 gi->event.button = button;
959 gi->event.off_borders = FALSE;
961 /* initialize delay counter */
962 DelayReached(&pressed_delay, 0);
964 if (gi->event_mask & GD_EVENT_PRESSED)
965 gi->callback_action(gi);
968 if (gadget_pressed_repeated)
970 gi->event.type = GD_EVENT_PRESSED;
972 if (gi->event_mask & GD_EVENT_REPEATED &&
973 DelayReached(&pressed_delay, GADGET_FRAME_DELAY))
974 gi->callback_action(gi);
979 if (gi->type & GD_TYPE_BUTTON)
981 if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
982 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
983 else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
984 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
987 if (gi->type & GD_TYPE_SCROLLBAR)
989 struct GadgetScrollbar *gs = &gi->scrollbar;
990 int old_item_position = gs->item_position;
992 gs->position = scrollbar_mouse_pos - gs->drag_position;
994 if (gs->position < 0)
996 if (gs->position > gs->position_max)
997 gs->position = gs->position_max;
1000 gs->items_max * (gs->position + gs->correction) / gs->size_max;
1002 if (gs->item_position < 0)
1003 gs->item_position = 0;
1004 if (gs->item_position > gs->items_max - 1)
1005 gs->item_position = gs->items_max - 1;
1007 if (old_item_position != gs->item_position)
1009 gi->event.item_position = gs->item_position;
1010 changed_position = TRUE;
1013 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1016 gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
1017 GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
1018 gi->event.type = GD_EVENT_MOVING;
1019 gi->event.off_borders = gadget_moving_off_borders;
1021 if (gi->event_mask & GD_EVENT_MOVING && changed_position &&
1022 (gadget_moving_inside || gi->event_mask & GD_EVENT_OFF_BORDERS))
1023 gi->callback_action(gi);
1026 if (gadget_released_inside)
1028 if (!(gi->type & GD_TYPE_TEXTINPUT))
1029 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1031 gi->state = GD_BUTTON_UNPRESSED;
1032 gi->event.type = GD_EVENT_RELEASED;
1034 if (gi->event_mask & GD_EVENT_RELEASED)
1035 gi->callback_action(gi);
1038 if (gadget_released_off_borders)
1040 if (gi->type & GD_TYPE_SCROLLBAR)
1041 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1043 gi->event.type = GD_EVENT_RELEASED;
1045 if (gi->event_mask & GD_EVENT_RELEASED &&
1046 gi->event_mask & GD_EVENT_OFF_BORDERS)
1047 gi->callback_action(gi);
1051 void HandleGadgetsKeyInput(Key key)
1053 struct GadgetInfo *gi = last_gi;
1054 char text[MAX_GADGET_TEXTSIZE];
1058 boolean legal_letter;
1060 if (gi == NULL || !(gi->type & GD_TYPE_TEXTINPUT) || !gi->mapped)
1063 text_length = strlen(gi->text.value);
1064 cursor_pos = gi->text.cursor_position;
1065 letter = getCharFromKey(key);
1066 legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
1067 letter >= '0' && letter <= '9' :
1070 if (legal_letter && text_length < gi->text.size)
1072 strcpy(text, gi->text.value);
1073 strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
1074 gi->text.value[cursor_pos] = letter;
1075 gi->text.cursor_position++;
1076 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1078 else if (key == KSYM_Left && cursor_pos > 0)
1080 gi->text.cursor_position--;
1081 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1083 else if (key == KSYM_Right && cursor_pos < text_length)
1085 gi->text.cursor_position++;
1086 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1088 else if (key == KSYM_BackSpace && cursor_pos > 0)
1090 strcpy(text, gi->text.value);
1091 strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
1092 gi->text.cursor_position--;
1093 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1095 else if (key == KSYM_Delete && cursor_pos < text_length)
1097 strcpy(text, gi->text.value);
1098 strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
1099 DrawGadget(gi, DG_PRESSED, DG_DIRECT);
1101 else if (key == KSYM_Return)
1103 CheckRangeOfNumericInputGadget(gi);
1104 DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
1106 gi->event.type = GD_EVENT_TEXT_RETURN;
1108 if (gi->event_mask & GD_EVENT_TEXT_RETURN)
1109 gi->callback_action(gi);