added scrolling any scrollbars under the mouse pointer with mouse wheel
[rocksndiamonds.git] / src / libgame / gadgets.c
index 9c07371bc31a7321e6422ea839f45133af95143f..75d0a8558970bcb8b2da5ba4f74ec5c4a25e85c2 100644 (file)
 
 #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;
@@ -89,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)
     {
@@ -382,16 +399,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, -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 : ' ');
@@ -411,7 +421,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;
@@ -448,6 +459,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);
@@ -556,7 +571,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,
@@ -695,6 +714,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,
@@ -708,7 +731,6 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
   }
   else
   {
-#if 1
     int x = gi->x;
     int y = gi->y;
 
@@ -716,11 +738,6 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                    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);
-#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);
-#endif
   }
 }
 
@@ -886,12 +903,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;
@@ -900,6 +923,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);
@@ -967,14 +994,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;
@@ -997,14 +1022,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;
@@ -1354,7 +1377,6 @@ static void MultiMapGadgets(int mode)
 
   while (gi != NULL)
   {
-#if 1
     int x = gi->x;
     int y = gi->y;
 
@@ -1363,15 +1385,6 @@ static void MultiMapGadgets(int mode)
        (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)
-#else
-    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) ||
-       (mode & MULTIMAP_ALL) == MULTIMAP_ALL)
-#endif
     {
       if (mode & MULTIMAP_UNMAP)
       {
@@ -1487,9 +1500,6 @@ boolean HandleGadgets(int mx, int my, int button)
   boolean gadget_dragging;
   boolean gadget_released;
   boolean gadget_released_inside;
-#if 0
-  boolean gadget_released_inside_select_line;
-#endif
   boolean gadget_released_inside_select_area;
   boolean gadget_released_off_borders;
   boolean changed_position = FALSE;
@@ -1591,19 +1601,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))
-  {
-#if 0
-    gadget_released_inside_select_line = insideSelectboxLine(last_gi, mx, my);
-#endif
     gadget_released_inside_select_area = insideSelectboxArea(last_gi, mx, my);
-  }
   else
-  {
-#if 0
-    gadget_released_inside_select_line = FALSE;
-#endif
     gadget_released_inside_select_area = FALSE;
-  }
 
   /* setting state for handling over-large selectbox */
   if (keep_selectbox_open && (press_event || !mouse_inside_select_line))
@@ -1627,7 +1627,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;
@@ -1788,7 +1789,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);
        }
@@ -1985,7 +1986,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;