X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fgadgets.c;h=57de63e72a36c581eb0a818a86fe301794d1817c;hb=2c89261a1186ffc19bd6e5f82e9369bee1545e2f;hp=aacadafad4cfec7fd7d80e42199eae8294ebc91b;hpb=c781e660ed2fe6ad36c9eee0a77d64ee07163030;p=rocksndiamonds.git diff --git a/src/libgame/gadgets.c b/src/libgame/gadgets.c index aacadafa..57de63e7 100644 --- a/src/libgame/gadgets.c +++ b/src/libgame/gadgets.c @@ -358,8 +358,9 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) /* gadget text value */ DrawTextToTextArea(gi->x + border_x, gi->y + border_y, - gi->textarea.value, font_nr, - gi->textarea.xsize, gi->textarea.ysize); + gi->textarea.value, font_nr, gi->textarea.xsize, + gi->textarea.xsize, gi->textarea.ysize, + BLIT_ON_BACKGROUND); cursor_letter = gi->textarea.value[gi->textarea.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); @@ -551,15 +552,15 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) { gi->selectbox.open = FALSE; - /* redraw closed selectbox */ - DrawGadget(gi, FALSE, FALSE); - /* restore background under selectbox */ BlitBitmap(gfx.field_save_buffer, drawto, gi->selectbox.x, gi->selectbox.y, gi->selectbox.width, gi->selectbox.height, gi->selectbox.x, gi->selectbox.y); + /* redraw closed selectbox */ + DrawGadget(gi, FALSE, FALSE); + redraw_selectbox = TRUE; } } @@ -588,7 +589,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) xpos, ypos); /* middle part of gadget */ - for (i=0; ibitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, design_body, @@ -635,7 +636,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) xpos, ypos); /* middle part of gadget */ - for (i=0; ibitmap, drawto, gd->x + gi->border.xsize, gd->y, design_body, gi->height, @@ -680,6 +681,22 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3); } +static int get_minimal_size_for_numeric_input(int minmax_value) +{ + int min_size = 1; /* value needs at least one digit */ + int i; + + /* add number of digits needed for absolute value */ + for (i = 10; i <= ABS(minmax_value); i *= 10) + min_size++; + + /* if min/max value is negative, add one digit for minus sign */ + if (minmax_value < 0) + min_size++; + + return min_size; +} + static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { int tag = first_tag; @@ -759,6 +776,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) case GDI_NUMBER_VALUE: gi->textinput.number_value = va_arg(ap, long); sprintf(gi->textinput.value, "%d", gi->textinput.number_value); + strcpy(gi->textinput.last_value, gi->textinput.value); gi->textinput.cursor_position = strlen(gi->textinput.value); break; @@ -768,6 +786,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { gi->textinput.number_value = gi->textinput.number_min; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); + strcpy(gi->textinput.last_value, gi->textinput.value); } break; @@ -777,6 +796,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { gi->textinput.number_value = gi->textinput.number_max; sprintf(gi->textinput.value, "%d", gi->textinput.number_value); + strcpy(gi->textinput.last_value, gi->textinput.value); } break; @@ -788,12 +808,15 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE - 1); strncpy(gi->textinput.value, va_arg(ap, char *), max_textsize); + strcpy(gi->textinput.last_value, gi->textinput.value); + gi->textinput.value[max_textsize] = '\0'; gi->textinput.cursor_position = strlen(gi->textinput.value); /* same tag also used for other gadget definitions */ strcpy(gi->textbutton.value, gi->textinput.value); strcpy(gi->textarea.value, gi->textinput.value); + strcpy(gi->textarea.last_value, gi->textinput.value); } break; @@ -804,10 +827,17 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->textinput.size = max_textsize; gi->textinput.value[max_textsize] = '\0'; + strcpy(gi->textinput.last_value, gi->textinput.value); /* same tag also used for other gadget definitions */ - strcpy(gi->textbutton.value, gi->textinput.value); - gi->textbutton.size = gi->textinput.size; + + gi->textarea.size = max_textsize; + gi->textarea.value[max_textsize] = '\0'; + strcpy(gi->textarea.last_value, gi->textinput.value); + + gi->textbutton.size = max_textsize; + gi->textbutton.value[max_textsize] = '\0'; + gi->selectbox.size = gi->textinput.size; } break; @@ -984,6 +1014,19 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; + if (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC) + { + int number_min = gi->textinput.number_min; + int number_max = gi->textinput.number_max; + int min_size_min = get_minimal_size_for_numeric_input(number_min); + int min_size_max = get_minimal_size_for_numeric_input(number_max); + int min_size = MAX(min_size_min, min_size_max); + + /* expand gadget text input size, if maximal value is too large */ + if (gi->textinput.size < min_size) + gi->textinput.size = min_size; + } + gi->width = 2 * border_xsize + (gi->textinput.size + 1) * font_width; gi->height = 2 * border_ysize + font_height; } @@ -1058,16 +1101,23 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) if (gi->type & GD_TYPE_SCROLLBAR) { struct GadgetScrollbar *gs = &gi->scrollbar; + int scrollbar_size_cmp; if (gi->width == 0 || gi->height == 0 || gs->items_max == 0 || gs->items_visible == 0) Error(ERR_EXIT, "scrollbar gadget incomplete (missing tags)"); /* calculate internal scrollbar values */ + gs->size_min = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? + gi->width : gi->height); gs->size_max = (gi->type == GD_TYPE_SCROLLBAR_VERTICAL ? gi->height : gi->width); - gs->size = gs->size_max * gs->items_visible / gs->items_max; - gs->position = gs->size_max * gs->item_position / gs->items_max; + + scrollbar_size_cmp = gs->size_max * gs->items_visible / gs->items_max; + gs->size = MAX(scrollbar_size_cmp, gs->size_min); + gs->size_max_cmp = (gs->size_max - (gs->size - scrollbar_size_cmp)); + + gs->position = gs->size_max_cmp * gs->item_position / gs->items_max; gs->position_max = gs->size_max - gs->size; gs->correction = gs->size_max / gs->items_max / 2; @@ -1281,6 +1331,22 @@ static boolean anySelectboxGadgetActive() return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped); } +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); +} + +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); +} + boolean anyTextGadgetActive() { return (anyTextInputGadgetActive() || @@ -1290,6 +1356,9 @@ boolean anyTextGadgetActive() void ClickOnGadget(struct GadgetInfo *gi, int button) { + if (!gi->mapped) + return; + /* simulate releasing mouse button over last gadget, if still pressed */ if (button_status) HandleGadgets(-1, -1, 0); @@ -1301,19 +1370,25 @@ void ClickOnGadget(struct GadgetInfo *gi, int button) HandleGadgets(gi->x, gi->y, 0); } -void HandleGadgets(int mx, int my, int button) +boolean HandleGadgets(int mx, int my, int button) { static struct GadgetInfo *last_info_gi = NULL; static unsigned long pressed_delay = 0; static int last_button = 0; static int last_mx = 0, last_my = 0; + static int pressed_mx = 0, pressed_my = 0; int scrollbar_mouse_pos = 0; struct GadgetInfo *new_gi, *gi; boolean press_event; boolean release_event; boolean mouse_moving; + boolean mouse_inside_select_line; + boolean mouse_inside_select_area; + boolean mouse_released_where_pressed; boolean gadget_pressed; boolean gadget_pressed_repeated; + boolean gadget_pressed_off_borders; + boolean gadget_pressed_inside_select_line; boolean gadget_moving; boolean gadget_moving_inside; boolean gadget_moving_off_borders; @@ -1326,7 +1401,7 @@ void HandleGadgets(int mx, int my, int button) /* check if there are any gadgets defined */ if (gadget_list_first_entry == NULL) - return; + return FALSE; /* simulated release of mouse button over last gadget */ if (mx == -1 && my == -1 && button == 0) @@ -1348,20 +1423,69 @@ void HandleGadgets(int mx, int my, int button) last_mx = mx; last_my = my; + if (press_event && new_gi != last_gi) + { + pressed_mx = mx; + pressed_my = my; + } + + mouse_released_where_pressed = + (release_event && mx == pressed_mx && my == pressed_my); + + mouse_inside_select_line = insideSelectboxLine(new_gi, mx, my); + mouse_inside_select_area = insideSelectboxArea(new_gi, mx, my); + + gadget_pressed_off_borders = (press_event && new_gi != last_gi); + + gadget_pressed_inside_select_line = + (press_event && new_gi != NULL && + new_gi->type & GD_TYPE_SELECTBOX && new_gi->selectbox.open && + insideSelectboxLine(new_gi, mx, my)); + /* if mouse button pressed outside text or selectbox gadget, deactivate it */ +#if 1 + if (anyTextGadgetActive() && + (gadget_pressed_off_borders || + (gadget_pressed_inside_select_line && !mouse_inside_select_area))) +#else if (anyTextGadgetActive() && button != 0 && !motion_status && new_gi != last_gi) +#endif { - CheckRangeOfNumericInputGadget(last_gi); /* in case of numeric gadget */ + struct GadgetInfo *gi = last_gi; + boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_LEAVING); + + /* check if text gadget has changed its value */ + if (gi->type & GD_TYPE_TEXT_INPUT) + { + CheckRangeOfNumericInputGadget(gi); + + if (strcmp(gi->textinput.value, gi->textinput.last_value) != 0) + strcpy(gi->textinput.last_value, gi->textinput.value); + else + gadget_changed = FALSE; + } - DrawGadget(last_gi, DG_UNPRESSED, last_gi->direct_draw); + /* selectbox does not change its value when closed by clicking outside */ + if (gi->type & GD_TYPE_SELECTBOX) + gadget_changed = FALSE; - last_gi->event.type = GD_EVENT_TEXT_LEAVING; + DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); - if (last_gi->event_mask & GD_EVENT_TEXT_LEAVING) - last_gi->callback_action(last_gi); + gi->event.type = GD_EVENT_TEXT_LEAVING; + +#if 1 + if (gadget_changed && !(gi->type & GD_TYPE_SELECTBOX)) + gi->callback_action(gi); +#else + if (gi->event_mask & GD_EVENT_TEXT_LEAVING) + gi->callback_action(gi); +#endif last_gi = NULL; + + if (gadget_pressed_inside_select_line) + new_gi = NULL; } gadget_pressed = @@ -1382,12 +1506,17 @@ void HandleGadgets(int mx, int my, int button) { struct GadgetInfo *gi = last_gi; +#if 1 + gadget_released_inside_select_line = insideSelectboxLine(gi, mx, my); + gadget_released_inside_select_area = insideSelectboxArea(gi, mx, my); +#else gadget_released_inside_select_line = (mx >= gi->x && mx < gi->x + gi->width && my >= gi->y && my < gi->y + gi->height); gadget_released_inside_select_area = (mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width && my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height); +#endif } else { @@ -1410,12 +1539,23 @@ void HandleGadgets(int mx, int my, int button) /* if mouse button released, no gadget needs to be handled anymore */ if (gadget_released) { - if (last_gi->type & GD_TYPE_SELECTBOX && +#if 1 + if (gi->type & GD_TYPE_SELECTBOX && + (mouse_released_where_pressed || + !gadget_released_inside_select_area)) /* selectbox stays open */ + { + gi->selectbox.stay_open = TRUE; + pressed_mx = 0; + pressed_my = 0; + } +#else + if (gi->type & GD_TYPE_SELECTBOX && (gadget_released_inside_select_line || gadget_released_off_borders)) /* selectbox stays open */ gi->selectbox.stay_open = TRUE; - else if (!(last_gi->type & GD_TYPE_TEXT_INPUT || - last_gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ +#endif + else if (!(gi->type & GD_TYPE_TEXT_INPUT || + gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ last_gi = NULL; } @@ -1469,7 +1609,7 @@ void HandleGadgets(int mx, int my, int button) if (gi->textarea.cursor_position != old_cursor_position) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } - else if (gi->type & GD_TYPE_SELECTBOX) + else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open) { int old_index = gi->selectbox.current_index; @@ -1590,7 +1730,7 @@ void HandleGadgets(int mx, int my, int button) /* don't handle this scrollbar anymore while mouse button pressed */ last_gi = NULL; - return; + return TRUE; } } @@ -1656,7 +1796,7 @@ void HandleGadgets(int mx, int my, int button) gs->position = gs->position_max; gs->item_position = - gs->items_max * (gs->position + gs->correction) / gs->size_max; + gs->items_max * (gs->position + gs->correction) / gs->size_max_cmp; if (gs->item_position < 0) gs->item_position = 0; @@ -1685,14 +1825,29 @@ void HandleGadgets(int mx, int my, int button) if (gadget_released_inside) { boolean deactivate_gadget = TRUE; + boolean gadget_changed = TRUE; if (gi->type & GD_TYPE_SELECTBOX) { +#if 1 + if (mouse_released_where_pressed || + !gadget_released_inside_select_area) /* selectbox stays open */ + { + deactivate_gadget = FALSE; + gadget_changed = FALSE; + } +#else if (gadget_released_inside_select_line || - gadget_released_off_borders) /* selectbox stays open */ + gadget_released_off_borders) /* selectbox stays open */ + { deactivate_gadget = FALSE; - else + gadget_changed = FALSE; + } +#endif + else if (gi->selectbox.index != gi->selectbox.current_index) gi->selectbox.index = gi->selectbox.current_index; + else + gadget_changed = FALSE; } if (deactivate_gadget && @@ -1703,8 +1858,15 @@ void HandleGadgets(int mx, int my, int button) gi->state = GD_BUTTON_UNPRESSED; gi->event.type = GD_EVENT_RELEASED; +#if 1 + if ((gi->event_mask & GD_EVENT_RELEASED) && gadget_changed) + { + gi->callback_action(gi); + } +#else if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget) gi->callback_action(gi); +#endif } if (gadget_released_off_borders) @@ -1722,6 +1884,9 @@ void HandleGadgets(int mx, int my, int button) /* handle gadgets unmapped/mapped between pressing and releasing */ if (release_event && !gadget_released && new_gi) new_gi->state = GD_BUTTON_UNPRESSED; + + return (gadget_pressed || gadget_pressed_repeated || + gadget_released || gadget_moving); } static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) @@ -1739,7 +1904,7 @@ static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); } -void HandleGadgetsKeyInput(Key key) +boolean HandleGadgetsKeyInput(Key key) { struct GadgetInfo *gi = last_gi; @@ -1747,14 +1912,28 @@ void HandleGadgetsKeyInput(Key key) !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA || gi->type & GD_TYPE_SELECTBOX)) - return; + return FALSE; if (key == KSYM_Return) /* valid for both text input and selectbox */ { + boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_RETURN); + if (gi->type & GD_TYPE_TEXT_INPUT) + { CheckRangeOfNumericInputGadget(gi); + + if (strcmp(gi->textinput.value, gi->textinput.last_value) != 0) + strcpy(gi->textinput.last_value, gi->textinput.value); + else + gadget_changed = FALSE; + } else if (gi->type & GD_TYPE_SELECTBOX) - gi->selectbox.index = gi->selectbox.current_index; + { + if (gi->selectbox.index != gi->selectbox.current_index) + gi->selectbox.index = gi->selectbox.current_index; + else + gadget_changed = FALSE; + } if (gi->type & GD_TYPE_TEXT_AREA) { @@ -1771,8 +1950,13 @@ void HandleGadgetsKeyInput(Key key) last_gi = NULL; } +#if 1 + if (gadget_changed) + gi->callback_action(gi); +#else if (gi->event_mask & GD_EVENT_TEXT_RETURN) gi->callback_action(gi); +#endif } else if (gi->type & GD_TYPE_TEXT_INPUT) /* only valid for text input */ { @@ -1899,4 +2083,6 @@ void HandleGadgetsKeyInput(Key key) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } + + return TRUE; }