X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fgadgets.c;h=b21ecdca09607e9afb25eb4dec7f1fb8ad302e19;hp=4ac2a294202b249eb88fc6831dc7b0c623fd6d6b;hb=1477a6b1b3a60b5a3b5ef82eb1e61b7df0984249;hpb=359536f46007d1b9148bed9c529056faa91b8aab diff --git a/src/libgame/gadgets.c b/src/libgame/gadgets.c index 4ac2a294..b21ecdca 100644 --- a/src/libgame/gadgets.c +++ b/src/libgame/gadgets.c @@ -1,15 +1,13 @@ -/*********************************************************** -* Artsoft Retro-Game Library * -*----------------------------------------------------------* -* (c) 1994-2006 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* gadgets.c * -***********************************************************/ +// ============================================================================ +// Artsoft Retro-Game Library +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// gadgets.c +// ============================================================================ #include #include @@ -26,6 +24,16 @@ #define DG_BUFFERED 0 #define DG_DIRECT 1 +#define GADGET_DEACTIVATED(g) ((g)->x < 0 || (g)->y < 0) + +#define OPTION_TEXT_SELECTABLE(g, t) \ + (t[0] != g->selectbox.char_unselectable && \ + t[0] != '\0' && \ + !strEqual(t, " ")) +#define CURRENT_OPTION_SELECTABLE(g) \ + OPTION_TEXT_SELECTABLE(g, g->selectbox.options[g->selectbox.current_index].text) + + static struct GadgetInfo *gadget_list_first_entry = NULL; static struct GadgetInfo *gadget_list_last_entry = NULL; static struct GadgetInfo *last_info_gi = NULL; @@ -88,6 +96,16 @@ static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my, boolean check_horizontal = (IS_WHEEL_BUTTON_HORIZONTAL(button) || GetKeyModState() & KMOD_Shift); + /* check for the first active scrollbar directly under the mouse pointer */ + for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) + { + if (gi->mapped && gi->active && + (gi->type & GD_TYPE_SCROLLBAR) && + mx >= gi->x && mx < gi->x + gi->width && + my >= gi->y && my < gi->y + gi->height) + return gi; + } + /* check for the first active scrollbar with matching mouse wheel area */ for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) { @@ -213,15 +231,24 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) case GD_TYPE_NORMAL_BUTTON: case GD_TYPE_CHECK_BUTTON: case GD_TYPE_RADIO_BUTTON: + BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, gi->width, gi->height, gi->x, gi->y); + if (gi->deco.design.bitmap) + { + // make sure that decoration does not overlap gadget border + int deco_x = gi->deco.x + (pressed ? gi->deco.xshift : 0); + int deco_y = gi->deco.y + (pressed ? gi->deco.yshift : 0); + int deco_width = MIN(gi->deco.width, gi->width - deco_x); + int deco_height = MIN(gi->deco.height, gi->height - deco_y); + BlitBitmap(gi->deco.design.bitmap, drawto, gi->deco.design.x, gi->deco.design.y, - gi->deco.width, gi->deco.height, - gi->x + gi->deco.x + (pressed ? gi->deco.xshift : 0), - gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0)); + deco_width, deco_height, gi->x + deco_x, gi->y + deco_y); + } + break; case GD_TYPE_TEXT_BUTTON: @@ -381,16 +408,9 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->height - 2 * border_y); /* gadget text value */ -#if 1 DrawTextBuffer(gi->x + border_x, gi->y + border_y, gi->textarea.value, - font_nr, gi->textarea.xsize, 0, -1, gi->textarea.ysize, + font_nr, gi->textarea.xsize, -1, gi->textarea.ysize, 0, BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE); -#else - DrawTextToTextArea(gi->x + border_x, gi->y + border_y, - gi->textarea.value, font_nr, gi->textarea.xsize, - gi->textarea.xsize, gi->textarea.ysize, - BLIT_ON_BACKGROUND); -#endif cursor_letter = gi->textarea.value[gi->textarea.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); @@ -410,7 +430,8 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) { int i; char text[MAX_GADGET_TEXTSIZE + 1]; - int font_nr = (pressed ? gi->font_active : gi->font); + int font_nr_default = (pressed ? gi->font_active : gi->font); + int font_nr = font_nr_default; int font_width = getFontWidth(font_nr); int font_height = getFontHeight(font_nr); int border_x = gi->border.xsize; @@ -447,6 +468,10 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->selectbox.size); text[gi->selectbox.size] = '\0'; + /* set font value */ + font_nr = (OPTION_TEXT_SELECTABLE(gi, text) ? font_nr_default : + gi->font_unselectable); + /* gadget text value */ DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); @@ -555,7 +580,11 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); text[gi->selectbox.size] = '\0'; - if (i == gi->selectbox.current_index) + font_nr = (OPTION_TEXT_SELECTABLE(gi, text) ? font_nr_default : + gi->font_unselectable); + + if (i == gi->selectbox.current_index && + OPTION_TEXT_SELECTABLE(gi, text)) { FillRectangle(drawto, gi->selectbox.x + border_x, @@ -694,6 +723,10 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) return; } + // do not use direct gadget drawing anymore; this worked as a speed-up once, + // but would slow things down a lot now the screen is always fully redrawn + direct = FALSE; + if (direct) { BlitBitmap(drawto, window, @@ -706,9 +739,15 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->selectbox.x, gi->selectbox.y); } else - redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD : - gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 : - gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3); + { + int x = gi->x; + int y = gi->y; + + redraw_mask |= (IN_GFX_FIELD_FULL(x, y) ? REDRAW_FIELD : + IN_GFX_DOOR_1(x, y) ? REDRAW_DOOR_1 : + IN_GFX_DOOR_2(x, y) ? REDRAW_DOOR_2 : + IN_GFX_DOOR_3(x, y) ? REDRAW_DOOR_3 : REDRAW_ALL); + } } static int get_minimal_size_for_numeric_input(int minmax_value) @@ -873,12 +912,18 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->font = va_arg(ap, int); if (gi->font_active == 0) gi->font_active = gi->font; + if (gi->font_unselectable == 0) + gi->font_unselectable = gi->font; break; case GDI_TEXT_FONT_ACTIVE: gi->font_active = va_arg(ap, int); break; + case GDI_TEXT_FONT_UNSELECTABLE: + gi->font_unselectable = va_arg(ap, int); + break; + case GDI_SELECTBOX_OPTIONS: gi->selectbox.options = va_arg(ap, struct ValueTextInfo *); break; @@ -887,6 +932,10 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->selectbox.index = va_arg(ap, int); break; + case GDI_SELECTBOX_CHAR_UNSELECTABLE: + gi->selectbox.char_unselectable = (char)va_arg(ap, int); + break; + case GDI_DESIGN_UNPRESSED: gi->design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *); gi->design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int); @@ -954,14 +1003,12 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->drawing.area_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ - if (gi->width == 0 && gi->height == 0 && - gi->drawing.item_xsize !=0 && gi->drawing.item_ysize !=0) + if (gi->drawing.item_xsize != 0 && gi->drawing.item_ysize != 0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } - else if (gi->drawing.item_xsize == 0 && gi->drawing.item_ysize == 0 && - gi->width != 0 && gi->height != 0) + else if (gi->width != 0 && gi->height != 0) { gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize; gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize; @@ -984,14 +1031,12 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->drawing.item_ysize = va_arg(ap, int); /* determine dependent values for drawing area gadget, if needed */ - if (gi->width == 0 && gi->height == 0 && - gi->drawing.area_xsize !=0 && gi->drawing.area_ysize !=0) + if (gi->drawing.area_xsize != 0 && gi->drawing.area_ysize != 0) { gi->width = gi->drawing.area_xsize * gi->drawing.item_xsize; gi->height = gi->drawing.area_ysize * gi->drawing.item_ysize; } - else if (gi->drawing.area_xsize == 0 && gi->drawing.area_ysize == 0 && - gi->width != 0 && gi->height != 0) + else if (gi->width != 0 && gi->height != 0) { gi->drawing.area_xsize = gi->width / gi->drawing.item_xsize; gi->drawing.area_ysize = gi->height / gi->drawing.item_ysize; @@ -1248,6 +1293,9 @@ void FreeGadget(struct GadgetInfo *gi) { struct GadgetInfo *gi_previous = gadget_list_first_entry; + if (gi == NULL) + return; + /* prevent "last_info_gi" from pointing to memory that will be freed */ if (last_info_gi == gi) last_info_gi = NULL; @@ -1292,7 +1340,7 @@ static struct GadgetInfo *last_gi = NULL; static void MapGadgetExt(struct GadgetInfo *gi, boolean redraw) { - if (gi == NULL || gi->mapped) + if (gi == NULL || gi->mapped || GADGET_DEACTIVATED(gi)) return; gi->mapped = TRUE; @@ -1324,9 +1372,11 @@ void UnmapGadget(struct GadgetInfo *gi) #define MULTIMAP_PLAYFIELD (1 << 3) #define MULTIMAP_DOOR_1 (1 << 4) #define MULTIMAP_DOOR_2 (1 << 5) +#define MULTIMAP_DOOR_3 (1 << 6) #define MULTIMAP_ALL (MULTIMAP_PLAYFIELD | \ - MULTIMAP_DOOR_1 | \ - MULTIMAP_DOOR_2) + MULTIMAP_DOOR_1 | \ + MULTIMAP_DOOR_2 | \ + MULTIMAP_DOOR_3) static void MultiMapGadgets(int mode) { @@ -1336,12 +1386,13 @@ static void MultiMapGadgets(int mode) while (gi != NULL) { - if ((mode & MULTIMAP_PLAYFIELD && - gi->x < gfx.sx + gfx.sxsize) || - (mode & MULTIMAP_DOOR_1 && - gi->x >= gfx.dx && gi->y < gfx.dy + gfx.dysize) || - (mode & MULTIMAP_DOOR_2 && - gi->x >= gfx.dx && gi->y > gfx.dy + gfx.dysize) || + int x = gi->x; + int y = gi->y; + + if ((mode & MULTIMAP_PLAYFIELD && IN_GFX_FIELD_FULL(x, y)) || + (mode & MULTIMAP_DOOR_1 && IN_GFX_DOOR_1(x, y)) || + (mode & MULTIMAP_DOOR_2 && IN_GFX_DOOR_2(x, y)) || + (mode & MULTIMAP_DOOR_3 && IN_GFX_DOOR_3(x, y)) || (mode & MULTIMAP_ALL) == MULTIMAP_ALL) { if (mode & MULTIMAP_UNMAP) @@ -1399,18 +1450,18 @@ boolean anyTextGadgetActive() static boolean insideSelectboxLine(struct GadgetInfo *gi, int mx, int my) { - return(gi != NULL && - gi->type & GD_TYPE_SELECTBOX && - mx >= gi->x && mx < gi->x + gi->width && - my >= gi->y && my < gi->y + gi->height); + return (gi != NULL && + gi->type & GD_TYPE_SELECTBOX && + mx >= gi->x && mx < gi->x + gi->width && + my >= gi->y && my < gi->y + gi->height); } static boolean insideSelectboxArea(struct GadgetInfo *gi, int mx, int my) { - return(gi != NULL && - gi->type & GD_TYPE_SELECTBOX && - mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && - my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height); + return (gi != NULL && + gi->type & GD_TYPE_SELECTBOX && + mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && + my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height); } void ClickOnGadget(struct GadgetInfo *gi, int button) @@ -1431,8 +1482,8 @@ void ClickOnGadget(struct GadgetInfo *gi, int button) boolean HandleGadgets(int mx, int my, int button) { - static unsigned long pressed_delay = 0; - static unsigned long pressed_delay_value = GADGET_FRAME_DELAY; + static unsigned int pressed_delay = 0; + static unsigned int pressed_delay_value = GADGET_FRAME_DELAY; static int last_button = 0; static int last_mx = 0, last_my = 0; static int pressed_mx = 0, pressed_my = 0; @@ -1458,7 +1509,6 @@ boolean HandleGadgets(int mx, int my, int button) boolean gadget_dragging; boolean gadget_released; boolean gadget_released_inside; - boolean gadget_released_inside_select_line; boolean gadget_released_inside_select_area; boolean gadget_released_off_borders; boolean changed_position = FALSE; @@ -1560,15 +1610,9 @@ boolean HandleGadgets(int mx, int my, int button) /* when handling selectbox, set additional state values */ if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX)) - { - gadget_released_inside_select_line = insideSelectboxLine(last_gi, mx, my); gadget_released_inside_select_area = insideSelectboxArea(last_gi, mx, my); - } else - { - gadget_released_inside_select_line = FALSE; gadget_released_inside_select_area = FALSE; - } /* setting state for handling over-large selectbox */ if (keep_selectbox_open && (press_event || !mouse_inside_select_line)) @@ -1592,7 +1636,8 @@ boolean HandleGadgets(int mx, int my, int button) if (gi->type & GD_TYPE_SELECTBOX && (keep_selectbox_open || mouse_released_where_pressed || - !gadget_released_inside_select_area)) /* selectbox stays open */ + !gadget_released_inside_select_area || + !CURRENT_OPTION_SELECTABLE(gi))) /* selectbox stays open */ { gi->selectbox.stay_open = TRUE; pressed_mx = 0; @@ -1753,7 +1798,7 @@ boolean HandleGadgets(int mx, int my, int button) { boolean scroll_single_step = ((GetKeyModState() & KMOD_Alt) != 0); - item_steps = (scroll_single_step ? 1 : DEFAULT_WHEEL_STEPS); + item_steps = (scroll_single_step ? 1 : wheel_steps); item_direction = (button == MB_WHEEL_UP || button == MB_WHEEL_LEFT ? -1 : +1); } @@ -1950,7 +1995,8 @@ boolean HandleGadgets(int mx, int my, int button) { if (keep_selectbox_open || mouse_released_where_pressed || - !gadget_released_inside_select_area) /* selectbox stays open */ + !gadget_released_inside_select_area || + !CURRENT_OPTION_SELECTABLE(gi)) /* selectbox stays open */ { deactivate_gadget = FALSE; gadget_changed = FALSE;