From: Holger Schemel Date: Thu, 19 Sep 2019 17:19:37 +0000 (+0200) Subject: added code for overlay touch buttons (currently not used) X-Git-Tag: 4.1.4.0~11 X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=commitdiff_plain;h=f73405762b7a66ebed17c0f6fa56e909d7e5626f added code for overlay touch buttons (currently not used) This adds support for overlay touch buttons to be used with the Android port, to address the following problems: * Especially when playing on smartphones, the display may be too small to use the most essential buttons, like the "yes" and "no" buttons of the door request dialog, or the "stop" and "pause" buttons on the game panel. * Additionally, the most important game panel buttons (again, mainly the "stop" and "pause" buttons) may not be accessible at all because of being covered by virtual buttons. * When configuring virtual buttons using recent Android versions, navigating to the next page is not possible anymore, because there is no "menu" button anymore. This was a hardware button opposite to the "back" button, so the "menu" and "back" buttons could be used to navigate to the next or previous page when configuring virtual buttons. * When thinking about a potential iOS port of the game, there is not even a "back" button (like on Android devices), so it is even more difficult to stop playing a game (as the "stop" button has to be touched instead of just hitting the "back" button, which simply does not exist on iOS devices). The next steps will be to use overlay touch buttons to solve some or all of the above problems. --- diff --git a/src/events.c b/src/events.c index 6054f740..32f71779 100644 --- a/src/events.c +++ b/src/events.c @@ -653,6 +653,7 @@ void HandleWindowEvent(WindowEvent *event) video.display_height = new_display_height; SDLSetScreenProperties(); + SetGadgetsPosition_OverlayTouchButtons(); // check if screen orientation has changed (should always be true here) if (nr != GRID_ACTIVE_NR()) @@ -1684,6 +1685,10 @@ void HandleButton(int mx, int my, int button, int button_nr) // always recognize potentially releasing already pressed gadgets if (button == MB_RELEASED) handle_gadgets = TRUE; + + // always recognize pressing or releasing overlay touch buttons + if (CheckPosition_OverlayTouchButtons(mx, my, button) && !motion_status) + handle_gadgets = TRUE; #endif if (HandleGlobalAnimClicks(mx, my, button, FALSE)) diff --git a/src/init.c b/src/init.c index a022f394..409858ca 100644 --- a/src/init.c +++ b/src/init.c @@ -275,6 +275,10 @@ static void InitBitmapPointers(void) void InitImageTextures(void) { + static int texture_graphics[] = + { + -1 + }; int i, j, k; FreeAllImageTextures(); @@ -300,6 +304,9 @@ void InitImageTextures(void) } } } + + for (i = 0; texture_graphics[i] > -1; i++) + CreateImageTextures(texture_graphics[i]); } #if 1 diff --git a/src/libgame/gadgets.c b/src/libgame/gadgets.c index 0295eec6..1004199f 100644 --- a/src/libgame/gadgets.c +++ b/src/libgame/gadgets.c @@ -228,6 +228,9 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) if (gi == NULL || gi->deactivated) return; + if (gi->overlay_touch_button) // will be drawn later (as texture) + return; + gd = (!gi->active ? &gi->alt_design[state] : gi->checked ? &gi->alt_design[state] : &gi->design[state]); @@ -762,6 +765,99 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) } } +static void SetGadgetPosition_OverlayTouchButton(struct GadgetInfo *gi) +{ + gi->x = gi->orig_x; + gi->y = gi->orig_y; + + if (gi->x < 0) + gi->x += video.screen_width; + if (gi->y < 0) + gi->y += video.screen_height; + + gi->x -= video.screen_xoffset; + gi->y -= video.screen_yoffset; +} + +void SetGadgetsPosition_OverlayTouchButtons(void) +{ + struct GadgetInfo *gi; + + if (gadget_list_first_entry == NULL) + return; + + for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) + if (gi->overlay_touch_button) + SetGadgetPosition_OverlayTouchButton(gi); +} + +static void DrawGadget_OverlayTouchButton(struct GadgetInfo *gi) +{ + struct GadgetDesign *gd; + int state = (gi->state ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED); + + if (gi == NULL || gi->deactivated) + return; + + gd = (!gi->active ? &gi->alt_design[state] : + gi->checked ? &gi->alt_design[state] : &gi->design[state]); + + int x = gi->x + video.screen_xoffset; + int y = gi->y + video.screen_yoffset; + int alpha = gi->overlay_touch_button_alpha; + int alpha_max = SDL_ALPHA_OPAQUE; + int alpha_step = ALPHA_FADING_STEPSIZE(alpha_max); + + if (gi->mapped) + { + if (alpha < alpha_max) + alpha = MIN(alpha + alpha_step, alpha_max); + } + else + { + alpha = MAX(0, alpha - alpha_step); + } + + gi->overlay_touch_button_alpha = alpha; + + if (alpha == 0) + return; + + switch (gi->type) + { + case GD_TYPE_NORMAL_BUTTON: + case GD_TYPE_CHECK_BUTTON: + case GD_TYPE_RADIO_BUTTON: + SDL_SetTextureAlphaMod(gd->bitmap->texture_masked, alpha); + SDL_SetTextureBlendMode(gd->bitmap->texture_masked, SDL_BLENDMODE_BLEND); + + BlitToScreenMasked(gd->bitmap, gd->x, gd->y, gi->width, gi->height, x, y); + break; + + default: + return; + } +} + +void DrawGadgets_OverlayTouchButtons(void) +{ + struct GadgetInfo *gi; + + if (gadget_list_first_entry == NULL) + return; + + for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next) + if (gi->overlay_touch_button) + DrawGadget_OverlayTouchButton(gi); +} + +boolean CheckPosition_OverlayTouchButtons(int mx, int my, int button) +{ + struct GadgetInfo *gi = getGadgetInfoFromMousePosition(mx, my, button); + + return (gi != NULL && gi->overlay_touch_button); +} + static int get_minimal_size_for_numeric_input(int minmax_value) { int min_size = 1; // value needs at least one digit @@ -816,11 +912,11 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) break; case GDI_X: - gi->x = va_arg(ap, int); + gi->x = gi->orig_x = va_arg(ap, int); break; case GDI_Y: - gi->y = va_arg(ap, int); + gi->y = gi->orig_y = va_arg(ap, int); break; case GDI_WIDTH: @@ -847,6 +943,12 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->direct_draw = (boolean)va_arg(ap, int); break; + case GDI_OVERLAY_TOUCH_BUTTON: + gi->overlay_touch_button = (boolean)va_arg(ap, int); + if (gi->overlay_touch_button) + SetGadgetPosition_OverlayTouchButton(gi); + break; + case GDI_CALLBACK_ACTION_ALWAYS: gi->callback_action_always = (boolean)va_arg(ap, int); break; @@ -1118,8 +1220,8 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->design[GD_BUTTON_PRESSED].bitmap == NULL)) gi->deactivated = TRUE; - // check if gadget is placed off-screen - if (gi->x < 0 || gi->y < 0) + // check if gadget is placed off-screen (and is no overlay touch button) + if ((gi->x < 0 || gi->y < 0) && !gi->overlay_touch_button) gi->deactivated = TRUE; // adjust gadget values in relation to other gadget values @@ -1301,6 +1403,8 @@ struct GadgetInfo *CreateGadget(int first_tag, ...) new_gadget->callback_action = default_callback_action; new_gadget->active = TRUE; new_gadget->direct_draw = TRUE; + new_gadget->overlay_touch_button = FALSE; + new_gadget->overlay_touch_button_alpha = 0; new_gadget->next = NULL; diff --git a/src/libgame/gadgets.h b/src/libgame/gadgets.h index 17fccafa..9f2d6e24 100644 --- a/src/libgame/gadgets.h +++ b/src/libgame/gadgets.h @@ -112,7 +112,8 @@ #define GDI_INFO_TEXT 48 #define GDI_ACTIVE 49 #define GDI_DIRECT_DRAW 50 -#define GDI_CALLBACK_ACTION_ALWAYS 51 +#define GDI_OVERLAY_TOUCH_BUTTON 51 +#define GDI_CALLBACK_ACTION_ALWAYS 52 // gadget deactivation hack #define GDI_ACTIVE_POS(a) ((a) < 0 ? POS_OFFSCREEN : (a)) @@ -237,6 +238,7 @@ struct GadgetInfo int custom_type_id; // custom gadget type identifier char info_text[MAX_INFO_TEXTSIZE + 1];// short popup info text int x, y; // gadget position + int orig_x, orig_y; // gadget position (original) int width, height; // gadget size unsigned int type; // type (button, text input, ...) unsigned int state; // state (pressed, released, ...) @@ -245,6 +247,8 @@ struct GadgetInfo boolean mapped; // gadget is mapped on the screen boolean active; // gadget is active boolean direct_draw; // directly draw to frontbuffer + boolean overlay_touch_button; // gadget is overlay touch button + int overlay_touch_button_alpha; // overlay touch button alpha value boolean callback_action_always; // also callback if gadget unchanged int font; // font to use when inactive int font_active; // font to use when active @@ -282,6 +286,10 @@ void UnmapGadget(struct GadgetInfo *); void UnmapAllGadgets(void); void RemapAllGadgets(void); +void SetGadgetsPosition_OverlayTouchButtons(void); +void DrawGadgets_OverlayTouchButtons(void); +boolean CheckPosition_OverlayTouchButtons(int, int, int); + boolean anyTextInputGadgetActive(void); boolean anyTextAreaGadgetActive(void); boolean anySelectboxGadgetActive(void); diff --git a/src/libgame/sdl.c b/src/libgame/sdl.c index 5b43d6c8..1184acd8 100644 --- a/src/libgame/sdl.c +++ b/src/libgame/sdl.c @@ -14,6 +14,7 @@ #include "joystick.h" #include "misc.h" #include "setup.h" +#include "gadgets.h" #define ENABLE_UNUSED_CODE 0 // currently unused functions @@ -39,6 +40,7 @@ void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32); #if defined(USE_TOUCH_INPUT_OVERLAY) // functions to draw overlay graphics for touch device input static void DrawTouchInputOverlay(void); +static void DrawTouchGadgetsOverlay(void); #endif void SDLLimitScreenUpdates(boolean enable) @@ -212,6 +214,9 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay) #if defined(USE_TOUCH_INPUT_OVERLAY) // draw overlay graphics for touch device input, if needed DrawTouchInputOverlay(); + + // draw overlay gadgets for touch device input, if needed + DrawTouchGadgetsOverlay(); #endif // global synchronization point of the game to align video frame delay @@ -2948,4 +2953,9 @@ static void DrawTouchInputOverlay(void) DrawTouchInputOverlay_ShowGridButtons(alpha); } + +static void DrawTouchGadgetsOverlay(void) +{ + DrawGadgets_OverlayTouchButtons(); +} #endif