added code for overlay touch buttons (currently not used)
authorHolger Schemel <info@artsoft.org>
Thu, 19 Sep 2019 17:19:37 +0000 (19:19 +0200)
committerHolger Schemel <info@artsoft.org>
Thu, 19 Sep 2019 17:19:37 +0000 (19:19 +0200)
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.

src/events.c
src/init.c
src/libgame/gadgets.c
src/libgame/gadgets.h
src/libgame/sdl.c

index 6054f74097006ca8d9b0140424f867b71b173da2..32f7177964af22b746b8c6727cd23d207f96a5da 100644 (file)
@@ -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))
index a022f3944ab4858500e60a9021175b0935ae3dc7..409858ca45e0c4e670534c8ecaa01076e719009a 100644 (file)
@@ -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
index 0295eec69a48d1b4cabfb4d08c44fe76bc4d1519..1004199f40d45bdd9cf405ca4398a71f1e75d045 100644 (file)
@@ -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;
 
index 17fccafad3a36a51ea5aeed663c05c97bd742af8..9f2d6e2408aa36cb5e0d204ac98bd24a30b01454 100644 (file)
 #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);
index 5b43d6c8e54d48f62a8aad41750539a7bb8863c0..1184acd84a4b227af94424e920b8b201bdb42344 100644 (file)
@@ -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